Skip to content

Commit 2d80505

Browse files
mandlebugamy-kwan
andauthored
[AIX] Support per global code model. (#79202)
Exploit the per global code model attribute on AIX. On AIX we need to update both the code sequence used to access the global (either 1 or 2 instructions for small and large code model respectively) and the storage mapping class that we emit the toc entry. --------- Co-authored-by: Amy Kwan <[email protected]>
1 parent e115c00 commit 2d80505

File tree

7 files changed

+344
-28
lines changed

7 files changed

+344
-28
lines changed

llvm/include/llvm/MC/MCSymbolXCOFF.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ class MCSymbolXCOFF : public MCSymbol {
2626

2727
static bool classof(const MCSymbol *S) { return S->isXCOFF(); }
2828

29+
enum CodeModel : uint8_t { CM_Small, CM_Large };
30+
2931
static StringRef getUnqualifiedName(StringRef Name) {
3032
if (Name.back() == ']') {
3133
StringRef Lhs, Rhs;
@@ -72,8 +74,22 @@ class MCSymbolXCOFF : public MCSymbol {
7274

7375
void setEHInfo() const { modifyFlags(SF_EHInfo, SF_EHInfo); }
7476

77+
bool hasPerSymbolCodeModel() const { return PerSymbolCodeModel.has_value(); }
78+
79+
CodeModel getPerSymbolCodeModel() const {
80+
assert(hasPerSymbolCodeModel() &&
81+
"Requested code model for symbol without one");
82+
return *PerSymbolCodeModel;
83+
}
84+
85+
void setPerSymbolCodeModel(MCSymbolXCOFF::CodeModel Model) {
86+
PerSymbolCodeModel = Model;
87+
}
88+
7589
private:
7690
std::optional<XCOFF::StorageClass> StorageClass;
91+
std::optional<CodeModel> PerSymbolCodeModel;
92+
7793
MCSectionXCOFF *RepresentedCsect = nullptr;
7894
XCOFF::VisibilityType VisibilityType = XCOFF::SYM_V_UNSPECIFIED;
7995
StringRef SymbolTableName;

llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2680,21 +2680,34 @@ MCSection *TargetLoweringObjectFileXCOFF::getSectionForFunctionDescriptor(
26802680

26812681
MCSection *TargetLoweringObjectFileXCOFF::getSectionForTOCEntry(
26822682
const MCSymbol *Sym, const TargetMachine &TM) const {
2683-
// Use TE storage-mapping class when large code model is enabled so that
2684-
// the chance of needing -bbigtoc is decreased. Also, the toc-entry for
2685-
// EH info is never referenced directly using instructions so it can be
2686-
// allocated with TE storage-mapping class.
2687-
// The "_$TLSML" symbol for TLS local-dynamic mode requires XMC_TC, otherwise
2688-
// the AIX assembler will complain.
2683+
const XCOFF::StorageMappingClass SMC = [](const MCSymbol *Sym,
2684+
const TargetMachine &TM) {
2685+
const MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(Sym);
2686+
2687+
// The "_$TLSML" symbol for TLS local-dynamic mode requires XMC_TC,
2688+
// otherwise the AIX assembler will complain.
2689+
if (XSym->getSymbolTableName() == "_$TLSML")
2690+
return XCOFF::XMC_TC;
2691+
2692+
// Use large code model toc entries for ehinfo symbols as they are
2693+
// never referenced directly. The runtime loads their TOC entry
2694+
// addresses from the trace-back table.
2695+
if (XSym->isEHInfo())
2696+
return XCOFF::XMC_TE;
2697+
2698+
// If the symbol does not have a code model specified use the module value.
2699+
if (!XSym->hasPerSymbolCodeModel())
2700+
return TM.getCodeModel() == CodeModel::Large ? XCOFF::XMC_TE
2701+
: XCOFF::XMC_TC;
2702+
2703+
return XSym->getPerSymbolCodeModel() == MCSymbolXCOFF::CM_Large
2704+
? XCOFF::XMC_TE
2705+
: XCOFF::XMC_TC;
2706+
}(Sym, TM);
2707+
26892708
return getContext().getXCOFFSection(
26902709
cast<MCSymbolXCOFF>(Sym)->getSymbolTableName(), SectionKind::getData(),
2691-
XCOFF::CsectProperties(
2692-
((TM.getCodeModel() == CodeModel::Large &&
2693-
cast<MCSymbolXCOFF>(Sym)->getSymbolTableName() != "_$TLSML") ||
2694-
cast<MCSymbolXCOFF>(Sym)->isEHInfo())
2695-
? XCOFF::XMC_TE
2696-
: XCOFF::XMC_TC,
2697-
XCOFF::XTY_SD));
2710+
XCOFF::CsectProperties(SMC, XCOFF::XTY_SD));
26982711
}
26992712

27002713
MCSection *TargetLoweringObjectFileXCOFF::getSectionForLSDA(

llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp

Lines changed: 63 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,35 @@ static void collectTOCStats(PPCAsmPrinter::TOCEntryType Type) {
474474
}
475475
}
476476

477+
static CodeModel::Model getCodeModel(const PPCSubtarget &S,
478+
const TargetMachine &TM,
479+
const MachineOperand &MO) {
480+
CodeModel::Model ModuleModel = TM.getCodeModel();
481+
482+
// If the operand is not a global address then there is no
483+
// global variable to carry an attribute.
484+
if (!(MO.getType() == MachineOperand::MO_GlobalAddress))
485+
return ModuleModel;
486+
487+
const GlobalValue *GV = MO.getGlobal();
488+
assert(GV && "expected global for MO_GlobalAddress");
489+
490+
return S.getCodeModel(TM, GV);
491+
}
492+
493+
static void setOptionalCodeModel(MCSymbolXCOFF *XSym, CodeModel::Model CM) {
494+
switch (CM) {
495+
case CodeModel::Large:
496+
XSym->setPerSymbolCodeModel(MCSymbolXCOFF::CM_Large);
497+
return;
498+
case CodeModel::Small:
499+
XSym->setPerSymbolCodeModel(MCSymbolXCOFF::CM_Small);
500+
return;
501+
default:
502+
report_fatal_error("Invalid code model for AIX");
503+
}
504+
}
505+
477506
/// lookUpOrCreateTOCEntry -- Given a symbol, look up whether a TOC entry
478507
/// exists for it. If not, create one. Then return a symbol that references
479508
/// the TOC entry.
@@ -1014,7 +1043,7 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
10141043
// relative to the toc-base.
10151044
if (IsAIX) {
10161045
assert(
1017-
TM.getCodeModel() == CodeModel::Small &&
1046+
getCodeModel(*Subtarget, TM, MO) == CodeModel::Small &&
10181047
"This pseudo should only be selected for 32-bit small code model.");
10191048
Exp = getTOCEntryLoadingExprForXCOFF(MOSymbol, Exp, VK);
10201049
TmpInst.getOperand(1) = MCOperand::createExpr(Exp);
@@ -1098,7 +1127,12 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
10981127
return;
10991128
}
11001129
case PPC::ADDIStocHA: {
1101-
assert((IsAIX && !IsPPC64 && TM.getCodeModel() == CodeModel::Large) &&
1130+
const MachineOperand &MO = MI->getOperand(2);
1131+
1132+
assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) &&
1133+
"Invalid operand for ADDIStocHA.");
1134+
assert((IsAIX && !IsPPC64 &&
1135+
getCodeModel(*Subtarget, TM, MO) == CodeModel::Large) &&
11021136
"This pseudo should only be selected for 32-bit large code model on"
11031137
" AIX.");
11041138

@@ -1108,10 +1142,6 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
11081142
// Change the opcode to ADDIS.
11091143
TmpInst.setOpcode(PPC::ADDIS);
11101144

1111-
const MachineOperand &MO = MI->getOperand(2);
1112-
assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) &&
1113-
"Invalid operand for ADDIStocHA.");
1114-
11151145
// Map the machine operand to its corresponding MCSymbol.
11161146
MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this);
11171147

@@ -1131,7 +1161,12 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
11311161
return;
11321162
}
11331163
case PPC::LWZtocL: {
1134-
assert(IsAIX && !IsPPC64 && TM.getCodeModel() == CodeModel::Large &&
1164+
const MachineOperand &MO = MI->getOperand(1);
1165+
1166+
assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) &&
1167+
"Invalid operand for LWZtocL.");
1168+
assert(IsAIX && !IsPPC64 &&
1169+
getCodeModel(*Subtarget, TM, MO) == CodeModel::Large &&
11351170
"This pseudo should only be selected for 32-bit large code model on"
11361171
" AIX.");
11371172

@@ -1141,10 +1176,6 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
11411176
// Change the opcode to lwz.
11421177
TmpInst.setOpcode(PPC::LWZ);
11431178

1144-
const MachineOperand &MO = MI->getOperand(1);
1145-
assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) &&
1146-
"Invalid operand for LWZtocL.");
1147-
11481179
// Map the machine operand to its corresponding MCSymbol.
11491180
MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this);
11501181

