diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def --- a/llvm/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def +++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/PowerPC64.def @@ -101,6 +101,7 @@ #undef R_PPC64_PCREL34 #undef R_PPC64_GOT_PCREL34 #undef R_PPC64_GOT_TLSGD_PCREL34 +#undef R_PPC64_GOT_TPREL_PCREL34 #undef R_PPC64_IRELATIVE #undef R_PPC64_REL16 #undef R_PPC64_REL16_LO @@ -200,6 +201,7 @@ ELF_RELOC(R_PPC64_PCREL34, 132) ELF_RELOC(R_PPC64_GOT_PCREL34, 133) ELF_RELOC(R_PPC64_GOT_TLSGD_PCREL34, 148) +ELF_RELOC(R_PPC64_GOT_TPREL_PCREL34, 150) ELF_RELOC(R_PPC64_IRELATIVE, 248) ELF_RELOC(R_PPC64_REL16, 249) ELF_RELOC(R_PPC64_REL16_LO, 250) diff --git a/llvm/include/llvm/MC/MCExpr.h b/llvm/include/llvm/MC/MCExpr.h --- a/llvm/include/llvm/MC/MCExpr.h +++ b/llvm/include/llvm/MC/MCExpr.h @@ -300,6 +300,8 @@ 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_TPREL_PCREL, // symbol@got@tprel@pcrel + VK_PPC_TLS_PCREL, // symbol@tls@pcrel VK_PPC_TLSLD, // symbol@tlsld VK_PPC_LOCAL, // symbol@local VK_PPC_NOTOC, // symbol@notoc diff --git a/llvm/lib/MC/MCExpr.cpp b/llvm/lib/MC/MCExpr.cpp --- a/llvm/lib/MC/MCExpr.cpp +++ b/llvm/lib/MC/MCExpr.cpp @@ -324,6 +324,10 @@ return "got@pcrel"; case VK_PPC_GOT_TLSGD_PCREL: return "got@tlsgd@pcrel"; + case VK_PPC_GOT_TPREL_PCREL: + return "got@tprel@pcrel"; + case VK_PPC_TLS_PCREL: + return "tls@pcrel"; case VK_PPC_TLSLD: return "tlsld"; case VK_PPC_LOCAL: return "local"; case VK_PPC_NOTOC: return "notoc"; @@ -457,6 +461,8 @@ .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@tprel@pcrel", VK_PPC_GOT_TPREL_PCREL) + .Case("tls@pcrel", VK_PPC_TLS_PCREL) .Case("notoc", VK_PPC_NOTOC) .Case("gdgot", VK_Hexagon_GD_GOT) .Case("gdplt", VK_Hexagon_GD_PLT) diff --git a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp --- a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp +++ b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp @@ -651,7 +651,8 @@ return CreateImm(CE->getValue(), S, E, IsPPC64); if (const MCSymbolRefExpr *SRE = dyn_cast(Val)) - if (SRE->getKind() == MCSymbolRefExpr::VK_PPC_TLS) + if (SRE->getKind() == MCSymbolRefExpr::VK_PPC_TLS || + SRE->getKind() == MCSymbolRefExpr::VK_PPC_TLS_PCREL) return CreateTLSReg(SRE, S, E, IsPPC64); if (const PPCMCExpr *TE = dyn_cast(Val)) { diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp @@ -141,6 +141,9 @@ case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_PCREL: Type = ELF::R_PPC64_GOT_TLSGD_PCREL34; break; + case MCSymbolRefExpr::VK_PPC_GOT_TPREL_PCREL: + Type = ELF::R_PPC64_GOT_TPREL_PCREL34; + break; } break; case FK_Data_4: @@ -410,6 +413,9 @@ else Type = ELF::R_PPC_TLS; break; + case MCSymbolRefExpr::VK_PPC_TLS_PCREL: + Type = ELF::R_PPC64_TLS; + break; } break; case PPC::fixup_ppc_imm34: diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp @@ -232,9 +232,10 @@ // Currently these are the only valid PCRelative Relocations. 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_TLSGD_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"); + "VK_PPC_GOT_TLSGD_PCREL or VK_PPC_GOT_TPREL_PCREL"); // Generate the fixup for the relocation. Fixups.push_back( MCFixup::create(0, Expr, @@ -346,8 +347,12 @@ // Add a fixup for the TLS register, which simply provides a relocation // hint to the linker that this statement is part of a relocation sequence. - // Return the thread-pointer register's encoding. - Fixups.push_back(MCFixup::create(0, MO.getExpr(), + // Return the thread-pointer register's encoding. Add a one byte displacement + // if using PC relative memops. + const MCExpr *Expr = MO.getExpr(); + const MCSymbolRefExpr *SRE = cast(Expr); + bool IsPCRel = SRE->getKind() == MCSymbolRefExpr::VK_PPC_TLS_PCREL; + Fixups.push_back(MCFixup::create(IsPCRel ? 1 : 0, Expr, (MCFixupKind)PPC::fixup_ppc_nofixup)); const Triple &TT = STI.getTargetTriple(); bool isPPC64 = TT.isPPC64(); diff --git a/llvm/lib/Target/PowerPC/PPC.h b/llvm/lib/Target/PowerPC/PPC.h --- a/llvm/lib/Target/PowerPC/PPC.h +++ b/llvm/lib/Target/PowerPC/PPC.h @@ -113,11 +113,20 @@ /// TLS General Dynamic model. MO_TLSGD_FLAG = 32, + /// MO_TPREL_FLAG - If this bit is set the symbol reference is relative to + /// TLS Initial Exec model. + MO_TPREL_FLAG = 64, + /// 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_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 + MO_GOT_TPREL_PCREL_FLAG = MO_GOT_FLAG | MO_TPREL_FLAG | MO_PCREL_FLAG, + /// The next are not flags but distinct values. MO_ACCESS_MASK = 0xf00, diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -2938,25 +2938,34 @@ } if (Model == TLSModel::InitialExec) { - SDValue TGA = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, 0); - SDValue TGATLS = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, - PPCII::MO_TLS); - SDValue GOTPtr; - if (is64bit) { - setUsesTOCBasePtr(DAG); - SDValue GOTReg = DAG.getRegister(PPC::X2, MVT::i64); - GOTPtr = DAG.getNode(PPCISD::ADDIS_GOT_TPREL_HA, dl, - PtrVT, GOTReg, TGA); + bool IsPCRel = Subtarget.isUsingPCRelativeCalls(); + SDValue TGA = DAG.getTargetGlobalAddress( + GV, dl, PtrVT, 0, IsPCRel ? PPCII::MO_GOT_TPREL_PCREL_FLAG : 0); + SDValue TGATLS = DAG.getTargetGlobalAddress( + GV, dl, PtrVT, 0, + IsPCRel ? (PPCII::MO_TLS | PPCII::MO_PCREL_FLAG) : PPCII::MO_TLS); + SDValue TPOffset; + if (IsPCRel) { + SDValue MatPCRel = DAG.getNode(PPCISD::MAT_PCREL_ADDR, dl, PtrVT, TGA); + TPOffset = DAG.getLoad(MVT::i64, dl, DAG.getEntryNode(), MatPCRel, + MachinePointerInfo()); } else { - if (!TM.isPositionIndependent()) - GOTPtr = DAG.getNode(PPCISD::PPC32_GOT, dl, PtrVT); - else if (picLevel == PICLevel::SmallPIC) - GOTPtr = DAG.getNode(PPCISD::GlobalBaseReg, dl, PtrVT); - else - GOTPtr = DAG.getNode(PPCISD::PPC32_PICGOT, dl, PtrVT); + SDValue GOTPtr; + if (is64bit) { + setUsesTOCBasePtr(DAG); + SDValue GOTReg = DAG.getRegister(PPC::X2, MVT::i64); + GOTPtr = + DAG.getNode(PPCISD::ADDIS_GOT_TPREL_HA, dl, PtrVT, GOTReg, TGA); + } else { + if (!TM.isPositionIndependent()) + GOTPtr = DAG.getNode(PPCISD::PPC32_GOT, dl, PtrVT); + else if (picLevel == PICLevel::SmallPIC) + GOTPtr = DAG.getNode(PPCISD::GlobalBaseReg, dl, PtrVT); + else + GOTPtr = DAG.getNode(PPCISD::PPC32_PICGOT, dl, PtrVT); + } + TPOffset = DAG.getNode(PPCISD::LD_GOT_TPREL_L, dl, PtrVT, TGA, GOTPtr); } - SDValue TPOffset = DAG.getNode(PPCISD::LD_GOT_TPREL_L, dl, - PtrVT, TGA, GOTPtr); return DAG.getNode(PPCISD::ADD_TLS, dl, PtrVT, TPOffset, TGATLS); } diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp @@ -2263,7 +2263,9 @@ {MO_GOT_FLAG, "ppc-got"}, {MO_PCREL_OPT_FLAG, "ppc-opt-pcrel"}, {MO_TLSGD_FLAG, "ppc-tlsgd"}, - {MO_GOT_TLSGD_PCREL_FLAG, "ppc-got-tlsgd-pcrel"}}; + {MO_TPREL_FLAG, "ppc-tprel"}, + {MO_GOT_TLSGD_PCREL_FLAG, "ppc-got-tlsgd-pcrel"}, + {MO_GOT_TPREL_PCREL_FLAG, "ppc-got-tprel-pcrel"}}; return makeArrayRef(TargetFlags); } diff --git a/llvm/lib/Target/PowerPC/PPCMCInstLower.cpp b/llvm/lib/Target/PowerPC/PPCMCInstLower.cpp --- a/llvm/lib/Target/PowerPC/PPCMCInstLower.cpp +++ b/llvm/lib/Target/PowerPC/PPCMCInstLower.cpp @@ -74,7 +74,9 @@ RefKind = MCSymbolRefExpr::VK_PPC_TOC_LO; break; case PPCII::MO_TLS: - RefKind = MCSymbolRefExpr::VK_PPC_TLS; + bool IsPCRel = (MO.getTargetFlags() & ~access) == PPCII::MO_PCREL_FLAG; + RefKind = IsPCRel ? MCSymbolRefExpr::VK_PPC_TLS_PCREL + : MCSymbolRefExpr::VK_PPC_TLS; break; } @@ -86,6 +88,8 @@ RefKind = MCSymbolRefExpr::VK_PPC_GOT_PCREL; 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) + RefKind = MCSymbolRefExpr::VK_PPC_GOT_TPREL_PCREL; const MachineInstr *MI = MO.getParent(); const MachineFunction *MF = MI->getMF(); diff --git a/llvm/test/CodeGen/PowerPC/pcrel-tls-initial-exec.ll b/llvm/test/CodeGen/PowerPC/pcrel-tls-initial-exec.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/pcrel-tls-initial-exec.ll @@ -0,0 +1,48 @@ +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \ +; RUN: -mcpu=pwr10 -ppc-asm-full-reg-names -enable-ppc-pcrel-tls < %s | \ +; RUN: FileCheck %s --check-prefix=CHECK-S +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \ +; RUN: -mcpu=pwr10 -ppc-asm-full-reg-names --filetype=obj \ +; RUN: -enable-ppc-pcrel-tls < %s | llvm-objdump --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 Initial Exec TLS Model. +; Note that with R_PPC64_TLS relocations, to distinguish PC relative +; TLS the relocation has a field value displaced by one byte from the +; beginning of the instruction. + +@x = external thread_local global i32, align 4 + +define i32* @InitialExecAddressLoad() { +; CHECK-S-LABEL: InitialExecAddressLoad: +; CHECK-S: # %bb.0: # %entry +; CHECK-S-NEXT: pld r3, x@got@tprel@pcrel(0), 1 +; CHECK-S-NEXT: add r3, r3, x@tls@pcrel +; CHECK-S-NEXT: blr +; CHECK-O-LABEL: : +; CHECK-O: 00 00 10 04 00 00 60 e4 pld 3, 0(0), 1 +; CHECK-O-NEXT: 0000000000000000: R_PPC64_GOT_TPREL_PCREL34 x +; CHECK-O-NEXT: 14 6a 63 7c add 3, 3, 13 +; CHECK-O-NEXT: 0000000000000009: R_PPC64_TLS x +; CHECK-O-NEXT: 20 00 80 4e blr +entry: + ret i32* @x +} + +define i32 @InitialExecValueLoad() { +; CHECK-S-LABEL: InitialExecValueLoad: +; CHECK-S: # %bb.0: # %entry +; CHECK-S-NEXT: pld r3, x@got@tprel@pcrel(0), 1 +; CHECK-S-NEXT: lwzx r3, r3, x@tls@pcrel +; CHECK-S-NEXT: blr +; CHECK-O-LABEL: : +; CHECK-O: 00 00 10 04 00 00 60 e4 pld 3, 0(0), 1 +; CHECK-O-NEXT: 0000000000000020: R_PPC64_GOT_TPREL_PCREL34 x +; CHECK-O-NEXT: 2e 68 63 7c lwzx 3, 3, 13 +; CHECK-O-NEXT: 0000000000000029: R_PPC64_TLS x +; CHECK-O-NEXT: 20 00 80 4e blr +entry: + %0 = load i32, i32* @x, align 4 + ret i32 %0 +} diff --git a/llvm/test/CodeGen/PowerPC/pcrel-tls.ll b/llvm/test/CodeGen/PowerPC/pcrel-tls.ll --- a/llvm/test/CodeGen/PowerPC/pcrel-tls.ll +++ b/llvm/test/CodeGen/PowerPC/pcrel-tls.ll @@ -1,7 +1,7 @@ ; RUN: not --crash llc -mcpu=pwr10 -mtriple=powerpc64le-unknown-linux-gnu \ ; RUN: -verify-machineinstrs -mattr=+pcrelative-memops -o - < %s 2>&1 | \ ; RUN: FileCheck %s --check-prefix=CHECK-PCREL -; RUN: not --crash llc -mcpu=pwr10 -mtriple=powerpc64le-unknown-linux-gnu \ +; RUN: llc -mcpu=pwr10 -mtriple=powerpc64le-unknown-linux-gnu \ ; RUN: -verify-machineinstrs -mattr=+pcrelative-memops -enable-ppc-pcrel-tls \ ; RUN: -o - < %s 2>&1 | FileCheck %s --check-prefix=CHECK-PCREL-TLS ; RUN: llc -mcpu=pwr10 -mtriple=powerpc64le-unknown-linux-gnu \ @@ -9,7 +9,7 @@ ; RUN: FileCheck %s --check-prefix=CHECK-NOPCREL ; CHECK-PCREL: Thread local storage is not supported with pc-relative addressing -; CHECK-PCREL-TLS: TOC pointer used in a function using PC-Relative addressing! +; CHECK-PCREL-TLS: blr ; CHECK-NOPCREL: blr @x = external thread_local global i32, align 4 diff --git a/llvm/test/MC/PowerPC/pcrel-tls-initial-exec-address-load-reloc.s b/llvm/test/MC/PowerPC/pcrel-tls-initial-exec-address-load-reloc.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/PowerPC/pcrel-tls-initial-exec-address-load-reloc.s @@ -0,0 +1,21 @@ +# 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@got@tprel@pcrel +# and x@tls@pcrel into R_PPC64_GOT_TPREL_PCREL34, and R_PPC64_TLS for initial +# exec relocations with address loaded. +# Note that with R_PPC64_TLS relocations, to distinguish PC relative +# TLS the relocation has a field value displaced by one byte from the +# beginning of the instruction. + +# MC-NOT: error: invalid variant + +# READOBJ: 0x0 R_PPC64_GOT_TPREL_PCREL34 x 0x0 +# READOBJ-NEXT: 0x9 R_PPC64_TLS x 0x0 + +InitialExec: # @InitialExec + pld 3, x@got@tprel@pcrel(0), 1 + add 3, 3, x@tls@pcrel + blr diff --git a/llvm/test/MC/PowerPC/pcrel-tls-initial-exec-value-load-reloc.s b/llvm/test/MC/PowerPC/pcrel-tls-initial-exec-value-load-reloc.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/PowerPC/pcrel-tls-initial-exec-value-load-reloc.s @@ -0,0 +1,21 @@ +# 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@got@tprel@pcrel +# and x@tls@pcrel into R_PPC64_GOT_TPREL_PCREL34, and R_PPC64_TLS for initial +# exec relocations with the value loaded. +# Note that with R_PPC64_TLS relocations, to distinguish PC relative +# TLS the relocation has a field value displaced by one byte from the +# beginning of the instruction. + +# MC-NOT: error: invalid variant + +# READOBJ: 0x0 R_PPC64_GOT_TPREL_PCREL34 x 0x0 +# READOBJ-NEXT: 0x9 R_PPC64_TLS x 0x0 + +InitialExecLoad: # @InitialExecLoad + pld 3, x@got@tprel@pcrel(0), 1 + lwzx 3, 3, x@tls@pcrel + blr