-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[PowerPC] Support local-dynamic TLS relocation on AIX #66316
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0e519e0
685619e
6ff54ca
dc6fbec
d979c44
09cf488
a6085eb
b5f60f7
fd68b57
9755a4a
92732a5
fe45c89
1d08e72
5c42342
30b26ae
62ce4ad
955fe59
4f51e52
8f82459
c34895f
51ec134
10822d3
0119567
1f8edff
9fbb330
f75ff08
595ef30
17ead44
e400223
3dde56f
1a95e93
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -116,6 +116,10 @@ std::pair<uint8_t, uint8_t> PPCXCOFFObjectWriter::getRelocTypeAndSignSize( | |
return {XCOFF::RelocationType::R_TLS_IE, SignAndSizeForFKData}; | ||
case MCSymbolRefExpr::VK_PPC_AIX_TLSLE: | ||
return {XCOFF::RelocationType::R_TLS_LE, SignAndSizeForFKData}; | ||
case MCSymbolRefExpr::VK_PPC_AIX_TLSLD: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think there could be concern regarding this setting, and I observed obj output and the asm-as output is a little bit different on "IsSigned" setting on relocations for symbol ".__tls_get_mod", for example: obj mode output processed by "llvm-readobj --relocs --expand-relocs"
asm mode output assembled by "as -a64 -many ", and then processed by "llvm-readobj --relocs --expand-relocs"
Notice they have different setting regarding "IsSigned" on the relocation for the ".__tls_get_mod" symbol. I took another look into the behavior of general-dynamic, and then I saw the same difference there: obj mode
asm mode
Looks like LD is aligned with GD in this particular behavior, so this may not be an issue. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am wondering, maybe the
|
||
return {XCOFF::RelocationType::R_TLS_LD, SignAndSizeForFKData}; | ||
case MCSymbolRefExpr::VK_PPC_AIX_TLSML: | ||
return {XCOFF::RelocationType::R_TLSML, SignAndSizeForFKData}; | ||
case MCSymbolRefExpr::VK_None: | ||
return {XCOFF::RelocationType::R_POS, SignAndSizeForFKData}; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -621,12 +621,23 @@ void PPCAsmPrinter::LowerPATCHPOINT(StackMaps &SM, const MachineInstr &MI) { | |
EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::NOP)); | ||
} | ||
|
||
/// This helper function creates the TlsGetAddr MCSymbol for AIX. We will | ||
/// create the csect and use the qual-name symbol instead of creating just the | ||
/// external symbol. | ||
/// This helper function creates the TlsGetAddr/TlsGetMod MCSymbol for AIX. We | ||
/// will create the csect and use the qual-name symbol instead of creating just | ||
/// the external symbol. | ||
static MCSymbol *createMCSymbolForTlsGetAddr(MCContext &Ctx, unsigned MIOpc) { | ||
StringRef SymName = | ||
MIOpc == PPC::GETtlsTpointer32AIX ? ".__get_tpointer" : ".__tls_get_addr"; | ||
StringRef SymName; | ||
switch (MIOpc) { | ||
default: | ||
SymName = ".__tls_get_addr"; | ||
break; | ||
case PPC::GETtlsTpointer32AIX: | ||
SymName = ".__get_tpointer"; | ||
break; | ||
case PPC::GETtlsMOD32AIX: | ||
case PPC::GETtlsMOD64AIX: | ||
SymName = ".__tls_get_mod"; | ||
break; | ||
} | ||
return Ctx | ||
.getXCOFFSection(SymName, SectionKind::getText(), | ||
XCOFF::CsectProperties(XCOFF::XMC_PR, XCOFF::XTY_ER)) | ||
|
@@ -668,14 +679,16 @@ void PPCAsmPrinter::EmitTlsCall(const MachineInstr *MI, | |
"GETtls[ld]ADDR[32] must read GPR3"); | ||
|
||
if (Subtarget->isAIXABI()) { | ||
// On AIX, the variable offset should already be in R4 and the region handle | ||
// should already be in R3. | ||
// For TLSGD, which currently is the only supported access model, we only | ||
// need to generate an absolute branch to .__tls_get_addr. | ||
// For TLSGD, the variable offset should already be in R4 and the region | ||
// handle should already be in R3. We generate an absolute branch to | ||
// .__tls_get_addr. For TLSLD, the module handle should already be in R3. | ||
// We generate an absolute branch to .__tls_get_mod. | ||
Register VarOffsetReg = Subtarget->isPPC64() ? PPC::X4 : PPC::R4; | ||
(void)VarOffsetReg; | ||
assert(MI->getOperand(2).isReg() && | ||
MI->getOperand(2).getReg() == VarOffsetReg && | ||
assert((MI->getOpcode() == PPC::GETtlsMOD32AIX || | ||
MI->getOpcode() == PPC::GETtlsMOD64AIX || | ||
(MI->getOperand(2).isReg() && | ||
MI->getOperand(2).getReg() == VarOffsetReg)) && | ||
"GETtls[ld]ADDR[32] must read GPR4"); | ||
EmitAIXTlsCallHelper(MI); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [edit: I misread the assembly below. The floating-point argument was not being reloaded.] The helper functions have special calling convention properties. For example, they do not use the FP registers. The IBM XL compiler was able to take advantage of that. For: __attribute__((tls_model("local-dynamic"))) __thread int x;
double g(int, double);
void f() {
double gg = g(0, 1.);
g(x, gg);
} The IBM XL compilers were able to make use of the returned
Clang/LLVM loads the value from the stack:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From what I've observed, Clang/LLVM uses the special GPR usage rules for the call to __tls_get_mod. But as you noted, FPRs are not handled as a special case. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you for looking into this! I tried the example, and it seems turn on optimization can help remove the FP load. We declared "Defs = [X0,X4,X5,X11,LR8,CR0]" for GETtlsMOD64AIX, and "Defs = [R0,R4,R5,R11,LR,CR0]" for GETtlsMOD32AIX. I think those FP registers should be treated as not touched by the call to __tls_get_mod. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks @orcguru. I misread the assembly 🤦♂️ (the extra instruction is not an |
||
return; | ||
|
@@ -844,6 +857,13 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) { | |
return MCSymbolRefExpr::VariantKind::VK_PPC_AIX_TLSGDM; | ||
if (Flag == PPCII::MO_TLSGD_FLAG || Flag == PPCII::MO_GOT_TLSGD_PCREL_FLAG) | ||
return MCSymbolRefExpr::VariantKind::VK_PPC_AIX_TLSGD; | ||
// For local-dynamic TLS access on AIX, we have one TOC entry for the symbol | ||
// (the variable offset) and one shared TOC entry for the module handle. | ||
// They are differentiated by MO_TLSLD_FLAG and MO_TLSLDM_FLAG. | ||
if (Flag == PPCII::MO_TLSLD_FLAG && IsAIX) | ||
orcguru marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return MCSymbolRefExpr::VariantKind::VK_PPC_AIX_TLSLD; | ||
if (Flag == PPCII::MO_TLSLDM_FLAG && IsAIX) | ||
return MCSymbolRefExpr::VariantKind::VK_PPC_AIX_TLSML; | ||
return MCSymbolRefExpr::VariantKind::VK_None; | ||
}; | ||
|
||
|
@@ -1354,6 +1374,11 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) { | |
.addExpr(SymGotTlsGD)); | ||
return; | ||
} | ||
case PPC::GETtlsMOD32AIX: | ||
case PPC::GETtlsMOD64AIX: | ||
// Transform: %r3 = GETtlsMODNNAIX %r3 (for NN == 32/64). | ||
// Into: BLA .__tls_get_mod() | ||
// Input parameter is a module handle (_$TLSML[TC]@ml) for all variables. | ||
case PPC::GETtlsADDR: | ||
// Transform: %x3 = GETtlsADDR %x3, @sym | ||
// Into: BL8_NOP_TLS __tls_get_addr(sym at tlsgd) | ||
|
@@ -2167,6 +2192,11 @@ void PPCAIXAsmPrinter::emitLinkage(const GlobalValue *GV, | |
} | ||
} | ||
|
||
// Do not emit the _$TLSML symbol. | ||
if (GV->getThreadLocalMode() == GlobalVariable::LocalDynamicTLSModel && | ||
GV->hasName() && GV->getName() == "_$TLSML") | ||
return; | ||
|
||
OutStreamer->emitXCOFFSymbolLinkageWithVisibility(GVSym, LinkageAttr, | ||
VisibilityAttr); | ||
} | ||
|
@@ -2981,11 +3011,13 @@ void PPCAIXAsmPrinter::emitInstruction(const MachineInstr *MI) { | |
MMI->hasDebugInfo()); | ||
break; | ||
} | ||
case PPC::GETtlsMOD32AIX: | ||
case PPC::GETtlsMOD64AIX: | ||
case PPC::GETtlsTpointer32AIX: | ||
case PPC::GETtlsADDR64AIX: | ||
case PPC::GETtlsADDR32AIX: { | ||
orcguru marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// A reference to .__tls_get_addr/.__get_tpointer is unknown to the | ||
// assembler so we need to emit an external symbol reference. | ||
// A reference to .__tls_get_mod/.__tls_get_addr/.__get_tpointer is unknown | ||
// to the assembler so we need to emit an external symbol reference. | ||
MCSymbol *TlsGetAddr = | ||
createMCSymbolForTlsGetAddr(OutContext, MI->getOpcode()); | ||
ExtSymSDNodeSymbols.insert(TlsGetAddr); | ||
|
Uh oh!
There was an error while loading. Please reload this page.