diff --git a/include/llvm/MC/MCAsmInfo.h b/include/llvm/MC/MCAsmInfo.h index b8a0e02394b..96b68c833dc 100644 --- a/include/llvm/MC/MCAsmInfo.h +++ b/include/llvm/MC/MCAsmInfo.h @@ -32,6 +32,10 @@ namespace llvm { enum ExceptionsType { None, DwarfCFI, SjLj, ARM, Win64 }; } + namespace LCOMM { + enum LCOMMType { None, NoAlignment, ByteAlignment }; + } + /// MCAsmInfo - This class is intended to be used as a base class for asm /// properties and features specific to the target. class MCAsmInfo { @@ -229,9 +233,9 @@ namespace llvm { /// .long a - b bool HasAggressiveSymbolFolding; // Defaults to true. - /// HasLCOMMDirective - This is true if the target supports the .lcomm - /// directive. - bool HasLCOMMDirective; // Defaults to false. + /// LCOMMDirectiveType - Describes if the target supports the .lcomm + /// directive and whether it has an alignment parameter. + LCOMM::LCOMMType LCOMMDirectiveType; // Defaults to LCOMM::None. /// COMMDirectiveAlignmentIsInBytes - True is COMMDirective's optional /// alignment is to be specified in bytes instead of log2(n). @@ -479,7 +483,9 @@ namespace llvm { bool hasAggressiveSymbolFolding() const { return HasAggressiveSymbolFolding; } - bool hasLCOMMDirective() const { return HasLCOMMDirective; } + LCOMM::LCOMMType getLCOMMDirectiveType() const { + return LCOMMDirectiveType; + } bool hasDotTypeDotSizeDirective() const {return HasDotTypeDotSizeDirective;} bool getCOMMDirectiveAlignmentIsInBytes() const { return COMMDirectiveAlignmentIsInBytes; diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h index c5c7583f103..4279ef50912 100644 --- a/include/llvm/MC/MCStreamer.h +++ b/include/llvm/MC/MCStreamer.h @@ -304,7 +304,9 @@ namespace llvm { /// /// @param Symbol - The common symbol to emit. /// @param Size - The size of the common symbol. - virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) = 0; + /// @param ByteAlignment - The alignment of the common symbol in bytes. + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) = 0; /// EmitZerofill - Emit the zerofill section and an optional symbol. /// diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index f7341fee4be..6084a3c8f59 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -290,10 +290,10 @@ void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { // Handle common and BSS local symbols (.lcomm). if (GVKind.isCommon() || GVKind.isBSSLocal()) { if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it. + unsigned Align = 1 << AlignLog; // Handle common symbols. if (GVKind.isCommon()) { - unsigned Align = 1 << AlignLog; if (!getObjFileLowering().getCommDirectiveSupportsAlignment()) Align = 0; @@ -307,17 +307,17 @@ void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { const MCSection *TheSection = getObjFileLowering().SectionForGlobal(GV, GVKind, Mang, TM); // .zerofill __DATA, __bss, _foo, 400, 5 - OutStreamer.EmitZerofill(TheSection, GVSym, Size, 1 << AlignLog); + OutStreamer.EmitZerofill(TheSection, GVSym, Size, Align); return; } - if (MAI->hasLCOMMDirective()) { + if (MAI->getLCOMMDirectiveType() != LCOMM::None && + (MAI->getLCOMMDirectiveType() != LCOMM::NoAlignment || Align == 1)) { // .lcomm _foo, 42 - OutStreamer.EmitLocalCommonSymbol(GVSym, Size); + OutStreamer.EmitLocalCommonSymbol(GVSym, Size, Align); return; } - unsigned Align = 1 << AlignLog; if (!getObjFileLowering().getCommDirectiveSupportsAlignment()) Align = 0; diff --git a/lib/MC/MCAsmInfo.cpp b/lib/MC/MCAsmInfo.cpp index 015ccd41249..a53c474c15b 100644 --- a/lib/MC/MCAsmInfo.cpp +++ b/lib/MC/MCAsmInfo.cpp @@ -65,7 +65,7 @@ MCAsmInfo::MCAsmInfo() { GlobalDirective = "\t.globl\t"; HasSetDirective = true; HasAggressiveSymbolFolding = true; - HasLCOMMDirective = false; + LCOMMDirectiveType = LCOMM::None; COMMDirectiveAlignmentIsInBytes = true; HasDotTypeDotSizeDirective = true; HasSingleParameterDotFile = true; diff --git a/lib/MC/MCAsmInfoCOFF.cpp b/lib/MC/MCAsmInfoCOFF.cpp index 7fc7d7abb23..cf6026b4ef8 100644 --- a/lib/MC/MCAsmInfoCOFF.cpp +++ b/lib/MC/MCAsmInfoCOFF.cpp @@ -19,7 +19,7 @@ using namespace llvm; MCAsmInfoCOFF::MCAsmInfoCOFF() { GlobalPrefix = "_"; COMMDirectiveAlignmentIsInBytes = false; - HasLCOMMDirective = true; + LCOMMDirectiveType = LCOMM::ByteAlignment; HasDotTypeDotSizeDirective = false; HasSingleParameterDotFile = false; PrivateGlobalPrefix = "L"; // Prefix for private global symbols diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp index 40eaf979fad..68154345c8d 100644 --- a/lib/MC/MCAsmStreamer.cpp +++ b/lib/MC/MCAsmStreamer.cpp @@ -158,7 +158,9 @@ public: /// /// @param Symbol - The common symbol to emit. /// @param Size - The size of the common symbol. - virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size); + /// @param Size - The alignment of the common symbol in bytes. + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment); virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, unsigned Size = 0, unsigned ByteAlignment = 0); @@ -484,9 +486,16 @@ void MCAsmStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, /// /// @param Symbol - The common symbol to emit. /// @param Size - The size of the common symbol. -void MCAsmStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { - assert(MAI.hasLCOMMDirective() && "Doesn't have .lcomm, can't emit it!"); +void MCAsmStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlign) { + assert(MAI.getLCOMMDirectiveType() != LCOMM::None && + "Doesn't have .lcomm, can't emit it!"); OS << "\t.lcomm\t" << *Symbol << ',' << Size; + if (ByteAlign > 1) { + assert(MAI.getLCOMMDirectiveType() == LCOMM::ByteAlignment && + "Alignment not supported on .lcomm!"); + OS << ',' << ByteAlign; + } EmitEOL(); } diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp index 573b3e48875..9ada08ea953 100644 --- a/lib/MC/MCELFStreamer.cpp +++ b/lib/MC/MCELFStreamer.cpp @@ -220,14 +220,14 @@ void MCELFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, SD.setSize(MCConstantExpr::Create(Size, getContext())); } -void MCELFStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { +void MCELFStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) { // FIXME: Should this be caught and done earlier? MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); MCELF::SetBinding(SD, ELF::STB_LOCAL); SD.setExternal(false); BindingExplicitlySet.insert(Symbol); - // FIXME: ByteAlignment is not needed here, but is required. - EmitCommonSymbol(Symbol, Size, 1); + EmitCommonSymbol(Symbol, Size, ByteAlignment); } void MCELFStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { diff --git a/lib/MC/MCELFStreamer.h b/lib/MC/MCELFStreamer.h index 9b5f3a8bbed..10bf7758099 100644 --- a/lib/MC/MCELFStreamer.h +++ b/lib/MC/MCELFStreamer.h @@ -74,7 +74,8 @@ public: SD.setSize(Value); } - virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size); + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment); virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, unsigned Size = 0, unsigned ByteAlignment = 0) { diff --git a/lib/MC/MCLoggingStreamer.cpp b/lib/MC/MCLoggingStreamer.cpp index 309752ec5f0..3fe8ac72c8e 100644 --- a/lib/MC/MCLoggingStreamer.cpp +++ b/lib/MC/MCLoggingStreamer.cpp @@ -133,9 +133,10 @@ public: return Child->EmitCommonSymbol(Symbol, Size, ByteAlignment); } - virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) { LogCall("EmitLocalCommonSymbol"); - return Child->EmitLocalCommonSymbol(Symbol, Size); + return Child->EmitLocalCommonSymbol(Symbol, Size, ByteAlignment); } virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp index 844793b488f..aa35815dd19 100644 --- a/lib/MC/MCMachOStreamer.cpp +++ b/lib/MC/MCMachOStreamer.cpp @@ -67,7 +67,8 @@ public: virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { assert(0 && "macho doesn't support this directive"); } - virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) { assert(0 && "macho doesn't support this directive"); } virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, diff --git a/lib/MC/MCNullStreamer.cpp b/lib/MC/MCNullStreamer.cpp index 9577af01020..a6c0adb6793 100644 --- a/lib/MC/MCNullStreamer.cpp +++ b/lib/MC/MCNullStreamer.cpp @@ -59,8 +59,8 @@ namespace { virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {} virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) {} - virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) {} - + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) {} virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, unsigned Size = 0, unsigned ByteAlignment = 0) {} virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, diff --git a/lib/MC/MCPureStreamer.cpp b/lib/MC/MCPureStreamer.cpp index 0b61c882d4d..086c9229bcd 100644 --- a/lib/MC/MCPureStreamer.cpp +++ b/lib/MC/MCPureStreamer.cpp @@ -86,7 +86,8 @@ public: virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { report_fatal_error("unsupported directive in pure streamer"); } - virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) { report_fatal_error("unsupported directive in pure streamer"); } virtual void EmitFileDirective(StringRef Filename) { diff --git a/lib/MC/WinCOFFStreamer.cpp b/lib/MC/WinCOFFStreamer.cpp index f79ba8e6890..7409daf3908 100644 --- a/lib/MC/WinCOFFStreamer.cpp +++ b/lib/MC/WinCOFFStreamer.cpp @@ -63,7 +63,8 @@ public: virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value); virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment); - virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size); + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment); virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol, unsigned Size,unsigned ByteAlignment); virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, @@ -304,11 +305,12 @@ void WinCOFFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, AddCommonSymbol(Symbol, Size, ByteAlignment, true); } -void WinCOFFStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { +void WinCOFFStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) { assert((Symbol->isInSection() ? Symbol->getSection().getVariant() == MCSection::SV_COFF : true) && "Got non COFF section in the COFF backend!"); - AddCommonSymbol(Symbol, Size, 1, false); + AddCommonSymbol(Symbol, Size, ByteAlignment, false); } void WinCOFFStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol, diff --git a/lib/Target/ARM/MCTargetDesc/ARMMCAsmInfo.cpp b/lib/Target/ARM/MCTargetDesc/ARMMCAsmInfo.cpp index 07e3540e31c..1c109e01528 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMMCAsmInfo.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMMCAsmInfo.cpp @@ -72,7 +72,7 @@ ARMELFMCAsmInfo::ARMELFMCAsmInfo() { Code32Directive = ".code\t32"; WeakRefDirective = "\t.weak\t"; - HasLCOMMDirective = true; + LCOMMDirectiveType = LCOMM::NoAlignment; HasLEB128 = true; SupportsDebugInformation = true; diff --git a/lib/Target/PTX/PTXMCAsmStreamer.cpp b/lib/Target/PTX/PTXMCAsmStreamer.cpp index bac55356933..5003fb5b8f5 100644 --- a/lib/Target/PTX/PTXMCAsmStreamer.cpp +++ b/lib/Target/PTX/PTXMCAsmStreamer.cpp @@ -132,7 +132,9 @@ public: /// /// @param Symbol - The common symbol to emit. /// @param Size - The size of the common symbol. - virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size); + /// @param ByteAlignment - The alignment of the common symbol in bytes. + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment); virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, unsigned Size = 0, unsigned ByteAlignment = 0); @@ -283,7 +285,8 @@ void PTXMCAsmStreamer::EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {} void PTXMCAsmStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) {} -void PTXMCAsmStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) {} +void PTXMCAsmStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) {} void PTXMCAsmStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol, unsigned Size, unsigned ByteAlignment) {} diff --git a/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp b/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp index b6d46dd34fa..e9424d8415f 100644 --- a/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp +++ b/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp @@ -60,7 +60,7 @@ PPCLinuxMCAsmInfo::PPCLinuxMCAsmInfo(bool is64Bit) { ZeroDirective = "\t.space\t"; Data64bitsDirective = is64Bit ? "\t.quad\t" : 0; - HasLCOMMDirective = true; + LCOMMDirectiveType = LCOMM::NoAlignment; AssemblerDialect = 0; // Old-Style mnemonics. } diff --git a/test/CodeGen/ARM/2010-12-15-elf-lcomm.ll b/test/CodeGen/ARM/2010-12-15-elf-lcomm.ll index a4bab85692d..5cfbb4f944f 100644 --- a/test/CodeGen/ARM/2010-12-15-elf-lcomm.ll +++ b/test/CodeGen/ARM/2010-12-15-elf-lcomm.ll @@ -5,7 +5,7 @@ @dummy = internal global i32 666 -@array00 = internal global [20 x i32] zeroinitializer +@array00 = internal global [80 x i8] zeroinitializer, align 1 @sum = internal global i32 55 @STRIDE = internal global i32 8 @@ -28,8 +28,9 @@ define i32 @main(i32 %argc) nounwind { %1 = load i32* @sum, align 4 - %2 = getelementptr [20 x i32]* @array00, i32 0, i32 %argc - %3 = load i32* %2, align 4 - %4 = add i32 %1, %3 - ret i32 %4; + %2 = getelementptr [80 x i8]* @array00, i32 0, i32 %argc + %3 = load i8* %2 + %4 = zext i8 %3 to i32 + %5 = add i32 %1, %4 + ret i32 %5 } diff --git a/test/CodeGen/ARM/elf-lcomm-align.ll b/test/CodeGen/ARM/elf-lcomm-align.ll new file mode 100644 index 00000000000..46792990e59 --- /dev/null +++ b/test/CodeGen/ARM/elf-lcomm-align.ll @@ -0,0 +1,14 @@ +; RUN: llc < %s -mtriple=arm-linux-gnueabi -O0 | FileCheck %s +; run with -O0 to avoid arm global merging. + +@c = internal global i8 0, align 1 +@x = internal global i32 0, align 4 + +; CHECK: .lcomm c,1 +; .lcomm doesn't support alignment. +; CHECK: .local x +; CHECK-NEXT: .comm x,4,4 + +define i32 @foo() nounwind { + ret i32 sub (i32 ptrtoint (i8* @c to i32), i32 ptrtoint (i32* @x to i32)) +} diff --git a/tools/lto/LTOModule.cpp b/tools/lto/LTOModule.cpp index 7c9489179a1..f6dc7d90bce 100644 --- a/tools/lto/LTOModule.cpp +++ b/tools/lto/LTOModule.cpp @@ -581,7 +581,8 @@ namespace { markDefined(*Symbol); } virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {} - virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) {} + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) {} virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) {} virtual void EmitBytes(StringRef Data, unsigned AddrSpace) {}