diff options
Diffstat (limited to 'llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp')
-rw-r--r-- | llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp | 172 |
1 files changed, 134 insertions, 38 deletions
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp index 5881a0a86ef7..bb1f1cc7f49a 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -9,6 +9,7 @@ #include "RISCVAsmBackend.h" #include "RISCVMCExpr.h" #include "llvm/ADT/APInt.h" +#include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDirectives.h" @@ -22,14 +23,75 @@ using namespace llvm; +Optional<MCFixupKind> RISCVAsmBackend::getFixupKind(StringRef Name) const { + if (STI.getTargetTriple().isOSBinFormatELF()) { + unsigned Type; + Type = llvm::StringSwitch<unsigned>(Name) +#define ELF_RELOC(X, Y) .Case(#X, Y) +#include "llvm/BinaryFormat/ELFRelocs/RISCV.def" +#undef ELF_RELOC + .Default(-1u); + if (Type != -1u) + return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type); + } + return None; +} + +const MCFixupKindInfo & +RISCVAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { + const static MCFixupKindInfo Infos[] = { + // This table *must* be in the order that the fixup_* kinds are defined in + // RISCVFixupKinds.h. + // + // name offset bits flags + {"fixup_riscv_hi20", 12, 20, 0}, + {"fixup_riscv_lo12_i", 20, 12, 0}, + {"fixup_riscv_lo12_s", 0, 32, 0}, + {"fixup_riscv_pcrel_hi20", 12, 20, + MCFixupKindInfo::FKF_IsPCRel | MCFixupKindInfo::FKF_IsTarget}, + {"fixup_riscv_pcrel_lo12_i", 20, 12, + MCFixupKindInfo::FKF_IsPCRel | MCFixupKindInfo::FKF_IsTarget}, + {"fixup_riscv_pcrel_lo12_s", 0, 32, + MCFixupKindInfo::FKF_IsPCRel | MCFixupKindInfo::FKF_IsTarget}, + {"fixup_riscv_got_hi20", 12, 20, MCFixupKindInfo::FKF_IsPCRel}, + {"fixup_riscv_tprel_hi20", 12, 20, 0}, + {"fixup_riscv_tprel_lo12_i", 20, 12, 0}, + {"fixup_riscv_tprel_lo12_s", 0, 32, 0}, + {"fixup_riscv_tprel_add", 0, 0, 0}, + {"fixup_riscv_tls_got_hi20", 12, 20, MCFixupKindInfo::FKF_IsPCRel}, + {"fixup_riscv_tls_gd_hi20", 12, 20, MCFixupKindInfo::FKF_IsPCRel}, + {"fixup_riscv_jal", 12, 20, MCFixupKindInfo::FKF_IsPCRel}, + {"fixup_riscv_branch", 0, 32, MCFixupKindInfo::FKF_IsPCRel}, + {"fixup_riscv_rvc_jump", 2, 11, MCFixupKindInfo::FKF_IsPCRel}, + {"fixup_riscv_rvc_branch", 0, 16, MCFixupKindInfo::FKF_IsPCRel}, + {"fixup_riscv_call", 0, 64, MCFixupKindInfo::FKF_IsPCRel}, + {"fixup_riscv_call_plt", 0, 64, MCFixupKindInfo::FKF_IsPCRel}, + {"fixup_riscv_relax", 0, 0, 0}, + {"fixup_riscv_align", 0, 0, 0}}; + static_assert((array_lengthof(Infos)) == RISCV::NumTargetFixupKinds, + "Not all fixup kinds added to Infos array"); + + // Fixup kinds from .reloc directive are like R_RISCV_NONE. They + // do not require any extra processing. + if (Kind >= FirstLiteralRelocationKind) + return MCAsmBackend::getFixupKindInfo(FK_NONE); + + if (Kind < FirstTargetFixupKind) + return MCAsmBackend::getFixupKindInfo(Kind); + + assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && + "Invalid kind!"); + return Infos[Kind - FirstTargetFixupKind]; +} + // If linker relaxation is enabled, or the relax option had previously been // enabled, always emit relocations even if the fixup can be resolved. This is // necessary for correctness as offsets may change during relaxation. bool RISCVAsmBackend::shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target) { - bool ShouldForce = false; - + if (Fixup.getKind() >= FirstLiteralRelocationKind) + return true; switch (Fixup.getTargetKind()) { default: break; @@ -44,40 +106,9 @@ bool RISCVAsmBackend::shouldForceRelocation(const MCAssembler &Asm, case RISCV::fixup_riscv_tls_got_hi20: case RISCV::fixup_riscv_tls_gd_hi20: return true; - case RISCV::fixup_riscv_pcrel_lo12_i: - case RISCV::fixup_riscv_pcrel_lo12_s: - // For pcrel_lo12, force a relocation if the target of the corresponding - // pcrel_hi20 is not in the same fragment. - const MCFixup *T = cast<RISCVMCExpr>(Fixup.getValue())->getPCRelHiFixup(); - if (!T) { - Asm.getContext().reportError(Fixup.getLoc(), - "could not find corresponding %pcrel_hi"); - return false; - } - - switch (T->getTargetKind()) { - default: - llvm_unreachable("Unexpected fixup kind for pcrel_lo12"); - break; - case RISCV::fixup_riscv_got_hi20: - case RISCV::fixup_riscv_tls_got_hi20: - case RISCV::fixup_riscv_tls_gd_hi20: - ShouldForce = true; - break; - case RISCV::fixup_riscv_pcrel_hi20: { - MCFragment *TFragment = T->getValue()->findAssociatedFragment(); - MCFragment *FixupFragment = Fixup.getValue()->findAssociatedFragment(); - assert(FixupFragment && "We should have a fragment for this fixup"); - ShouldForce = - !TFragment || TFragment->getParent() != FixupFragment->getParent(); - break; - } - } - break; } - return ShouldForce || STI.getFeatureBits()[RISCV::FeatureRelax] || - ForceRelocs; + return STI.getFeatureBits()[RISCV::FeatureRelax] || ForceRelocs; } bool RISCVAsmBackend::fixupNeedsRelaxationAdvanced(const MCFixup &Fixup, @@ -108,10 +139,10 @@ bool RISCVAsmBackend::fixupNeedsRelaxationAdvanced(const MCFixup &Fixup, } } -void RISCVAsmBackend::relaxInstruction(const MCInst &Inst, - const MCSubtargetInfo &STI, - MCInst &Res) const { +void RISCVAsmBackend::relaxInstruction(MCInst &Inst, + const MCSubtargetInfo &STI) const { // TODO: replace this with call to auto generated uncompressinstr() function. + MCInst Res; switch (Inst.getOpcode()) { default: llvm_unreachable("Opcode not expected!"); @@ -142,6 +173,7 @@ void RISCVAsmBackend::relaxInstruction(const MCInst &Inst, Res.addOperand(Inst.getOperand(0)); break; } + Inst = std::move(Res); } // Given a compressed control flow instruction this function returns @@ -284,13 +316,77 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, } } +bool RISCVAsmBackend::evaluateTargetFixup( + const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFixup &Fixup, + const MCFragment *DF, const MCValue &Target, uint64_t &Value, + bool &WasForced) { + const MCFixup *AUIPCFixup; + const MCFragment *AUIPCDF; + MCValue AUIPCTarget; + switch (Fixup.getTargetKind()) { + default: + llvm_unreachable("Unexpected fixup kind!"); + case RISCV::fixup_riscv_pcrel_hi20: + AUIPCFixup = &Fixup; + AUIPCDF = DF; + AUIPCTarget = Target; + break; + case RISCV::fixup_riscv_pcrel_lo12_i: + case RISCV::fixup_riscv_pcrel_lo12_s: { + AUIPCFixup = cast<RISCVMCExpr>(Fixup.getValue())->getPCRelHiFixup(&AUIPCDF); + if (!AUIPCFixup) { + Asm.getContext().reportError(Fixup.getLoc(), + "could not find corresponding %pcrel_hi"); + return true; + } + + // MCAssembler::evaluateFixup will emit an error for this case when it sees + // the %pcrel_hi, so don't duplicate it when also seeing the %pcrel_lo. + const MCExpr *AUIPCExpr = AUIPCFixup->getValue(); + if (!AUIPCExpr->evaluateAsRelocatable(AUIPCTarget, &Layout, AUIPCFixup)) + return true; + break; + } + } + + if (!AUIPCTarget.getSymA() || AUIPCTarget.getSymB()) + return false; + + const MCSymbolRefExpr *A = AUIPCTarget.getSymA(); + const MCSymbol &SA = A->getSymbol(); + if (A->getKind() != MCSymbolRefExpr::VK_None || SA.isUndefined()) + return false; + + auto *Writer = Asm.getWriterPtr(); + if (!Writer) + return false; + + bool IsResolved = Writer->isSymbolRefDifferenceFullyResolvedImpl( + Asm, SA, *AUIPCDF, false, true); + if (!IsResolved) + return false; + + Value = Layout.getSymbolOffset(SA) + AUIPCTarget.getConstant(); + Value -= Layout.getFragmentOffset(AUIPCDF) + AUIPCFixup->getOffset(); + + if (shouldForceRelocation(Asm, *AUIPCFixup, AUIPCTarget)) { + WasForced = true; + return false; + } + + return true; +} + void RISCVAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef<char> Data, uint64_t Value, bool IsResolved, const MCSubtargetInfo *STI) const { + MCFixupKind Kind = Fixup.getKind(); + if (Kind >= FirstLiteralRelocationKind) + return; MCContext &Ctx = Asm.getContext(); - MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind()); + MCFixupKindInfo Info = getFixupKindInfo(Kind); if (!Value) return; // Doesn't change encoding. // Apply any target-specific value adjustments. |