#undef R_PPC64_PCREL34
#undef R_PPC64_GOT_PCREL34
#undef R_PPC64_TPREL34
+#undef R_PPC64_DTPREL34
#undef R_PPC64_GOT_TLSGD_PCREL34
+#undef R_PPC64_GOT_TLSLD_PCREL34
#undef R_PPC64_GOT_TPREL_PCREL34
#undef R_PPC64_IRELATIVE
#undef R_PPC64_REL16
ELF_RELOC(R_PPC64_PCREL34, 132)
ELF_RELOC(R_PPC64_GOT_PCREL34, 133)
ELF_RELOC(R_PPC64_TPREL34, 146)
+ELF_RELOC(R_PPC64_DTPREL34, 147)
ELF_RELOC(R_PPC64_GOT_TLSGD_PCREL34, 148)
+ELF_RELOC(R_PPC64_GOT_TLSLD_PCREL34, 149)
ELF_RELOC(R_PPC64_GOT_TPREL_PCREL34, 150)
ELF_RELOC(R_PPC64_IRELATIVE, 248)
ELF_RELOC(R_PPC64_REL16, 249)
VK_PPC_GOT_TLSLD_HA, // symbol@got@tlsld@ha
VK_PPC_GOT_PCREL, // symbol@got@pcrel
VK_PPC_GOT_TLSGD_PCREL, // symbol@got@tlsgd@pcrel
+ VK_PPC_GOT_TLSLD_PCREL, // symbol@got@tlsld@pcrel
VK_PPC_GOT_TPREL_PCREL, // symbol@got@tprel@pcrel
VK_PPC_TLS_PCREL, // symbol@tls@pcrel
VK_PPC_TLSLD, // symbol@tlsld
return "got@pcrel";
case VK_PPC_GOT_TLSGD_PCREL:
return "got@tlsgd@pcrel";
+ case VK_PPC_GOT_TLSLD_PCREL:
+ return "got@tlsld@pcrel";
case VK_PPC_GOT_TPREL_PCREL:
return "got@tprel@pcrel";
case VK_PPC_TLS_PCREL:
.Case("got@tlsld@ha", VK_PPC_GOT_TLSLD_HA)
.Case("got@pcrel", VK_PPC_GOT_PCREL)
.Case("got@tlsgd@pcrel", VK_PPC_GOT_TLSGD_PCREL)
+ .Case("got@tlsld@pcrel", VK_PPC_GOT_TLSLD_PCREL)
.Case("got@tprel@pcrel", VK_PPC_GOT_TPREL_PCREL)
.Case("tls@pcrel", VK_PPC_TLS_PCREL)
.Case("notoc", VK_PPC_NOTOC)
case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_PCREL:
Type = ELF::R_PPC64_GOT_TLSGD_PCREL34;
break;
+ case MCSymbolRefExpr::VK_PPC_GOT_TLSLD_PCREL:
+ Type = ELF::R_PPC64_GOT_TLSLD_PCREL34;
+ break;
case MCSymbolRefExpr::VK_PPC_GOT_TPREL_PCREL:
Type = ELF::R_PPC64_GOT_TPREL_PCREL34;
break;
switch (Modifier) {
default:
report_fatal_error("Unsupported Modifier for fixup_ppc_imm34.");
+ case MCSymbolRefExpr::VK_DTPREL:
+ Type = ELF::R_PPC64_DTPREL34;
+ break;
case MCSymbolRefExpr::VK_TPREL:
Type = ELF::R_PPC64_TPREL34;
break;
assert((SRE->getKind() == MCSymbolRefExpr::VK_PCREL ||
SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_PCREL ||
SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_TLSGD_PCREL ||
+ SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_TLSLD_PCREL ||
SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_TPREL_PCREL) &&
"VariantKind must be VK_PCREL or VK_PPC_GOT_PCREL or "
- "VK_PPC_GOT_TLSGD_PCREL or VK_PPC_GOT_TPREL_PCREL");
+ "VK_PPC_GOT_TLSGD_PCREL or VK_PPC_GOT_TLSLD_PCREL or "
+ "VK_PPC_GOT_TPREL_PCREL.");
// Generate the fixup for the relocation.
Fixups.push_back(
MCFixup::create(0, Expr,
/// TLS Initial Exec model.
MO_TPREL_FLAG = 64,
+ /// MO_TLSLD_FLAG - If this bit is set the symbol reference is relative to
+ /// TLS Local Dynamic model.
+ MO_TLSLD_FLAG = 128,
+
/// MO_GOT_TLSGD_PCREL_FLAG - A combintaion of flags, if these bits are set
/// they should produce the relocation @got@tlsgd@pcrel.
/// Fix up is VK_PPC_GOT_TLSGD_PCREL
MO_GOT_TLSGD_PCREL_FLAG = MO_PCREL_FLAG | MO_GOT_FLAG | MO_TLSGD_FLAG,
+ /// MO_GOT_TLSLD_PCREL_FLAG - A combintaion of flags, if these bits are set
+ /// they should produce the relocation @got@tlsld@pcrel.
+ /// Fix up is VK_PPC_GOT_TLSLD_PCREL
+ MO_GOT_TLSLD_PCREL_FLAG = MO_PCREL_FLAG | MO_GOT_FLAG | MO_TLSLD_FLAG,
+
/// MO_GOT_TPREL_PCREL_FLAG - A combintaion of flags, if these bits are set
/// they should produce the relocation @got@tprel@pcrel.
/// Fix up is VK_PPC_GOT_TPREL_PCREL
unsigned Opcode = PPC::BL8_NOP_TLS;
assert(MI->getNumOperands() >= 3 && "Expecting at least 3 operands from MI");
- if (MI->getOperand(2).getTargetFlags() == PPCII::MO_GOT_TLSGD_PCREL_FLAG) {
+ if (MI->getOperand(2).getTargetFlags() == PPCII::MO_GOT_TLSGD_PCREL_FLAG ||
+ MI->getOperand(2).getTargetFlags() == PPCII::MO_GOT_TLSLD_PCREL_FLAG) {
Kind = MCSymbolRefExpr::VK_PPC_NOTOC;
Opcode = PPC::BL8_NOTOC_TLS;
}
.addExpr(SymDtprel));
return;
}
+ case PPC::PADDIdtprel: {
+ // Transform: %rd = PADDIdtprel %rs, @sym
+ // Into: %rd = PADDI8 %rs, sym@dtprel
+ const MachineOperand &MO = MI->getOperand(2);
+ const GlobalValue *GValue = MO.getGlobal();
+ MCSymbol *MOSymbol = getSymbol(GValue);
+ const MCExpr *SymDtprel = MCSymbolRefExpr::create(
+ MOSymbol, MCSymbolRefExpr::VK_DTPREL, OutContext);
+ EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::PADDI8)
+ .addReg(MI->getOperand(0).getReg())
+ .addReg(MI->getOperand(1).getReg())
+ .addExpr(SymDtprel));
+ return;
+ }
+
case PPC::ADDIdtprelL:
// Transform: %xd = ADDIdtprelL %xs, @sym
// Into: %xd = ADDI8 %xs, sym@dtprel@l
case PPCISD::ADDI_TLSLD_L_ADDR: return "PPCISD::ADDI_TLSLD_L_ADDR";
case PPCISD::ADDIS_DTPREL_HA: return "PPCISD::ADDIS_DTPREL_HA";
case PPCISD::ADDI_DTPREL_L: return "PPCISD::ADDI_DTPREL_L";
+ case PPCISD::PADDI_DTPREL:
+ return "PPCISD::PADDI_DTPREL";
case PPCISD::VADD_SPLAT: return "PPCISD::VADD_SPLAT";
case PPCISD::SC: return "PPCISD::SC";
case PPCISD::CLRBHRB: return "PPCISD::CLRBHRB";
}
if (Model == TLSModel::LocalDynamic) {
+ if (Subtarget.isUsingPCRelativeCalls()) {
+ SDValue TGA = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0,
+ PPCII::MO_GOT_TLSLD_PCREL_FLAG);
+ SDValue MatPCRel =
+ DAG.getNode(PPCISD::TLS_DYNAMIC_MAT_PCREL_ADDR, dl, PtrVT, TGA);
+ return DAG.getNode(PPCISD::PADDI_DTPREL, dl, PtrVT, MatPCRel, TGA);
+ }
+
SDValue TGA = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, 0);
SDValue GOTPtr;
if (is64bit) {
/// sym\@got\@dtprel\@l.
ADDI_DTPREL_L,
+ /// G8RC = PADDI_DTPREL %x3, Symbol - For the pc-rel based local-dynamic TLS
+ /// model, produces a PADDI8 instruction that adds X3 to sym\@dtprel.
+ PADDI_DTPREL,
+
/// VRRC = VADD_SPLAT Elt, EltSize - Temporary node to be expanded
/// during instruction selection to optimize a BUILD_VECTOR into
/// operations on splats. This is necessary to avoid losing these
[(set i64:$rD,
(PPCaddiDtprelL i64:$reg, tglobaltlsaddr:$disp))]>,
isPPC64;
+def PADDIdtprel : PPCEmitTimePseudo<(outs g8rc:$rD), (ins g8rc_nox0:$reg, s16imm64:$disp),
+ "#PADDIdtprel",
+ [(set i64:$rD,
+ (PPCpaddiDtprel i64:$reg, tglobaltlsaddr:$disp))]>,
+ isPPC64;
let PPC970_Unit = 2 in {
let Interpretation64Bit = 1, isCodeGenOnly = 1 in {
{MO_GOT_FLAG, "ppc-got"},
{MO_PCREL_OPT_FLAG, "ppc-opt-pcrel"},
{MO_TLSGD_FLAG, "ppc-tlsgd"},
+ {MO_TLSLD_FLAG, "ppc-tlsld"},
{MO_TPREL_FLAG, "ppc-tprel"},
{MO_GOT_TLSGD_PCREL_FLAG, "ppc-got-tlsgd-pcrel"},
+ {MO_GOT_TLSLD_PCREL_FLAG, "ppc-got-tlsld-pcrel"},
{MO_GOT_TPREL_PCREL_FLAG, "ppc-got-tprel-pcrel"}};
return makeArrayRef(TargetFlags);
}
SDTCisSameAs<0, 3>, SDTCisInt<0> ]>>;
def PPCaddisDtprelHA : SDNode<"PPCISD::ADDIS_DTPREL_HA", SDTIntBinOp>;
def PPCaddiDtprelL : SDNode<"PPCISD::ADDI_DTPREL_L", SDTIntBinOp>;
+def PPCpaddiDtprel : SDNode<"PPCISD::PADDI_DTPREL", SDTIntBinOp>;
def PPCvperm : SDNode<"PPCISD::VPERM", SDT_PPCvperm, []>;
def PPCxxsplt : SDNode<"PPCISD::XXSPLT", SDT_PPCVecSplat, []>;
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_TLSLD_PCREL_FLAG)
+ RefKind = MCSymbolRefExpr::VK_PPC_GOT_TLSLD_PCREL;
else if (MO.getTargetFlags() == PPCII::MO_GOT_TPREL_PCREL_FLAG)
RefKind = MCSymbolRefExpr::VK_PPC_GOT_TPREL_PCREL;
bool Changed = false;
bool NeedFence = true;
bool Is64Bit = MBB.getParent()->getSubtarget<PPCSubtarget>().isPPC64();
- bool IsTLSGDPCREL = false;
+ bool IsPCREL = false;
for (MachineBasicBlock::iterator I = MBB.begin(), IE = MBB.end();
I != IE;) {
MachineInstr &MI = *I;
- IsTLSGDPCREL = isTLSGDPCREL(MI);
+ IsPCREL = isPCREL(MI);
if (MI.getOpcode() != PPC::ADDItlsgdLADDR &&
MI.getOpcode() != PPC::ADDItlsldLADDR &&
MI.getOpcode() != PPC::ADDItlsgdLADDR32 &&
- MI.getOpcode() != PPC::ADDItlsldLADDR32 && !IsTLSGDPCREL) {
+ MI.getOpcode() != PPC::ADDItlsldLADDR32 && !IsPCREL) {
// Although we create ADJCALLSTACKDOWN and ADJCALLSTACKUP
// as scheduling fences, we skip creating fences if we already
// have existing ADJCALLSTACKDOWN/UP to avoid nesting,
Register InReg = PPC::NoRegister;
Register GPR3 = Is64Bit ? PPC::X3 : PPC::R3;
SmallVector<Register, 3> OrigRegs = {OutReg, GPR3};
- if (!IsTLSGDPCREL) {
+ if (!IsPCREL) {
InReg = MI.getOperand(1).getReg();
OrigRegs.push_back(InReg);
}
Opc2 = PPC::GETtlsldADDR32;
break;
case PPC::PADDI8pc:
- assert(IsTLSGDPCREL && "Expecting General Dynamic PCRel");
+ assert(IsPCREL && "Expecting General/Local Dynamic PCRel");
Opc1 = PPC::PADDI8pc;
- Opc2 = PPC::GETtlsADDR;
+ Opc2 = MI.getOperand(2).getTargetFlags() ==
+ PPCII::MO_GOT_TLSGD_PCREL_FLAG
+ ? PPC::GETtlsADDR
+ : PPC::GETtlsldADDR;
}
// We create ADJCALLSTACKUP and ADJCALLSTACKDOWN around _tls_get_addr
.addImm(0);
MachineInstr *Addi;
- if (IsTLSGDPCREL) {
+ if (IsPCREL) {
Addi = BuildMI(MBB, I, DL, TII->get(Opc1), GPR3).addImm(0);
} else {
// Expand into two ops built prior to the existing instruction.
MachineInstr *Call = (BuildMI(MBB, I, DL, TII->get(Opc2), GPR3)
.addReg(GPR3));
- if (IsTLSGDPCREL)
+ if (IsPCREL)
Call->addOperand(MI.getOperand(2));
else
Call->addOperand(MI.getOperand(3));
}
public:
- bool isTLSGDPCREL(const MachineInstr &MI) {
+ bool isPCREL(const MachineInstr &MI) {
return (MI.getOpcode() == PPC::PADDI8pc) &&
(MI.getOperand(2).getTargetFlags() ==
- PPCII::MO_GOT_TLSGD_PCREL_FLAG);
+ PPCII::MO_GOT_TLSGD_PCREL_FLAG ||
+ MI.getOperand(2).getTargetFlags() ==
+ PPCII::MO_GOT_TLSLD_PCREL_FLAG);
}
+
bool runOnMachineFunction(MachineFunction &MF) override {
TII = MF.getSubtarget<PPCSubtarget>().getInstrInfo();
LIS = &getAnalysis<LiveIntervals>();
--- /dev/null
+; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -mcpu=pwr10 \
+; RUN: -ppc-asm-full-reg-names --relocation-model=pic -enable-ppc-pcrel-tls < %s | FileCheck %s --check-prefix=CHECK-S
+; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu -mcpu=pwr10 \
+; RUN: -ppc-asm-full-reg-names --relocation-model=pic -enable-ppc-pcrel-tls --filetype=obj < %s | \
+; RUN: llvm-objdump --mcpu=pwr10 --no-show-raw-insn -dr - | 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 Local Dynamic TLS Model.
+
+@x = hidden thread_local global i32 0, align 4
+
+define nonnull i32* @LocalDynamicAddressLoad() {
+ ; CHECK-S-LABEL: LocalDynamicAddressLoad:
+ ; CHECK-S: paddi r3, 0, x@got@tlsld@pcrel, 1
+ ; CHECK-S-NEXT: bl __tls_get_addr@notoc(x@tlsld)
+ ; CHECK-S-NEXT: paddi r3, r3, x@DTPREL, 0
+ ; CHECK-S-NEXT: addi r1, r1, 32
+ ; CHECK-S-NEXT: ld r0, 16(r1)
+ ; CHECK-S-NEXT: mtlr r0
+ ; CHECK-S-NEXT: blr
+ ; CHECK-O-LABEL: <LocalDynamicAddressLoad>:
+ ; CHECK-O: c: paddi 3, 0, 0, 1
+ ; CHECK-O-NEXT: 000000000000000c: R_PPC64_GOT_TLSLD_PCREL34 x
+ ; CHECK-O-NEXT: 14: bl 0x14
+ ; CHECK-O-NEXT: 0000000000000014: R_PPC64_TLSLD x
+ ; CHECK-O-NEXT: 0000000000000014: R_PPC64_REL24_NOTOC __tls_get_addr
+ ; CHECK-O-NEXT: 18: paddi 3, 3, 0, 0
+ ; CHECK-O-NEXT: 0000000000000018: R_PPC64_DTPREL34 x
+ entry:
+ ret i32* @x
+}
+
+define i32 @LocalDynamicValueLoad() {
+ ; CHECK-S-LABEL: LocalDynamicValueLoad:
+ ; CHECK-S: paddi r3, 0, x@got@tlsld@pcrel, 1
+ ; CHECK-S-NEXT: bl __tls_get_addr@notoc(x@tlsld)
+ ; CHECK-S-NEXT: paddi r3, r3, x@DTPREL, 0
+ ; CHECK-S-NEXT: lwz r3, 0(r3)
+ ; CHECK-S-NEXT: addi r1, r1, 32
+ ; CHECK-S-NEXT: ld r0, 16(r1)
+ ; CHECK-S-NEXT: mtlr r0
+ ; CHECK-S-NEXT: blr
+ ; CHECK-O-LABEL: <LocalDynamicValueLoad>:
+ ; CHECK-O: 4c: paddi 3, 0, 0, 1
+ ; CHECK-O-NEXT: 000000000000004c: R_PPC64_GOT_TLSLD_PCREL34 x
+ ; CHECK-O-NEXT: 54: bl 0x54
+ ; CHECK-O-NEXT: 0000000000000054: R_PPC64_TLSLD x
+ ; CHECK-O-NEXT: 0000000000000054: R_PPC64_REL24_NOTOC __tls_get_addr
+ ; CHECK-O-NEXT: 58: paddi 3, 3, 0, 0
+ ; CHECK-O-NEXT: 0000000000000058: R_PPC64_DTPREL34 x
+ ; CHECK-O-NEXT: 60: lwz 3, 0(3)
+ entry:
+ %0 = load i32, i32* @x, align 4
+ ret i32 %0
+}
--- /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 @got@tlsld@pcrel
+# x@tlsld, __tls_get_addr@notoc and x@DTPREL into R_PPC64_GOT_TLSLD_PCREL34,
+# R_PPC64_TLSLD, R_PPC64_REL24_NOTOC and R_PPC64_DTPREL34 for local dynamic
+# relocations with address/value loaded
+
+# MC-NOT: error: invalid variant
+
+# READOBJ: 0x0 R_PPC64_GOT_TLSLD_PCREL34 x 0x0
+# READOBJ-NEXT: 0x8 R_PPC64_TLSLD x 0x0
+# READOBJ-NEXT: 0x8 R_PPC64_REL24_NOTOC __tls_get_addr 0x0
+# READOBJ-NEXT: 0xC R_PPC64_DTPREL34 x 0x0
+# READOBJ-NEXT: 0x18 R_PPC64_GOT_TLSLD_PCREL34 x 0x0
+# READOBJ-NEXT: 0x20 R_PPC64_TLSLD x 0x0
+# READOBJ-NEXT: 0x20 R_PPC64_REL24_NOTOC __tls_get_addr 0x0
+# READOBJ-NEXT: 0x24 R_PPC64_DTPREL34 x 0x0
+
+LocalDynamicAddrLoad:
+ paddi 3, 0, x@got@tlsld@pcrel, 1
+ bl __tls_get_addr@notoc(x@tlsld)
+ paddi 3, 3, x@DTPREL, 0
+ blr
+
+LocalDynamicValueLoad:
+ paddi 3, 0, x@got@tlsld@pcrel, 1
+ bl __tls_get_addr@notoc(x@tlsld)
+ paddi 3, 3, x@DTPREL, 0
+ lwz 3, 0(3)
+ blr