@@ -1183,8 +1214,12 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
11831214

11841215
const bool GlobalToc =
11851216
MO.isGlobal() && Subtarget->isGVIndirectSymbol(MO.getGlobal());
1217+
1218+
const CodeModel::Model CM =
1219+
IsAIX ? getCodeModel(*Subtarget, TM, MO) : TM.getCodeModel();
1220+
11861221
if (GlobalToc || MO.isJTI() || MO.isBlockAddress() ||
1187-
(MO.isCPI() && TM.getCodeModel() == CodeModel::Large))
1222+
(MO.isCPI() && CM == CodeModel::Large))
11881223
MOSymbol = lookUpOrCreateTOCEntry(MOSymbol, getTOCEntryTypeForMO(MO), VK);
11891224

11901225
VK = IsAIX ? MCSymbolRefExpr::VK_PPC_U : MCSymbolRefExpr::VK_PPC_TOC_HA;
@@ -1225,8 +1260,9 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
12251260
const MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this);
12261261

12271262
MCSymbolRefExpr::VariantKind VK = GetVKForMO(MO);
1228-
1229-
if (!MO.isCPI() || TM.getCodeModel() == CodeModel::Large)
1263+
CodeModel::Model CM =
1264+
IsAIX ? getCodeModel(*Subtarget, TM, MO) : TM.getCodeModel();
1265+
if (!MO.isCPI() || CM == CodeModel::Large)
12301266
MOSymbol = lookUpOrCreateTOCEntry(MOSymbol, getTOCEntryTypeForMO(MO), VK);
12311267

12321268
VK = IsAIX ? MCSymbolRefExpr::VK_PPC_L : MCSymbolRefExpr::VK_PPC_TOC_LO;
@@ -2984,6 +3020,10 @@ bool PPCAIXAsmPrinter::doInitialization(Module &M) {
29843020
}
29853021

29863022
setCsectAlignment(&G);
3023+
std::optional<CodeModel::Model> OptionalCodeModel = G.getCodeModel();
3024+
if (OptionalCodeModel)
3025+
setOptionalCodeModel(cast<MCSymbolXCOFF>(getSymbol(&G)),
3026+
*OptionalCodeModel);
29873027
}
29883028

29893029
for (const auto &F : M)
@@ -3005,6 +3045,15 @@ bool PPCAIXAsmPrinter::doInitialization(Module &M) {
30053045
false);
30063046
}
30073047

3048+
const GlobalVariable *GVar =
3049+
dyn_cast_or_null<GlobalVariable>(Alias.getAliaseeObject());
3050+
if (GVar) {
3051+
std::optional<CodeModel::Model> OptionalCodeModel = GVar->getCodeModel();
3052+
if (OptionalCodeModel)
3053+
setOptionalCodeModel(cast<MCSymbolXCOFF>(getSymbol(&Alias)),
3054+
*OptionalCodeModel);
3055+
}
3056+
30083057
GOAliasMap[Aliasee].push_back(&Alias);
30093058
}
30103059

llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,24 @@ static bool hasTocDataAttr(SDValue Val, unsigned PointerSize) {
524524
return true;
525525
}
526526

