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

Reply via email to