Skip to content

Commit 06d5aef

Browse files
committed
[AIX] Support per global code model.
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.
1 parent b32845c commit 06d5aef

File tree

6 files changed

+279
-30
lines changed

6 files changed

+279
-30
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 codemodel for symbol with out 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: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2680,21 +2680,35 @@ 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+
2686+
const MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(Sym);
2687+
2688+
// The "_$TLSML" symbol for TLS local-dynamic mode requires XMC_TC, otherwise
2689+
// the AIX assembler will complain.
2690+
if (XSym->getSymbolTableName() == "_$TLSML")
2691+
return XCOFF::XMC_TC;
2692+
2693+
// Use large code model toc entries for ehinfo symbols as they are
2694+
// never refrenced directly. The runtime loads their TOC entries
2695+
// address from the trace-back table.
2696+
if (XSym->isEHInfo())
2697+
return XCOFF::XMC_TE;
2698+
2699+
// If the symbol does not have a code model specified use the module value.
2700+
if (!XSym->hasPerSymbolCodeModel())
2701+
return TM.getCodeModel() == CodeModel::Large ? XCOFF::XMC_TE
2702+
: XCOFF::XMC_TC;
2703+
2704+
return XSym->getPerSymbolCodeModel() == MCSymbolXCOFF::CM_Large
2705+
? XCOFF::XMC_TE
2706+
: XCOFF::XMC_TC;
2707+
}(Sym, TM);
2708+
26892709
return getContext().getXCOFFSection(
26902710
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));
2711+
XCOFF::CsectProperties(SMC, XCOFF::XTY_SD));
26982712
}
26992713

