[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