[PowerPC][PCRelative] Thread Local Storage Support for Initial Exec

This patch is the initial support for the Intial Exec Thread Local
Local Storage model to produce code sequence and relocations correct
to the ABI for the model when using PC relative memory operations.

Reviewed By: stefanp

Differential Revision: https://reviews.llvm.org/D81947
This commit is contained in:
Kamau Bridgeman 2020-06-16 11:18:38 -05:00
parent a081868921
commit 365f861c45
13 changed files with 160 additions and 24 deletions

View file

@ -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_PCREL_OPT, 123)
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)

View file

@ -300,6 +300,8 @@ public:
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

View file

@ -324,6 +324,10 @@ StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) {
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 @@ MCSymbolRefExpr::getVariantKindForName(StringRef Name) {
.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)

View file

@ -651,7 +651,8 @@ public:
return CreateImm(CE->getValue(), S, E, IsPPC64);
if (const MCSymbolRefExpr *SRE = dyn_cast<MCSymbolRefExpr>(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<PPCMCExpr>(Val)) {

View file

@ -141,6 +141,9 @@ unsigned PPCELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
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 @@ unsigned PPCELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
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:

View file

@ -232,9 +232,10 @@ PPCMCCodeEmitter::getMemRI34PCRelEncoding(const MCInst &MI, unsigned OpNo,
// 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 @@ unsigned PPCMCCodeEmitter::getTLSRegEncoding(const MCInst &MI, unsigned OpNo,
// 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<MCSymbolRefExpr>(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();

View file

@ -113,11 +113,20 @@ namespace llvm {
/// 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,

View file

@ -2978,25 +2978,34 @@ SDValue PPCTargetLowering::LowerGlobalTLSAddress(SDValue Op,
}
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);
}

View file

@ -2274,7 +2274,9 @@ PPCInstrInfo::getSerializableBitmaskMachineOperandTargetFlags() const {
{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);
}

View file

@ -74,7 +74,9 @@ static MCOperand GetSymbolRef(const MachineOperand &MO, const MCSymbol *Symbol,
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 @@ static MCOperand GetSymbolRef(const MachineOperand &MO, const MCSymbol *Symbol,
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();

View file

@ -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: <InitialExecAddressLoad>:
; 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: <InitialExecValueLoad>:
; 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
}

View file

@ -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:
pld 3, x@got@tprel@pcrel(0), 1
add 3, 3, x@tls@pcrel
blr

View file

@ -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:
pld 3, x@got@tprel@pcrel(0), 1
lwzx 3, 3, x@tls@pcrel
blr