[compiler-rt] [llvm] [JITLink] Add orc-runtime support for SystemZ (PR #171062)

via llvm-commits llvm-commits at lists.llvm.org
Sun Dec 7 15:48:40 PST 2025


https://github.com/anoopkg6 created https://github.com/llvm/llvm-project/pull/171062

Add orc-runtime support and tests for SystemZ.

>From 2ed7081674d13d399660418d1a0749cef927b107 Mon Sep 17 00:00:00 2001
From: anoopkg6 <anoopkg6 at github.com>
Date: Mon, 8 Dec 2025 00:09:43 +0100
Subject: [PATCH] [JITLink] Add orc-runtime support and tests for systemz

---
 .../cmake/Modules/AllSupportedArchDefs.cmake  |   2 +-
 .../Linux/systemz/ehframe-default.cpp         |  14 +++
 .../Linux/systemz/ehframe-libunwind.cpp       |  15 +++
 .../TestCases/Linux/systemz/lit.local.cfg.py  |   5 +
 .../TestCases/Linux/systemz/lljit-ehframe.cpp |  15 +++
 .../systemz/lljit-initialize-deinitialize.ll  |  32 ++++++
 .../systemz/priority-static-initializer.S     | 100 ++++++++++++++++++
 .../TestCases/Linux/systemz/trivial-atexit.S  |  42 ++++++++
 .../Linux/systemz/trivial-cxa-atexit.S        |  41 +++++++
 .../systemz/trivial-static-initializer.S      |  35 ++++++
 .../llvm/ExecutionEngine/JITLink/systemz.h    |   2 -
 .../ExecutionEngine/Orc/ELFNixPlatform.cpp    |   5 +
 12 files changed, 305 insertions(+), 3 deletions(-)
 create mode 100644 compiler-rt/test/orc/TestCases/Linux/systemz/ehframe-default.cpp
 create mode 100644 compiler-rt/test/orc/TestCases/Linux/systemz/ehframe-libunwind.cpp
 create mode 100644 compiler-rt/test/orc/TestCases/Linux/systemz/lit.local.cfg.py
 create mode 100644 compiler-rt/test/orc/TestCases/Linux/systemz/lljit-ehframe.cpp
 create mode 100644 compiler-rt/test/orc/TestCases/Linux/systemz/lljit-initialize-deinitialize.ll
 create mode 100644 compiler-rt/test/orc/TestCases/Linux/systemz/priority-static-initializer.S
 create mode 100644 compiler-rt/test/orc/TestCases/Linux/systemz/trivial-atexit.S
 create mode 100644 compiler-rt/test/orc/TestCases/Linux/systemz/trivial-cxa-atexit.S
 create mode 100644 compiler-rt/test/orc/TestCases/Linux/systemz/trivial-static-initializer.S

diff --git a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
index f2317de8916e9..9065bb2de4943 100644
--- a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
+++ b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake
@@ -114,7 +114,7 @@ set(ALL_SHADOWCALLSTACK_SUPPORTED_ARCH ${ARM64})
 
 if (UNIX)
   if (OS_NAME MATCHES "Linux")
-    set(ALL_ORC_SUPPORTED_ARCH ${X86_64} ${ARM64} ${ARM32} ${PPC64} ${LOONGARCH64})
+    set(ALL_ORC_SUPPORTED_ARCH ${X86_64} ${ARM64} ${ARM32} ${PPC64} ${LOONGARCH64} ${S390X})
   else()
     set(ALL_ORC_SUPPORTED_ARCH ${X86_64} ${ARM64} ${ARM32})
   endif()
diff --git a/compiler-rt/test/orc/TestCases/Linux/systemz/ehframe-default.cpp b/compiler-rt/test/orc/TestCases/Linux/systemz/ehframe-default.cpp
new file mode 100644
index 0000000000000..0f7dcec4b5a5b
--- /dev/null
+++ b/compiler-rt/test/orc/TestCases/Linux/systemz/ehframe-default.cpp
@@ -0,0 +1,14 @@
+// RUN: %clangxx -fexceptions -fPIC -c -o %t %s
+// RUN: %llvm_jitlink %t
+
+extern "C" void llvm_jitlink_setTestResultOverride(long Value);
+
+int main(int argc, char *argv[]) {
+  llvm_jitlink_setTestResultOverride(1);
+  try {
+    throw 0;
+  } catch (int X) {
+    llvm_jitlink_setTestResultOverride(X);
+  }
+  return 0;
+}
diff --git a/compiler-rt/test/orc/TestCases/Linux/systemz/ehframe-libunwind.cpp b/compiler-rt/test/orc/TestCases/Linux/systemz/ehframe-libunwind.cpp
new file mode 100644
index 0000000000000..f56aa8fba950f
--- /dev/null
+++ b/compiler-rt/test/orc/TestCases/Linux/systemz/ehframe-libunwind.cpp
@@ -0,0 +1,15 @@
+// REQUIRES: libunwind-available
+// RUN: %clangxx -fexceptions -fPIC -c -o %t %s
+// RUN: env LD_PRELOAD=%shared_libunwind %llvm_jitlink %t
+
+extern "C" void llvm_jitlink_setTestResultOverride(long Value);
+
+int main(int argc, char *argv[]) {
+  llvm_jitlink_setTestResultOverride(1);
+  try {
+    throw 0;
+  } catch (int X) {
+    llvm_jitlink_setTestResultOverride(X);
+  }
+  return 0;
+}
diff --git a/compiler-rt/test/orc/TestCases/Linux/systemz/lit.local.cfg.py b/compiler-rt/test/orc/TestCases/Linux/systemz/lit.local.cfg.py
new file mode 100644
index 0000000000000..493eeca02b583
--- /dev/null
+++ b/compiler-rt/test/orc/TestCases/Linux/systemz/lit.local.cfg.py
@@ -0,0 +1,5 @@
+if config.root.host_arch != "s390x":
+    config.unsupported = True
+
+if config.target_arch != "s390x":
+    config.unsupported = True
diff --git a/compiler-rt/test/orc/TestCases/Linux/systemz/lljit-ehframe.cpp b/compiler-rt/test/orc/TestCases/Linux/systemz/lljit-ehframe.cpp
new file mode 100644
index 0000000000000..b73ec2387028e
--- /dev/null
+++ b/compiler-rt/test/orc/TestCases/Linux/systemz/lljit-ehframe.cpp
@@ -0,0 +1,15 @@
+// RUN: %clangxx -fPIC -emit-llvm -c -o %t %s
+// RUN: %lli_orc_jitlink -relocation-model=pic %t | FileCheck %s
+
+// CHECK: catch
+
+#include <stdio.h>
+
+int main(int argc, char *argv[]) {
+  try {
+    throw 0;
+  } catch (int X) {
+    puts("catch");
+  }
+  return 0;
+}
diff --git a/compiler-rt/test/orc/TestCases/Linux/systemz/lljit-initialize-deinitialize.ll b/compiler-rt/test/orc/TestCases/Linux/systemz/lljit-initialize-deinitialize.ll
new file mode 100644
index 0000000000000..34bfc10b9d897
--- /dev/null
+++ b/compiler-rt/test/orc/TestCases/Linux/systemz/lljit-initialize-deinitialize.ll
@@ -0,0 +1,32 @@
+; RUN: %lli_orc_jitlink %s | FileCheck %s
+
+; CHECK: constructor
+; CHECK-NEXT: main
+; CHECK-NEXT: destructor
+
+ at __dso_handle = external hidden global i8
+ at .str = private unnamed_addr constant [5 x i8] c"main\00", align 1
+ at .str.1 = private unnamed_addr constant [12 x i8] c"constructor\00", align 1
+ at .str.2 = private unnamed_addr constant [11 x i8] c"destructor\00", align 1
+ at llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @constructor, i8* null }]
+
+define dso_local void @destructor(i8* %0) {
+  %2 = tail call i32 @puts(i8* nonnull dereferenceable(1) getelementptr inbounds ([11 x i8], [11 x i8]* @.str.2, i64 0, i64 0))
+  ret void
+}
+
+declare i32 @__cxa_atexit(void (i8*)*, i8*, i8*)
+
+; Function Attrs: nofree norecurse nounwind uwtable
+define dso_local i32 @main(i32 %0, i8** nocapture readnone %1) local_unnamed_addr #2 {
+  %3 = tail call i32 @puts(i8* nonnull dereferenceable(1) getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0))
+  ret i32 0
+}
+
+declare i32 @puts(i8* nocapture readonly)
+
+define internal void @constructor() {
+  %1 = tail call i32 @puts(i8* nonnull dereferenceable(1) getelementptr inbounds ([12 x i8], [12 x i8]* @.str.1, i64 0, i64 0)) #5
+  %2 = tail call i32 @__cxa_atexit(void (i8*)* @destructor, i8* null, i8* nonnull @__dso_handle) #5
+  ret void
+}
diff --git a/compiler-rt/test/orc/TestCases/Linux/systemz/priority-static-initializer.S b/compiler-rt/test/orc/TestCases/Linux/systemz/priority-static-initializer.S
new file mode 100644
index 0000000000000..24db1fbac141d
--- /dev/null
+++ b/compiler-rt/test/orc/TestCases/Linux/systemz/priority-static-initializer.S
@@ -0,0 +1,100 @@
+// Test that ELF static initializers with different constructor priorities work
+// and are executed in the proper order.
+//
+// RUN: %clang -c -o %t %s
+// RUN: %llvm_jitlink %t | FileCheck %s
+
+// CHECK: constructor 100
+// CHECK-NEXT: constructor 200
+// CHECK-NEXT: constructor 65535
+// CHECK-NEXT: main
+// CHECK-NEXT: destructor
+
+        .text
+
+        .globl  destructor
+        .p2align        4, 0x90
+        .type   destructor, at function
+destructor:
+.Ldestructor$local:
+        larl    %r2, .Lstr.d
+        jg     puts at PLT
+
+        .globl  main
+        .p2align        4, 0x90
+        .type   main, at function
+main:
+.Lmain$local:
+        stmg    %r14, %r15, 112(%r15)
+        aghi    %r15, -160
+        larl    %r2, .Lstr
+        brasl   %r14, puts at PLT
+        lghi    %r2, 0
+        lmg     %r14, %r15, 272(%r15)
+        br      %r14
+
+        .p2align        4
+        .type   constructor.65535, at function
+constructor.65535:
+        stmg    %r14, %r15, 112(%r15)
+        aghi    %r15, -160
+        larl    %r2, .Lstr.65535
+        brasl   %r14, puts at PLT
+        lgrl    %r4, __dso_handle
+        lgrl    %r2, .Ldestructor$local at GOT
+        lghi    %r3, 0
+        lmg     %r14, %r15, 272(%r15)
+        jg      __cxa_atexit at PLT
+
+        .p2align        4
+        .type   constructor.200, at function
+constructor.200:
+        larl    %r2, .Lstr.200
+        jg     puts at PLT
+
+        .p2align        4
+        .type   constructor.100, at function
+constructor.100:
+        larl    %r2, .Lstr.100
+        jg     puts at PLT
+
+        .hidden __dso_handle
+        .section        .init_array.101,"aw", at init_array
+        .p2align        3, 0x0
+        .quad   constructor.100
+        .section        .init_array.200,"aw", at init_array
+        .p2align        3, 0x0
+        .quad   constructor.200
+        .section        .init_array,"aw", at init_array
+        .p2align        3, 0x0
+        .quad   constructor.65535
+        .type   .Lstr.d, at object
+        .section        .rodata.str1.2,"aMS", at progbits,1
+        .p2align        1, 0x0
+.Lstr.d:
+        .asciz  "destructor"
+        .size   .Lstr.d, 11
+
+        .type   .Lstr.100, at object
+        .p2align        1, 0x0
+.Lstr.100:
+        .asciz  "constructor 100"
+        .size   .Lstr.100, 16
+
+        .type   .Lstr.200, at object
+        .p2align        1, 0x0
+.Lstr.200:
+        .asciz  "constructor 200"
+        .size   .Lstr.200, 16
+
+        .type   .Lstr.65535, at object
+        .p2align        1, 0x0
+.Lstr.65535:
+        .asciz  "constructor 65535"
+        .size   .Lstr.65535, 18
+
+        .type   .Lstr, at object
+        .p2align        1, 0x0
+.Lstr:
+        .asciz  "main"
+        .size   .Lstr, 5
diff --git a/compiler-rt/test/orc/TestCases/Linux/systemz/trivial-atexit.S b/compiler-rt/test/orc/TestCases/Linux/systemz/trivial-atexit.S
new file mode 100644
index 0000000000000..36b357501aede
--- /dev/null
+++ b/compiler-rt/test/orc/TestCases/Linux/systemz/trivial-atexit.S
@@ -0,0 +1,42 @@
+// REQUIRES: disabled
+//   This test is disabled until a proper atexit interpose can be implemented:
+//   the current one assumes that atexit is defined in the dylib that calls it,
+//   which is not true in general. See
+//   https://github.com/llvm/llvm-project/issues/74641
+//
+// RUN: %clang -c -o %t %s
+// RUN: %llvm_jitlink %t
+
+        .text
+// OnExit destructor resets the test result override to zero.
+        .section        .text._ZN6OnExitD2Ev,"axG", at progbits,_ZN6OnExitD2Ev,comdat
+        .p2align        4
+        .type   _ZN6OnExitD2Ev, at function
+_ZN6OnExitD2Ev:
+        .cfi_startproc
+        lghi    %r2, 0
+        jg      llvm_jitlink_setTestResultOverride at PLT
+        .cfi_endproc
+
+// main registers the atexit and sets the test result to one.
+        .globl  main
+        .p2align        4
+        .type   main, at function
+main:
+        .cfi_startproc
+# %bb.0:
+        stmg    %r14, %r15, 48(%r15)
+        lgrl    %r2, _ZN6OnExitD2Ev at GOT
+        brasl   %r14, atexit at PLT
+        lghi    %r2, 1
+        brasl   %r14, llvm_jitlink_setTestResultOverride at PLT
+        lghi    %r2, 0
+        lmg     %r14, %r15, 48(%r15)
+        br      %r14
+.Lfunc_end1:
+        .size   main, .Lfunc_end1-main
+        .cfi_endproc
+
+        .type   _ZL6onExit, at object
+        .local  _ZL6onExit
+        .comm   _ZL6onExit,1,2
diff --git a/compiler-rt/test/orc/TestCases/Linux/systemz/trivial-cxa-atexit.S b/compiler-rt/test/orc/TestCases/Linux/systemz/trivial-cxa-atexit.S
new file mode 100644
index 0000000000000..e5d5191b088fb
--- /dev/null
+++ b/compiler-rt/test/orc/TestCases/Linux/systemz/trivial-cxa-atexit.S
@@ -0,0 +1,41 @@
+// Test that the runtime correctly interposes ___cxa_atexit.
+//
+// RUN: %clang -c -o %t %s
+// RUN: %llvm_jitlink %t
+
+        .text
+// OnExit destructor resets the test result override to zero.
+        .section        .text._ZN6OnExitD2Ev,"axG", at progbits,_ZN6OnExitD2Ev,comdat
+        .p2align        4
+        .type   _ZN6OnExitD2Ev, at function
+_ZN6OnExitD2Ev:
+        .cfi_startproc
+        lghi    %r2, 0
+        jg llvm_jitlink_setTestResultOverride at PLT
+        .cfi_endproc
+
+// main registers the atexit and sets the test result to one.
+        .globl  main
+        .p2align        4
+        .type   main, at function
+main:
+        .cfi_startproc
+# %bb.0:
+        stmg    %r14, %r15, 48(%r15)
+        lgrl    %r2, _ZN6OnExitD2Ev at GOT
+        lgrl    %r4, __dso_handle at GOT
+        larl    %r3, _ZL6onExit
+        brasl   %r14, __cxa_atexit at PLT
+        lghi    %r2, 1
+        brasl   %r14, llvm_jitlink_setTestResultOverride at PLT
+        lghi    %r2, 0
+        lmg     %r14, %r15, 48(%r15)
+        br      %r14
+.Lfunc_end1:
+        .size   main, .Lfunc_end1-main
+        .cfi_endproc
+
+        .type   _ZL6onExit, at object
+        .local  _ZL6onExit
+        .comm   _ZL6onExit,1,2
+        .hidden __dso_handle
diff --git a/compiler-rt/test/orc/TestCases/Linux/systemz/trivial-static-initializer.S b/compiler-rt/test/orc/TestCases/Linux/systemz/trivial-static-initializer.S
new file mode 100644
index 0000000000000..872a70a01b888
--- /dev/null
+++ b/compiler-rt/test/orc/TestCases/Linux/systemz/trivial-static-initializer.S
@@ -0,0 +1,35 @@
+// Test that basic ELF static initializers work. The main function in this
+// test returns the value of 'x', which is initially 1 in the data section,
+// and reset to 0 if the _static_init function is run. If the static initializer
+// does not run then main will return 1, causing the test to be treated as a
+// failure.
+//
+// RUN: %clang -c -o %t %s
+// RUN: %llvm_jitlink %t
+
+	.text
+
+        .globl  main         
+        .p2align        4
+main:
+        lgrl    %r1, x at GOT
+        lgf     %r2, 0(%r1)
+        br      %r14
+
+# static initializer sets the value of 'x' to zero.
+        .p2align        4
+_static_init:
+        lgrl    %r1, x at GOT
+        mvhi    0(%r1), 0
+	br 	%r14
+
+        .data
+        .globl  x
+        .p2align        2, 0x0
+x:
+        .long   1
+        .size   x, 4
+
+        .section        .init_array,"aw", at init_array
+        .p2align        3, 0x0
+        .quad   _static_init
diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h b/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
index dde3448cd5da7..09ec56db6826f 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/systemz.h
@@ -814,8 +814,6 @@ class GOTTableManager : public TableManager<GOTTableManager> {
   static StringRef getSectionName() { return "$__GOT"; }
 
   bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
-    if (E.getTarget().isDefined())
-      return false;
     Edge::Kind KindToSet = Edge::Invalid;
     switch (E.getKind()) {
     case systemz::RequestGOTAndTransformToDelta12FromGOT:
diff --git a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
index 9ac8c5ef66de6..7dc1ae520f132 100644
--- a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp
@@ -11,6 +11,7 @@
 #include "llvm/ExecutionEngine/JITLink/aarch64.h"
 #include "llvm/ExecutionEngine/JITLink/loongarch.h"
 #include "llvm/ExecutionEngine/JITLink/ppc64.h"
+#include "llvm/ExecutionEngine/JITLink/systemz.h"
 #include "llvm/ExecutionEngine/JITLink/x86_64.h"
 #include "llvm/ExecutionEngine/Orc/AbsoluteSymbols.h"
 #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
@@ -153,6 +154,9 @@ class DSOHandleMaterializationUnit : public MaterializationUnit {
     case Triple::loongarch64:
       EdgeKind = jitlink::loongarch::Pointer64;
       break;
+    case Triple::systemz:
+      EdgeKind = jitlink::systemz::Pointer64;
+      break;
     default:
       llvm_unreachable("Unrecognized architecture");
     }
@@ -367,6 +371,7 @@ bool ELFNixPlatform::supportedTarget(const Triple &TT) {
   // right now.
   case Triple::ppc64le:
   case Triple::loongarch64:
+  case Triple::systemz:
     return true;
   default:
     return false;



More information about the llvm-commits mailing list