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 + +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 + +@__dso_handle = external hidden global i8 +@.str = private unnamed_addr constant [5 x i8] c"main\00", align 1 +@.str.1 = private unnamed_addr constant [12 x i8] c"constructor\00", align 1 +@.str.2 = private unnamed_addr constant [11 x i8] c"destructor\00", align 1 +@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,@function +destructor: +.Ldestructor$local: + larl %r2, .Lstr.d + jg puts@PLT + + .globl main + .p2align 4, 0x90 + .type main,@function +main: +.Lmain$local: + stmg %r14, %r15, 112(%r15) + aghi %r15, -160 + larl %r2, .Lstr + brasl %r14, puts@PLT + lghi %r2, 0 + lmg %r14, %r15, 272(%r15) + br %r14 + + .p2align 4 + .type constructor.65535,@function +constructor.65535: + stmg %r14, %r15, 112(%r15) + aghi %r15, -160 + larl %r2, .Lstr.65535 + brasl %r14, puts@PLT + lgrl %r4, __dso_handle + lgrl %r2, .Ldestructor$local@GOT + lghi %r3, 0 + lmg %r14, %r15, 272(%r15) + jg __cxa_atexit@PLT + + .p2align 4 + .type constructor.200,@function +constructor.200: + larl %r2, .Lstr.200 + jg puts@PLT + + .p2align 4 + .type constructor.100,@function +constructor.100: + larl %r2, .Lstr.100 + jg puts@PLT + + .hidden __dso_handle + .section .init_array.101,"aw",@init_array + .p2align 3, 0x0 + .quad constructor.100 + .section .init_array.200,"aw",@init_array + .p2align 3, 0x0 + .quad constructor.200 + .section .init_array,"aw",@init_array + .p2align 3, 0x0 + .quad constructor.65535 + .type .Lstr.d,@object + .section .rodata.str1.2,"aMS",@progbits,1 + .p2align 1, 0x0 +.Lstr.d: + .asciz "destructor" + .size .Lstr.d, 11 + + .type .Lstr.100,@object + .p2align 1, 0x0 +.Lstr.100: + .asciz "constructor 100" + .size .Lstr.100, 16 + + .type .Lstr.200,@object + .p2align 1, 0x0 +.Lstr.200: + .asciz "constructor 200" + .size .Lstr.200, 16 + + .type .Lstr.65535,@object + .p2align 1, 0x0 +.Lstr.65535: + .asciz "constructor 65535" + .size .Lstr.65535, 18 + + .type .Lstr,@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",@progbits,_ZN6OnExitD2Ev,comdat + .p2align 4 + .type _ZN6OnExitD2Ev,@function +_ZN6OnExitD2Ev: + .cfi_startproc + lghi %r2, 0 + jg llvm_jitlink_setTestResultOverride@PLT + .cfi_endproc + +// main registers the atexit and sets the test result to one. + .globl main + .p2align 4 + .type main,@function +main: + .cfi_startproc +# %bb.0: + stmg %r14, %r15, 48(%r15) + lgrl %r2, _ZN6OnExitD2Ev@GOT + brasl %r14, atexit@PLT + lghi %r2, 1 + brasl %r14, llvm_jitlink_setTestResultOverride@PLT + lghi %r2, 0 + lmg %r14, %r15, 48(%r15) + br %r14 +.Lfunc_end1: + .size main, .Lfunc_end1-main + .cfi_endproc + + .type _ZL6onExit,@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",@progbits,_ZN6OnExitD2Ev,comdat + .p2align 4 + .type _ZN6OnExitD2Ev,@function +_ZN6OnExitD2Ev: + .cfi_startproc + lghi %r2, 0 + jg llvm_jitlink_setTestResultOverride@PLT + .cfi_endproc + +// main registers the atexit and sets the test result to one. + .globl main + .p2align 4 + .type main,@function +main: + .cfi_startproc +# %bb.0: + stmg %r14, %r15, 48(%r15) + lgrl %r2, _ZN6OnExitD2Ev@GOT + lgrl %r4, __dso_handle@GOT + larl %r3, _ZL6onExit + brasl %r14, __cxa_atexit@PLT + lghi %r2, 1 + brasl %r14, llvm_jitlink_setTestResultOverride@PLT + lghi %r2, 0 + lmg %r14, %r15, 48(%r15) + br %r14 +.Lfunc_end1: + .size main, .Lfunc_end1-main + .cfi_endproc + + .type _ZL6onExit,@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@GOT + lgf %r2, 0(%r1) + br %r14 + +# static initializer sets the value of 'x' to zero. + .p2align 4 +_static_init: + lgrl %r1, x@GOT + mvhi 0(%r1), 0 + br %r14 + + .data + .globl x + .p2align 2, 0x0 +x: + .long 1 + .size x, 4 + + .section .init_array,"aw",@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 { 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;