527+
static CodeModel::Model getCodeModel(const PPCSubtarget &Subtarget,
528+
const TargetMachine &TM,
529+
const SDNode *Node) {
530+
// If there isn't an attribute to override the module code model
531+
// this will be the effective code model.
532+
CodeModel::Model ModuleModel = TM.getCodeModel();
533+
534+
GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Node->getOperand(0));
535+
if (!GA)
536+
return ModuleModel;
537+
538+
const GlobalValue *GV = GA->getGlobal();
539+
if (!GV)
540+
return ModuleModel;
541+
542+
return Subtarget.getCodeModel(TM, GV);
543+
}
544+
527545
/// isInt32Immediate - This method tests to see if the node is a 32-bit constant
528546
/// operand. If so Imm will receive the 32-bit value.
529547
static bool isInt32Immediate(SDNode *N, unsigned &Imm) {
@@ -6059,7 +6077,8 @@ void PPCDAGToDAGISel::Select(SDNode *N) {
60596077
const bool isAIXABI = Subtarget->isAIXABI();
60606078

60616079
// PowerPC only support small, medium and large code model.
6062-
const CodeModel::Model CModel = TM.getCodeModel();
6080+
const CodeModel::Model CModel = getCodeModel(*Subtarget, TM, N);
6081+
60636082
assert(!(CModel == CodeModel::Tiny || CModel == CodeModel::Kernel) &&
60646083
"PowerPC doesn't support tiny or kernel code models.");
60656084

llvm/lib/Target/PowerPC/PPCSubtarget.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,14 +186,63 @@ bool PPCSubtarget::enableSubRegLiveness() const {
186186
}
187187

188188
bool PPCSubtarget::isGVIndirectSymbol(const GlobalValue *GV) const {
189+
if (isAIXABI()) {
190+
if (const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV))
191+
// On AIX the only symbols that aren't indirect are toc-data.
192+
return !GVar->hasAttribute("toc-data");
193+
194+
return true;
195+
}
196+
189197
// Large code model always uses the TOC even for local symbols.
190198
if (TM.getCodeModel() == CodeModel::Large)
191199
return true;
200+
192201
if (TM.shouldAssumeDSOLocal(GV))
193202
return false;
194203
return true;
195204
}
196205

206+
CodeModel::Model PPCSubtarget::getCodeModel(const TargetMachine &TM,
207+
const GlobalValue *GV) const {
208+
// If there isn't an attribute to override the module code model
209+
// this will be the effective code model.
210+
CodeModel::Model ModuleModel = TM.getCodeModel();
211+
212+
// Initially support per global code model for AIX only.
213+
if (!isAIXABI())
214+
return ModuleModel;
215+
216+
// Only GlobalVariables carry an attribute which can override the module code
217+
// model.
218+
assert(GV && "Unexpected NULL GlobalValue");
219+
const GlobalVariable *GlobalVar =
220+
[](const GlobalValue *GV) -> const GlobalVariable * {
221+
const GlobalVariable *Var = dyn_cast<GlobalVariable>(GV);
222+
if (Var)
223+
return Var;
224+
225+
const GlobalAlias *Alias = dyn_cast<GlobalAlias>(GV);
226+
if (Alias)
227+
return dyn_cast<GlobalVariable>(Alias->getAliaseeObject());
228+
229+
return nullptr;
230+
}(GV);
231+
232+
if (!GlobalVar)
233+
return ModuleModel;
234+
235+
std::optional<CodeModel::Model> MaybeCodeModel = GlobalVar->getCodeModel();
236+
if (MaybeCodeModel) {
237+
CodeModel::Model CM = *MaybeCodeModel;
238+
assert((CM == CodeModel::Small || CM == CodeModel::Large) &&
239+
"invalid code model for AIX");
240+
return CM;
241+
}
242+
243+
return ModuleModel;
244+
}
245+
197246
bool PPCSubtarget::isELFv2ABI() const { return TM.isELFv2ABI(); }
198247
bool PPCSubtarget::isPPC64() const { return TM.isPPC64(); }
199248

llvm/lib/Target/PowerPC/PPCSubtarget.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,10 @@ class PPCSubtarget : public PPCGenSubtargetInfo {
245245
/// True if the GV will be accessed via an indirect symbol.
246246
bool isGVIndirectSymbol(const GlobalValue *GV) const;
247247

248+
/// Calculates the effective code model for argument GV.
249+
CodeModel::Model getCodeModel(const TargetMachine &TM,
250+
const GlobalValue *GV) const;
251+
248252
/// True if the ABI is descriptor based.
249253
bool usesFunctionDescriptors() const {
250254
// Both 32-bit and 64-bit AIX are descriptor based. For ELF only the 64-bit

0 commit comments

Comments
 (0)