27002714
MCSection *TargetLoweringObjectFileXCOFF::getSectionForLSDA(

llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp

Lines changed: 84 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,63 @@ 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+
assert(S.isAIXABI() && "ELF per global code model not supported yet");
481+
482+
CodeModel::Model ModuleModel = TM.getCodeModel();
483+
484+
// If the operand is not a global address then there is no
485+
// global variable to carry an attribute.
486+
if (!(MO.getType() == MachineOperand::MO_GlobalAddress))
487+
return ModuleModel;
488+
489+
const GlobalValue *GV = MO.getGlobal();
490+
assert(GV && "expected global for MO_GlobalAddress");
491+
492+
if (!isa<GlobalVariable>(GV))
493+
return ModuleModel;
494+
495+
std::optional<CodeModel::Model> MaybeCodeModel =
496+
dyn_cast<GlobalVariable>(GV)->getCodeModel();
497+
if (MaybeCodeModel)
498+
return *MaybeCodeModel;
499+
500+
return ModuleModel;
501+
}
502+
503+
static void checkPerGlobalCodeModel(const GlobalValue *GV, MCSymbol *Sym) {
504+
// ELF per global code model not supported yet.
505+
if (!isa<MCSymbolXCOFF>(Sym))
506+
return;
507+
508+
// Symbols that aren't global variables cannot have the attribute.
509+
if (!isa<GlobalVariable>(GV))
510+
return;
511+
512+
const GlobalVariable *GVar = cast<GlobalVariable>(GV);
513+
std::optional<CodeModel::Model> MaybeCM = GVar->getCodeModel();
514+
515+
// No overriding atribute.
516+
if (!MaybeCM)
517+
return;
518+
519+
CodeModel::Model CM = *MaybeCM;
520+
521+
MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(Sym);
522+
switch (CM) {
523+
case CodeModel::Large:
524+
XSym->setPerSymbolCodeModel(MCSymbolXCOFF::CM_Large);
525+
return;
526+
case CodeModel::Small:
527+
XSym->setPerSymbolCodeModel(MCSymbolXCOFF::CM_Small);
528+
return;
529+
default:
530+
report_fatal_error("Invlaid code model for AIX");
531+
}
532+
}
533+
477534
/// lookUpOrCreateTOCEntry -- Given a symbol, look up whether a TOC entry
478535
/// exists for it. If not, create one. Then return a symbol that references
479536
/// the TOC entry.
@@ -723,8 +780,12 @@ void PPCAsmPrinter::EmitTlsCall(const MachineInstr *MI,
723780
static MCSymbol *getMCSymbolForTOCPseudoMO(const MachineOperand &MO,
724781
AsmPrinter &AP) {
725782
switch (MO.getType()) {
726-
case MachineOperand::MO_GlobalAddress:
727-
return AP.getSymbol(MO.getGlobal());
783+
case MachineOperand::MO_GlobalAddress: {
784+
const GlobalValue *GV = MO.getGlobal();
785+
MCSymbol *Sym = AP.getSymbol(GV);
786+
checkPerGlobalCodeModel(GV, Sym);
787+
return Sym;
788+
}
728789
case MachineOperand::MO_ConstantPoolIndex:
729790
return AP.GetCPISymbol(MO.getIndex());
730791
case MachineOperand::MO_JumpTableIndex:
@@ -1014,7 +1075,7 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
10141075
// relative to the toc-base.
10151076
if (IsAIX) {
10161077
assert(
1017-
TM.getCodeModel() == CodeModel::Small &&
1078+
getCodeModel(*Subtarget, TM, MO) == CodeModel::Small &&
10181079
"This pseudo should only be selected for 32-bit small code model.");
10191080
Exp = getTOCEntryLoadingExprForXCOFF(MOSymbol, Exp, VK);
10201081
TmpInst.getOperand(1) = MCOperand::createExpr(Exp);
@@ -1098,7 +1159,12 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
10981159
return;
10991160
}
11001161
case PPC::ADDIStocHA: {
1101-
assert((IsAIX && !IsPPC64 && TM.getCodeModel() == CodeModel::Large) &&
1162+
const MachineOperand &MO = MI->getOperand(2);
1163+
1164+
assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) &&
1165+
"Invalid operand for ADDIStocHA.");
1166+
assert((IsAIX && !IsPPC64 &&
1167+
getCodeModel(*Subtarget, TM, MO) == CodeModel::Large) &&
11021168
"This pseudo should only be selected for 32-bit large code model on"
11031169
" AIX.");
11041170

@@ -1108,10 +1174,6 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
11081174
// Change the opcode to ADDIS.
11091175
TmpInst.setOpcode(PPC::ADDIS);
11101176

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

@@ -1131,7 +1193,12 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
11311193
return;
11321194
}
11331195
case PPC::LWZtocL: {
1134-
assert(IsAIX && !IsPPC64 && TM.getCodeModel() == CodeModel::Large &&
1196+
const MachineOperand &MO = MI->getOperand(1);
1197+
1198+
assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) &&
1199+
"Invalid operand for LWZtocL.");
1200+
assert(IsAIX && !IsPPC64 &&
1201+
getCodeModel(*Subtarget, TM, MO) == CodeModel::Large &&
11351202
"This pseudo should only be selected for 32-bit large code model on"
11361203
" AIX.");
11371204

@@ -1141,10 +1208,6 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
11411208
// Change the opcode to lwz.
11421209
TmpInst.setOpcode(PPC::LWZ);
11431210

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

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

11841247
const bool GlobalToc =
11851248
MO.isGlobal() && Subtarget->isGVIndirectSymbol(MO.getGlobal());
1249+
1250+
const CodeModel::Model CM =
1251+
IsAIX ? getCodeModel(*Subtarget, TM, MO) : TM.getCodeModel();
1252+
11861253
if (GlobalToc || MO.isJTI() || MO.isBlockAddress() ||
1187-
(MO.isCPI() && TM.getCodeModel() == CodeModel::Large))
1254+
(MO.isCPI() && CM == CodeModel::Large))
11881255
MOSymbol = lookUpOrCreateTOCEntry(MOSymbol, getTOCEntryTypeForMO(MO), VK);
11891256

11901257
VK = IsAIX ? MCSymbolRefExpr::VK_PPC_U : MCSymbolRefExpr::VK_PPC_TOC_HA;
@@ -1225,8 +1292,9 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
12251292
const MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this);
12261293

