OSDN Git Service

[PowerPC] Implement Thread Local Storage Support for Local Exec
authorKamau Bridgeman <kamau.bridgeman@ibm.com>
Fri, 11 Sep 2020 14:33:33 +0000 (10:33 -0400)
committerAlbion Fung <albionapc@gmail.com>
Mon, 14 Sep 2020 19:16:28 +0000 (14:16 -0500)
This patch is the initial support for the Local Exec Thread Local
Storage model to produce code sequence and relocations correct
to the ABI for the model when using PC relative memory operations.

Patch by: Kamau Bridgeman

Differential Revision: https://reviews.llvm.org/D83404

llvm/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def
llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp
llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
llvm/lib/Target/PowerPC/PPCISelLowering.cpp
llvm/lib/Target/PowerPC/PPCISelLowering.h
llvm/lib/Target/PowerPC/PPCInstrInfo.td
llvm/lib/Target/PowerPC/PPCInstrPrefix.td
llvm/lib/Target/PowerPC/PPCMCInstLower.cpp
llvm/test/CodeGen/PowerPC/pcrel-tls-local-exec.ll [new file with mode: 0644]
llvm/test/MC/PowerPC/pcrel-tls-local-exec-address-load-reloc.s [new file with mode: 0644]
llvm/test/MC/PowerPC/pcrel-tls-local-exec-value-load-reloc.s [new file with mode: 0644]

index 2cf021a..901af67 100644 (file)
 #undef R_PPC64_PCREL_OPT
 #undef R_PPC64_PCREL34
 #undef R_PPC64_GOT_PCREL34
+#undef R_PPC64_TPREL34
 #undef R_PPC64_GOT_TLSGD_PCREL34
 #undef R_PPC64_GOT_TPREL_PCREL34
 #undef R_PPC64_IRELATIVE
@@ -200,6 +201,7 @@ ELF_RELOC(R_PPC64_REL24_NOTOC,          116)
 ELF_RELOC(R_PPC64_PCREL_OPT,            123)
 ELF_RELOC(R_PPC64_PCREL34,              132)
 ELF_RELOC(R_PPC64_GOT_PCREL34,          133)
+ELF_RELOC(R_PPC64_TPREL34,              146)
 ELF_RELOC(R_PPC64_GOT_TLSGD_PCREL34,    148)
 ELF_RELOC(R_PPC64_GOT_TPREL_PCREL34,    150)
 ELF_RELOC(R_PPC64_IRELATIVE,            248)
index 006cd57..601e11d 100644 (file)
@@ -419,7 +419,13 @@ unsigned PPCELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
       }
       break;
     case PPC::fixup_ppc_imm34:
