Index: llvm/trunk/include/llvm/MC/MCStreamer.h =================================================================== --- llvm/trunk/include/llvm/MC/MCStreamer.h +++ llvm/trunk/include/llvm/MC/MCStreamer.h @@ -537,6 +537,15 @@ /// \param Symbol - Symbol the image relative relocation should point to. virtual void EmitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset); + /// Emits an lcomm directive with XCOFF csect information. + /// + /// \param Symbol - The symbol we are emiting. + /// \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, + unsigned ByteAlignment); + /// Emit an ELF .size directive. /// /// This corresponds to an assembler statement such as: Index: llvm/trunk/include/llvm/MC/MCXCOFFStreamer.h =================================================================== --- llvm/trunk/include/llvm/MC/MCXCOFFStreamer.h +++ llvm/trunk/include/llvm/MC/MCXCOFFStreamer.h @@ -26,6 +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, + unsigned ByteAlign) override; }; } // end namespace llvm Index: llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp =================================================================== --- llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -1836,11 +1836,12 @@ // Common symbols go into a csect with matching name which will get mapped // into the .bss section. - if (Kind.isCommon()) { + if (Kind.isBSSLocal() || Kind.isCommon()) { SmallString<128> Name; getNameWithPrefix(Name, GO, TM); - return getContext().getXCOFFSection(Name, XCOFF::XMC_RW, XCOFF::XTY_CM, - Kind, /* BeginSymbolName */ nullptr); + return getContext().getXCOFFSection( + Name, Kind.isBSSLocal() ? XCOFF::XMC_BS : XCOFF::XMC_RW, XCOFF::XTY_CM, + Kind, /* BeginSymbolName */ nullptr); } if (Kind.isText()) Index: llvm/trunk/lib/MC/MCAsmInfoXCOFF.cpp =================================================================== --- llvm/trunk/lib/MC/MCAsmInfoXCOFF.cpp +++ llvm/trunk/lib/MC/MCAsmInfoXCOFF.cpp @@ -16,4 +16,5 @@ IsLittleEndian = false; HasDotTypeDotSizeDirective = false; COMMDirectiveAlignmentIsInBytes = false; + LCOMMDirectiveAlignmentType = LCOMM::Log2Alignment; } Index: llvm/trunk/lib/MC/MCAsmStreamer.cpp =================================================================== --- llvm/trunk/lib/MC/MCAsmStreamer.cpp +++ llvm/trunk/lib/MC/MCAsmStreamer.cpp @@ -162,6 +162,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, + unsigned ByteAlign) override; void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override; void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) override; @@ -757,6 +759,24 @@ EmitEOL(); } +// 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, + 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(); + OS << ',' << Log2_32(ByteAlignment); + + EmitEOL(); +} + void MCAsmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) { assert(MAI->hasDotTypeDotSizeDirective()); OS << "\t.size\t"; Index: llvm/trunk/lib/MC/MCSectionXCOFF.cpp =================================================================== --- llvm/trunk/lib/MC/MCSectionXCOFF.cpp +++ llvm/trunk/lib/MC/MCSectionXCOFF.cpp @@ -28,9 +28,11 @@ return; } - if (getKind().isCommon()) { - if (getMappingClass() != XCOFF::XMC_RW) - llvm_unreachable("Unsupported storage-mapping class for common csect"); + if (getKind().isBSSLocal() || getKind().isCommon()) { + if (getMappingClass() != XCOFF::XMC_RW && + getMappingClass() != XCOFF::XMC_BS) + llvm_unreachable("Generated a storage-mapping class for a common/bss " + "csect we don't understand how to switch to."); if (getCSectType() != XCOFF::XTY_CM) llvm_unreachable("wrong csect type for .bss csect"); // Don't have to print a directive for switching to section for commons. Index: llvm/trunk/lib/MC/MCStreamer.cpp =================================================================== --- llvm/trunk/lib/MC/MCStreamer.cpp +++ llvm/trunk/lib/MC/MCStreamer.cpp @@ -1055,6 +1055,10 @@ void MCStreamer::EmitCOFFSymbolType(int Type) { llvm_unreachable("this directive only supported on COFF targets"); } +void MCStreamer::EmitXCOFFLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlign) { + llvm_unreachable("this directive only supported on XCOFF targets"); +} void MCStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {} void MCStreamer::emitELFSymverDirective(StringRef AliasName, const MCSymbol *Aliasee) {} Index: llvm/trunk/lib/MC/MCXCOFFStreamer.cpp =================================================================== --- llvm/trunk/lib/MC/MCXCOFFStreamer.cpp +++ llvm/trunk/lib/MC/MCXCOFFStreamer.cpp @@ -57,3 +57,8 @@ S->getAssembler().setRelaxAll(true); return S; } + +void MCXCOFFStreamer::EmitXCOFFLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlign) { + llvm_unreachable("Not implemented yet."); +} \ No newline at end of file Index: llvm/trunk/lib/Target/PowerPC/PPCAsmPrinter.cpp =================================================================== --- llvm/trunk/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ llvm/trunk/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -1659,7 +1659,7 @@ report_fatal_error("COMDAT not yet supported by AIX."); SectionKind GVKind = getObjFileLowering().getKindForGlobal(GV, TM); - if (!GVKind.isCommon()) + if (!GVKind.isCommon() && !GVKind.isBSSLocal()) report_fatal_error("Only common variables are supported on AIX for now."); // Create the containing csect and switch to it. @@ -1673,7 +1673,11 @@ unsigned Align = GV->getAlignment() ? GV->getAlignment() : DL.getPreferredAlignment(GV); uint64_t Size = DL.getTypeAllocSize(GV->getType()->getElementType()); - OutStreamer->EmitCommonSymbol(XSym, Size, Align); + + if (GVKind.isBSSLocal()) + OutStreamer->EmitXCOFFLocalCommonSymbol(XSym, Size, Align); + else + OutStreamer->EmitCommonSymbol(XSym, Size, Align); } /// createPPCAsmPrinterPass - Returns a pass that prints the PPC assembly code Index: llvm/trunk/test/CodeGen/PowerPC/aix-xcoff-lcomm.ll =================================================================== --- llvm/trunk/test/CodeGen/PowerPC/aix-xcoff-lcomm.ll +++ llvm/trunk/test/CodeGen/PowerPC/aix-xcoff-lcomm.ll @@ -0,0 +1,10 @@ +; RUN: llc -mtriple powerpc-ibm-aix-xcoff < %s | FileCheck %s +; RUN: llc -mtriple powerpc64-ibm-aix-xcoff < %s | FileCheck %s + +@a = internal global i32 0, align 4 +@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