diff --git a/compiler-rt/test/orc/TestCases/Linux/ppc64/Inputs/trivial-tls-main.cpp b/compiler-rt/test/orc/TestCases/Linux/ppc64/Inputs/trivial-tls-main.cpp new file mode 100644 index 00000000000000..d6757fdd4154c7 --- /dev/null +++ b/compiler-rt/test/orc/TestCases/Linux/ppc64/Inputs/trivial-tls-main.cpp @@ -0,0 +1,30 @@ +#include +#include +#include + +thread_local int x = 0; +thread_local int y = 1; +thread_local int z = -1; + +extern int TestPOWER10(); + +int Test() { return x + y + z; } + +static bool CPUModelIsPOWER10() { + std::string line; + std::ifstream cpuinfo("/proc/cpuinfo", std::ios::in); + if (!cpuinfo.is_open()) + return false; + while (std::getline(cpuinfo, line)) { + if (line.find("cpu") != std::string::npos && + line.find("POWER10") != std::string::npos) + return true; + } + return false; +} + +int main() { + if (CPUModelIsPOWER10()) + return TestPOWER10(); + return Test(); +} diff --git a/compiler-rt/test/orc/TestCases/Linux/ppc64/Inputs/trivial-tls-pwr10.cpp b/compiler-rt/test/orc/TestCases/Linux/ppc64/Inputs/trivial-tls-pwr10.cpp new file mode 100644 index 00000000000000..a6fb3088af6299 --- /dev/null +++ b/compiler-rt/test/orc/TestCases/Linux/ppc64/Inputs/trivial-tls-pwr10.cpp @@ -0,0 +1,5 @@ +extern thread_local int x; +extern thread_local int y; +extern thread_local int z; + +int __attribute__((target("arch=pwr10"))) TestPOWER10() { return x + y + z; } diff --git a/compiler-rt/test/orc/TestCases/Linux/ppc64/trivial-tls-pwr10.test b/compiler-rt/test/orc/TestCases/Linux/ppc64/trivial-tls-pwr10.test new file mode 100644 index 00000000000000..93561b1645c332 --- /dev/null +++ b/compiler-rt/test/orc/TestCases/Linux/ppc64/trivial-tls-pwr10.test @@ -0,0 +1,9 @@ +// RUN: rm -rf %t && mkdir -p %t +// RUN: %clangxx -fPIC -c -o %t/main.o %S/Inputs/trivial-tls-main.cpp +// RUN: %clangxx -fPIC -c -o %t/pwr10.o %S/Inputs/trivial-tls-pwr10.cpp +// RUN: %llvm_jitlink %t/main.o %t/pwr10.o +// FIXME: We seperate pwr10 code from main object file due to currrent +// implementation only supports one PLT stub for the same symbol. +// For example, `bl __tls_get_addr` in one object file has only one PLT stub, +// however we need another different PLT stub for `bl __tls_get_addr@notoc` +// whose target symbol is also `__tls_get_addr`. diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/ppc64.h b/llvm/include/llvm/ExecutionEngine/JITLink/ppc64.h index ff932f6022bdc8..b7239144559861 100644 --- a/llvm/include/llvm/ExecutionEngine/JITLink/ppc64.h +++ b/llvm/include/llvm/ExecutionEngine/JITLink/ppc64.h @@ -61,6 +61,7 @@ enum EdgeKind_ppc64 : Edge::Kind { RequestCallNoTOC, RequestTLSDescInGOTAndTransformToTOCDelta16HA, RequestTLSDescInGOTAndTransformToTOCDelta16LO, + RequestTLSDescInGOTAndTransformToDelta34, }; enum PLTCallStubKind { @@ -202,6 +203,10 @@ class PLTTableManager : public TableManager> { static StringRef getSectionName() { return "$__STUBS"; } + // FIXME: One external symbol can only have one PLT stub in a object file. + // This is a limitation when we need different PLT stubs for the same symbol. + // For example, we need two different PLT stubs for `bl __tls_get_addr` and + // `bl __tls_get_addr@notoc`. bool visitEdge(LinkGraph &G, Block *B, Edge &E) { bool isExternal = E.getTarget().isExternal(); Edge::Kind K = E.getKind(); diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_ppc64.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_ppc64.cpp index bf1d22ac9a4305..25b1dd9d3d1253 100644 --- a/llvm/lib/ExecutionEngine/JITLink/ELF_ppc64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ELF_ppc64.cpp @@ -43,17 +43,22 @@ class TLSInfoTableManager_ELF_ppc64 bool visitEdge(LinkGraph &G, Block *B, Edge &E) { Edge::Kind K = E.getKind(); - if (K == ppc64::RequestTLSDescInGOTAndTransformToTOCDelta16HA) { + switch (K) { + case ppc64::RequestTLSDescInGOTAndTransformToTOCDelta16HA: E.setKind(ppc64::TOCDelta16HA); E.setTarget(this->getEntryForTarget(G, E.getTarget())); return true; - } - if (K == ppc64::RequestTLSDescInGOTAndTransformToTOCDelta16LO) { + case ppc64::RequestTLSDescInGOTAndTransformToTOCDelta16LO: E.setKind(ppc64::TOCDelta16LO); E.setTarget(this->getEntryForTarget(G, E.getTarget())); return true; + case ppc64::RequestTLSDescInGOTAndTransformToDelta34: + E.setKind(ppc64::Delta34); + E.setTarget(this->getEntryForTarget(G, E.getTarget())); + return true; + default: + return false; } - return false; } Symbol &createEntry(LinkGraph &G, Symbol &Target) { @@ -234,10 +239,15 @@ class ELFLinkGraphBuilder_ppc64 if (ELFReloc == ELF::R_PPC64_TLSLD) return make_error("Local-dynamic TLS model is not supported", inconvertibleErrorCode()); + if (ELFReloc == ELF::R_PPC64_PCREL_OPT) // TODO: Support PCREL optimization, now ignore it. return Error::success(); + if (ELFReloc == ELF::R_PPC64_TPREL34) + return make_error("Local-exec TLS model is not supported", + inconvertibleErrorCode()); + auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec); if (!ObjSymbol) return ObjSymbol.takeError(); @@ -372,6 +382,9 @@ class ELFLinkGraphBuilder_ppc64 case ELF::R_PPC64_GOT_TLSGD16_LO: Kind = ppc64::RequestTLSDescInGOTAndTransformToTOCDelta16LO; break; + case ELF::R_PPC64_GOT_TLSGD_PCREL34: + Kind = ppc64::RequestTLSDescInGOTAndTransformToDelta34; + break; } Edge GE(Kind, Offset, *GraphSymbol, Addend); diff --git a/llvm/lib/ExecutionEngine/JITLink/ppc64.cpp b/llvm/lib/ExecutionEngine/JITLink/ppc64.cpp index ac4a62a503919e..27484aaf205901 100644 --- a/llvm/lib/ExecutionEngine/JITLink/ppc64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ppc64.cpp @@ -134,6 +134,8 @@ const char *getEdgeKindName(Edge::Kind K) { return "RequestTLSDescInGOTAndTransformToTOCDelta16HA"; case RequestTLSDescInGOTAndTransformToTOCDelta16LO: return "RequestTLSDescInGOTAndTransformToTOCDelta16LO"; + case RequestTLSDescInGOTAndTransformToDelta34: + return "RequestTLSDescInGOTAndTransformToDelta34"; default: return getGenericEdgeKindName(static_cast(K)); } diff --git a/llvm/test/ExecutionEngine/JITLink/ppc64/ELF_ppc64_relocations.s b/llvm/test/ExecutionEngine/JITLink/ppc64/ELF_ppc64_relocations.s index bcee29d1d34f60..8f28a8662cbd67 100644 --- a/llvm/test/ExecutionEngine/JITLink/ppc64/ELF_ppc64_relocations.s +++ b/llvm/test/ExecutionEngine/JITLink/ppc64/ELF_ppc64_relocations.s @@ -1,3 +1,4 @@ +# REQUIRES: system-linux # RUN: rm -rf %t && mkdir -p %t # RUN: llvm-mc --triple=powerpc64le-unknown-linux-gnu --filetype=obj -o \ # RUN: %t/elf_reloc.o --defsym LE=1 %s @@ -9,6 +10,7 @@ # RUN: --abs external_addr16_data=0x6000 \ # RUN: --abs external_addr32_data=0x36668840 \ # RUN: --abs pcrel_external_var=0x36668860 \ +# RUN: --abs pcrel_external_tls=0x36668880 \ # RUN: --check %s %t/elf_reloc.o # RUN: llvm-mc --triple=powerpc64-unknown-linux-gnu --filetype=obj -o \ # RUN: %t/elf_reloc.o %s @@ -20,6 +22,7 @@ # RUN: --abs external_addr16_data=0x6000 \ # RUN: --abs external_addr32_data=0x36668840 \ # RUN: --abs pcrel_external_var=0x36668860 \ +# RUN: --abs pcrel_external_tls=0x36668880 \ # RUN: --check %s %t/elf_reloc.o # jitlink-check: section_addr(elf_reloc.o, $__GOT) + 0x8000 = __TOC__ @@ -255,6 +258,22 @@ reloc_got_pcrel34: blr .size reloc_got_pcrel34,.-reloc_got_pcrel34 + .global reloc_tlsgd_pcrel34 + .p2align 4 + .type reloc_tlsgd_pcrel34,@function +reloc_tlsgd_pcrel34: + mflr 0 + std 0, 16(1) + stdu 1, -32(1) + paddi 3, 0, pcrel_external_tls@got@tlsgd@pcrel, 1 + bl __tls_get_addr@notoc(a@tlsgd) + lwa 3, 0(3) + addi 1, 1, 32 + ld 0, 16(1) + mtlr 0 + blr + .size reloc_tlsgd_pcrel34,.-reloc_tlsgd_pcrel34 + .type .L.str,@object .section .rodata.str1.1,"aMS",@progbits,1 .L.str: