Index: llvm/include/llvm/BinaryFormat/XCOFF.h =================================================================== --- llvm/include/llvm/BinaryFormat/XCOFF.h +++ llvm/include/llvm/BinaryFormat/XCOFF.h @@ -13,6 +13,7 @@ #ifndef LLVM_BINARYFORMAT_XCOFF_H #define LLVM_BINARYFORMAT_XCOFF_H +#include "llvm/ADT/StringRef.h" #include namespace llvm { @@ -251,6 +252,8 @@ TCPU_970 = 19 ///< PPC970 - PowerPC 64-bit architecture. }; +StringRef getMappingClassString(XCOFF::StorageMappingClass SMC); + } // end namespace XCOFF } // end namespace llvm Index: llvm/include/llvm/MC/MCAsmInfo.h =================================================================== --- llvm/include/llvm/MC/MCAsmInfo.h +++ llvm/include/llvm/MC/MCAsmInfo.h @@ -454,6 +454,9 @@ unsigned Encoding, MCStreamer &Streamer) const; + /// Return true if C is an acceptable character inside a symbol name. + virtual bool isAcceptableChar(char C) const; + /// Return true if the identifier \p Name does not need quotes to be /// syntactically correct. virtual bool isValidUnquotedName(StringRef Name) const; Index: llvm/include/llvm/MC/MCAsmInfoXCOFF.h =================================================================== --- llvm/include/llvm/MC/MCAsmInfoXCOFF.h +++ llvm/include/llvm/MC/MCAsmInfoXCOFF.h @@ -20,9 +20,9 @@ MCAsmInfoXCOFF(); public: - // Return true only when the identifier Name does not need quotes to be - // syntactically correct for XCOFF. - bool isValidUnquotedName(StringRef Name) const override; + // Return true only when C is an acceptable character inside a + // MCSymbolXCOFF. + bool isAcceptableChar(char C) const override; }; } // end namespace llvm Index: llvm/include/llvm/MC/MCSectionXCOFF.h =================================================================== --- llvm/include/llvm/MC/MCSectionXCOFF.h +++ llvm/include/llvm/MC/MCSectionXCOFF.h @@ -16,11 +16,10 @@ #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/XCOFF.h" #include "llvm/MC/MCSection.h" +#include "llvm/MC/MCSymbolXCOFF.h" namespace llvm { -class MCSymbol; - // This class represents an XCOFF `Control Section`, more commonly referred to // as a csect. A csect represents the smallest possible unit of data/code which // will be relocated as a single block. A csect can either be: @@ -38,14 +37,18 @@ XCOFF::StorageMappingClass MappingClass; XCOFF::SymbolType Type; XCOFF::StorageClass StorageClass; + MCSymbolXCOFF *const QualName; MCSectionXCOFF(StringRef Section, XCOFF::StorageMappingClass SMC, XCOFF::SymbolType ST, XCOFF::StorageClass SC, SectionKind K, - MCSymbol *Begin) + MCSymbolXCOFF *QualName, MCSymbol *Begin) : MCSection(SV_XCOFF, K, Begin), Name(Section), MappingClass(SMC), - Type(ST), StorageClass(SC) { + Type(ST), StorageClass(SC), QualName(QualName) { assert((ST == XCOFF::XTY_SD || ST == XCOFF::XTY_CM) && "Invalid or unhandled type for csect."); + assert(QualName != nullptr && "QualName is needed."); + QualName->setStorageClass(SC); + QualName->setContainingCsect(this); } public: @@ -59,6 +62,7 @@ XCOFF::StorageMappingClass getMappingClass() const { return MappingClass; } XCOFF::StorageClass getStorageClass() const { return StorageClass; } XCOFF::SymbolType getCSectType() const { return Type; } + MCSymbolXCOFF *getQualNameSymbol() const { return QualName; } void PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T, raw_ostream &OS, Index: llvm/include/llvm/MC/MCStreamer.h =================================================================== --- llvm/include/llvm/MC/MCStreamer.h +++ llvm/include/llvm/MC/MCStreamer.h @@ -546,11 +546,13 @@ /// Emits an lcomm directive with XCOFF csect information. /// - /// \param Symbol - The symbol we are emiting. + /// \param LabelSym - Label on the block of storage. /// \param Size - The size of the block of storage. - /// \param ByteAlignment - The alignment of the symbol in bytes. Must be a power - /// of 2. - virtual void EmitXCOFFLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + /// \param CsectSym - Csect name for the block of storage. + /// \param ByteAlignment - The alignment of the symbol in bytes. Must be a + /// power of 2. + virtual void EmitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, uint64_t Size, + MCSymbol *CsectSym, unsigned ByteAlignment); /// Emit an ELF .size directive. Index: llvm/include/llvm/MC/MCXCOFFStreamer.h =================================================================== --- llvm/include/llvm/MC/MCXCOFFStreamer.h +++ llvm/include/llvm/MC/MCXCOFFStreamer.h @@ -26,7 +26,8 @@ uint64_t Size = 0, unsigned ByteAlignment = 0, SMLoc Loc = SMLoc()) override; void EmitInstToData(const MCInst &Inst, const MCSubtargetInfo &) override; - void EmitXCOFFLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + void EmitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, uint64_t Size, + MCSymbol *CsectSym, unsigned ByteAlign) override; }; Index: llvm/lib/BinaryFormat/CMakeLists.txt =================================================================== --- llvm/lib/BinaryFormat/CMakeLists.txt +++ llvm/lib/BinaryFormat/CMakeLists.txt @@ -8,6 +8,7 @@ MsgPackReader.cpp MsgPackWriter.cpp Wasm.cpp + XCOFF.cpp ADDITIONAL_HEADER_DIRS ${LLVM_MAIN_INCLUDE_DIR}/llvm/BinaryFormat Index: llvm/lib/BinaryFormat/XCOFF.cpp =================================================================== --- /dev/null +++ llvm/lib/BinaryFormat/XCOFF.cpp @@ -0,0 +1,28 @@ +//===-- llvm/BinaryFormat/XCOFF.cpp - The XCOFF file format -----*- C++/-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/BinaryFormat/XCOFF.h" + +using namespace llvm; + +StringRef XCOFF::getMappingClassString(XCOFF::StorageMappingClass SMC) { + switch (SMC) { + case XCOFF::XMC_DS: + return "DS"; + case XCOFF::XMC_RW: + return "RW"; + case XCOFF::XMC_PR: + return "PR"; + case XCOFF::XMC_TC0: + return "TC0"; + case XCOFF::XMC_BS: + return "BS"; + default: + report_fatal_error("Unhandled storage-mapping class."); + } +} Index: llvm/lib/MC/MCAsmInfo.cpp =================================================================== --- llvm/lib/MC/MCAsmInfo.cpp +++ llvm/lib/MC/MCAsmInfo.cpp @@ -100,7 +100,7 @@ return MCBinaryExpr::createSub(Res, PC, Context); } -static bool isAcceptableChar(char C) { +bool MCAsmInfo::isAcceptableChar(char C) const { return (C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z') || (C >= '0' && C <= '9') || C == '_' || C == '$' || C == '.' || C == '@'; } Index: llvm/lib/MC/MCAsmInfoXCOFF.cpp =================================================================== --- llvm/lib/MC/MCAsmInfoXCOFF.cpp +++ llvm/lib/MC/MCAsmInfoXCOFF.cpp @@ -26,10 +26,11 @@ SupportsQuotedNames = false; } -bool MCAsmInfoXCOFF::isValidUnquotedName(StringRef Name) const { - // FIXME: Remove this function when we stop using "TOC[TC0]" as a symbol name. - if (Name.equals("TOC[TC0]")) +bool MCAsmInfoXCOFF::isAcceptableChar(char C) const { + // QualName is allowed for a MCSymbolXCOFF, and + // QualName contains '[' and ']'. + if (C == '[' || C == ']') return true; - return MCAsmInfo::isValidUnquotedName(Name); + return MCAsmInfo::isAcceptableChar(C); } Index: llvm/lib/MC/MCAsmStreamer.cpp =================================================================== --- llvm/lib/MC/MCAsmStreamer.cpp +++ llvm/lib/MC/MCAsmStreamer.cpp @@ -164,7 +164,8 @@ void EmitCOFFSectionIndex(MCSymbol const *Symbol) override; void EmitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) override; void EmitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) override; - void EmitXCOFFLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + void EmitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, uint64_t Size, + MCSymbol *CsectSym, unsigned ByteAlign) override; void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override; void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, @@ -765,16 +766,18 @@ // We need an XCOFF-specific version of this directive as the AIX syntax // requires a QualName argument identifying the csect name and storage mapping // class to appear before the alignment if we are specifying it. -void MCAsmStreamer::EmitXCOFFLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, +void MCAsmStreamer::EmitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, + uint64_t Size, + MCSymbol *CsectSym, unsigned ByteAlignment) { assert(MAI->getLCOMMDirectiveAlignmentType() == LCOMM::Log2Alignment && "We only support writing log base-2 alignment format with XCOFF."); assert(isPowerOf2_32(ByteAlignment) && "Alignment must be a power of 2."); OS << "\t.lcomm\t"; - Symbol->print(OS, MAI); - OS << ',' << Size; - OS << ',' << Symbol->getName(); + LabelSym->print(OS, MAI); + OS << ',' << Size << ','; + CsectSym->print(OS, MAI); OS << ',' << Log2_32(ByteAlignment); EmitEOL(); Index: llvm/lib/MC/MCContext.cpp =================================================================== --- llvm/lib/MC/MCContext.cpp +++ llvm/lib/MC/MCContext.cpp @@ -15,6 +15,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/COFF.h" #include "llvm/BinaryFormat/ELF.h" +#include "llvm/BinaryFormat/XCOFF.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCCodeView.h" #include "llvm/MC/MCDwarf.h" @@ -550,13 +551,15 @@ // Otherwise, return a new section. StringRef CachedName = Entry.first.SectionName; + MCSymbol *QualName = getOrCreateSymbol( + CachedName + "[" + XCOFF::getMappingClassString(SMC) + "]"); MCSymbol *Begin = nullptr; if (BeginSymName) Begin = createTempSymbol(BeginSymName, false); - MCSectionXCOFF *Result = new (XCOFFAllocator.Allocate()) - MCSectionXCOFF(CachedName, SMC, Type, SC, Kind, Begin); + MCSectionXCOFF *Result = new (XCOFFAllocator.Allocate()) MCSectionXCOFF( + CachedName, SMC, Type, SC, Kind, cast(QualName), Begin); Entry.second = Result; auto *F = new MCDataFragment(); Index: llvm/lib/MC/MCSectionXCOFF.cpp =================================================================== --- llvm/lib/MC/MCSectionXCOFF.cpp +++ llvm/lib/MC/MCSectionXCOFF.cpp @@ -15,18 +15,6 @@ MCSectionXCOFF::~MCSectionXCOFF() = default; -static StringRef getMappingClassString(XCOFF::StorageMappingClass SMC) { - switch (SMC) { - case XCOFF::XMC_DS: - return "DS"; - case XCOFF::XMC_RW: - return "RW"; - case XCOFF::XMC_PR: - return "PR"; - default: - report_fatal_error("Unhandled storage-mapping class."); - } -} void MCSectionXCOFF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T, raw_ostream &OS, @@ -35,9 +23,7 @@ if (getMappingClass() != XCOFF::XMC_PR) report_fatal_error("Unhandled storage-mapping class for .text csect"); - OS << "\t.csect " << getSectionName() << "[" - << getMappingClassString(getMappingClass()) - << "]" << '\n'; + OS << "\t.csect " << QualName->getName() << '\n'; return; } @@ -45,8 +31,7 @@ switch (getMappingClass()) { case XCOFF::XMC_RW: case XCOFF::XMC_DS: - OS << "\t.csect " << getSectionName() << "[" - << getMappingClassString(getMappingClass()) << "]" << '\n'; + OS << "\t.csect " << QualName->getName() << '\n'; break; case XCOFF::XMC_TC0: OS << "\t.toc\n"; Index: llvm/lib/MC/MCStreamer.cpp =================================================================== --- llvm/lib/MC/MCStreamer.cpp +++ llvm/lib/MC/MCStreamer.cpp @@ -1063,7 +1063,8 @@ void MCStreamer::EmitCOFFSymbolType(int Type) { llvm_unreachable("this directive only supported on COFF targets"); } -void MCStreamer::EmitXCOFFLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, +void MCStreamer::EmitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, uint64_t Size, + MCSymbol *CsectSym, unsigned ByteAlign) { llvm_unreachable("this directive only supported on XCOFF targets"); } Index: llvm/lib/MC/MCXCOFFStreamer.cpp =================================================================== --- llvm/lib/MC/MCXCOFFStreamer.cpp +++ llvm/lib/MC/MCXCOFFStreamer.cpp @@ -94,8 +94,9 @@ return S; } -void MCXCOFFStreamer::EmitXCOFFLocalCommonSymbol(MCSymbol *Symbol, +void MCXCOFFStreamer::EmitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, uint64_t Size, + MCSymbol *CsectSym, unsigned ByteAlignment) { - EmitCommonSymbol(Symbol, Size, ByteAlignment); + EmitCommonSymbol(CsectSym, Size, ByteAlignment); } Index: llvm/lib/MC/XCOFFObjectWriter.cpp =================================================================== --- llvm/lib/MC/XCOFFObjectWriter.cpp +++ llvm/lib/MC/XCOFFObjectWriter.cpp @@ -78,15 +78,7 @@ // (approximately) the same storage mapping class. For example all the csects // with a storage mapping class of `xmc_pr` will get placed into the same // container. -struct CsectGroup { - enum LabelDefinitionSupport : bool { - LabelDefSupported = true, - LabelDefUnsupported = false - }; - - const LabelDefinitionSupport SupportLabelDef; - std::deque Csects; -}; +using CsectGroup = std::deque; using CsectGroups = std::deque; @@ -132,7 +124,7 @@ Index = UninitializedIndex; // Clear any csects we have stored. for (auto *Group : Groups) - Group->Csects.clear(); + Group->clear(); } Section(const char *N, XCOFF::SectionTypeFlags Flags, bool IsVirtual, @@ -157,9 +149,9 @@ // CsectGroups. These store the csects which make up different parts of // the sections. Should have one for each set of csects that get mapped into // the same section and get handled in a 'similar' way. - CsectGroup ProgramCodeCsects{CsectGroup::LabelDefSupported, {}}; - CsectGroup DataCsects{CsectGroup::LabelDefSupported, {}}; - CsectGroup BSSCsects{CsectGroup::LabelDefUnsupported, {}}; + CsectGroup ProgramCodeCsects; + CsectGroup DataCsects; + CsectGroup BSSCsects; // The Predefined sections. Section Text; @@ -294,8 +286,8 @@ continue; CsectGroup &Group = getCsectGroup(MCSec); - Group.Csects.emplace_back(MCSec); - WrapperMap[MCSec] = &Group.Csects.back(); + Group.emplace_back(MCSec); + WrapperMap[MCSec] = &Group.back(); } for (const MCSymbol &S : Asm.symbols()) { @@ -309,6 +301,11 @@ assert(WrapperMap.find(ContainingCsect) != WrapperMap.end() && "Expected containing csect to exist in map"); + // If the symbol is the Csect itself, we don't need to put the symbol + // into Csect's Syms. + if (XSym == ContainingCsect->getQualNameSymbol()) + continue; + // Lookup the containing csect and add the symbol to it. WrapperMap[ContainingCsect]->Syms.emplace_back(XSym); @@ -339,7 +336,7 @@ assert(CurrentAddressLocation == Section->Address && "We should have no padding between sections."); for (const auto *Group : Section->Groups) { - for (const auto &Csect : Group->Csects) { + for (const auto &Csect : *Group) { if (uint32_t PaddingSize = Csect.Address - CurrentAddressLocation) W.OS.write_zeros(PaddingSize); Asm.writeSectionData(W.OS, Csect.MCCsect, Layout); @@ -527,20 +524,14 @@ continue; for (const auto *Group : Section->Groups) { - if (Group->Csects.empty()) + if (Group->empty()) continue; - const bool SupportLabelDef = Group->SupportLabelDef; const int16_t SectionIndex = Section->Index; - for (const auto &Csect : Group->Csects) { + for (const auto &Csect : *Group) { // Write out the control section first and then each symbol in it. writeSymbolTableEntryForControlSection( Csect, SectionIndex, Csect.MCCsect->getStorageClass()); - if (!SupportLabelDef) { - assert(Csect.Syms.size() == 1 && "Csect should only contain 1 symbol " - "which is its label definition."); - continue; - } for (const auto Sym : Csect.Syms) writeSymbolTableEntryForCsectMemberLabel( @@ -563,9 +554,8 @@ for (auto *Section : Sections) { const bool IsEmpty = - llvm::all_of(Section->Groups, [](const CsectGroup *Group) { - return Group->Csects.empty(); - }); + llvm::all_of(Section->Groups, + [](const CsectGroup *Group) { return Group->empty(); }); if (IsEmpty) continue; @@ -576,11 +566,10 @@ bool SectionAddressSet = false; for (auto *Group : Section->Groups) { - if (Group->Csects.empty()) + if (Group->empty()) continue; - const bool SupportLabelDef = Group->SupportLabelDef; - for (auto &Csect : Group->Csects) { + for (auto &Csect : *Group) { const MCSectionXCOFF *MCSec = Csect.MCCsect; Csect.Address = alignTo(Address, MCSec->getAlignment()); Csect.Size = Layout.getSectionAddressSize(MCSec); @@ -588,10 +577,7 @@ Csect.SymbolTableIndex = SymbolTableIndex; // 1 main and 1 auxiliary symbol table entry for the csect. SymbolTableIndex += 2; - - if (!SupportLabelDef) - continue; - + for (auto &Sym : Csect.Syms) { Sym.SymbolTableIndex = SymbolTableIndex; // 1 main and 1 auxiliary symbol table entry for each contained @@ -601,7 +587,7 @@ } if (!SectionAddressSet) { - Section->Address = Group->Csects.front().Address; + Section->Address = Group->front().Address; SectionAddressSet = true; } } Index: llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp =================================================================== --- llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -1752,15 +1752,15 @@ "not supported yet."); // Create the containing csect and switch to it. - MCSectionXCOFF *CSect = cast( + MCSectionXCOFF *Csect = cast( getObjFileLowering().SectionForGlobal(GV, GVKind, TM)); - OutStreamer->SwitchSection(CSect); + OutStreamer->SwitchSection(Csect); // Create the symbol, set its storage class, and emit it. MCSymbolXCOFF *GVSym = cast(getSymbol(GV)); GVSym->setStorageClass( TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(GV)); - GVSym->setContainingCsect(CSect); + GVSym->setContainingCsect(Csect); const DataLayout &DL = GV->getParent()->getDataLayout(); @@ -1771,9 +1771,10 @@ uint64_t Size = DL.getTypeAllocSize(GV->getType()->getElementType()); if (GVKind.isBSSLocal()) - OutStreamer->EmitXCOFFLocalCommonSymbol(GVSym, Size, Align); + OutStreamer->EmitXCOFFLocalCommonSymbol( + GVSym, Size, Csect->getQualNameSymbol(), Align); else - OutStreamer->EmitCommonSymbol(GVSym, Size, Align); + OutStreamer->EmitCommonSymbol(Csect->getQualNameSymbol(), Size, Align); return; } @@ -1813,11 +1814,9 @@ return; // Emit TOC base. - MCSymbol *TOCBaseSym = OutContext.getOrCreateSymbol(StringRef("TOC[TC0]")); MCSectionXCOFF *TOCBaseSection = OutStreamer->getContext().getXCOFFSection( StringRef("TOC"), XCOFF::XMC_TC0, XCOFF::XTY_SD, XCOFF::C_HIDEXT, SectionKind::getData()); - cast(TOCBaseSym)->setContainingCsect(TOCBaseSection); // Switch to section to emit TOC base. OutStreamer->SwitchSection(TOCBaseSection); } Index: llvm/test/CodeGen/PowerPC/aix-xcoff-data.ll =================================================================== --- llvm/test/CodeGen/PowerPC/aix-xcoff-data.ll +++ llvm/test/CodeGen/PowerPC/aix-xcoff-data.ll @@ -84,13 +84,13 @@ ; CHECK-NEXT: .llong 4613937818241073152 ; CHECK-NEXT: .llong 4616189618054758400 -; CHECK-NEXT: .comm a,4,2 -; CHECK-NEXT: .comm b,8,3 -; CHECK-NEXT: .comm c,2,1 -; CHECK-NEXT: .comm d,8,3 -; CHECK-NEXT: .comm f,4,2 -; CHECK-NEXT: .comm over_aligned_comm,8,5 -; CHECK-NEXT: .comm array,33,0 +; CHECK-NEXT: .comm a[RW],4,2 +; CHECK-NEXT: .comm b[RW],8,3 +; CHECK-NEXT: .comm c[RW],2,1 +; CHECK-NEXT: .comm d[RW],8,3 +; CHECK-NEXT: .comm f[RW],4,2 +; CHECK-NEXT: .comm over_aligned_comm[RW],8,5 +; CHECK-NEXT: .comm array[RW],33,0 ; OBJ: File: {{.*}}aix-xcoff-data.ll.tmp.o ; OBJ-NEXT: Format: aixcoff-rs6000 Index: llvm/test/CodeGen/PowerPC/aix-xcoff-lcomm.ll =================================================================== --- llvm/test/CodeGen/PowerPC/aix-xcoff-lcomm.ll +++ llvm/test/CodeGen/PowerPC/aix-xcoff-lcomm.ll @@ -14,9 +14,9 @@ @b = internal global i64 0, align 8 @c = internal global i16 0, align 2 -; CHECK: .lcomm a,4,a,2 -; CHECK-NEXT: .lcomm b,8,b,3 -; CHECK-NEXT: .lcomm c,2,c,1 +; CHECK: .lcomm a,4,a[BS],2 +; CHECK-NEXT: .lcomm b,8,b[BS],3 +; CHECK-NEXT: .lcomm c,2,c[BS],1 ; OBJ: File: {{.*}}aix-xcoff-lcomm.ll.tmp.o ; OBJ-NEXT: Format: aixcoff-rs6000