[llvm] [JITLink] Add GOT indirection optimization for SystemZ (PR #171919)

via llvm-commits llvm-commits at lists.llvm.org
Fri Dec 12 11:16:23 PST 2025


https://github.com/anoopkg6 updated https://github.com/llvm/llvm-project/pull/171919

>From bc84ff3e9b8aa7f9f7cbb07e59c6c42c0524db5f Mon Sep 17 00:00:00 2001
From: anoopkg6 <anoopkg6 at github.com>
Date: Thu, 11 Dec 2025 18:07:58 +0100
Subject: [PATCH 1/2] [JITLink] Add Got indirection optimization

---
 .../llvm/ExecutionEngine/JITLink/systemz.h    | 30 +++++++++++++-
 .../ExecutionEngine/JITLink/ELF_systemz.cpp   |  2 +-
 llvm/lib/ExecutionEngine/JITLink/systemz.cpp  | 40 +++++++++++++++++++
 .../systemz/ELF_systemz_reloc_call_pic.s      | 19 +++------
 4 files changed, 75 insertions(+), 16 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h b/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
index bfd22ec753074..3b11d7cb6d35d 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
@@ -219,6 +219,24 @@ enum EdgeKind_systemz : Edge::Kind {
   ///
   DeltaPLT32dbl,
 
+  /// Relaxable version of DeltaPLT32dbl.
+  ///
+  /// The edge kind has the same fixup expression as DeltaPLT32dbl,
+  /// but identifies the call/branch as being to a pointer jump stub that may be
+  /// bypassed with a direct jump to the ultimate target if the ultimate target
+  /// is within range of the fixup location.
+  ///
+  /// Fixup expression:
+  ///   Fixup <- (Target - Fixup + Addend) >> 1 : int32
+  ///
+  /// Errors:
+  ///   - The result of the fixup expression before shifting right by 1 must
+  ///     fit into an int33, otherwise an out-of-range error will be returned.
+  ///   - The result of the fixup expression  before shifting right by 1 must
+  ///     be multiple of 2, otherwise an alignment error will be returned.
+  ///
+  Delta32dblToPtrJumpStubBypassable,
+
   /// A 24-bit Delta shifted by 1.
   ///
   /// Delta from the fixup to the PLT slot for the target. This will lead to
@@ -652,6 +670,7 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E,
     break;
   }
   case Delta32dbl:
+  case Delta32dblToPtrJumpStubBypassable:
   case DeltaPLT32dbl: {
     int64_t Value = S + A - P;
     if (!LLVM_UNLIKELY(isInt<33>(Value)))
@@ -891,12 +910,15 @@ class PLTTableManager : public TableManager<PLTTableManager> {
       return false;
 
     switch (E.getKind()) {
+    case systemz::DeltaPLT32dbl: {
+      E.setKind(systemz::Delta32dblToPtrJumpStubBypassable);
+      break;
+    }
     case systemz::DeltaPLT32:
     case systemz::DeltaPLT64:
     case systemz::DeltaPLT12dbl:
     case systemz::DeltaPLT16dbl:
     case systemz::DeltaPLT24dbl:
-    case systemz::DeltaPLT32dbl:
     case systemz::Delta16PLTFromGOT:
     case systemz::Delta32PLTFromGOT:
     case systemz::Delta64PLTFromGOT:
@@ -930,6 +952,12 @@ class PLTTableManager : public TableManager<PLTTableManager> {
   Section *StubsSection = nullptr;
 };
 
+/// Optimize the GOT and Stub relocations if the edge target address is in
+/// range - Edge of kind is marked as Delta32dblToPtrJumpStubBypassable.
+/// For this edge kind, if the target is in range, replace a indirect jump
+/// by plt stub with a direct jump to the target.
+LLVM_ABI Error optimizeGOTAndStubAccesses(LinkGraph &G);
+
 } // namespace systemz
 } // namespace jitlink
 } // namespace llvm
diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
index 50acd6ea2e542..a4ff7796deedc 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
@@ -475,7 +475,7 @@ void link_ELF_systemz(std::unique_ptr<LinkGraph> G,
             identifyELFSectionStartAndEndSymbols));
 
     // TODO: Add GOT/Stubs optimizer pass.
-    // Config.PreFixupPasses.push_back(systemz::optimizeGOTAndStubAccesses);
+    Config.PreFixupPasses.push_back(systemz::optimizeGOTAndStubAccesses);
   }
 
   if (auto Err = Ctx->modifyPassConfig(*G, Config))
diff --git a/llvm/lib/ExecutionEngine/JITLink/systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
index dbb924c3f9291..221e903250d58 100644
--- a/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
@@ -106,11 +106,51 @@ const char *getEdgeKindName(Edge::Kind R) {
     return "RequestGOTAndTransformToDelta32dbl";
   case RequestTLSDescInGOTAndTransformToDelta64FromGOT:
     return "RequestTLSDescInGOTAndTransformToDelta64FromGOT";
+  case Delta32dblToPtrJumpStubBypassable:
+    return "Delta32dblToPtrJumpStubBypassable";
   default:
     return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
   }
 }
 
