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 @@ -100,6 +100,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 @@ -198,6 +199,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 @@ -321,6 +321,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"; @@ -439,6 +443,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 @@ -666,7 +666,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 FK_Data_8: 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 @@ -216,9 +216,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, @@ -330,8 +331,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 @@ -111,11 +111,20 @@ /// TLS General Dynamic model. MO_TLSGD_FLAG = 16, + /// MO_TPREL_FLAG - If this bit is set the symbol reference is relative to + /// TLS Initial Exec model. + MO_TPREL_FLAG = 32, + /// 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_PCREL_FLAG | MO_GOT_FLAG | MO_TPREL_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 @@ -3076,25 +3076,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 @@ -2272,7 +2272,9 @@ {MO_PCREL_FLAG, "ppc-pcrel"}, {MO_GOT_FLAG, "ppc-got"}, {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 @@ -86,6 +86,10 @@ 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; + else if (MO.getTargetFlags() == (PPCII::MO_TLS | PPCII::MO_PCREL_FLAG)) + RefKind = MCSymbolRefExpr::VK_PPC_TLS_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,41 @@ +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \ +; RUN: -mcpu=future -ppc-asm-full-reg-names < %s | \ +; RUN: FileCheck %s --check-prefix=CHECK-S +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \ +; RUN: -mcpu=future -ppc-asm-full-reg-names --filetype=obj < %s | \ +; RUN: llvm-objdump --mcpu=future -dr - | FileCheck %s --check-prefix=CHECK-O + +@x = external thread_local global i32, align 4 + +define i32* @InitialExec() { +; CHECK-S-LABEL: InitialExec: +; 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 @InitialExecLoad() { +; CHECK-S-LABEL: InitialExecLoad: +; 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/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,33 @@ +# 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_TLSGD_PCREL34, R_PPC64_TLSGD +# and R_PPC64_REL24_NOTOC for general dynamic relocations with address loaded + +# MC-NOT: error: invalid variant + +# READOBJ: 0x0 R_PPC64_GOT_TPREL_PCREL34 x 0x0 +# READOBJ-NEXT: 0x9 R_PPC64_TLS x 0x0 + + .text + .abiversion 2 + .file "InitialExec.addr.c" + .globl InitialExec # -- Begin function InitialExec + .p2align 4 + .type InitialExec,@function +InitialExec: # @InitialExec +.Lfunc_begin0: +# %bb.0: # %entry + pld 3, x@got@tprel@pcrel(0), 1 + add 3, 3, x@tls@pcrel + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size InitialExec, .Lfunc_end0-.Lfunc_begin0 + # -- End function + .section ".note.GNU-stack","",@progbits + .addrsig 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,33 @@ +# 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_TLSGD_PCREL34, R_PPC64_TLSGD +# and R_PPC64_REL24_NOTOC for general dynamic relocations with address loaded + +# MC-NOT: error: invalid variant + +# READOBJ: 0x0 R_PPC64_GOT_TPREL_PCREL34 x 0x0 +# READOBJ-NEXT: 0x9 R_PPC64_TLS x 0x0 + + .text + .abiversion 2 + .file "InitialExec.value.c" + .globl InitialExecLoad # -- Begin function InitialExecLoad + .p2align 4 + .type InitialExecLoad,@function +InitialExecLoad: # @InitialExecLoad +.Lfunc_begin0: +# %bb.0: # %entry + pld 3, x@got@tprel@pcrel(0), 1 + lwzx 3, 3, x@tls@pcrel + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size InitialExecLoad, .Lfunc_end0-.Lfunc_begin0 + # -- End function + .section ".note.GNU-stack","",@progbits + .addrsig