-      report_fatal_error("Unsupported Modifier for fixup_ppc_imm34.");
+      switch (Modifier) {
+      default:
+        report_fatal_error("Unsupported Modifier for fixup_ppc_imm34.");
+      case MCSymbolRefExpr::VK_TPREL:
+        Type = ELF::R_PPC64_TPREL34;
+        break;
+      }
       break;
     case FK_Data_8:
       switch (Modifier) {
index 62bb5cc..a70e746 100644 (file)
@@ -691,6 +691,8 @@ bool PPCDAGToDAGISel::tryTLSXFormLoad(LoadSDNode *LD) {
   SDValue Offset = LD->getOffset();
   if (!Offset.isUndef())
     return false;
+  if (Base.getOperand(1).getOpcode() == PPCISD::TLS_LOCAL_EXEC_MAT_ADDR)
+    return false;
 
   SDLoc dl(LD);
   EVT MemVT = LD->getMemoryVT();
index 469fe97..66711f6 100644 (file)
@@ -1512,6 +1512,8 @@ const char *PPCTargetLowering::getTargetNodeName(unsigned Opcode) const {
   case PPCISD::MAT_PCREL_ADDR:  return "PPCISD::MAT_PCREL_ADDR";
   case PPCISD::TLS_DYNAMIC_MAT_PCREL_ADDR:
     return "PPCISD::TLS_DYNAMIC_MAT_PCREL_ADDR";
+  case PPCISD::TLS_LOCAL_EXEC_MAT_ADDR:
+    return "PPCISD::TLS_LOCAL_EXEC_MAT_ADDR";
   case PPCISD::LD_SPLAT:        return "PPCISD::LD_SPLAT";
   case PPCISD::FNMSUB:          return "PPCISD::FNMSUB";
   case PPCISD::STRICT_FADDRTZ:
@@ -3015,6 +3017,15 @@ SDValue PPCTargetLowering::LowerGlobalTLSAddress(SDValue Op,
   TLSModel::Model Model = TM.getTLSModel(GV);
 
   if (Model == TLSModel::LocalExec) {
+    if (Subtarget.isUsingPCRelativeCalls()) {
+      SDValue TLSReg = DAG.getRegister(PPC::X13, MVT::i64);
+      SDValue TGA = DAG.getTargetGlobalAddress(
+          GV, dl, PtrVT, 0, (PPCII::MO_PCREL_FLAG | PPCII::MO_TPREL_FLAG));
+      SDValue MatAddr =
+          DAG.getNode(PPCISD::TLS_LOCAL_EXEC_MAT_ADDR, dl, PtrVT, TGA);
+      return DAG.getNode(PPCISD::ADD_TLS, dl, PtrVT, TLSReg, MatAddr);
+    }
+
     SDValue TGAHi = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0,
                                                PPCII::MO_TPREL_HA);
     SDValue TGALo = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0,
index 05c9a5d..3e900e2 100644 (file)
@@ -441,6 +441,11 @@ namespace llvm {
     /// through an add like PADDI.
     TLS_DYNAMIC_MAT_PCREL_ADDR,
 
+    /// TLS_LOCAL_EXEC_MAT_ADDR = Materialize an address for TLS global address
+    /// when using local exec access models, and when prefixed instructions are
+    /// available. This is used with ADD_TLS to produce an add like PADDI.
+    TLS_LOCAL_EXEC_MAT_ADDR,
+
     // Constrained conversion from floating point to int
     STRICT_FCTIDZ = ISD::FIRST_TARGET_STRICTFP_OPCODE,
     STRICT_FCTIWZ,
index bf7ad63..30605a2 100644 (file)
@@ -368,6 +368,8 @@ def PPCprobedalloca : SDNode<"PPCISD::PROBED_ALLOCA", SDTDynOp, [SDNPHasChain]>;
 def PPCmatpcreladdr : SDNode<"PPCISD::MAT_PCREL_ADDR", SDTIntUnaryOp, []>;
 def PPCtlsdynamatpcreladdr : SDNode<"PPCISD::TLS_DYNAMIC_MAT_PCREL_ADDR",
                                     SDTIntUnaryOp, []>;
+def PPCtlslocalexecmataddr : SDNode<"PPCISD::TLS_LOCAL_EXEC_MAT_ADDR",
+                                    SDTIntUnaryOp, []>;
 
 //===----------------------------------------------------------------------===//
 // PowerPC specific transformation functions and pattern fragments.
index 73321de..55872a4 100644 (file)
@@ -829,6 +829,10 @@ let Predicates = [PCRelativeMemops], AddedComplexity = 500 in {
   // PPCtlsdynamatpcreladdr node is used for TLS dynamic models to materialize
   // tls global address with paddi instruction.
   def : Pat<(PPCtlsdynamatpcreladdr pcreladdr:$addr), (PADDI8pc 0, $addr)>;
+  // PPCtlslocalexecmataddr node is used for TLS local exec models to
+  // materialize tls global address with paddi instruction.
+  def : Pat<(PPCaddTls i64:$in, (PPCtlslocalexecmataddr tglobaltlsaddr:$addr)),
+            (PADDI8 $in, $addr)>;
 }
 
 let Predicates = [PrefixInstrs] in {
index 795abed..1358bec 100644 (file)
@@ -86,6 +86,8 @@ static MCOperand GetSymbolRef(const MachineOperand &MO, const MCSymbol *Symbol,
     RefKind = MCSymbolRefExpr::VK_PCREL;
   else if (MO.getTargetFlags() == (PPCII::MO_PCREL_FLAG | PPCII::MO_GOT_FLAG))
     RefKind = MCSymbolRefExpr::VK_PPC_GOT_PCREL;
+  else if (MO.getTargetFlags() == (PPCII::MO_PCREL_FLAG | PPCII::MO_TPREL_FLAG))
+    RefKind = MCSymbolRefExpr::VK_TPREL;
   else if (MO.getTargetFlags() == PPCII::MO_GOT_TLSGD_PCREL_FLAG)
     RefKind = MCSymbolRefExpr::VK_PPC_GOT_TLSGD_PCREL;
   else if (MO.getTargetFlags() == PPCII::MO_GOT_TPREL_PCREL_FLAG)
diff --git a/llvm/test/CodeGen/PowerPC/pcrel-tls-local-exec.ll b/llvm/test/CodeGen/PowerPC/pcrel-tls-local-exec.ll
new file mode 100644 (file)
index 0000000..4724599
--- /dev/null
@@ -0,0 +1,74 @@
+; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \
+; RUN:   -enable-ppc-pcrel-tls -mcpu=pwr10 -ppc-asm-full-reg-names \
+; RUN:   < %s | FileCheck %s --check-prefix=CHECK-S
+; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \
+; RUN:   -enable-ppc-pcrel-tls -mcpu=pwr10 -ppc-asm-full-reg-names \
+; RUN:   --filetype=obj < %s | llvm-objdump --no-show-raw-insn --mcpu=pwr10 -dr - \
+; RUN:   | FileCheck %s --check-prefix=CHECK-O
+
+; These test cases are to ensure that when using pc relative memory operations
+; ABI correct code and relocations are produced for the Local Exec TLS Model.
+
+@x = thread_local global i32 0, align 4
+@y = thread_local global [5 x i32] [i32 0, i32 0, i32 0, i32 0, i32 0], align 4
+
+define i32* @LocalExecAddressLoad() {
+; CHECK-S-LABEL: LocalExecAddressLoad:
+; CHECK-S:       # %bb.0: # %entry
+; CHECK-S-NEXT:    paddi r3, r13, x@TPREL, 0
+; CHECK-S-NEXT:    blr
+; CHECK-O-LABEL: <LocalExecAddressLoad>:
+; CHECK-O:         0: paddi 3, 13, 0, 0
+; CHECK-O-NEXT:    0000000000000000:  R_PPC64_TPREL34 x
+; CHECK-O-NEXT:    8: blr
+entry:
+  ret i32* @x
+}
+
+define i32 @LocalExecValueLoad() {
+; CHECK-S-LABEL: LocalExecValueLoad:
+; CHECK-S:       # %bb.0: # %entry
+; CHECK-S-NEXT:    paddi r3, r13, x@TPREL, 0
+; CHECK-S-NEXT:    lwz r3, 0(r3)
+; CHECK-S-NEXT:    blr
+; CHECK-O-LABEL: <LocalExecValueLoad>:
+; CHECK-O:         20: paddi 3, 13, 0, 0
+; CHECK-O-NEXT:    0000000000000020:  R_PPC64_TPREL34 x
+; CHECK-O-NEXT:    28: lwz 3, 0(3)
+; CHECK-O-NEXT:    2c: blr
+entry:
+  %0 = load i32, i32* @x, align 4
+  ret i32 %0
+}
+
+define i32 @LocalExecValueLoadOffset() {
+; CHECK-S-LABEL: LocalExecValueLoadOffset:
+; CHECK-S:       # %bb.0: # %entry
+; CHECK-S-NEXT:    paddi r3, r13, y@TPREL, 0
+; CHECK-S-NEXT:    lwz r3, 12(r3)
+; CHECK-S-NEXT:    blr
+; CHECK-O-LABEL: <LocalExecValueLoadOffset>:
+; CHECK-O:         40: paddi 3, 13, 0, 0
+; CHECK-O-NEXT:    0000000000000040:  R_PPC64_TPREL34 y
+; CHECK-O-NEXT:    48: lwz 3, 12(3)
+; CHECK-O-NEXT:    4c: blr
+entry:
+  %0 = load i32, i32* getelementptr inbounds ([5 x i32], [5 x i32]* @y, i64 0, i64 3), align 4
+  ret i32 %0
+}
+
+
+define i32* @LocalExecValueLoadOffsetNoLoad() {
+; CHECK-S-LABEL: LocalExecValueLoadOffsetNoLoad:
+; CHECK-S:       # %bb.0: # %entry
+; CHECK-S-NEXT:    paddi r3, r13, y@TPREL, 0
+; CHECK-S-NEXT:    addi r3, r3, 12
+; CHECK-S-NEXT:    blr
+; CHECK-O-LABEL: <LocalExecValueLoadOffsetNoLoad>:
+; CHECK-O:         60: paddi 3, 13, 0, 0
+; CHECK-O-NEXT:    0000000000000060:  R_PPC64_TPREL34 y
+; CHECK-O-NEXT:    68: addi 3, 3, 12
+; CHECK-O-NEXT:    6c: blr
+entry:
+  ret i32* getelementptr inbounds ([5 x i32], [5 x i32]* @y, i64 0, i64 3)
+}
diff --git a/llvm/test/MC/PowerPC/pcrel-tls-local-exec-address-load-reloc.s b/llvm/test/MC/PowerPC/pcrel-tls-local-exec-address-load-reloc.s
new file mode 100644 (file)
index 0000000..ae3eb8b
--- /dev/null
@@ -0,0 +1,15 @@
+# RUN: llvm-mc -triple=powerpc64le-unknown-unknown -filetype=obj %s 2>&1 | \
+# RUN: FileCheck %s -check-prefix=MC
+# RUN: llvm-mc -triple=powerpc64le-unknown-unknown -filetype=obj %s | \
+# RUN: llvm-readobj -r - | FileCheck %s -check-prefix=READOBJ
+
+# This test checks that on Power PC we can correctly convert x@TPREL
+# into R_PPC64_TPREL34 for local exec relocations with address loaded.
+
+# MC-NOT:    error: invalid variant
+
+# READOBJ:        0x0 R_PPC64_TPREL34 x 0x0
+
+LocalExec:
+       paddi 3, 13, x@TPREL, 0
+       blr
diff --git a/llvm/test/MC/PowerPC/pcrel-tls-local-exec-value-load-reloc.s b/llvm/test/MC/PowerPC/pcrel-tls-local-exec-value-load-reloc.s
new file mode 100644 (file)
index 0000000..6ebee2f
--- /dev/null
@@ -0,0 +1,16 @@
+# RUN: llvm-mc -triple=powerpc64le-unknown-unknown -filetype=obj %s 2>&1 | \
+# RUN: FileCheck %s -check-prefix=MC
+# RUN: llvm-mc -triple=powerpc64le-unknown-unknown -filetype=obj %s | \
+# RUN: llvm-readobj -r - | FileCheck %s -check-prefix=READOBJ
+
+# This test checks that on Power PC we can correctly convert x@TPREL
+# into R_PPC64_TPREL34 for local exec relocations with the value loaded.
+
+# MC-NOT:    error: invalid variant
+
+# READOBJ:        0x0 R_PPC64_TPREL34 x 0x0
+
+LocalExecLoad:
+       paddi 3, 13, x@TPREL, 0
+       lwz 3, 0(3)
+       blr