diff --git a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake index d14745ef9d138..3742f0176f9e6 100644 --- a/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake +++ b/compiler-rt/cmake/Modules/AllSupportedArchDefs.cmake @@ -85,7 +85,7 @@ endif() set(ALL_SHADOWCALLSTACK_SUPPORTED_ARCH ${ARM64}) if (UNIX) -set(ALL_ORC_SUPPORTED_ARCH ${X86_64} ${ARM64} ${ARM32}) +set(ALL_ORC_SUPPORTED_ARCH ${X86_64} ${ARM64} ${ARM32} ${PPC64}) endif() if (WIN32) diff --git a/compiler-rt/test/orc/TestCases/Linux/ppc64/ehframe-default.cpp b/compiler-rt/test/orc/TestCases/Linux/ppc64/ehframe-default.cpp new file mode 100644 index 0000000000000..0f7dcec4b5a5b --- /dev/null +++ b/compiler-rt/test/orc/TestCases/Linux/ppc64/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/ppc64/ehframe-libunwind.cpp b/compiler-rt/test/orc/TestCases/Linux/ppc64/ehframe-libunwind.cpp new file mode 100644 index 0000000000000..f56aa8fba950f --- /dev/null +++ b/compiler-rt/test/orc/TestCases/Linux/ppc64/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/ppc64/lit.local.cfg.py b/compiler-rt/test/orc/TestCases/Linux/ppc64/lit.local.cfg.py new file mode 100644 index 0000000000000..db1dc1c10a135 --- /dev/null +++ b/compiler-rt/test/orc/TestCases/Linux/ppc64/lit.local.cfg.py @@ -0,0 +1,7 @@ +# TODO: jitlink for ppc64/powerpc64 hasn't been well tested yet. +# We should support it in the future. +if config.root.host_arch != "ppc64le": + config.unsupported = True + +if config.target_arch != "powerpc64le": + config.unsupported = True diff --git a/compiler-rt/test/orc/TestCases/Linux/ppc64/lljit-ehframe.cpp b/compiler-rt/test/orc/TestCases/Linux/ppc64/lljit-ehframe.cpp new file mode 100644 index 0000000000000..b73ec2387028e --- /dev/null +++ b/compiler-rt/test/orc/TestCases/Linux/ppc64/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/ppc64/lljit-initialize-deinitialize.ll b/compiler-rt/test/orc/TestCases/Linux/ppc64/lljit-initialize-deinitialize.ll new file mode 100644 index 0000000000000..34bfc10b9d897 --- /dev/null +++ b/compiler-rt/test/orc/TestCases/Linux/ppc64/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/ppc64/priority-static-initializer.S b/compiler-rt/test/orc/TestCases/Linux/ppc64/priority-static-initializer.S new file mode 100644 index 0000000000000..7eef13c285913 --- /dev/null +++ b/compiler-rt/test/orc/TestCases/Linux/ppc64/priority-static-initializer.S @@ -0,0 +1,188 @@ +// 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 + .abiversion 2 + .globl constructor.100 + .p2align 4 + .type constructor.100,@function +constructor.100: +.Lfunc_begin0: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry constructor.100, .Lfunc_lep0-.Lfunc_gep0 + mflr 0 + stdu 1, -32(1) + std 0, 48(1) + addis 3, 2, .L.str@toc@ha + addi 3, 3, .L.str@toc@l + bl puts + nop + addi 1, 1, 32 + ld 0, 16(1) + mtlr 0 + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size constructor.100, .Lfunc_end0-.Lfunc_begin0 + + .globl constructor.200 + .p2align 4 + .type constructor.200,@function +constructor.200: +.Lfunc_begin1: +.Lfunc_gep1: + addis 2, 12, .TOC.-.Lfunc_gep1@ha + addi 2, 2, .TOC.-.Lfunc_gep1@l +.Lfunc_lep1: + .localentry constructor.200, .Lfunc_lep1-.Lfunc_gep1 + mflr 0 + stdu 1, -32(1) + std 0, 48(1) + addis 3, 2, .L.str.1@toc@ha + addi 3, 3, .L.str.1@toc@l + bl puts + nop + addi 1, 1, 32 + ld 0, 16(1) + mtlr 0 + blr + .long 0 + .quad 0 +.Lfunc_end1: + .size constructor.200, .Lfunc_end1-.Lfunc_begin1 + + .globl constructor.65535 + .p2align 4 + .type constructor.65535,@function +constructor.65535: +.Lfunc_begin2: +.Lfunc_gep2: + addis 2, 12, .TOC.-.Lfunc_gep2@ha + addi 2, 2, .TOC.-.Lfunc_gep2@l +.Lfunc_lep2: + .localentry constructor.65535, .Lfunc_lep2-.Lfunc_gep2 + mflr 0 + stdu 1, -32(1) + std 0, 48(1) + addis 3, 2, .L.str.2@toc@ha + addi 3, 3, .L.str.2@toc@l + bl puts + nop + addis 3, 2, destructor@toc@ha + addi 3, 3, destructor@toc@l + addis 5, 2, __dso_handle@toc@ha + addi 5, 5, __dso_handle@toc@l + li 4, 0 + bl __cxa_atexit + nop + addi 1, 1, 32 + ld 0, 16(1) + mtlr 0 + blr + .long 0 + .quad 0 +.Lfunc_end2: + .size constructor.65535, .Lfunc_end2-.Lfunc_begin2 + + .globl destructor + .p2align 4 + .type destructor,@function +destructor: +.Lfunc_begin3: +.Lfunc_gep3: + addis 2, 12, .TOC.-.Lfunc_gep3@ha + addi 2, 2, .TOC.-.Lfunc_gep3@l +.Lfunc_lep3: + .localentry destructor, .Lfunc_lep3-.Lfunc_gep3 + mflr 0 + stdu 1, -32(1) + std 0, 48(1) + addis 3, 2, .L.str.3@toc@ha + addi 3, 3, .L.str.3@toc@l + bl puts + nop + addi 1, 1, 32 + ld 0, 16(1) + mtlr 0 + blr + .long 0 + .quad 0 +.Lfunc_end3: + .size destructor, .Lfunc_end3-.Lfunc_begin3 + + .globl main + .p2align 4 + .type main,@function +main: +.Lfunc_begin4: +.Lfunc_gep4: + addis 2, 12, .TOC.-.Lfunc_gep4@ha + addi 2, 2, .TOC.-.Lfunc_gep4@l +.Lfunc_lep4: + .localentry main, .Lfunc_lep4-.Lfunc_gep4 + mflr 0 + stdu 1, -32(1) + std 0, 48(1) + addis 3, 2, .L.str.4@toc@ha + addi 3, 3, .L.str.4@toc@l + bl puts + nop + li 3, 0 + addi 1, 1, 32 + ld 0, 16(1) + mtlr 0 + blr + .long 0 + .quad 0 +.Lfunc_end4: + .size main, .Lfunc_end4-.Lfunc_begin4 + + .hidden __dso_handle + .type .L.str,@object + .section .rodata.str1.1,"aMS",@progbits,1 +.L.str: + .asciz "constructor 100" + .size .L.str, 16 + + .type .L.str.1,@object +.L.str.1: + .asciz "constructor 200" + .size .L.str.1, 16 + + .type .L.str.2,@object +.L.str.2: + .asciz "constructor 65535" + .size .L.str.2, 18 + + .type .L.str.3,@object +.L.str.3: + .asciz "destructor" + .size .L.str.3, 11 + + .type .L.str.4,@object +.L.str.4: + .asciz "main" + .size .L.str.4, 5 + + .section .init_array.100,"aw",@init_array + .p2align 3 + .quad constructor.100 + .section .init_array.200,"aw",@init_array + .p2align 3 + .quad constructor.200 + .section .init_array,"aw",@init_array + .p2align 3 + .quad constructor.65535 diff --git a/compiler-rt/test/orc/TestCases/Linux/ppc64/trivial-atexit.S b/compiler-rt/test/orc/TestCases/Linux/ppc64/trivial-atexit.S new file mode 100644 index 0000000000000..eaa8ac1088bfa --- /dev/null +++ b/compiler-rt/test/orc/TestCases/Linux/ppc64/trivial-atexit.S @@ -0,0 +1,63 @@ +// Test that the runtime correctly interposes atexit. +// +// RUN: %clang -c -o %t %s +// RUN: %llvm_jitlink %t + + .text + .abiversion 2 +// on_exit_hook destructor resets the test result override to zero. + .globl on_exit_hook + .p2align 4 + .type on_exit_hook,@function +on_exit_hook: +.Lfunc_begin0: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry on_exit_hook, .Lfunc_lep0-.Lfunc_gep0 + mflr 0 + stdu 1, -32(1) + std 0, 48(1) + li 3, 0 + bl llvm_jitlink_setTestResultOverride + nop + addi 1, 1, 32 + ld 0, 16(1) + mtlr 0 + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size on_exit_hook, .Lfunc_end0-.Lfunc_begin0 + +// main registers the atexit and sets the test result to one. + .globl main + .p2align 4 + .type main,@function +main: +.Lfunc_begin1: +.Lfunc_gep1: + addis 2, 12, .TOC.-.Lfunc_gep1@ha + addi 2, 2, .TOC.-.Lfunc_gep1@l +.Lfunc_lep1: + .localentry main, .Lfunc_lep1-.Lfunc_gep1 + mflr 0 + stdu 1, -32(1) + std 0, 48(1) + addis 3, 2, on_exit_hook@toc@ha + addi 3, 3, on_exit_hook@toc@l + bl atexit + nop + li 3, 1 + bl llvm_jitlink_setTestResultOverride + nop + li 3, 0 + addi 1, 1, 32 + ld 0, 16(1) + mtlr 0 + blr + .long 0 + .quad 0 +.Lfunc_end1: + .size main, .Lfunc_end1-.Lfunc_begin1 diff --git a/compiler-rt/test/orc/TestCases/Linux/ppc64/trivial-cxa-atexit.S b/compiler-rt/test/orc/TestCases/Linux/ppc64/trivial-cxa-atexit.S new file mode 100644 index 0000000000000..8a74725a373e0 --- /dev/null +++ b/compiler-rt/test/orc/TestCases/Linux/ppc64/trivial-cxa-atexit.S @@ -0,0 +1,66 @@ +// Test that the runtime correctly interposes ___cxa_atexit. +// +// RUN: %clang -c -o %t %s +// RUN: %llvm_jitlink %t + .text + .abiversion 2 + .file "cxa-atexit.c" + .globl on_exit_hook + .p2align 4 + .type on_exit_hook,@function +on_exit_hook: +.Lfunc_begin0: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry on_exit_hook, .Lfunc_lep0-.Lfunc_gep0 + mflr 0 + stdu 1, -32(1) + std 0, 48(1) + li 3, 0 + bl llvm_jitlink_setTestResultOverride + nop + addi 1, 1, 32 + ld 0, 16(1) + mtlr 0 + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size on_exit_hook, .Lfunc_end0-.Lfunc_begin0 + + .globl main + .p2align 4 + .type main,@function +main: +.Lfunc_begin1: +.Lfunc_gep1: + addis 2, 12, .TOC.-.Lfunc_gep1@ha + addi 2, 2, .TOC.-.Lfunc_gep1@l +.Lfunc_lep1: + .localentry main, .Lfunc_lep1-.Lfunc_gep1 + mflr 0 + stdu 1, -32(1) + std 0, 48(1) + addis 3, 2, on_exit_hook@toc@ha + addi 3, 3, on_exit_hook@toc@l + li 4, 0 + addis 5, 2, __dso_handle@toc@ha + addi 5, 5, __dso_handle@toc@l + bl __cxa_atexit + nop + li 3, 1 + bl llvm_jitlink_setTestResultOverride + nop + li 3, 0 + addi 1, 1, 32 + ld 0, 16(1) + mtlr 0 + blr + .long 0 + .quad 0 +.Lfunc_end1: + .size main, .Lfunc_end1-.Lfunc_begin1 + + .hidden __dso_handle diff --git a/compiler-rt/test/orc/TestCases/Linux/ppc64/trivial-static-initializer.S b/compiler-rt/test/orc/TestCases/Linux/ppc64/trivial-static-initializer.S new file mode 100644 index 0000000000000..9d84b259f3a72 --- /dev/null +++ b/compiler-rt/test/orc/TestCases/Linux/ppc64/trivial-static-initializer.S @@ -0,0 +1,59 @@ +// 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 + .abiversion 2 + .file "init.c" + .globl static_init + .p2align 4 + .type static_init,@function +static_init: +.Lfunc_begin0: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry static_init, .Lfunc_lep0-.Lfunc_gep0 + addis 3, 2, x@toc@ha + li 4, 0 + stw 4, x@toc@l(3) + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size static_init, .Lfunc_end0-.Lfunc_begin0 + + .globl main + .p2align 4 + .type main,@function +main: +.Lfunc_begin1: +.Lfunc_gep1: + addis 2, 12, .TOC.-.Lfunc_gep1@ha + addi 2, 2, .TOC.-.Lfunc_gep1@l +.Lfunc_lep1: + .localentry main, .Lfunc_lep1-.Lfunc_gep1 + addis 3, 2, x@toc@ha + lwa 3, x@toc@l(3) + blr + .long 0 + .quad 0 +.Lfunc_end1: + .size main, .Lfunc_end1-.Lfunc_begin1 + + .type x,@object + .data + .globl x + .p2align 2, 0x0 +x: + .long 1 + .size x, 4 + + .section .init_array.0,"aw",@init_array + .p2align 3 + .quad static_init diff --git a/compiler-rt/test/orc/TestCases/Linux/ppc64/trivial-tls.S b/compiler-rt/test/orc/TestCases/Linux/ppc64/trivial-tls.S new file mode 100644 index 0000000000000..745e472d6a6b1 --- /dev/null +++ b/compiler-rt/test/orc/TestCases/Linux/ppc64/trivial-tls.S @@ -0,0 +1,77 @@ +// XFAIL: target={{powerpc64.*}} +// 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. + + .text + .abiversion 2 + .file "tlstest.cpp" + .globl main # -- Begin function main + .p2align 4 + .type main,@function +main: # @main +.Lfunc_begin0: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry main, .Lfunc_lep0-.Lfunc_gep0 +# %bb.0: # %entry + mflr 0 + std 30, -16(1) # 8-byte Folded Spill + stdu 1, -48(1) + addis 3, 2, x@got@tlsgd@ha + std 0, 64(1) + addi 3, 3, x@got@tlsgd@l + bl __tls_get_addr(x@tlsgd) + nop + lwz 30, 0(3) + addis 3, 2, y@got@tlsgd@ha + addi 3, 3, y@got@tlsgd@l + bl __tls_get_addr(y@tlsgd) + nop + lwz 3, 0(3) + addis 4, 2, z@got@tlsgd@ha + add 30, 3, 30 + addi 3, 4, z@got@tlsgd@l + bl __tls_get_addr(z@tlsgd) + nop + lwz 3, 0(3) + add 3, 30, 3 + extsw 3, 3 + addi 1, 1, 48 + ld 0, 16(1) + ld 30, -16(1) # 8-byte Folded Reload + mtlr 0 + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size main, .Lfunc_end0-.Lfunc_begin0 + # -- End function + .type x,@object # @x + .section .tbss,"awT",@nobits + .globl x + .p2align 2, 0x0 +x: + .long 0 # 0x0 + .size x, 4 + + .type y,@object # @y + .section .tdata,"awT",@progbits + .globl y + .p2align 2, 0x0 +y: + .long 1 # 0x1 + .size y, 4 + + .type z,@object # @z + .globl z + .p2align 2, 0x0 +z: + .long 4294967295 # 0xffffffff + .size z, 4 diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_ppc64.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_ppc64.cpp index 02fdf4a62afd6..9a6a019fd6569 100644 --- a/llvm/lib/ExecutionEngine/JITLink/ELF_ppc64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ELF_ppc64.cpp @@ -192,6 +192,9 @@ class ELFLinkGraphBuilder_ppc64 case ELF::R_PPC64_ADDR64: Kind = ppc64::Pointer64; break; + case ELF::R_PPC64_ADDR32: + Kind = ppc64::Pointer32; + break; case ELF::R_PPC64_TOC16_HA: Kind = ppc64::TOCDelta16HA; break; diff --git a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp index 1bb4ecdff2991..c08b8b037fa29 100644 --- a/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ELFNixPlatform.cpp @@ -11,6 +11,7 @@ #include "llvm/BinaryFormat/ELF.h" #include "llvm/ExecutionEngine/JITLink/ELF_x86_64.h" #include "llvm/ExecutionEngine/JITLink/aarch64.h" +#include "llvm/ExecutionEngine/JITLink/ppc64.h" #include "llvm/ExecutionEngine/JITLink/x86_64.h" #include "llvm/ExecutionEngine/Orc/DebugUtils.h" #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" @@ -54,6 +55,16 @@ class DSOHandleMaterializationUnit : public MaterializationUnit { Endianness = support::endianness::little; EdgeKind = jitlink::aarch64::Pointer64; break; + case Triple::ppc64: + PointerSize = 8; + Endianness = support::endianness::big; + EdgeKind = jitlink::ppc64::Pointer64; + break; + case Triple::ppc64le: + PointerSize = 8; + Endianness = support::endianness::little; + EdgeKind = jitlink::ppc64::Pointer64; + break; default: llvm_unreachable("Unrecognized architecture"); } @@ -238,6 +249,9 @@ bool ELFNixPlatform::supportedTarget(const Triple &TT) { switch (TT.getArch()) { case Triple::x86_64: case Triple::aarch64: + // FIXME: jitlink for ppc64 hasn't been well tested, leave it unsupported + // right now. + case Triple::ppc64le: return true; default: return false;