[compiler-rt] [llvm] [JITLink] Add TLS support for SystemZ (PR #171559)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Dec 10 15:48:35 PST 2025
https://github.com/anoopkg6 updated https://github.com/llvm/llvm-project/pull/171559
>From 5aa262b94e60fbce2153f892896a43dd314c99fc Mon Sep 17 00:00:00 2001
From: anoopkg6 <anoopkg6 at github.com>
Date: Wed, 10 Dec 2025 03:13:37 +0100
Subject: [PATCH 1/2] [JITLink] TLS support for SystemZ. Original patch #170706
included orc-runtime changes. This patch is on top of separate patch #171062
created for orc-runtime from original patch #170706.
---
compiler-rt/lib/orc/CMakeLists.txt | 1 +
compiler-rt/lib/orc/elfnix_tls.systemz.S | 43 ++++++++++++
.../orc/TestCases/Linux/systemz/trivial-tls.S | 67 +++++++++++++++++++
.../llvm/ExecutionEngine/JITLink/systemz.h | 15 +++++
.../ExecutionEngine/JITLink/ELF_systemz.cpp | 66 +++++++++++++++++-
llvm/lib/ExecutionEngine/JITLink/systemz.cpp | 2 +
.../ExecutionEngine/Orc/ELFNixPlatform.cpp | 5 ++
7 files changed, 198 insertions(+), 1 deletion(-)
create mode 100644 compiler-rt/lib/orc/elfnix_tls.systemz.S
create mode 100644 compiler-rt/test/orc/TestCases/Linux/systemz/trivial-tls.S
diff --git a/compiler-rt/lib/orc/CMakeLists.txt b/compiler-rt/lib/orc/CMakeLists.txt
index b8d1b03b788c9..649d988d9d608 100644
--- a/compiler-rt/lib/orc/CMakeLists.txt
+++ b/compiler-rt/lib/orc/CMakeLists.txt
@@ -119,6 +119,7 @@ else() # not Apple
elfnix_tls.x86-64.S
elfnix_tls.aarch64.S
elfnix_tls.ppc64.S
+ elfnix_tls.systemz.S
sysv_reenter.arm64.S
sysv_reenter.x86-64.S
)
diff --git a/compiler-rt/lib/orc/elfnix_tls.systemz.S b/compiler-rt/lib/orc/elfnix_tls.systemz.S
new file mode 100644
index 0000000000000..5244473beded9
--- /dev/null
+++ b/compiler-rt/lib/orc/elfnix_tls.systemz.S
@@ -0,0 +1,43 @@
+
+//===-- orc_rt_elfnix_tls_systemz.s -------------------------------*- ASM -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of the ORC runtime support library.
+//
+//===----------------------------------------------------------------------===//
+
+// The special thing about the s390 TLS ABI is that we do not have the
+// standard __tls_get_addr function but the __tls_get_offset function
+// which differs in two important aspects:
+// 1) __tls_get_offset gets a got offset instead of a pointer to the
+// tls_index structure
+// 2) __tls_get_offset returns the offset of the requested variable to
+// the thread descriptor instead of a pointer to the variable.
+
+// The content of this file is systemz-only
+
+#if defined(__s390x__)
+
+ .text
+ // returns offset of TLV from TP in %r2, all other registers preserved
+ .globl ___orc_rt_elfnix_tls_get_offset
+___orc_rt_elfnix_tls_get_offset:
+ stmg %r14, %r15, 48(%r15)
+ aghi %r15, -240
+ // Pass pointer to tls_index.
+ la %r2,0(%r2,%r12)
+ brasl %r14, __orc_rt_elfnix_tls_get_addr_impl
+ // Return offset from TP.
+ ear %r0, %a0
+ sllg %r0, %r0, 32
+ ear %r0, %a1
+ sgr %r2, %r0
+ lmg %r14, %r15, 288(%r15)
+ br %r14
+
+#endif // defined(__s390x__)
diff --git a/compiler-rt/test/orc/TestCases/Linux/systemz/trivial-tls.S b/compiler-rt/test/orc/TestCases/Linux/systemz/trivial-tls.S
new file mode 100644
index 0000000000000..4bf1c578bd1d7
--- /dev/null
+++ b/compiler-rt/test/orc/TestCases/Linux/systemz/trivial-tls.S
@@ -0,0 +1,67 @@
+// RUN: %clang -c -o %t %s
+// RUN: %llvm_jitlink %t
+//
+// Test that basic ELF TLS work by adding together TLSs with values
+// 0, 1, and -1, and returning the result (0 for success). This setup
+// tests both zero-initialized (.tbss) and non-zero-initialized
+// (.tdata) sections.
+
+ .section .data.rel.ro,"aw", at progbits
+ .p2align 3, 0x0
+.LCPI0_0:
+ .quad x at TLSGD
+.LCPI0_1:
+ .quad y at TLSGD
+.LCPI0_2:
+ .quad z at TLSGD
+
+ .text
+ .globl main
+ .p2align 4
+ .type main, at function
+main:
+ stmg %r10, %r15, 80(%r15)
+ aghi %r15, -160
+ lgrl %r2, .LCPI0_0
+ larl %r12, _GLOBAL_OFFSET_TABLE_
+ brasl %r14, __tls_get_offset at PLT:tls_gdcall:x
+ lgr %r13, %r2
+ lgrl %r2, .LCPI0_1
+ brasl %r14, __tls_get_offset at PLT:tls_gdcall:y
+ ear %r0, %a0
+ sllg %r11, %r0, 32
+ ear %r11, %a1
+ l %r10, 0(%r2,%r11)
+ lgrl %r2, .LCPI0_2
+ a %r10, 0(%r13,%r11)
+ brasl %r14, __tls_get_offset at PLT:tls_gdcall:z
+ a %r10, 0(%r2,%r11)
+ lgfr %r2, %r10
+ lmg %r10, %r15, 240(%r15)
+ br %r14
+.Lfunc_end0:
+ .size main, .Lfunc_end0-main
+
+
+ .type x, at object # @x
+ .section .tbss,"awT", at nobits
+ .globl x
+ .p2align 2, 0x0
+x:
+ .long 0 # 0x0
+ .size x, 4
+
+ .type y, at object # @y
+ .section .tdata,"awT", at progbits
+ .globl y
+ .p2align 2, 0x0
+y:
+ .long 1 # 0x1
+ .size y, 4
+
+ .type z, at object # @z
+ .globl z
+ .p2align 2, 0x0
+z:
+ .long 4294967295 # 0xffffffff
+ .size z, 4
diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h b/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
index 09ec56db6826f..bfd22ec753074 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
@@ -507,6 +507,21 @@ enum EdgeKind_systemz : Edge::Kind {
///
RequestGOTAndTransformToDelta32dbl,
+ /// A TLSInfo entry getter/constructor, transformed to Delta64FromGOT.
+ ///
+ /// Indicates that this edge should be transformed into a Delta64FromGOT
+ /// targeting the TLSInfo entry for the edge's current target. A TLSInfo
+ /// entry for the target should be created if one does not already exist.
+ ///
+ /// 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.
+ ///
+ RequestTLSDescInGOTAndTransformToDelta64FromGOT,
+
/// A 32-bit Delta to GOT base.
///
/// Fixup expression:
diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
index 29eeecceea766..50acd6ea2e542 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_systemz.cpp
@@ -27,12 +27,67 @@ using namespace llvm::jitlink;
namespace {
constexpr StringRef ELFGOTSymbolName = "_GLOBAL_OFFSET_TABLE_";
+constexpr StringRef ELFTLSInfoSectionName = "$__TLSINFO";
+
+// TLS Info Builder.
+class TLSInfoTableManager_ELF_systemz
+ : public TableManager<TLSInfoTableManager_ELF_systemz> {
+public:
+ static StringRef getSectionName() { return ELFTLSInfoSectionName; }
+
+ static const uint8_t TLSInfoEntryContent[16];
+
+ bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
+ if (E.getKind() ==
+ systemz::RequestTLSDescInGOTAndTransformToDelta64FromGOT) {
+ LLVM_DEBUG({
+ dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
+ << formatv("{0:x}", B->getFixupAddress(E)) << " ("
+ << formatv("{0:x}", B->getAddress()) << " + "
+ << formatv("{0:x}", E.getOffset()) << ")\n";
+ });
+ E.setKind(systemz::Delta64FromGOT);
+ E.setTarget(getEntryForTarget(G, E.getTarget()));
+ return true;
+ }
+ return false;
+ }
+
+ Symbol &createEntry(LinkGraph &G, Symbol &Target) {
+ // the TLS Info entry's key value will be written by the fixTLVSectionByName
+ // pass, so create mutable content.
+ auto &TLSInfoEntry = G.createMutableContentBlock(
+ getTLSInfoSection(G), G.allocateContent(getTLSInfoEntryContent()),
+ orc::ExecutorAddr(), 8, 0);
+ TLSInfoEntry.addEdge(systemz::Pointer64, 8, Target, 0);
+ return G.addAnonymousSymbol(TLSInfoEntry, 0, 16, false, false);
+ }
+
+private:
+ Section &getTLSInfoSection(LinkGraph &G) {
+ if (!TLSInfoTable)
+ TLSInfoTable = &G.createSection(getSectionName(), orc::MemProt::Read);
+ return *TLSInfoTable;
+ }
+
+ ArrayRef<char> getTLSInfoEntryContent() const {
+ return {reinterpret_cast<const char *>(TLSInfoEntryContent),
+ sizeof(TLSInfoEntryContent)};
+ }
+
+ Section *TLSInfoTable = nullptr;
+};
+
+const uint8_t TLSInfoTableManager_ELF_systemz::TLSInfoEntryContent[16] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
Error buildTables_ELF_systemz(LinkGraph &G) {
LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
systemz::GOTTableManager GOT;
systemz::PLTTableManager PLT(GOT);
- visitExistingEdges(G, GOT, PLT);
+ TLSInfoTableManager_ELF_systemz TLSInfo;
+ visitExistingEdges(G, GOT, PLT, TLSInfo);
return Error::success();
}
@@ -329,6 +384,15 @@ class ELFLinkGraphBuilder_systemz
Kind = systemz::Delta32dblGOTBase;
break;
}
+ // Tag for function call in general dynamic TLS code.
+ case ELF::R_390_TLS_GDCALL: {
+ break;
+ }
+ // Direct 64 bit for general dynamic thread local data.
+ case ELF::R_390_TLS_GD64: {
+ Kind = systemz::RequestTLSDescInGOTAndTransformToDelta64FromGOT;
+ break;
+ }
default:
return make_error<JITLinkError>(
"In " + G->getName() + ": Unsupported systemz relocation type " +
diff --git a/llvm/lib/ExecutionEngine/JITLink/systemz.cpp b/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
index f6cc29fa6e6a1..dbb924c3f9291 100644
--- a/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/systemz.cpp
@@ -104,6 +104,8 @@ const char *getEdgeKindName(Edge::Kind R) {
return "RequestGOTAndTransformToDelta12FromGOT";
case RequestGOTAndTransformToDelta32dbl:
return "RequestGOTAndTransformToDelta32dbl";
+ case RequestTLSDescInGOTAndTransformToDelta64FromGOT:
+ return "RequestTLSDescInGOTAndTransformToDelta64FromGOT";
default:
return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
}
diff --git a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
index 7dc1ae520f132..0a761290373aa 100644
--- a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
@@ -988,6 +988,7 @@ Error ELFNixPlatform::ELFNixPlatformPlugin::fixTLVSectionsAndEdges(
jitlink::LinkGraph &G, JITDylib &JD) {
auto TLSGetAddrSymbolName = G.intern("__tls_get_addr");
auto TLSDescResolveSymbolName = G.intern("__tlsdesc_resolver");
+ auto TLSGetOffsetSymbolName = G.intern("__tls_get_offset");
for (auto *Sym : G.external_symbols()) {
if (Sym->getName() == TLSGetAddrSymbolName) {
auto TLSGetAddr =
@@ -997,6 +998,10 @@ Error ELFNixPlatform::ELFNixPlatformPlugin::fixTLVSectionsAndEdges(
auto TLSGetAddr =
MP.getExecutionSession().intern("___orc_rt_elfnix_tlsdesc_resolver");
Sym->setName(std::move(TLSGetAddr));
+ } else if (Sym->getName() == TLSGetOffsetSymbolName) {
+ auto TLSGetAddr =
+ MP.getExecutionSession().intern("___orc_rt_elfnix_tls_get_offset");
+ Sym->setName(std::move(TLSGetAddr));
}
}
>From 6abd15979a4a88d5b90effc48726575c83479225 Mon Sep 17 00:00:00 2001
From: anoopkg6 <anoopkg6 at github.com>
Date: Thu, 11 Dec 2025 00:39:44 +0100
Subject: [PATCH 2/2] Incorporate code review feedback
---
compiler-rt/lib/orc/elfnix_tls.systemz.S | 29 ++++++++++++------------
1 file changed, 14 insertions(+), 15 deletions(-)
diff --git a/compiler-rt/lib/orc/elfnix_tls.systemz.S b/compiler-rt/lib/orc/elfnix_tls.systemz.S
index 5244473beded9..4e116c92a5a88 100644
--- a/compiler-rt/lib/orc/elfnix_tls.systemz.S
+++ b/compiler-rt/lib/orc/elfnix_tls.systemz.S
@@ -1,4 +1,3 @@
-
//===-- orc_rt_elfnix_tls_systemz.s -------------------------------*- ASM -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
@@ -23,21 +22,21 @@
#if defined(__s390x__)
- .text
- // returns offset of TLV from TP in %r2, all other registers preserved
- .globl ___orc_rt_elfnix_tls_get_offset
+ .text
+ // returns offset of TLV from TP in %r2.
+ .globl ___orc_rt_elfnix_tls_get_offset
___orc_rt_elfnix_tls_get_offset:
- stmg %r14, %r15, 48(%r15)
- aghi %r15, -240
- // Pass pointer to tls_index.
- la %r2,0(%r2,%r12)
- brasl %r14, __orc_rt_elfnix_tls_get_addr_impl
+ stmg %r14, %r15, 112(%r15)
+ aghi %r15, -160
+ // Pass pointer to tls_index.
+ la %r2, 0(%r2, %r12)
+ brasl %r14, __orc_rt_elfnix_tls_get_addr_impl
// Return offset from TP.
- ear %r0, %a0
- sllg %r0, %r0, 32
- ear %r0, %a1
- sgr %r2, %r0
- lmg %r14, %r15, 288(%r15)
- br %r14
+ ear %r0, %a0
+ sllg %r0, %r0, 32
+ ear %r0, %a1
+ sgr %r2, %r0
+ lmg %r14, %r15, 272(%r15)
+ br %r14
#endif // defined(__s390x__)
More information about the llvm-commits
mailing list