[llvm-branch-commits] [llvm] ea58f6b - [JITLink][LoongArch] Add reloc types for LA32R/LA32S (#175353)
Cullen Rhodes via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Jan 22 00:27:50 PST 2026
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.
More information about the llvm-branch-commits
mailing list