Index: lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "MCTargetDesc/RISCVFixupKinds.h" +#include "MCTargetDesc/RISCVMCExpr.h" #include "MCTargetDesc/RISCVMCTargetDesc.h" #include "llvm/ADT/APInt.h" #include "llvm/MC/MCAsmBackend.h" @@ -36,6 +37,16 @@ : MCAsmBackend(), STI(STI), OSABI(OSABI), Is64Bit(Is64Bit) {} ~RISCVAsmBackend() override {} + bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target) override { + if (Fixup.getKind() == RISCV::fixup_riscv_pcrel_lo12_i) { + const MCExpr *T = cast(Fixup.getValue())->getPCRelHiExpr(); + if (T->findAssociatedFragment() != Fixup.getValue()->findAssociatedFragment()) + return true; + } + return false; + } + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef Data, uint64_t Value, bool IsResolved) const override; Index: lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h +++ lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h @@ -37,6 +37,8 @@ int64_t evaluateAsInt64(int64_t Value) const; + bool evaluatePCRelLo(MCValue &Res, const MCAsmLayout *Layout, const MCFixup *Fixup) const; + explicit RISCVMCExpr(const MCExpr *Expr, VariantKind Kind) : Expr(Expr), Kind(Kind) {} @@ -48,6 +50,13 @@ const MCExpr *getSubExpr() const { return Expr; } + /// Get the MCExpr of the VK_RISCV_PCREL_HI Fixup that the + /// VK_RISCV_PCREL_LO points to. + /// + /// \returns nullptr if this isn't a VK_RISCV_PCREL_LO pointing to a + /// VK_RISCV_PCREL_HI. + const MCExpr *getPCRelHiExpr() const; + void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override; bool evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout, const MCFixup *Fixup) const override; Index: lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp @@ -12,6 +12,7 @@ // //===----------------------------------------------------------------------===// +#include "RISCVFixupKinds.h" #include "RISCVMCExpr.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" @@ -39,9 +40,83 @@ OS << ')'; } +const MCExpr *RISCVMCExpr::getPCRelHiExpr() const { + MCValue AUIPCLoc; + if (!getSubExpr()->evaluateAsRelocatable(AUIPCLoc, nullptr, nullptr)) + return nullptr; + + const MCSymbolRefExpr *AUIPCSRE = AUIPCLoc.getSymA(); + if (!AUIPCSRE) + return nullptr; + + const auto *DF = + dyn_cast_or_null(AUIPCSRE->findAssociatedFragment()); + if (!DF) + return nullptr; + + const MCSymbol *AUIPCSymbol = &AUIPCSRE->getSymbol(); + const MCExpr *TargetExpr = nullptr; + for (const MCFixup &F : DF->getFixups()) { + if (F.getKind() != RISCV::fixup_riscv_pcrel_hi20) + continue; + if (F.getOffset() != AUIPCSymbol->getOffset()) + continue; + TargetExpr = F.getValue(); + break; + } + return TargetExpr; +} + +bool RISCVMCExpr::evaluatePCRelLo(MCValue &Res, const MCAsmLayout *Layout, + const MCFixup *Fixup) const { + // VK_RISCV_PCREL_LO has to be handled specially. The MCExpr inside is + // actually the location of a auipc instruction with a VK_RISCV_PCREL_HI fixup + // pointing to the real target. We need to generate an MCValue in the form of + // ( + ). The Fixup + // is pcrel relative to the VK_RISCV_PCREL_LO fixup, so we need to add the + // offset to the VK_RISCV_PCREL_HI Fixup from VK_RISCV_PCREL_LO to correct. + MCValue AUIPCLoc; + if (!getSubExpr()->evaluateAsValue(AUIPCLoc, *Layout)) + return false; + + const MCSymbolRefExpr *AUIPCSRE = AUIPCLoc.getSymA(); + // Don't try to evaluate %pcrel_hi/%pcrel_lo pairs that cross fragment + // boundries. + if (!AUIPCSRE || + findAssociatedFragment() != AUIPCSRE->findAssociatedFragment()) + return false; + + const MCSymbol *AUIPCSymbol = &AUIPCSRE->getSymbol(); + if (!AUIPCSymbol) + return false; + + const MCExpr *TargetExpr = getPCRelHiExpr(); + if (!TargetExpr) + return false; + + MCValue Target; + if (!TargetExpr->evaluateAsValue(Target, *Layout)) + return false; + + if (!Target.getSymA() || !Target.getSymA()->getSymbol().isInSection()) + return false; + + if (&Target.getSymA()->getSymbol().getSection() != + findAssociatedFragment()->getParent()) + return false; + + uint64_t AUIPCOffset = AUIPCSymbol->getOffset(); + + Res = MCValue::get(Target.getSymA(), nullptr, + Target.getConstant() + (Fixup->getOffset() - AUIPCOffset)); + return true; +} + bool RISCVMCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout, const MCFixup *Fixup) const { + if (Kind == VK_RISCV_PCREL_LO && evaluatePCRelLo(Res, Layout, Fixup)) + return true; return getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup); } Index: test/MC/RISCV/fixups.s =================================================================== --- test/MC/RISCV/fixups.s +++ test/MC/RISCV/fixups.s @@ -24,15 +24,23 @@ # CHECK-FIXUP: fixup A - offset: 0, value: %lo(val), kind: fixup_riscv_lo12_s # CHECK-INSTR: sw a0, 1656(t1) +1: +auipc t1, %pcrel_hi(.LBB0) +# CHECK-FIXUP: fixup A - offset: 0, value: %pcrel_hi(.LBB0), kind: fixup_riscv_pcrel_hi20 +# CHECK-INSTR: auipc t1, 0 +addi t1, t1, %pcrel_lo(1b) +# CHECK-FIXUP: fixup A - offset: 0, value: %pcrel_lo(.Ltmp0), kind: fixup_riscv_pcrel_lo12_i +# CHECK-INSTR: addi t1, t1, -16 + jal zero, .LBB0 # CHECK-FIXUP: fixup A - offset: 0, value: .LBB0, kind: fixup_riscv_jal -# CHECK-INSTR: jal zero, -16 +# CHECK-INSTR: jal zero, -24 jal zero, .LBB2 # CHECK-FIXUP: fixup A - offset: 0, value: .LBB2, kind: fixup_riscv_jal # CHECK-INSTR: jal zero, 330996 beq a0, a1, .LBB0 # CHECK-FIXUP: fixup A - offset: 0, value: .LBB0, kind: fixup_riscv_branch -# CHECK-INSTR: beq a0, a1, -24 +# CHECK-INSTR: beq a0, a1, -32 blt a0, a1, .LBB1 # CHECK-FIXUP: fixup A - offset: 0, value: .LBB1, kind: fixup_riscv_branch # CHECK-INSTR: blt a0, a1, 1108 Index: test/MC/RISCV/pcrel-hilo.s =================================================================== --- /dev/null +++ test/MC/RISCV/pcrel-hilo.s @@ -0,0 +1,19 @@ +# RUN: llvm-mc -triple riscv32 -riscv-no-aliases < %s -show-encoding \ +# RUN: | FileCheck -check-prefix=CHECK-FIXUP %s +# RUN: llvm-mc -filetype=obj -triple riscv32 < %s \ +# RUN: | llvm-objdump -riscv-no-aliases -d - \ +# RUN: | FileCheck -check-prefix=CHECK-INSTR %s +# RUN: llvm-mc -filetype=obj -triple=riscv32 %s \ +# RUN: | llvm-readobj -r | FileCheck %s -check-prefix=CHECK-REL + + .global foo +1: +auipc t1, %pcrel_hi(foo) +# CHECK-FIXUP: fixup A - offset: 0, value: %pcrel_hi(foo), kind: fixup_riscv_pcrel_hi20 +# CHECK-INSTR: auipc t1, 0 +addi t1, t1, %pcrel_lo(1b) +# CHECK-FIXUP: fixup A - offset: 0, value: %pcrel_lo(.Ltmp0), kind: fixup_riscv_pcrel_lo12_i +# CHECK-INSTR: addi t1, t1, 0 + +# CHECK-REL: 0x0 R_RISCV_PCREL_HI20 foo 0x0 +# CHECK-REL: 0x4 R_RISCV_PCREL_LO12_I .text 0x0