#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
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)
}
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) {
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();
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:
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,
/// 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,
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.
// 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 {
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)
--- /dev/null
+; 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)
+}
--- /dev/null
+# 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
--- /dev/null
+# 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