1 //===-- RISCVMCExpr.cpp - RISCV specific MC expression classes ------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file contains the implementation of the assembly expression modifiers 11 // accepted by the RISCV architecture (e.g. ":lo12:", ":gottprel_g1:", ...). 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "RISCV.h" 16 #include "RISCVMCExpr.h" 17 #include "RISCVFixupKinds.h" 18 #include "llvm/MC/MCAssembler.h" 19 #include "llvm/MC/MCContext.h" 20 #include "llvm/MC/MCStreamer.h" 21 #include "llvm/MC/MCSymbolELF.h" 22 #include "llvm/MC/MCValue.h" 23 #include "llvm/Support/ErrorHandling.h" 24 25 using namespace llvm; 26 27 #define DEBUG_TYPE "riscvmcexpr" 28 29 const RISCVMCExpr *RISCVMCExpr::create(const MCExpr *Expr, VariantKind Kind, 30 MCContext &Ctx) { 31 return new (Ctx) RISCVMCExpr(Expr, Kind); 32 } 33 34 void RISCVMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const { 35 bool HasVariant = 36 ((getKind() != VK_RISCV_None) && (getKind() != VK_RISCV_CALL)); 37 if (HasVariant) 38 OS << '%' << getVariantKindName(getKind()) << '('; 39 Expr->print(OS, MAI); 40 if (HasVariant) 41 OS << ')'; 42 } 43 44 const MCFixup *RISCVMCExpr::getPCRelHiFixup() const { 45 MCValue AUIPCLoc; 46 if (!getSubExpr()->evaluateAsRelocatable(AUIPCLoc, nullptr, nullptr)) 47 return nullptr; 48 49 const MCSymbolRefExpr *AUIPCSRE = AUIPCLoc.getSymA(); 50 if (!AUIPCSRE) 51 return nullptr; 52 53 const auto *DF = 54 dyn_cast_or_null<MCDataFragment>(AUIPCSRE->findAssociatedFragment()); 55 if (!DF) 56 return nullptr; 57 58 const MCSymbol *AUIPCSymbol = &AUIPCSRE->getSymbol(); 59 for (const MCFixup &F : DF->getFixups()) { 60 if (F.getOffset() != AUIPCSymbol->getOffset()) 61 continue; 62 63 switch ((unsigned)F.getKind()) { 64 default: 65 continue; 66 case RISCV::fixup_riscv_pcrel_hi20: 67 return &F; 68 } 69 } 70 71 return nullptr; 72 } 73 74 bool RISCVMCExpr::evaluatePCRelLo(MCValue &Res, const MCAsmLayout *Layout, 75 const MCFixup *Fixup) const { 76 // VK_RISCV_PCREL_LO has to be handled specially. The MCExpr inside is 77 // actually the location of a auipc instruction with a VK_RISCV_PCREL_HI fixup 78 // pointing to the real target. We need to generate an MCValue in the form of 79 // (<real target> + <offset from this fixup to the auipc fixup>). The Fixup 80 // is pcrel relative to the VK_RISCV_PCREL_LO fixup, so we need to add the 81 // offset to the VK_RISCV_PCREL_HI Fixup from VK_RISCV_PCREL_LO to correct. 82 MCValue AUIPCLoc; 83 if (!getSubExpr()->evaluateAsValue(AUIPCLoc, *Layout)) 84 return false; 85 86 const MCSymbolRefExpr *AUIPCSRE = AUIPCLoc.getSymA(); 87 // Don't try to evaluate %pcrel_hi/%pcrel_lo pairs that cross fragment 88 // boundries. 89 if (!AUIPCSRE || 90 findAssociatedFragment() != AUIPCSRE->findAssociatedFragment()) 91 return false; 92 93 const MCSymbol *AUIPCSymbol = &AUIPCSRE->getSymbol(); 94 if (!AUIPCSymbol) 95 return false; 96 97 const MCFixup *TargetFixup = getPCRelHiFixup(); 98 if (!TargetFixup) 99 return false; 100 101 if ((unsigned)TargetFixup->getKind() != RISCV::fixup_riscv_pcrel_hi20) 102 return false; 103 104 MCValue Target; 105 if (!TargetFixup->getValue()->evaluateAsValue(Target, *Layout)) 106 return false; 107 108 if (!Target.getSymA() || !Target.getSymA()->getSymbol().isInSection()) 109 return false; 110 111 if (&Target.getSymA()->getSymbol().getSection() != 112 findAssociatedFragment()->getParent()) 113 return false; 114 115 uint64_t AUIPCOffset = AUIPCSymbol->getOffset(); 116 117 Res = MCValue::get(Target.getSymA(), nullptr, 118 Target.getConstant() + (Fixup->getOffset() - AUIPCOffset)); 119 return true; 120 } 121 122 bool RISCVMCExpr::evaluateAsRelocatableImpl(MCValue &Res, 123 const MCAsmLayout *Layout, 124 const MCFixup *Fixup) const { 125 if (Kind == VK_RISCV_PCREL_LO && evaluatePCRelLo(Res, Layout, Fixup)) 126 return true; 127 128 if (!getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup)) 129 return false; 130 131 // Some custom fixup types are not valid with symbol difference expressions 132 if (Res.getSymA() && Res.getSymB()) { 133 switch (getKind()) { 134 default: 135 return true; 136 case VK_RISCV_LO: 137 case VK_RISCV_HI: 138 case VK_RISCV_PCREL_LO: 139 case VK_RISCV_PCREL_HI: 140 return false; 141 } 142 } 143 144 return true; 145 } 146 147 void RISCVMCExpr::visitUsedExpr(MCStreamer &Streamer) const { 148 Streamer.visitUsedExpr(*getSubExpr()); 149 } 150 151 RISCVMCExpr::VariantKind RISCVMCExpr::getVariantKindForName(StringRef name) { 152 return StringSwitch<RISCVMCExpr::VariantKind>(name) 153 .Case("lo", VK_RISCV_LO) 154 .Case("hi", VK_RISCV_HI) 155 .Case("pcrel_lo", VK_RISCV_PCREL_LO) 156 .Case("pcrel_hi", VK_RISCV_PCREL_HI) 157 .Default(VK_RISCV_Invalid); 158 } 159 160 StringRef RISCVMCExpr::getVariantKindName(VariantKind Kind) { 161 switch (Kind) { 162 default: 163 llvm_unreachable("Invalid ELF symbol kind"); 164 case VK_RISCV_LO: 165 return "lo"; 166 case VK_RISCV_HI: 167 return "hi"; 168 case VK_RISCV_PCREL_LO: 169 return "pcrel_lo"; 170 case VK_RISCV_PCREL_HI: 171 return "pcrel_hi"; 172 } 173 } 174 175 bool RISCVMCExpr::evaluateAsConstant(int64_t &Res) const { 176 MCValue Value; 177 178 if (Kind == VK_RISCV_PCREL_HI || Kind == VK_RISCV_PCREL_LO || 179 Kind == VK_RISCV_CALL) 180 return false; 181 182 if (!getSubExpr()->evaluateAsRelocatable(Value, nullptr, nullptr)) 183 return false; 184 185 if (!Value.isAbsolute()) 186 return false; 187 188 Res = evaluateAsInt64(Value.getConstant()); 189 return true; 190 } 191 192 int64_t RISCVMCExpr::evaluateAsInt64(int64_t Value) const { 193 switch (Kind) { 194 default: 195 llvm_unreachable("Invalid kind"); 196 case VK_RISCV_LO: 197 return SignExtend64<12>(Value); 198 case VK_RISCV_HI: 199 // Add 1 if bit 11 is 1, to compensate for low 12 bits being negative. 200 return ((Value + 0x800) >> 12) & 0xfffff; 201 } 202 } 203