[llvm] [AIX] Support per global code model. (PR #79202)
Sean Fertile via llvm-commits
llvm-commits at lists.llvm.org
Wed Mar 6 05:56:16 PST 2024
https://github.com/mandlebug updated https://github.com/llvm/llvm-project/pull/79202
>From 06d5aef46acc2f94f74b8ef566ef7cc47de05c25 Mon Sep 17 00:00:00 2001
From: Sean Fertile <sd.fertile at gmail.com>
Date: Tue, 23 Jan 2024 12:55:17 -0500
Subject: [PATCH 1/5] [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.
---
llvm/include/llvm/MC/MCSymbolXCOFF.h | 16 +++
.../CodeGen/TargetLoweringObjectFileImpl.cpp | 40 ++++---
llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 100 ++++++++++++++---
llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp | 40 ++++++-
llvm/lib/Target/PowerPC/PPCSubtarget.cpp | 9 ++
.../CodeGen/PowerPC/aix-codemodel-attr.ll | 104 ++++++++++++++++++
6 files changed, 279 insertions(+), 30 deletions(-)
create mode 100644 llvm/test/CodeGen/PowerPC/aix-codemodel-attr.ll
diff --git a/llvm/include/llvm/MC/MCSymbolXCOFF.h b/llvm/include/llvm/MC/MCSymbolXCOFF.h
index 11c3b8831ba517..49374494b9ed1d 100644
--- a/llvm/include/llvm/MC/MCSymbolXCOFF.h
+++ b/llvm/include/llvm/MC/MCSymbolXCOFF.h
@@ -26,6 +26,8 @@ class MCSymbolXCOFF : public MCSymbol {
static bool classof(const MCSymbol *S) { return S->isXCOFF(); }
+ enum CodeModel : uint8_t { CM_Small, CM_Large };
+
static StringRef getUnqualifiedName(StringRef Name) {
if (Name.back() == ']') {
StringRef Lhs, Rhs;
@@ -72,8 +74,22 @@ class MCSymbolXCOFF : public MCSymbol {
void setEHInfo() const { modifyFlags(SF_EHInfo, SF_EHInfo); }
+ bool hasPerSymbolCodeModel() const { return PerSymbolCodeModel.has_value(); }
+
+ CodeModel getPerSymbolCodeModel() const {
+ assert(hasPerSymbolCodeModel() &&
+ "Requested codemodel for symbol with out one");
+ return *PerSymbolCodeModel;
+ }
+
+ void setPerSymbolCodeModel(MCSymbolXCOFF::CodeModel Model) {
+ PerSymbolCodeModel = Model;
+ }
+
private:
std::optional<XCOFF::StorageClass> StorageClass;
+ std::optional<CodeModel> PerSymbolCodeModel;
+
MCSectionXCOFF *RepresentedCsect = nullptr;
XCOFF::VisibilityType VisibilityType = XCOFF::SYM_V_UNSPECIFIED;
StringRef SymbolTableName;
diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index 6943ce261d9d9c..0d30239fd2e866 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -2680,21 +2680,35 @@ MCSection *TargetLoweringObjectFileXCOFF::getSectionForFunctionDescriptor(
MCSection *TargetLoweringObjectFileXCOFF::getSectionForTOCEntry(
const MCSymbol *Sym, const TargetMachine &TM) const {
- // Use TE storage-mapping class when large code model is enabled so that
- // the chance of needing -bbigtoc is decreased. Also, the toc-entry for
- // EH info is never referenced directly using instructions so it can be
- // allocated with TE storage-mapping class.
- // The "_$TLSML" symbol for TLS local-dynamic mode requires XMC_TC, otherwise
- // the AIX assembler will complain.
+ const XCOFF::StorageMappingClass SMC = [](const MCSymbol *Sym,
+ const TargetMachine &TM) {
+
+ const MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(Sym);
+
+ // The "_$TLSML" symbol for TLS local-dynamic mode requires XMC_TC, otherwise
+ // the AIX assembler will complain.
+ if (XSym->getSymbolTableName() == "_$TLSML")
+ return XCOFF::XMC_TC;
+
+ // Use large code model toc entries for ehinfo symbols as they are
+ // never refrenced directly. The runtime loads their TOC entries
+ // address from the trace-back table.
+ if (XSym->isEHInfo())
+ return XCOFF::XMC_TE;
+
+ // If the symbol does not have a code model specified use the module value.
+ if (!XSym->hasPerSymbolCodeModel())
+ return TM.getCodeModel() == CodeModel::Large ? XCOFF::XMC_TE
+ : XCOFF::XMC_TC;
+
+ return XSym->getPerSymbolCodeModel() == MCSymbolXCOFF::CM_Large
+ ? XCOFF::XMC_TE
+ : XCOFF::XMC_TC;
+ }(Sym, TM);
+
return getContext().getXCOFFSection(
cast<MCSymbolXCOFF>(Sym)->getSymbolTableName(), SectionKind::getData(),
- XCOFF::CsectProperties(
- ((TM.getCodeModel() == CodeModel::Large &&
- cast<MCSymbolXCOFF>(Sym)->getSymbolTableName() != "_$TLSML") ||
- cast<MCSymbolXCOFF>(Sym)->isEHInfo())
- ? XCOFF::XMC_TE
- : XCOFF::XMC_TC,
- XCOFF::XTY_SD));
+ XCOFF::CsectProperties(SMC, XCOFF::XTY_SD));
}
MCSection *TargetLoweringObjectFileXCOFF::getSectionForLSDA(
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 9396ca22dacf86..904d6d1ec3e5aa 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -474,6 +474,63 @@ static void collectTOCStats(PPCAsmPrinter::TOCEntryType Type) {
}
}
+static CodeModel::Model getCodeModel(const PPCSubtarget &S,
+ const TargetMachine &TM,
+ const MachineOperand &MO) {
+ assert(S.isAIXABI() && "ELF per global code model not supported yet");
+
+ CodeModel::Model ModuleModel = TM.getCodeModel();
+
+ // If the operand is not a global address then there is no
+ // global variable to carry an attribute.
+ if (!(MO.getType() == MachineOperand::MO_GlobalAddress))
+ return ModuleModel;
+
+ const GlobalValue *GV = MO.getGlobal();
+ assert(GV && "expected global for MO_GlobalAddress");
+
+ if (!isa<GlobalVariable>(GV))
+ return ModuleModel;
+
+ std::optional<CodeModel::Model> MaybeCodeModel =
+ dyn_cast<GlobalVariable>(GV)->getCodeModel();
+ if (MaybeCodeModel)
+ return *MaybeCodeModel;
+
+ return ModuleModel;
+}
+
+static void checkPerGlobalCodeModel(const GlobalValue *GV, MCSymbol *Sym) {
+ // ELF per global code model not supported yet.
+ if (!isa<MCSymbolXCOFF>(Sym))
+ return;
+
+ // Symbols that aren't global variables cannot have the attribute.
+ if (!isa<GlobalVariable>(GV))
+ return;
+
+ const GlobalVariable *GVar = cast<GlobalVariable>(GV);
+ std::optional<CodeModel::Model> MaybeCM = GVar->getCodeModel();
+
+ // No overriding atribute.
+ if (!MaybeCM)
+ return;
+
+ CodeModel::Model CM = *MaybeCM;
+
+ MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(Sym);
+ switch (CM) {
+ case CodeModel::Large:
+ XSym->setPerSymbolCodeModel(MCSymbolXCOFF::CM_Large);
+ return;
+ case CodeModel::Small:
+ XSym->setPerSymbolCodeModel(MCSymbolXCOFF::CM_Small);
+ return;
+ default:
+ report_fatal_error("Invlaid code model for AIX");
+ }
+}
+
/// lookUpOrCreateTOCEntry -- Given a symbol, look up whether a TOC entry
/// exists for it. If not, create one. Then return a symbol that references
/// the TOC entry.
@@ -723,8 +780,12 @@ void PPCAsmPrinter::EmitTlsCall(const MachineInstr *MI,
static MCSymbol *getMCSymbolForTOCPseudoMO(const MachineOperand &MO,
AsmPrinter &AP) {
switch (MO.getType()) {
- case MachineOperand::MO_GlobalAddress:
- return AP.getSymbol(MO.getGlobal());
+ case MachineOperand::MO_GlobalAddress: {
+ const GlobalValue *GV = MO.getGlobal();
+ MCSymbol *Sym = AP.getSymbol(GV);
+ checkPerGlobalCodeModel(GV, Sym);
+ return Sym;
+ }
case MachineOperand::MO_ConstantPoolIndex:
return AP.GetCPISymbol(MO.getIndex());
case MachineOperand::MO_JumpTableIndex:
@@ -1014,7 +1075,7 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
// relative to the toc-base.
if (IsAIX) {
assert(
- TM.getCodeModel() == CodeModel::Small &&
+ getCodeModel(*Subtarget, TM, MO) == CodeModel::Small &&
"This pseudo should only be selected for 32-bit small code model.");
Exp = getTOCEntryLoadingExprForXCOFF(MOSymbol, Exp, VK);
TmpInst.getOperand(1) = MCOperand::createExpr(Exp);
@@ -1098,7 +1159,12 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
return;
}
case PPC::ADDIStocHA: {
- assert((IsAIX && !IsPPC64 && TM.getCodeModel() == CodeModel::Large) &&
+ const MachineOperand &MO = MI->getOperand(2);
+
+ assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) &&
+ "Invalid operand for ADDIStocHA.");
+ assert((IsAIX && !IsPPC64 &&
+ getCodeModel(*Subtarget, TM, MO) == CodeModel::Large) &&
"This pseudo should only be selected for 32-bit large code model on"
" AIX.");
@@ -1108,10 +1174,6 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
// Change the opcode to ADDIS.
TmpInst.setOpcode(PPC::ADDIS);
- const MachineOperand &MO = MI->getOperand(2);
- assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) &&
- "Invalid operand for ADDIStocHA.");
-
// Map the machine operand to its corresponding MCSymbol.
MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this);
@@ -1131,7 +1193,12 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
return;
}
case PPC::LWZtocL: {
- assert(IsAIX && !IsPPC64 && TM.getCodeModel() == CodeModel::Large &&
+ const MachineOperand &MO = MI->getOperand(1);
+
+ assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) &&
+ "Invalid operand for LWZtocL.");
+ assert(IsAIX && !IsPPC64 &&
+ getCodeModel(*Subtarget, TM, MO) == CodeModel::Large &&
"This pseudo should only be selected for 32-bit large code model on"
" AIX.");
@@ -1141,10 +1208,6 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
// Change the opcode to lwz.
TmpInst.setOpcode(PPC::LWZ);
- const MachineOperand &MO = MI->getOperand(1);
- assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) &&
- "Invalid operand for LWZtocL.");
-
// Map the machine operand to its corresponding MCSymbol.
MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this);
@@ -1183,8 +1246,12 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
const bool GlobalToc =
MO.isGlobal() && Subtarget->isGVIndirectSymbol(MO.getGlobal());
+
+ const CodeModel::Model CM =
+ IsAIX ? getCodeModel(*Subtarget, TM, MO) : TM.getCodeModel();
+
if (GlobalToc || MO.isJTI() || MO.isBlockAddress() ||
- (MO.isCPI() && TM.getCodeModel() == CodeModel::Large))
+ (MO.isCPI() && CM == CodeModel::Large))
MOSymbol = lookUpOrCreateTOCEntry(MOSymbol, getTOCEntryTypeForMO(MO), VK);
VK = IsAIX ? MCSymbolRefExpr::VK_PPC_U : MCSymbolRefExpr::VK_PPC_TOC_HA;
@@ -1225,8 +1292,9 @@ void PPCAsmPrinter::emitInstruction(const MachineInstr *MI) {
const MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this);
MCSymbolRefExpr::VariantKind VK = GetVKForMO(MO);
-
- if (!MO.isCPI() || TM.getCodeModel() == CodeModel::Large)
+ CodeModel::Model CM =
+ IsAIX ? getCodeModel(*Subtarget, TM, MO) : TM.getCodeModel();
+ if (!MO.isCPI() || CM == CodeModel::Large)
MOSymbol = lookUpOrCreateTOCEntry(MOSymbol, getTOCEntryTypeForMO(MO), VK);
VK = IsAIX ? MCSymbolRefExpr::VK_PPC_L : MCSymbolRefExpr::VK_PPC_TOC_LO;
diff --git a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
index 9e5f0b36616d1b..6ca540562e8c19 100644
--- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
@@ -558,6 +558,43 @@ static bool hasTocDataAttr(SDValue Val, unsigned PointerSize) {
return true;
}
+static CodeModel::Model getCodeModel(const PPCSubtarget &Subtarget,
+ const TargetMachine &TM,
+ const SDNode *Node) {
+ // If there isn't an attribute to override the module code model
+ // this will be the effective code model.
+ CodeModel::Model ModuleModel = TM.getCodeModel();
+
+ // Initially support per global code model for AIX only.
+ if (!Subtarget.isAIXABI())
+ return ModuleModel;
+
+ // If the operand is not a global address there is no
+ // GlobalVariable to query for an attribute.
+ SDValue Operand = Node->getOperand(0);
+ if (!isa<GlobalAddressSDNode>(Operand))
+ return ModuleModel;
+
+ GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Operand);
+ if (!GA)
+ return ModuleModel;
+
+ const GlobalValue *GV = GA->getGlobal();
+ if (!GV || !isa<GlobalVariable>(GV))
+ return ModuleModel;
+
+ std::optional<CodeModel::Model> MaybeCodeModel =
+ dyn_cast<GlobalVariable>(GV)->getCodeModel();
+ if (MaybeCodeModel) {
+ CodeModel::Model CM = *MaybeCodeModel;
+ assert((CM == CodeModel::Small || CM == CodeModel::Large) &&
+ "invalid code model for AIX");
+ return CM;
+ }
+
+ return ModuleModel;
+}
+
/// isInt32Immediate - This method tests to see if the node is a 32-bit constant
/// operand. If so Imm will receive the 32-bit value.
static bool isInt32Immediate(SDNode *N, unsigned &Imm) {
@@ -6093,7 +6130,8 @@ void PPCDAGToDAGISel::Select(SDNode *N) {
const bool isAIXABI = Subtarget->isAIXABI();
// PowerPC only support small, medium and large code model.
- const CodeModel::Model CModel = TM.getCodeModel();
+ const CodeModel::Model CModel = getCodeModel(*Subtarget, TM, N);
+
assert(!(CModel == CodeModel::Tiny || CModel == CodeModel::Kernel) &&
"PowerPC doesn't support tiny or kernel code models.");
diff --git a/llvm/lib/Target/PowerPC/PPCSubtarget.cpp b/llvm/lib/Target/PowerPC/PPCSubtarget.cpp
index 2735bdee3bcfcc..90175ce1ba3d08 100644
--- a/llvm/lib/Target/PowerPC/PPCSubtarget.cpp
+++ b/llvm/lib/Target/PowerPC/PPCSubtarget.cpp
@@ -189,6 +189,15 @@ bool PPCSubtarget::isGVIndirectSymbol(const GlobalValue *GV) const {
// Large code model always uses the TOC even for local symbols.
if (TM.getCodeModel() == CodeModel::Large)
return true;
+
+ // AIX may have a per global code model attribute.
+ if (isAIXABI() && isa<GlobalVariable>(GV)) {
+ const GlobalVariable *GVar = cast<GlobalVariable>(GV);
+ std::optional<CodeModel::Model> OptionalCM = GVar->getCodeModel();
+ if (OptionalCM && *OptionalCM == CodeModel::Large)
+ return true;
+ }
+
if (TM.shouldAssumeDSOLocal(*GV->getParent(), GV))
return false;
return true;
diff --git a/llvm/test/CodeGen/PowerPC/aix-codemodel-attr.ll b/llvm/test/CodeGen/PowerPC/aix-codemodel-attr.ll
new file mode 100644
index 00000000000000..14bc2a378668b9
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/aix-codemodel-attr.ll
@@ -0,0 +1,104 @@
+; RUN: llc --verify-machineinstrs -mtriple powerpc-ibm-aix --code-model=small < \
+; RUN: %s | FileCheck --check-prefixes=CHECK,CHECK32 %s
+
+; RUN: llc --verify-machineinstrs -mtriple powerpc-ibm-aix --code-model=large < \
+; RUN: %s | FileCheck --check-prefixes=CHECK,CHECK32 %s
+
+; RUN: llc --verify-machineinstrs -mtriple powerpc64-ibm-aix --code-model=small < \
+; RUN: %s | FileCheck --check-prefixes=CHECK,CHECK64 %s
+
+; RUN: llc --verify-machineinstrs -mtriple powerpc64-ibm-aix --code-model=large < \
+; RUN: %s | FileCheck --check-prefixes=CHECK,CHECK64 %s
+
+ at a = external dso_local global i32, code_model "small", align 4
+ at b = external dso_local global i32, code_model "large", align 4
+ at c = dso_local global i32 55, code_model "small", align 4
+ at d = dso_local global i32 41, code_model "large", align 4
+
+
+define i32 @A() local_unnamed_addr {
+entry:
+ %0 = load i32, ptr @a, align 4
+ ret i32 %0
+}
+; CHECK32: lwz [[SCRATCH:[0-9]+]], L..C[[TL_A:[0-9]+]](2) # @a
+; CHECK64: ld [[SCRATCH:[0-9]+]], L..C[[TL_A:[0-9]+]](2) # @a
+; CHECK: lwz 3, 0([[SCRATCH]])
+; CHECK: blr
+
+define i32 @B() local_unnamed_addr {
+entry:
+ %0 = load i32, ptr @b, align 4
+ ret i32 %0
+}
+; CHECK: addis [[HI:[0-9]+]], L..C[[TL_B:[0-9]+]]@u(2)
+; CHECK32: lwz [[ADDR:[0-9]+]], L..C[[TL_B]]@l([[HI]])
+; CHECK64: ld [[ADDR:[0-9]+]], L..C[[TL_B]]@l([[HI]])
+; CHECK: lwz 3, 0([[ADDR]])
+; CHECK: blr
+
+define i32 @C() local_unnamed_addr {
+entry:
+ %0 = load i32, ptr @c, align 4
+ ret i32 %0
+}
+; CHECK32: lwz [[SCRATCH:[0-9]+]], L..C[[TL_C:[0-9]+]](2) # @c
+; CHECK64: ld [[SCRATCH:[0-9]+]], L..C[[TL_C:[0-9]+]](2) # @c
+; CHECK: lwz 3, 0([[SCRATCH]])
+; CHECK: blr
+
+define i32 @D() local_unnamed_addr {
+entry:
+ %0 = load i32, ptr @d, align 4
+ ret i32 %0
+}
+; CHECK: addis [[HI:[0-9]+]], L..C[[TL_D:[0-9]+]]@u(2)
+; CHECK32: lwz [[ADDR:[0-9]+]], L..C[[TL_D]]@l([[HI]])
+; CHECK64: ld [[ADDR:[0-9]+]], L..C[[TL_D]]@l([[HI]])
+; CHECK: lwz 3, 0([[ADDR]])
+; CHECK: blr
+
+define noundef nonnull ptr @addr_a() local_unnamed_addr {
+entry:
+ ret ptr @a
+}
+; CHECK32: lwz 3, L..C[[TL_A]](2) # @a
+; CHECK64: ld 3, L..C[[TL_A]](2) # @a
+; CHECK: blr
+
+define noundef nonnull ptr @addr_b() local_unnamed_addr {
+entry:
+ ret ptr @b
+}
+; CHECK: addis [[HI:[0-9]+]], L..C[[TL_B]]@u(2)
+; CHECK32: lwz 3, L..C[[TL_B]]@l([[HI]])
+; CHECK64: ld 3, L..C[[TL_B]]@l([[HI]])
+; CHECK: blr
+
+
+define noundef nonnull ptr @addr_c() local_unnamed_addr {
+entry:
+ ret ptr @c
+}
+; CHECK32: lwz 3, L..C[[TL_C]](2) # @c
+; CHECK64: ld 3, L..C[[TL_C]](2) # @c
+; CHECK: blr
+
+define noundef nonnull ptr @addr_d() local_unnamed_addr {
+entry:
+ ret ptr @d
+}
+; CHECK: addis [[HI:[0-9]+]], L..C[[TL_D]]@u(2)
+; CHECK32: lwz 3, L..C[[TL_D]]@l([[HI]])
+; CHECK64: ld 3, L..C[[TL_D]]@l([[HI]])
+; CHECK: blr
+
+;; Check TOC entires have correct storage mapping class
+; CHECK: L..C[[TL_A]]:
+; CHECK: .tc a[TC],a[UA]
+; CHECK: L..C[[TL_B]]:
+; CHECK: .tc b[TE],b[UA]
+; CHECK: L..C[[TL_C]]:
+; CHECK: .tc c[TC],c[RW]
+; CHECK: L..C[[TL_D]]:
+; CHECK: .tc d[TE],d[RW]
>From 792c839540ffb25e1d0944c61d70c44508701696 Mon Sep 17 00:00:00 2001
From: Sean Fertile <sd.fertile at gmail.com>
Date: Wed, 24 Jan 2024 23:52:45 -0500
Subject: [PATCH 2/5] Address first round of review comments.
- convert assert to early return.
- change dyn_cast<> following an isa<> to a cast<>
- remove a null check after a cast<>
---
llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 7 ++++---
llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp | 6 +-----
2 files changed, 5 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 904d6d1ec3e5aa..a17e65687f942a 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -477,9 +477,10 @@ static void collectTOCStats(PPCAsmPrinter::TOCEntryType Type) {
static CodeModel::Model getCodeModel(const PPCSubtarget &S,
const TargetMachine &TM,
const MachineOperand &MO) {
- assert(S.isAIXABI() && "ELF per global code model not supported yet");
-
CodeModel::Model ModuleModel = TM.getCodeModel();
+ // Per global code model is only support on AIX.
+ if (!S.isAIXABI())
+ return ModuleModel;
// If the operand is not a global address then there is no
// global variable to carry an attribute.
@@ -493,7 +494,7 @@ static CodeModel::Model getCodeModel(const PPCSubtarget &S,
return ModuleModel;
std::optional<CodeModel::Model> MaybeCodeModel =
- dyn_cast<GlobalVariable>(GV)->getCodeModel();
+ cast<GlobalVariable>(GV)->getCodeModel();
if (MaybeCodeModel)
return *MaybeCodeModel;
diff --git a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
index 6ca540562e8c19..eeeabd535e82a1 100644
--- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
@@ -575,11 +575,7 @@ static CodeModel::Model getCodeModel(const PPCSubtarget &Subtarget,
if (!isa<GlobalAddressSDNode>(Operand))
return ModuleModel;
- GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Operand);
- if (!GA)
- return ModuleModel;
-
- const GlobalValue *GV = GA->getGlobal();
+ const GlobalValue *GV = cast<GlobalAddressSDNode>(Operand)->getGlobal();
if (!GV || !isa<GlobalVariable>(GV))
return ModuleModel;
>From 4be525f1580af617c4a3e2d90553758094c1851c Mon Sep 17 00:00:00 2001
From: Sean Fertile <sd.fertile at gmail.com>
Date: Tue, 20 Feb 2024 13:47:55 -0500
Subject: [PATCH 3/5] Address second round of review comments.
- Change setting per global code model on MCSymbol to the ASMPrinters
initialization so it happens once.
- Add some globals without explicit code models to the lit test.
---
llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 29 ++++-----
.../CodeGen/PowerPC/aix-codemodel-attr.ll | 59 +++++++++++++++----
2 files changed, 58 insertions(+), 30 deletions(-)
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index a17e65687f942a..150c9f2bfb893c 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -501,25 +501,16 @@ static CodeModel::Model getCodeModel(const PPCSubtarget &S,
return ModuleModel;
}
-static void checkPerGlobalCodeModel(const GlobalValue *GV, MCSymbol *Sym) {
- // ELF per global code model not supported yet.
- if (!isa<MCSymbolXCOFF>(Sym))
- return;
-
+static std::optional<CodeModel::Model>
+hasPerGlobalCodeModel(const GlobalValue *GV) {
// Symbols that aren't global variables cannot have the attribute.
if (!isa<GlobalVariable>(GV))
- return;
-
- const GlobalVariable *GVar = cast<GlobalVariable>(GV);
- std::optional<CodeModel::Model> MaybeCM = GVar->getCodeModel();
+ return std::nullopt;
- // No overriding atribute.
- if (!MaybeCM)
- return;
-
- CodeModel::Model CM = *MaybeCM;
+ return cast<GlobalVariable>(GV)->getCodeModel();
+}
- MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(Sym);
+static void setOptionalCodeModel(MCSymbolXCOFF *XSym, CodeModel::Model CM) {
switch (CM) {
case CodeModel::Large:
XSym->setPerSymbolCodeModel(MCSymbolXCOFF::CM_Large);
@@ -528,7 +519,7 @@ static void checkPerGlobalCodeModel(const GlobalValue *GV, MCSymbol *Sym) {
XSym->setPerSymbolCodeModel(MCSymbolXCOFF::CM_Small);
return;
default:
- report_fatal_error("Invlaid code model for AIX");
+ report_fatal_error("Invalid code model for AIX");
}
}
@@ -784,7 +775,6 @@ static MCSymbol *getMCSymbolForTOCPseudoMO(const MachineOperand &MO,
case MachineOperand::MO_GlobalAddress: {
const GlobalValue *GV = MO.getGlobal();
MCSymbol *Sym = AP.getSymbol(GV);
- checkPerGlobalCodeModel(GV, Sym);
return Sym;
}
case MachineOperand::MO_ConstantPoolIndex:
@@ -3030,6 +3020,11 @@ bool PPCAIXAsmPrinter::doInitialization(Module &M) {
}
setCsectAlignment(&G);
+ std::optional<CodeModel::Model> OptionalCodeModel =
+ hasPerGlobalCodeModel(&G);
+ if (OptionalCodeModel)
+ setOptionalCodeModel(cast<MCSymbolXCOFF>(getSymbol(&G)),
+ *OptionalCodeModel);
}
for (const auto &F : M)
diff --git a/llvm/test/CodeGen/PowerPC/aix-codemodel-attr.ll b/llvm/test/CodeGen/PowerPC/aix-codemodel-attr.ll
index 14bc2a378668b9..c3e28a06860cd2 100644
--- a/llvm/test/CodeGen/PowerPC/aix-codemodel-attr.ll
+++ b/llvm/test/CodeGen/PowerPC/aix-codemodel-attr.ll
@@ -1,20 +1,21 @@
; RUN: llc --verify-machineinstrs -mtriple powerpc-ibm-aix --code-model=small < \
-; RUN: %s | FileCheck --check-prefixes=CHECK,CHECK32 %s
+; RUN: %s | FileCheck --check-prefixes=CHECK,CHECK32,CHECK-SMALL,CHECK-SMALL32 %s
; RUN: llc --verify-machineinstrs -mtriple powerpc-ibm-aix --code-model=large < \
-; RUN: %s | FileCheck --check-prefixes=CHECK,CHECK32 %s
+; RUN: %s | FileCheck --check-prefixes=CHECK,CHECK32,CHECK-LARGE,CHECK-LARGE32 %s
; RUN: llc --verify-machineinstrs -mtriple powerpc64-ibm-aix --code-model=small < \
-; RUN: %s | FileCheck --check-prefixes=CHECK,CHECK64 %s
+; RUN: %s | FileCheck --check-prefixes=CHECK,CHECK64,CHECK-SMALL,CHECK-SMALL64 %s
; RUN: llc --verify-machineinstrs -mtriple powerpc64-ibm-aix --code-model=large < \
-; RUN: %s | FileCheck --check-prefixes=CHECK,CHECK64 %s
+; RUN: %s | FileCheck --check-prefixes=CHECK,CHECK64,CHECK-LARGE,CHECK-LARGE64 %s
@a = external dso_local global i32, code_model "small", align 4
@b = external dso_local global i32, code_model "large", align 4
@c = dso_local global i32 55, code_model "small", align 4
@d = dso_local global i32 41, code_model "large", align 4
-
+ at e = external dso_local global i32, align 4
+ at f = dso_local global i32 2748, align 4
define i32 @A() local_unnamed_addr {
entry:
@@ -58,6 +59,32 @@ entry:
; CHECK: lwz 3, 0([[ADDR]])
; CHECK: blr
+define i32 @E() {
+entry:
+ %0 = load i32, ptr @e, align 4
+ ret i32 %0
+}
+; CHECK-LARGE: addis [[HI:[0-9]+]], L..C[[TL_E:[0-9]+]]@u(2)
+; CHECK-LARGE32: lwz [[SCRATCH:[0-9]+]], L..C[[TL_E]]@l([[HI]])
+; CHECK-SMALL32: lwz [[SCRATCH:[0-9]+]], L..C[[TL_E:[0-9]+]](2)
+; CHECK-LARGE64: ld [[SCRATCH:[0-9]+]], L..C[[TL_E]]@l([[HI]])
+; CHECK-SMALL64: ld [[SCRATCH:[0-9]+]], L..C[[TL_E:[0-9]+]](2)
+; CHECK: lwz 3, 0([[SCRATCH]])
+; CHECK: blr
+
+define i32 @F() {
+entry:
+ %0 = load i32, ptr @f, align 4
+ ret i32 %0
+}
+; CHECK-LARGE: addis [[HI:[0-9]+]], L..C[[TL_F:[0-9]+]]@u(2)
+; CHECK-LARGE32: lwz [[SCRATCH:[0-9]+]], L..C[[TL_F]]@l([[HI]])
+; CHECK-SMALL32: lwz [[SCRATCH:[0-9]+]], L..C[[TL_F:[0-9]+]](2)
+; CHECK-LARGE64: ld [[SCRATCH:[0-9]+]], L..C[[TL_F]]@l([[HI]])
+; CHECK-SMALL64: ld [[SCRATCH:[0-9]+]], L..C[[TL_F:[0-9]+]](2)
+; CHECK: lwz 3, 0([[SCRATCH]])
+; CHECK: blr
+
define noundef nonnull ptr @addr_a() local_unnamed_addr {
entry:
ret ptr @a
@@ -94,11 +121,17 @@ entry:
; CHECK: blr
;; Check TOC entires have correct storage mapping class
-; CHECK: L..C[[TL_A]]:
-; CHECK: .tc a[TC],a[UA]
-; CHECK: L..C[[TL_B]]:
-; CHECK: .tc b[TE],b[UA]
-; CHECK: L..C[[TL_C]]:
-; CHECK: .tc c[TC],c[RW]
-; CHECK: L..C[[TL_D]]:
-; CHECK: .tc d[TE],d[RW]
+; CHECK: L..C[[TL_A]]:
+; CHECK: .tc a[TC],a[UA]
+; CHECK: L..C[[TL_B]]:
+; CHECK: .tc b[TE],b[UA]
+; CHECK: L..C[[TL_C]]:
+; CHECK: .tc c[TC],c[RW]
+; CHECK: L..C[[TL_D]]:
+; CHECK: .tc d[TE],d[RW]
+; CHECK: L..C[[TL_E]]:
+; CHECK-SMALL: .tc e[TC],e[UA]
+; CHECK-LARGE: .tc e[TE],e[UA]
+; CHECK: L..C[[TL_F]]:
+; CHECK-SMALL: .tc f[TC],f[RW]
+; CHECK-LARGE: .tc f[TE],f[RW]
>From 9e5eb9a31b7c0d1b92882875ddf0733978aff553 Mon Sep 17 00:00:00 2001
From: Sean Fertile <sd.fertile at gmail.com>
Date: Wed, 28 Feb 2024 13:31:07 -0500
Subject: [PATCH 4/5] Address third reound of review comments.
- Fixed some spelling mistakes in comments.
- renamed function that retreives the per global code model.
- updated the AIX specific code in isGVIndirectSymbol.
---
.../lib/CodeGen/TargetLoweringObjectFileImpl.cpp | 4 ++--
llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 6 +++---
llvm/lib/Target/PowerPC/PPCSubtarget.cpp | 16 ++++++++--------
3 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index 0d30239fd2e866..c4e8db8ad30728 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -2691,8 +2691,8 @@ MCSection *TargetLoweringObjectFileXCOFF::getSectionForTOCEntry(
return XCOFF::XMC_TC;
// Use large code model toc entries for ehinfo symbols as they are
- // never refrenced directly. The runtime loads their TOC entries
- // address from the trace-back table.
+ // never refrenced directly. The runtime loads their TOC entry
+ // addresses from the trace-back table.
if (XSym->isEHInfo())
return XCOFF::XMC_TE;
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 150c9f2bfb893c..27fcba9a19b890 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -478,7 +478,7 @@ static CodeModel::Model getCodeModel(const PPCSubtarget &S,
const TargetMachine &TM,
const MachineOperand &MO) {
CodeModel::Model ModuleModel = TM.getCodeModel();
- // Per global code model is only support on AIX.
+ // Per global code model is only supported on AIX.
if (!S.isAIXABI())
return ModuleModel;
@@ -502,7 +502,7 @@ static CodeModel::Model getCodeModel(const PPCSubtarget &S,
}
static std::optional<CodeModel::Model>
-hasPerGlobalCodeModel(const GlobalValue *GV) {
+getPerGlobalCodeModel(const GlobalValue *GV) {
// Symbols that aren't global variables cannot have the attribute.
if (!isa<GlobalVariable>(GV))
return std::nullopt;
@@ -3021,7 +3021,7 @@ bool PPCAIXAsmPrinter::doInitialization(Module &M) {
setCsectAlignment(&G);
std::optional<CodeModel::Model> OptionalCodeModel =
- hasPerGlobalCodeModel(&G);
+ getPerGlobalCodeModel(&G);
if (OptionalCodeModel)
setOptionalCodeModel(cast<MCSymbolXCOFF>(getSymbol(&G)),
*OptionalCodeModel);
diff --git a/llvm/lib/Target/PowerPC/PPCSubtarget.cpp b/llvm/lib/Target/PowerPC/PPCSubtarget.cpp
index 90175ce1ba3d08..cc8ddb3f2c8dbe 100644
--- a/llvm/lib/Target/PowerPC/PPCSubtarget.cpp
+++ b/llvm/lib/Target/PowerPC/PPCSubtarget.cpp
@@ -186,18 +186,18 @@ bool PPCSubtarget::enableSubRegLiveness() const {
}
bool PPCSubtarget::isGVIndirectSymbol(const GlobalValue *GV) const {
+ if (isAIXABI() && isa<GlobalVariable>(GV)) {
+ // On AIX the only symbols that aren't indirect are toc-data.
+ if (cast<GlobalVariable>(GV)->hasAttribute("toc-data"))
+ return false;
+
+ return true;
+ }
+
// Large code model always uses the TOC even for local symbols.
if (TM.getCodeModel() == CodeModel::Large)
return true;
- // AIX may have a per global code model attribute.
- if (isAIXABI() && isa<GlobalVariable>(GV)) {
- const GlobalVariable *GVar = cast<GlobalVariable>(GV);
- std::optional<CodeModel::Model> OptionalCM = GVar->getCodeModel();
- if (OptionalCM && *OptionalCM == CodeModel::Large)
- return true;
- }
-
if (TM.shouldAssumeDSOLocal(*GV->getParent(), GV))
return false;
return true;
>From bb8722e9d4d9d41d72ce5b324f58d5d1a49692f6 Mon Sep 17 00:00:00 2001
From: Sean Fertile <sd.fertile at gmail.com>
Date: Tue, 5 Mar 2024 09:44:33 -0500
Subject: [PATCH 5/5] Fix formating.
---
llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
index c4e8db8ad30728..05555c6111ca42 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -2682,11 +2682,10 @@ MCSection *TargetLoweringObjectFileXCOFF::getSectionForTOCEntry(
const MCSymbol *Sym, const TargetMachine &TM) const {
const XCOFF::StorageMappingClass SMC = [](const MCSymbol *Sym,
const TargetMachine &TM) {
-
const MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(Sym);
- // The "_$TLSML" symbol for TLS local-dynamic mode requires XMC_TC, otherwise
- // the AIX assembler will complain.
+ // The "_$TLSML" symbol for TLS local-dynamic mode requires XMC_TC,
+ // otherwise the AIX assembler will complain.
if (XSym->getSymbolTableName() == "_$TLSML")
return XCOFF::XMC_TC;
More information about the llvm-commits
mailing list