+Error optimizeGOTAndStubAccesses(LinkGraph &G) {
+  LLVM_DEBUG(dbgs() << "Optimizing GOT entries and stubs:\n");
+
+  for (auto *B : G.blocks())
+    for (auto &E : B->edges()) {
+      if (E.getKind() == systemz::Delta32dblToPtrJumpStubBypassable) {
+        auto &StubBlock = E.getTarget().getBlock();
+        assert(StubBlock.getSize() == sizeof(Pointer64JumpStubContent) &&
+               "Stub block should be stub sized");
+        assert(StubBlock.edges_size() == 1 &&
+               "Stub block should only have one outgoing edge");
+
+        auto &GOTBlock = StubBlock.edges().begin()->getTarget().getBlock();
+        assert(GOTBlock.getSize() == G.getPointerSize() &&
+               "GOT block should be pointer sized");
+        assert(GOTBlock.edges_size() == 1 &&
+               "GOT block should only have one outgoing edge");
+
+        auto &GOTTarget = GOTBlock.edges().begin()->getTarget();
+        orc::ExecutorAddr EdgeAddr = B->getAddress() + E.getOffset();
+        orc::ExecutorAddr TargetAddr = GOTTarget.getAddress();
+
+        int64_t Displacement = TargetAddr - EdgeAddr;
+        if (isInt<32>(Displacement)) {
+          E.setKind(systemz::Delta32dbl);
+          E.setTarget(GOTTarget);
+          LLVM_DEBUG({
+            dbgs() << "  Replaced stub branch with direct branch:\n    ";
+            printEdge(dbgs(), *B, E, getEdgeKindName(E.getKind()));
+            dbgs() << "\n";
+          });
+        }
+      }
+    }
+
+  return Error::success();
+}
+
 } // namespace systemz
 } // namespace jitlink
 } // namespace llvm
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_call_pic.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_call_pic.s
index 743181655a5cc..92e8ebfd891d0 100644
--- a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_call_pic.s
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_call_pic.s
@@ -72,21 +72,12 @@ test_call_extern_plt_stub:
 
         .size   test_call_extern_plt_stub, .-test_call_extern_plt_stub
 
-# Check R_390_PLT32(DeltaPLT32dbl) handling with a call to an external. 
-# This produces a Delta32dbl edge, because externals are not defined 
-# locally. During resolution, the target turns out to be in-range from the 
-# callsite.
-### TODO: edge can be relaxed in post-allocation optimization, it will then
-### require:
-### jitlink-check: decode_operand(test_call_extern, 1) = \
-### jitlink-check:     extern_in_range32 - test_call_extern
-#
-# Same as test_call_extern_plt(no-optimization)
+# Check Delta32dblToPtrJumpStubBypassable optimization for a call to an
+# external. This produces Delta32dbl edge, because externals are not defined
+# locally.  During resolution, the target turns out to be in-range from the
+# callsite and so the edge is relaxed in post-allocation optimization.
 # jitlink-check: decode_operand(test_call_extern, 1) = \
-# jitlink-check:     stub_addr(elf_pic_reloc.o, extern_in_range32) - \
-# jitlink-check:        test_call_extern
-# jitlink-check: *{8}(got_addr(elf_pic_reloc.o, extern_in_range32)) = \
-# jitlink-check:     extern_in_range32
+# jitlink-check:     extern_in_range32 - test_call_extern
         .globl  test_call_extern
         .p2align       4
         .type   test_call_extern, at function

>From 3f5646201fc9d046c61802892573611425d8ab8c Mon Sep 17 00:00:00 2001
From: anoopkg6 <anoopkg6 at github.com>
Date: Fri, 12 Dec 2025 18:30:52 +0100
Subject: [PATCH 2/2] Added addend to edge offset from target qnd check
 isInt<33> to optimize GOT/Stub

---
 llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp              | 2 +-
 llvm/lib/ExecutionEngine/JITLink/systemz.cpp                  | 4 ++--
 .../ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_plt.s   | 4 ++--
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
index a4ff7796deedc..42cf926b3c34b 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
@@ -474,7 +474,7 @@ void link_ELF_systemz(std::unique_ptr<LinkGraph> G,
         createDefineExternalSectionStartAndEndSymbolsPass(
             identifyELFSectionStartAndEndSymbols));
 
-    // TODO: Add GOT/Stubs optimizer pass.
+    // Add GOT/Stubs optimizer pass.
     Config.PreFixupPasses.push_back(systemz::optimizeGOTAndStubAccesses);
   }
 
diff --git a/llvm/lib/ExecutionEngine/JITLink/systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
index 221e903250d58..dc6abe61dc6f8 100644
--- a/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
@@ -135,8 +135,8 @@ Error optimizeGOTAndStubAccesses(LinkGraph &G) {
         orc::ExecutorAddr EdgeAddr = B->getAddress() + E.getOffset();
         orc::ExecutorAddr TargetAddr = GOTTarget.getAddress();
 
-        int64_t Displacement = TargetAddr - EdgeAddr;
-        if (isInt<32>(Displacement)) {
+        int64_t Displacement = TargetAddr + E.getAddend() - EdgeAddr;
+        if (isInt<33>(Displacement)) {
           E.setKind(systemz::Delta32dbl);
           E.setTarget(GOTTarget);
           LLVM_DEBUG({
diff --git a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_plt.s b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_plt.s
index 47f064b45816a..3759efe817d8d 100644
--- a/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_plt.s
+++ b/llvm/test/ExecutionEngine/JITLink/systemz/ELF_systemz_reloc_plt.s
@@ -6,8 +6,8 @@
 # RUN: llvm-jitlink -noexec \
 # RUN:     -slab-allocate 100Kb -slab-address 0xffff0000 -slab-page-size 4096 \
 # RUN:     -abs external_data=0x1 \
-# RUN:    -abs foo=0x6ff04040 \
-# RUN:    -abs bar=0x6ff04048 \
+# RUN:    -abs foo=0x76ff04040 \
+# RUN:    -abs bar=0x76ff04048 \
 # RUN:     -check %s %t/elf_reloc.o
 
 # Check R_390_PLT32/64 relocations.



More information about the llvm-commits mailing list