[llvm] [AIX] Support per global code model. (PR #79202)

Sean Fertile via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 20 11:06:00 PST 2024


https://github.com/mandlebug updated https://github.com/llvm/llvm-project/pull/79202

>From 38b4d54d88e5d4a9c706bdfcbbfd9607f5e7d295 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/3] [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  |  29 +++--
 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, 272 insertions(+), 26 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 a69b71451736fa..218f4b4f074482 100644
--- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
@@ -2653,17 +2653,28 @@ 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.
+  const XCOFF::StorageMappingClass SMC = [](const MCSymbol *Sym,
+                                            const TargetMachine &TM) {
+    const MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(Sym);
+    // 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)->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 780b22b4fbe65e..1c18c6b2d34673 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -466,6 +466,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.
@@ -702,8 +759,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:
@@ -985,7 +1046,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);
@@ -1069,7 +1130,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.");
 
@@ -1079,10 +1145,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);
 
@@ -1102,7 +1164,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.");
 
@@ -1112,10 +1179,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);
 
@@ -1154,8 +1217,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;
@@ -1196,8 +1263,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 26ed74108ec36c..a0b60c51d5c7f9 100644
--- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
@@ -561,6 +561,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) {
@@ -6085,7 +6122,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 c9740818c9bfd6..8481bf35af0890 100644
--- a/llvm/lib/Target/PowerPC/PPCSubtarget.cpp
+++ b/llvm/lib/Target/PowerPC/PPCSubtarget.cpp
@@ -176,6 +176,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 adaf5616560e07a51bcf7385127f432e8ec204e5 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/3] 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 1c18c6b2d34673..09f3098e24c111 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -469,9 +469,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.
@@ -485,7 +486,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 a0b60c51d5c7f9..dbe3c246ffffb6 100644
--- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
@@ -578,11 +578,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 90272c53ff2b956c26745c0764ac4a3abb832757 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/3] 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 09f3098e24c111..e88787137fbadc 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -493,25 +493,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);
@@ -520,7 +511,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");
   }
 }
 
@@ -763,7 +754,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:
@@ -2854,6 +2844,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]



More information about the llvm-commits mailing list