diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h --- a/llvm/include/llvm/MC/MCStreamer.h +++ b/llvm/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: diff --git a/llvm/include/llvm/MC/MCXCOFFStreamer.h b/llvm/include/llvm/MC/MCXCOFFStreamer.h --- a/llvm/include/llvm/MC/MCXCOFFStreamer.h +++ b/llvm/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 diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -1851,11 +1851,13 @@ // Common symbols go into a csect with matching name which will get mapped // into the .bss section. - if (Kind.isCommon()) { + if (Kind.isBSS() || 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()) diff --git a/llvm/lib/MC/MCAsmInfoXCOFF.cpp b/llvm/lib/MC/MCAsmInfoXCOFF.cpp --- a/llvm/lib/MC/MCAsmInfoXCOFF.cpp +++ b/llvm/lib/MC/MCAsmInfoXCOFF.cpp @@ -16,4 +16,5 @@ IsLittleEndian = false; HasDotTypeDotSizeDirective = false; COMMDirectiveAlignmentIsInBytes = false; + LCOMMDirectiveAlignmentType = LCOMM::Log2Alignment; } diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/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"; diff --git a/llvm/lib/MC/MCSectionXCOFF.cpp b/llvm/lib/MC/MCSectionXCOFF.cpp --- a/llvm/lib/MC/MCSectionXCOFF.cpp +++ b/llvm/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().isBSS() || getKind().isCommon()) { + if (getMappingClass() != XCOFF::XMC_RW && + getMappingClass() != XCOFF::XMC_BS) + llvm_unreachable( + "Unsupported storage-mapping class for common/bss csect."); 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. diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp --- a/llvm/lib/MC/MCStreamer.cpp +++ b/llvm/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) {} diff --git a/llvm/lib/MC/MCXCOFFStreamer.cpp b/llvm/lib/MC/MCXCOFFStreamer.cpp --- a/llvm/lib/MC/MCXCOFFStreamer.cpp +++ b/llvm/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 diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp --- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -1659,8 +1659,8 @@ report_fatal_error("COMDAT not yet supported by AIX."); SectionKind GVKind = getObjFileLowering().getKindForGlobal(GV, TM); - if (!GVKind.isCommon()) - report_fatal_error("Only common variables are supported on AIX for now."); + if (!GVKind.isCommon() && !GVKind.isBSS()) + report_fatal_error("Only common variables are supported on AIX."); // Create the containing csect and switch to it. MCSectionXCOFF *CSect = cast( @@ -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 diff --git a/llvm/test/CodeGen/PowerPC/aix-xcoff-lcomm.ll b/llvm/test/CodeGen/PowerPC/aix-xcoff-lcomm.ll new file mode 100644 --- /dev/null +++ b/llvm/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