Author: hev Date: 2026-01-22T08:27:36Z New Revision: ea58f6b4c0274c3c2a6b5132712c65e5cd8c80c1
URL: https://github.com/llvm/llvm-project/commit/ea58f6b4c0274c3c2a6b5132712c65e5cd8c80c1 DIFF: https://github.com/llvm/llvm-project/commit/ea58f6b4c0274c3c2a6b5132712c65e5cd8c80c1.diff LOG: [JITLink][LoongArch] Add reloc types for LA32R/LA32S (#175353) (cherry picked from commit 9c7904bac281caf68be377daa4366c1f166c39f2) Added: Modified: llvm/include/llvm/ExecutionEngine/JITLink/loongarch.h llvm/lib/ExecutionEngine/JITLink/ELF_loongarch.cpp llvm/lib/ExecutionEngine/JITLink/loongarch.cpp llvm/test/ExecutionEngine/JITLink/LoongArch/ELF_loongarch32_relocations.s Removed: ################################################################################ diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/loongarch.h b/llvm/include/llvm/ExecutionEngine/JITLink/loongarch.h index 1bb18e38bab33..2da2a4201ae16 100644 --- a/llvm/include/llvm/ExecutionEngine/JITLink/loongarch.h +++ b/llvm/include/llvm/ExecutionEngine/JITLink/loongarch.h @@ -170,6 +170,30 @@ enum EdgeKind_loongarch : Edge::Kind { /// PageOffset12, + /// The upper 20 bits of the offset from the fixup to the target. + /// + /// Fixup expression: + /// Fixup <- (Target + Addend - Fixup + 0x800) >> 12 : int20 + /// + /// Notes: + /// For PCADDU12I fixups. + /// + /// Errors: + /// - The result of the fixup expression must fit into an int20 otherwise an + /// out-of-range error will be returned. + /// + PCAddHi20, + + /// The lower 12 bits of the offset from the paired PCADDU12I (the initial + /// target) to the final target it points to. + /// + /// Typically used to fix up ADDI/LD_W/LD_D immediates. + /// + /// Fixup expression: + /// Fixup <- (FinalTarget - InitialTarget) & 0xfff : int12 + /// + PCAddLo12, + /// A GOT entry getter/constructor, transformed to Page20 pointing at the GOT /// entry for the original target. /// @@ -206,6 +230,49 @@ enum EdgeKind_loongarch : Edge::Kind { /// RequestGOTAndTransformToPageOffset12, + /// A GOT entry getter/constructor, transformed to PCAddHi20 pointing at the + /// GOT entry for the original target. + /// + /// Indicates that this edge should be transformed into a PCAddHi20 targeting + /// the GOT entry for the edge's current target, maintaining the same addend. + /// A GOT entry for the target should be created if one does not already + /// exist. + /// + /// Edges of this kind are usually handled by a GOT/PLT builder pass inserted + /// by default. + /// + /// Fixup expression: + /// NONE + /// + /// Errors: + /// - *ASSERTION* Failure to handle edges of this kind prior to the fixup + /// phase will result in an assert/unreachable during the fixup phase. + /// + RequestGOTAndTransformToPCAddHi20, + + /// A 30-bit PC-relative call. + /// + /// Represents a PC-relative call to a target within [-4G, +4G) + /// The target must be 4-byte aligned. For adjacent pcaddu12i+jirl + /// instruction pairs. + /// + /// Fixup expression: + /// Fixup <- (Target - Fixup + Addend) >> 2 : int30 + /// + /// Notes: + /// The '30' in the name refers to the number operand bits and follows the + /// naming convention used by the corresponding ELF relocations. Since the low + /// two bits must be zero (because of the 4-byte alignment of the target) the + /// operand is effectively a signed 32-bit number. + /// + /// Errors: + /// - The result of the unshifted part of the fixup expression must be + /// 4-byte aligned otherwise an alignment error will be returned. + /// - The result of the fixup expression must fit into an int30 otherwise an + /// out-of-range error will be returned. + /// + Call30PCRel, + /// A 36-bit PC-relative call. /// /// Represents a PC-relative call to a target within [-128G - 0x20000, +128G @@ -399,6 +466,9 @@ class GOTTableManager : public TableManager<GOTTableManager> { case RequestGOTAndTransformToPageOffset12: KindToSet = PageOffset12; break; + case RequestGOTAndTransformToPCAddHi20: + KindToSet = PCAddHi20; + break; default: return false; } @@ -437,7 +507,8 @@ class PLTTableManager : public TableManager<PLTTableManager> { static StringRef getSectionName() { return "$__STUBS"; } bool visitEdge(LinkGraph &G, Block *B, Edge &E) { - if ((E.getKind() == Branch26PCRel || E.getKind() == Call36PCRel) && + if ((E.getKind() == Branch26PCRel || E.getKind() == Call36PCRel || + E.getKind() == Call30PCRel) && !E.getTarget().isDefined()) { DEBUG_WITH_TYPE("jitlink", { dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at " diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_loongarch.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_loongarch.cpp index ee4a3280f18c4..167c0fa72830a 100644 --- a/llvm/lib/ExecutionEngine/JITLink/ELF_loongarch.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ELF_loongarch.cpp @@ -37,9 +37,41 @@ class ELFJITLinker_loongarch : public JITLinker<ELFJITLinker_loongarch> { ELFJITLinker_loongarch(std::unique_ptr<JITLinkContext> Ctx, std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig) - : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {} + : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) { + JITLinkerBase::getPassConfig().PostAllocationPasses.push_back( + [this](LinkGraph &G) { return gatherLoongArchPCAddHi20(G); }); + } private: + DenseMap<std::pair<const Block *, orc::ExecutorAddrDiff>, const Edge *> + RelPCAddHi20Map; + + Error gatherLoongArchPCAddHi20(LinkGraph &G) { + for (Block *B : G.blocks()) + for (Edge &E : B->edges()) + if (E.getKind() == PCAddHi20) + RelPCAddHi20Map[{B, E.getOffset()}] = &E; + + return Error::success(); + } + + Expected<const Edge &> getLoongArchPCAddHi20(const Edge &E) const { + using namespace loongarch; + assert((E.getKind() == PCAddLo12) && + "Can only have high relocation for PCAddLo12"); + + const Symbol &Sym = E.getTarget(); + const Block &B = Sym.getBlock(); + orc::ExecutorAddrDiff Offset = Sym.getOffset() + E.getAddend(); + + auto It = RelPCAddHi20Map.find({&B, Offset}); + if (It != RelPCAddHi20Map.end()) + return *It->second; + + return make_error<JITLinkError>("No PCAddHi20 relocation type be found " + "for PCAddLo12 relocation type"); + } + /// Apply fixup expression for edge to block content. Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { using namespace support; @@ -149,6 +181,48 @@ class ELFJITLinker_loongarch : public JITLinker<ELFJITLinker_loongarch> { *(ulittle32_t *)FixupPtr = RawInstr | Imm11_0; break; } + case PCAddHi20: { + uint64_t Target = TargetAddress + Addend; + int64_t Delta = Target - FixupAddress + 0x800; + + if (!isInt<32>(Delta)) + return makeTargetOutOfRangeError(G, B, E); + + uint32_t RawInstr = *(little32_t *)FixupPtr; + uint32_t Imm31_12 = extractBits(Delta, /*Hi=*/31, /*Lo=*/12) << 5; + *(little32_t *)FixupPtr = RawInstr | Imm31_12; + break; + } + case PCAddLo12: { + auto RelPCAddHi20 = getLoongArchPCAddHi20(E); + if (!RelPCAddHi20) + return RelPCAddHi20.takeError(); + int64_t Delta = + (RelPCAddHi20->getTarget().getAddress() + RelPCAddHi20->getAddend()) - + (E.getTarget().getAddress() + E.getAddend()); + + uint32_t RawInstr = *(ulittle32_t *)FixupPtr; + uint32_t Imm11_0 = extractBits(Delta, /*Hi=*/11, /*Lo=*/0) << 10; + *(ulittle32_t *)FixupPtr = RawInstr | Imm11_0; + break; + } + case Call30PCRel: { + int64_t Value = TargetAddress - FixupAddress + Addend; + + if (Value != llvm::SignExtend64(Value, 32)) + return makeTargetOutOfRangeError(G, B, E); + + if (!isShiftedInt<30, 2>(Value)) + return makeAlignmentError(orc::ExecutorAddr(FixupAddress), Value, 4, E); + + uint32_t Pcaddu12i = *(little32_t *)FixupPtr; + uint32_t Hi20 = extractBits(Value, /*Hi=*/31, /*Lo=*/12) << 5; + *(little32_t *)FixupPtr = Pcaddu12i | Hi20; + uint32_t Jirl = *(little32_t *)(FixupPtr + 4); + uint32_t Lo10 = extractBits(Value, /*Hi=*/11, /*Lo=*/2) << 10; + *(little32_t *)(FixupPtr + 4) = Jirl | Lo10; + break; + } case Call36PCRel: { int64_t Value = TargetAddress - FixupAddress + Addend; @@ -534,6 +608,8 @@ class ELFLinkGraphBuilder_loongarch : public ELFLinkGraphBuilder<ELFT> { return RequestGOTAndTransformToPage20; case ELF::R_LARCH_GOT_PC_LO12: return RequestGOTAndTransformToPageOffset12; + case ELF::R_LARCH_CALL30: + return Call30PCRel; case ELF::R_LARCH_CALL36: return Call36PCRel; case ELF::R_LARCH_ADD6: @@ -562,6 +638,13 @@ class ELFLinkGraphBuilder_loongarch : public ELFLinkGraphBuilder<ELFT> { return SubUleb128; case ELF::R_LARCH_ALIGN: return AlignRelaxable; + case ELF::R_LARCH_PCADD_HI20: + return PCAddHi20; + case ELF::R_LARCH_PCADD_LO12: + case ELF::R_LARCH_GOT_PCADD_LO12: + return PCAddLo12; + case ELF::R_LARCH_GOT_PCADD_HI20: + return RequestGOTAndTransformToPCAddHi20; } return make_error<JITLinkError>( diff --git a/llvm/lib/ExecutionEngine/JITLink/loongarch.cpp b/llvm/lib/ExecutionEngine/JITLink/loongarch.cpp index 55389adb31b60..69609c1b9c982 100644 --- a/llvm/lib/ExecutionEngine/JITLink/loongarch.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/loongarch.cpp @@ -49,8 +49,12 @@ const char *getEdgeKindName(Edge::Kind K) { KIND_NAME_CASE(Branch26PCRel) KIND_NAME_CASE(Page20) KIND_NAME_CASE(PageOffset12) + KIND_NAME_CASE(PCAddHi20) + KIND_NAME_CASE(PCAddLo12) KIND_NAME_CASE(RequestGOTAndTransformToPage20) KIND_NAME_CASE(RequestGOTAndTransformToPageOffset12) + KIND_NAME_CASE(RequestGOTAndTransformToPCAddHi20) + KIND_NAME_CASE(Call30PCRel) KIND_NAME_CASE(Call36PCRel) KIND_NAME_CASE(Add6) KIND_NAME_CASE(Add8) diff --git a/llvm/test/ExecutionEngine/JITLink/LoongArch/ELF_loongarch32_relocations.s b/llvm/test/ExecutionEngine/JITLink/LoongArch/ELF_loongarch32_relocations.s index da9f9982aade7..50de1c237dafe 100644 --- a/llvm/test/ExecutionEngine/JITLink/LoongArch/ELF_loongarch32_relocations.s +++ b/llvm/test/ExecutionEngine/JITLink/LoongArch/ELF_loongarch32_relocations.s @@ -39,24 +39,43 @@ local_func_jump26: b local_func .size local_func_jump26, .-local_func_jump26 +## Check R_LARCH_PCADD_HI20 / R_LARCH_PCADD_LO12 relocation of a local symbol. + +# jitlink-check: decode_operand(test_pcadd_hi20, 1)[19:0] = \ +# jitlink-check: (named_data - test_pcadd_hi20)[31:12] + \ +# jitlink-check: (named_data - test_pcadd_hi20)[11:11] +# jitlink-check: decode_operand(test_pcadd_lo12, 2)[11:0] = \ +# jitlink-check: (named_data - test_pcadd_hi20)[11:0] + .globl test_pcadd_hi20 + .p2align 2 +test_pcadd_hi20: + pcaddu12i $a0, %pcadd_hi20(named_data) + .size test_pcadd_hi20, .-test_pcadd_hi20 + + .globl test_pcadd_lo12 + .p2align 2 +test_pcadd_lo12: + addi.w $a0, $a0, %pcadd_lo12(test_pcadd_hi20) + .size test_pcadd_lo12, .-test_pcadd_lo12 + ## Check R_LARCH_PCALA_HI20 / R_LARCH_PCALA_LO12 relocation of a local symbol. -# jitlink-check: decode_operand(test_pcalau12i_pcrel, 1)[19:0] = \ -# jitlink-check: (named_data - test_pcalau12i_pcrel)[31:12] + \ +# jitlink-check: decode_operand(test_pc_hi20, 1)[19:0] = \ +# jitlink-check: (named_data - test_pc_hi20)[31:12] + \ # jitlink-check: named_data[11:11] -# jitlink-check: decode_operand(test_addi_pcrel_lo12, 2)[11:0] = \ +# jitlink-check: decode_operand(test_pc_lo12, 2)[11:0] = \ # jitlink-check: (named_data)[11:0] - .globl test_pcalau12i_pcrel + .globl test_pc_hi20 .p2align 2 -test_pcalau12i_pcrel: +test_pc_hi20: pcalau12i $a0, %pc_hi20(named_data) - .size test_pcalau12i_pcrel, .-test_pcalau12i_pcrel + .size test_pc_hi20, .-test_pc_hi20 - .globl test_addi_pcrel_lo12 + .globl test_pc_lo12 .p2align 2 -test_addi_pcrel_lo12: +test_pc_lo12: addi.w $a0, $a0, %pc_lo12(named_data) - .size test_addi_pcrel_lo12, .-test_addi_pcrel_lo12 + .size test_pc_lo12, .-test_pc_lo12 ## Check that calls/jumps to external functions trigger the generation of stubs ## and GOT entries. @@ -68,6 +87,12 @@ test_addi_pcrel_lo12: # jitlink-check: decode_operand(test_external_jump, 0) = \ # jitlink-check: (stub_addr(elf_reloc.o, external_func) - \ # jitlink-check: test_external_jump)[27:0] +# jitlink-check: decode_operand(test_external_call30, 1)[19:0] = \ +# jitlink-check: (stub_addr(elf_reloc.o, external_func) - \ +# jitlink-check: test_external_call30)[31:12] +# jitlink-check: decode_operand(test_external_call30 + 4, 2)[17:0] = \ +# jitlink-check: (stub_addr(elf_reloc.o, external_func) - \ +# jitlink-check: test_external_call30)[11:0] .globl test_external_call .p2align 2 test_external_call: @@ -80,28 +105,73 @@ test_external_jump: b external_func .size test_external_jump, .-test_external_jump + .globl test_external_call30 + .p2align 2 +test_external_call30: + pcaddu12i $ra, %call30(external_func) + jirl $ra, $ra, 0 + .size test_external_call30, .-test_external_call30 + +## Check R_LARCH_GOT_PCADD_HI20 / R_LARCH_GOT_PCADD_LO12 handling with a +## reference to an external symbol. Validate both the reference to the GOT +## entry, and also the content of the GOT entry. + +# jitlink-check: *{4}(got_addr(elf_reloc.o, external_data)) = external_data +# jitlink-check: decode_operand(test_got_pcadd_hi20_external, 1)[19:0] = \ +# jitlink-check: (got_addr(elf_reloc.o, external_data) - \ +# jitlink-check: test_got_pcadd_hi20_external)[31:12] + \ +# jitlink-check: (got_addr(elf_reloc.o, external_data) - \ +# jitlink-check: test_got_pcadd_hi20_external)[11:11] +# jitlink-check: decode_operand(test_got_pcadd_lo12_external, 2)[11:0] = \ +# jitlink-check: (got_addr(elf_reloc.o, external_data) - \ +# jitlink-check: test_got_pcadd_hi20_external)[11:0] + .globl test_got_pcadd_hi20_external + .p2align 2 +test_got_pcadd_hi20_external: + pcaddu12i $a0, %got_pcadd_hi20(external_data) + .size test_got_pcadd_hi20_external, .-test_got_pcadd_hi20_external + + .globl test_got_pcadd_lo12_external + .p2align 2 +test_got_pcadd_lo12_external: + ld.w $a0, $a0, %got_pcadd_lo12(test_got_pcadd_hi20_external) + .size test_got_pcadd_lo12_external, .-test_got_pcadd_lo12_external + ## Check R_LARCH_GOT_PC_HI20 / R_LARCH_GOT_PC_LO12 handling with a reference to ## an external symbol. Validate both the reference to the GOT entry, and also ## the content of the GOT entry. # jitlink-check: *{4}(got_addr(elf_reloc.o, external_data)) = external_data -# jitlink-check: decode_operand(test_gotpage_external, 1)[19:0] = \ +# jitlink-check: decode_operand(test_got_pc_hi20_external, 1)[19:0] = \ # jitlink-check: (got_addr(elf_reloc.o, external_data)[31:12] - \ -# jitlink-check: test_gotpage_external[31:12] + \ +# jitlink-check: test_got_pc_hi20_external[31:12] + \ # jitlink-check: got_addr(elf_reloc.o, external_data)[11:11])[19:0] -# jitlink-check: decode_operand(test_gotoffset12_external, 2)[11:0] = \ +# jitlink-check: decode_operand(test_got_pc_lo12_external, 2)[11:0] = \ # jitlink-check: got_addr(elf_reloc.o, external_data)[11:0] - .globl test_gotpage_external + .globl test_got_pc_hi20_external .p2align 2 -test_gotpage_external: +test_got_pc_hi20_external: pcalau12i $a0, %got_pc_hi20(external_data) - .size test_gotpage_external, .-test_gotpage_external + .size test_got_pc_hi20_external, .-test_got_pc_hi20_external - .globl test_gotoffset12_external + .globl test_got_pc_lo12_external .p2align 2 -test_gotoffset12_external: +test_got_pc_lo12_external: ld.w $a0, $a0, %got_pc_lo12(external_data) - .size test_gotoffset12_external, .-test_gotoffset12_external + .size test_got_pc_lo12_external, .-test_got_pc_lo12_external + +## Check R_LARCH_CALL30 relocation of a local function call. + +# jitlink-check: decode_operand(local_func_call30, 1)[19:0] = \ +# jitlink-check: (local_func - local_func_call30)[31:12] +# jitlink-check: decode_operand(local_func_call30 + 4, 2)[17:0] = \ +# jitlink-check: (local_func - local_func_call30)[11:0] + .globl local_func_call30 + .p2align 2 +local_func_call30: + pcaddu12i $ra, %call30(local_func) + jirl $ra, $ra, 0 + .size local_func_call30, .-local_func_call30 ## Check R_LARCH_B16 relocation for compare and branch instructions. _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