12271294
MCSymbolRefExpr::VariantKind VK = GetVKForMO(MO);
1228-
1229-
if (!MO.isCPI() || TM.getCodeModel() == CodeModel::Large)
1295+
CodeModel::Model CM =
1296+
IsAIX ? getCodeModel(*Subtarget, TM, MO) : TM.getCodeModel();
1297+
if (!MO.isCPI() || CM == CodeModel::Large)
12301298
MOSymbol = lookUpOrCreateTOCEntry(MOSymbol, getTOCEntryTypeForMO(MO), VK);
12311299

12321300
VK = IsAIX ? MCSymbolRefExpr::VK_PPC_L : MCSymbolRefExpr::VK_PPC_TOC_LO;

llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,43 @@ static bool hasTocDataAttr(SDValue Val, unsigned PointerSize) {
558558
return true;
559559
}
560560

561+
static CodeModel::Model getCodeModel(const PPCSubtarget &Subtarget,
562+
const TargetMachine &TM,
563+
const SDNode *Node) {
564+
// If there isn't an attribute to override the module code model
565+
// this will be the effective code model.
566+
CodeModel::Model ModuleModel = TM.getCodeModel();
567+
568+
// Initially support per global code model for AIX only.
569+
if (!Subtarget.isAIXABI())
570+
return ModuleModel;
571+
572+
// If the operand is not a global address there is no
573+
// GlobalVariable to query for an attribute.
574+
SDValue Operand = Node->getOperand(0);
575+
if (!isa<GlobalAddressSDNode>(Operand))
576+
return ModuleModel;
577+
578+
GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Operand);
579+
if (!GA)
580+
return ModuleModel;
581+
582+
const GlobalValue *GV = GA->getGlobal();
583+
if (!GV || !isa<GlobalVariable>(GV))
584+
return ModuleModel;
585+
586+
std::optional<CodeModel::Model> MaybeCodeModel =
587+
dyn_cast<GlobalVariable>(GV)->getCodeModel();
588+
if (MaybeCodeModel) {
589+
CodeModel::Model CM = *MaybeCodeModel;
590+
assert((CM == CodeModel::Small || CM == CodeModel::Large) &&
591+
"invalid code model for AIX");
592+
return CM;
593+
}
594+
595+
return ModuleModel;
596+
}
597+
561598
/// isInt32Immediate - This method tests to see if the node is a 32-bit constant
562599
/// operand. If so Imm will receive the 32-bit value.
563600
static bool isInt32Immediate(SDNode *N, unsigned &Imm) {
@@ -6093,7 +6130,8 @@ void PPCDAGToDAGISel::Select(SDNode *N) {
60936130
const bool isAIXABI = Subtarget->isAIXABI();
60946131

60956132
// PowerPC only support small, medium and large code model.
6096-
const CodeModel::Model CModel = TM.getCodeModel();
6133+
const CodeModel::Model CModel = getCodeModel(*Subtarget, TM, N);
6134+
60976135
assert(!(CModel == CodeModel::Tiny || CModel == CodeModel::Kernel) &&
60986136
"PowerPC doesn't support tiny or kernel code models.");
60996137

llvm/lib/Target/PowerPC/PPCSubtarget.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,15 @@ bool PPCSubtarget::isGVIndirectSymbol(const GlobalValue *GV) const {
189189
// Large code model always uses the TOC even for local symbols.
190190
if (TM.getCodeModel() == CodeModel::Large)
191191
return true;
192+
193+
// AIX may have a per global code model attribute.
194+
if (isAIXABI() && isa<GlobalVariable>(GV)) {
195+
const GlobalVariable *GVar = cast<GlobalVariable>(GV);
196+
std::optional<CodeModel::Model> OptionalCM = GVar->getCodeModel();
197+
if (OptionalCM && *OptionalCM == CodeModel::Large)
198+
return true;
199+
}
200+
192201
if (TM.shouldAssumeDSOLocal(*GV->getParent(), GV))
193202
return false;
194203
return true;

0 commit comments

Comments
 (0)