From bd9621aeb062a889764d7b8a96d2d6d8353ad347 Mon Sep 17 00:00:00 2001 From: Sean Fertile Date: Tue, 23 Jan 2024 12:55:17 -0500 Subject: [PATCH 1/9] [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 11c3b8831ba51..49374494b9ed1 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 StorageClass; + std::optional 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 6943ce261d9d9..0d30239fd2e86 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(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(Sym)->getSymbolTableName(), SectionKind::getData(), - XCOFF::CsectProperties( - ((TM.getCodeModel() == CodeModel::Large && - cast(Sym)->getSymbolTableName() != "_$TLSML") || - cast(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 45f446bd2042f..25b6e9a0fd6a2 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(GV)) + return ModuleModel; + + std::optional MaybeCodeModel = + dyn_cast(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(Sym)) + return; + + // Symbols that aren't global variables cannot have the attribute. + if (!isa(GV)) + return; + + const GlobalVariable *GVar = cast(GV); + std::optional MaybeCM = GVar->getCodeModel(); + + // No overriding atribute. + if (!MaybeCM) + return; + + CodeModel::Model CM = *MaybeCM; + + MCSymbolXCOFF *XSym = cast(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 0c25accd1d6ce..c0d705de5fa3c 100644 --- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp @@ -524,6 +524,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(Operand)) + return ModuleModel; + + GlobalAddressSDNode *GA = cast(Operand); + if (!GA) + return ModuleModel; + + const GlobalValue *GV = GA->getGlobal(); + if (!GV || !isa(GV)) + return ModuleModel; + + std::optional MaybeCodeModel = + dyn_cast(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) { @@ -6059,7 +6096,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 5380ec1c4c0d9..e7e55ea1063b2 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(GV)) { + const GlobalVariable *GVar = cast(GV); + std::optional OptionalCM = GVar->getCodeModel(); + if (OptionalCM && *OptionalCM == CodeModel::Large) + return true; + } + if (TM.shouldAssumeDSOLocal(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 0000000000000..14bc2a378668b --- /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 + +@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 + + +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 f9be21b842d133bb4b7a256f057d3cde276fe003 Mon Sep 17 00:00:00 2001 From: Sean Fertile Date: Wed, 24 Jan 2024 23:52:45 -0500 Subject: [PATCH 2/9] 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 25b6e9a0fd6a2..5c73f86a5fa99 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 MaybeCodeModel = - dyn_cast(GV)->getCodeModel(); + cast(GV)->getCodeModel(); if (MaybeCodeModel) return *MaybeCodeModel; diff --git a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp index c0d705de5fa3c..ce7ffad902b8e 100644 --- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp @@ -541,11 +541,7 @@ static CodeModel::Model getCodeModel(const PPCSubtarget &Subtarget, if (!isa(Operand)) return ModuleModel; - GlobalAddressSDNode *GA = cast(Operand); - if (!GA) - return ModuleModel; - - const GlobalValue *GV = GA->getGlobal(); + const GlobalValue *GV = cast(Operand)->getGlobal(); if (!GV || !isa(GV)) return ModuleModel; From 8207b6a6adcfe98b7a7271f0d2738c75a013fa6f Mon Sep 17 00:00:00 2001 From: Sean Fertile Date: Tue, 20 Feb 2024 13:47:55 -0500 Subject: [PATCH 3/9] 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 5c73f86a5fa99..75da279196bb1 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(Sym)) - return; - +static std::optional +hasPerGlobalCodeModel(const GlobalValue *GV) { // Symbols that aren't global variables cannot have the attribute. if (!isa(GV)) - return; - - const GlobalVariable *GVar = cast(GV); - std::optional MaybeCM = GVar->getCodeModel(); + return std::nullopt; - // No overriding atribute. - if (!MaybeCM) - return; - - CodeModel::Model CM = *MaybeCM; + return cast(GV)->getCodeModel(); +} - MCSymbolXCOFF *XSym = cast(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: @@ -3053,6 +3043,11 @@ bool PPCAIXAsmPrinter::doInitialization(Module &M) { } setCsectAlignment(&G); + std::optional OptionalCodeModel = + hasPerGlobalCodeModel(&G); + if (OptionalCodeModel) + setOptionalCodeModel(cast(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 14bc2a378668b..c3e28a06860cd 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 - +@e = external dso_local global i32, align 4 +@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 eca388db7590f9185ca7cb5aabec8a5c747ca9c2 Mon Sep 17 00:00:00 2001 From: Sean Fertile Date: Wed, 28 Feb 2024 13:31:07 -0500 Subject: [PATCH 4/9] 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 0d30239fd2e86..c4e8db8ad3072 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 75da279196bb1..59c68422a4599 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 -hasPerGlobalCodeModel(const GlobalValue *GV) { +getPerGlobalCodeModel(const GlobalValue *GV) { // Symbols that aren't global variables cannot have the attribute. if (!isa(GV)) return std::nullopt; @@ -3044,7 +3044,7 @@ bool PPCAIXAsmPrinter::doInitialization(Module &M) { setCsectAlignment(&G); std::optional OptionalCodeModel = - hasPerGlobalCodeModel(&G); + getPerGlobalCodeModel(&G); if (OptionalCodeModel) setOptionalCodeModel(cast(getSymbol(&G)), *OptionalCodeModel); diff --git a/llvm/lib/Target/PowerPC/PPCSubtarget.cpp b/llvm/lib/Target/PowerPC/PPCSubtarget.cpp index e7e55ea1063b2..13cfa0b75705c 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(GV)) { + // On AIX the only symbols that aren't indirect are toc-data. + if (cast(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(GV)) { - const GlobalVariable *GVar = cast(GV); - std::optional OptionalCM = GVar->getCodeModel(); - if (OptionalCM && *OptionalCM == CodeModel::Large) - return true; - } - if (TM.shouldAssumeDSOLocal(GV)) return false; return true; From 8e712ecaf5dd1f70ed7ab8528b5387146ab5fa26 Mon Sep 17 00:00:00 2001 From: Sean Fertile Date: Tue, 5 Mar 2024 09:44:33 -0500 Subject: [PATCH 5/9] 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 c4e8db8ad3072..05555c6111ca4 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(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; From eb09fd50b8cbb4aad2193d99a04a3ac89ef9092d Mon Sep 17 00:00:00 2001 From: Sean Fertile <35576261+mandlebug@users.noreply.github.com> Date: Thu, 7 Mar 2024 10:46:53 -0500 Subject: [PATCH 6/9] Update llvm/include/llvm/MC/MCSymbolXCOFF.h Co-authored-by: Amy Kwan --- llvm/include/llvm/MC/MCSymbolXCOFF.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/include/llvm/MC/MCSymbolXCOFF.h b/llvm/include/llvm/MC/MCSymbolXCOFF.h index 49374494b9ed1..3bf4491e8fe2f 100644 --- a/llvm/include/llvm/MC/MCSymbolXCOFF.h +++ b/llvm/include/llvm/MC/MCSymbolXCOFF.h @@ -78,7 +78,7 @@ class MCSymbolXCOFF : public MCSymbol { CodeModel getPerSymbolCodeModel() const { assert(hasPerSymbolCodeModel() && - "Requested codemodel for symbol with out one"); + "Requested code model for symbol without one"); return *PerSymbolCodeModel; } From 980ae19cdaecfbc8110c81ebce074d883e03acc5 Mon Sep 17 00:00:00 2001 From: Sean Fertile <35576261+mandlebug@users.noreply.github.com> Date: Thu, 7 Mar 2024 10:47:14 -0500 Subject: [PATCH 7/9] Update llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp Co-authored-by: Amy Kwan --- llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index 05555c6111ca4..15b59421a0f44 100644 --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -2690,7 +2690,7 @@ 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 entry + // never referenced directly. The runtime loads their TOC entry // addresses from the trace-back table. if (XSym->isEHInfo()) return XCOFF::XMC_TE; From 39c7802dac84a62d92e6de64b47a58f240383c8b Mon Sep 17 00:00:00 2001 From: Sean Fertile Date: Thu, 7 Mar 2024 11:05:24 -0500 Subject: [PATCH 8/9] Minor format/style changes to PPCSubtarget::isGVIndirectSymbol - use dyn_cast instad of isa + cast - remove erroneously added newline in otherwise untouched code. --- llvm/lib/Target/PowerPC/PPCSubtarget.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Target/PowerPC/PPCSubtarget.cpp b/llvm/lib/Target/PowerPC/PPCSubtarget.cpp index 13cfa0b75705c..9f50edf76df96 100644 --- a/llvm/lib/Target/PowerPC/PPCSubtarget.cpp +++ b/llvm/lib/Target/PowerPC/PPCSubtarget.cpp @@ -186,10 +186,10 @@ bool PPCSubtarget::enableSubRegLiveness() const { } bool PPCSubtarget::isGVIndirectSymbol(const GlobalValue *GV) const { - if (isAIXABI() && isa(GV)) { - // On AIX the only symbols that aren't indirect are toc-data. - if (cast(GV)->hasAttribute("toc-data")) - return false; + if (isAIXABI()) { + if (const GlobalVariable *GVar = dyn_cast(GV)) + // On AIX the only symbols that aren't indirect are toc-data. + return !GVar->hasAttribute("toc-data"); return true; } From a77ce54838c05c3fdf387a0a0fb18aedc960b562 Mon Sep 17 00:00:00 2001 From: Sean Fertile Date: Mon, 11 Mar 2024 17:20:56 -0400 Subject: [PATCH 9/9] Address comments round five. - Added support for looking through aliases to the aliasees objects code model, along with lit testing. - Split the shared code of 'getCodeModel' into PPCSubtarget and have PPCISelDAGToDAG and PPCAsmPrinter use that. - Undo unintended change to 'getMCSymbolForTOCPsudoMO' that was left when addressing earlier comments. --- llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 41 ++++++------------- llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp | 25 +++-------- llvm/lib/Target/PowerPC/PPCSubtarget.cpp | 40 ++++++++++++++++++ llvm/lib/Target/PowerPC/PPCSubtarget.h | 4 ++ .../CodeGen/PowerPC/aix-codemodel-attr.ll | 29 +++++++++++++ 5 files changed, 91 insertions(+), 48 deletions(-) diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp index 59c68422a4599..64cae1caa6437 100644 --- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -478,9 +478,6 @@ static CodeModel::Model getCodeModel(const PPCSubtarget &S, const TargetMachine &TM, const MachineOperand &MO) { CodeModel::Model ModuleModel = TM.getCodeModel(); - // Per global code model is only supported 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. @@ -490,24 +487,7 @@ static CodeModel::Model getCodeModel(const PPCSubtarget &S, const GlobalValue *GV = MO.getGlobal(); assert(GV && "expected global for MO_GlobalAddress"); - if (!isa(GV)) - return ModuleModel; - - std::optional MaybeCodeModel = - cast(GV)->getCodeModel(); - if (MaybeCodeModel) - return *MaybeCodeModel; - - return ModuleModel; -} - -static std::optional -getPerGlobalCodeModel(const GlobalValue *GV) { - // Symbols that aren't global variables cannot have the attribute. - if (!isa(GV)) - return std::nullopt; - - return cast(GV)->getCodeModel(); + return S.getCodeModel(TM, GV); } static void setOptionalCodeModel(MCSymbolXCOFF *XSym, CodeModel::Model CM) { @@ -772,11 +752,8 @@ void PPCAsmPrinter::EmitTlsCall(const MachineInstr *MI, static MCSymbol *getMCSymbolForTOCPseudoMO(const MachineOperand &MO, AsmPrinter &AP) { switch (MO.getType()) { - case MachineOperand::MO_GlobalAddress: { - const GlobalValue *GV = MO.getGlobal(); - MCSymbol *Sym = AP.getSymbol(GV); - return Sym; - } + case MachineOperand::MO_GlobalAddress: + return AP.getSymbol(MO.getGlobal()); case MachineOperand::MO_ConstantPoolIndex: return AP.GetCPISymbol(MO.getIndex()); case MachineOperand::MO_JumpTableIndex: @@ -3043,8 +3020,7 @@ bool PPCAIXAsmPrinter::doInitialization(Module &M) { } setCsectAlignment(&G); - std::optional OptionalCodeModel = - getPerGlobalCodeModel(&G); + std::optional OptionalCodeModel = G.getCodeModel(); if (OptionalCodeModel) setOptionalCodeModel(cast(getSymbol(&G)), *OptionalCodeModel); @@ -3069,6 +3045,15 @@ bool PPCAIXAsmPrinter::doInitialization(Module &M) { false); } + const GlobalVariable *GVar = + dyn_cast_or_null(Alias.getAliaseeObject()); + if (GVar) { + std::optional OptionalCodeModel = GVar->getCodeModel(); + if (OptionalCodeModel) + setOptionalCodeModel(cast(getSymbol(&Alias)), + *OptionalCodeModel); + } + GOAliasMap[Aliasee].push_back(&Alias); } diff --git a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp index ce7ffad902b8e..dfea9e7709240 100644 --- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp @@ -531,30 +531,15 @@ static CodeModel::Model getCodeModel(const PPCSubtarget &Subtarget, // 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(Operand)) + GlobalAddressSDNode *GA = dyn_cast(Node->getOperand(0)); + if (!GA) return ModuleModel; - const GlobalValue *GV = cast(Operand)->getGlobal(); - if (!GV || !isa(GV)) + const GlobalValue *GV = GA->getGlobal(); + if (!GV) return ModuleModel; - std::optional MaybeCodeModel = - dyn_cast(GV)->getCodeModel(); - if (MaybeCodeModel) { - CodeModel::Model CM = *MaybeCodeModel; - assert((CM == CodeModel::Small || CM == CodeModel::Large) && - "invalid code model for AIX"); - return CM; - } - - return ModuleModel; + return Subtarget.getCodeModel(TM, GV); } /// isInt32Immediate - This method tests to see if the node is a 32-bit constant diff --git a/llvm/lib/Target/PowerPC/PPCSubtarget.cpp b/llvm/lib/Target/PowerPC/PPCSubtarget.cpp index 9f50edf76df96..653d9bda99192 100644 --- a/llvm/lib/Target/PowerPC/PPCSubtarget.cpp +++ b/llvm/lib/Target/PowerPC/PPCSubtarget.cpp @@ -203,6 +203,46 @@ bool PPCSubtarget::isGVIndirectSymbol(const GlobalValue *GV) const { return true; } +CodeModel::Model PPCSubtarget::getCodeModel(const TargetMachine &TM, + const GlobalValue *GV) const { + // 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 (!isAIXABI()) + return ModuleModel; + + // Only GlobalVariables carry an attribute which can override the module code + // model. + assert(GV && "Unexpected NULL GlobalValue"); + const GlobalVariable *GlobalVar = + [](const GlobalValue *GV) -> const GlobalVariable * { + const GlobalVariable *Var = dyn_cast(GV); + if (Var) + return Var; + + const GlobalAlias *Alias = dyn_cast(GV); + if (Alias) + return dyn_cast(Alias->getAliaseeObject()); + + return nullptr; + }(GV); + + if (!GlobalVar) + return ModuleModel; + + std::optional MaybeCodeModel = GlobalVar->getCodeModel(); + if (MaybeCodeModel) { + CodeModel::Model CM = *MaybeCodeModel; + assert((CM == CodeModel::Small || CM == CodeModel::Large) && + "invalid code model for AIX"); + return CM; + } + + return ModuleModel; +} + bool PPCSubtarget::isELFv2ABI() const { return TM.isELFv2ABI(); } bool PPCSubtarget::isPPC64() const { return TM.isPPC64(); } diff --git a/llvm/lib/Target/PowerPC/PPCSubtarget.h b/llvm/lib/Target/PowerPC/PPCSubtarget.h index 306a52dca8362..bf35f8ec151b1 100644 --- a/llvm/lib/Target/PowerPC/PPCSubtarget.h +++ b/llvm/lib/Target/PowerPC/PPCSubtarget.h @@ -245,6 +245,10 @@ class PPCSubtarget : public PPCGenSubtargetInfo { /// True if the GV will be accessed via an indirect symbol. bool isGVIndirectSymbol(const GlobalValue *GV) const; + /// Calculates the effective code model for argument GV. + CodeModel::Model getCodeModel(const TargetMachine &TM, + const GlobalValue *GV) const; + /// True if the ABI is descriptor based. bool usesFunctionDescriptors() const { // Both 32-bit and 64-bit AIX are descriptor based. For ELF only the 64-bit diff --git a/llvm/test/CodeGen/PowerPC/aix-codemodel-attr.ll b/llvm/test/CodeGen/PowerPC/aix-codemodel-attr.ll index c3e28a06860cd..ef1156e338a89 100644 --- a/llvm/test/CodeGen/PowerPC/aix-codemodel-attr.ll +++ b/llvm/test/CodeGen/PowerPC/aix-codemodel-attr.ll @@ -17,6 +17,14 @@ @e = external dso_local global i32, align 4 @f = dso_local global i32 2748, align 4 +@large_aliasee = global i32 10, code_model "large", align 4 +@small_aliasee = global i32 171, code_model "small", align 4 +@normal_aliasee = global i32 2748, align 4 + +@al = alias i32, ptr @large_aliasee +@as = alias i32, ptr @small_aliasee +@an = alias i32, ptr @normal_aliasee + define i32 @A() local_unnamed_addr { entry: %0 = load i32, ptr @a, align 4 @@ -120,6 +128,23 @@ entry: ; CHECK64: ld 3, L..C[[TL_D]]@l([[HI]]) ; CHECK: blr +define i32 @G() { + %tmp = load i32, ptr @al + ret i32 %tmp +} +; CHECK: addis [[HI:[0-9]+]], L..C[[TL_AL:[0-9]+]]@u(2) +; CHECK32: lwz [[ADDR:[0-9]+]], L..C[[TL_AL]]@l([[HI]]) +; CHECK64: ld [[ADDR:[0-9]+]], L..C[[TL_AL]]@l([[HI]]) +; CHECK: lwz 3, 0([[ADDR]]) + +define i32 @H() { + %tmp = load i32, ptr @as + ret i32 %tmp +} +; CHECK32: lwz [[ADDR:[0-9]+]], L..C[[TL_AS:[0-9]+]](2) +; CHECK64: ld [[ADDR:[0-9]+]], L..C[[TL_AS:[0-9]+]](2) +; CHECK: lwz 3, 0([[ADDR]]) + ;; Check TOC entires have correct storage mapping class ; CHECK: L..C[[TL_A]]: ; CHECK: .tc a[TC],a[UA] @@ -135,3 +160,7 @@ entry: ; CHECK: L..C[[TL_F]]: ; CHECK-SMALL: .tc f[TC],f[RW] ; CHECK-LARGE: .tc f[TE],f[RW] +; CHECK: L..C[[TL_AL]]: +; CHECK: .tc al[TE],al +; CHECK: L..C[[TL_AS]]: +; CHECK: .tc as[TC],as