[llvm] [JITLink] Add GOT indirection optimization for SystemZ (PR #171919)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Dec 12 08:50:56 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] [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
More information about the llvm-commits
mailing list