Don't drop alignment info on local common symbols.

- On COFF the .lcomm directive has an alignment argument.
- On ELF we fall back to .local + .comm

Based on a patch by NAKAMURA Takumi.

Fixes PR9337, PR9483 and PR10128.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@138976 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Benjamin Kramer
2011-09-01 23:04:27 +00:00
parent 7df496d2ad
commit 36a16015ac
19 changed files with 80 additions and 38 deletions

View File

@@ -32,6 +32,10 @@ namespace llvm {
enum ExceptionsType { None, DwarfCFI, SjLj, ARM, Win64 }; 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 /// MCAsmInfo - This class is intended to be used as a base class for asm
/// properties and features specific to the target. /// properties and features specific to the target.
class MCAsmInfo { class MCAsmInfo {
@@ -229,9 +233,9 @@ namespace llvm {
/// .long a - b /// .long a - b
bool HasAggressiveSymbolFolding; // Defaults to true. bool HasAggressiveSymbolFolding; // Defaults to true.
/// HasLCOMMDirective - This is true if the target supports the .lcomm /// LCOMMDirectiveType - Describes if the target supports the .lcomm
/// directive. /// directive and whether it has an alignment parameter.
bool HasLCOMMDirective; // Defaults to false. LCOMM::LCOMMType LCOMMDirectiveType; // Defaults to LCOMM::None.
/// COMMDirectiveAlignmentIsInBytes - True is COMMDirective's optional /// COMMDirectiveAlignmentIsInBytes - True is COMMDirective's optional
/// alignment is to be specified in bytes instead of log2(n). /// alignment is to be specified in bytes instead of log2(n).
@@ -479,7 +483,9 @@ namespace llvm {
bool hasAggressiveSymbolFolding() const { bool hasAggressiveSymbolFolding() const {
return HasAggressiveSymbolFolding; return HasAggressiveSymbolFolding;
} }
bool hasLCOMMDirective() const { return HasLCOMMDirective; } LCOMM::LCOMMType getLCOMMDirectiveType() const {
return LCOMMDirectiveType;
}
bool hasDotTypeDotSizeDirective() const {return HasDotTypeDotSizeDirective;} bool hasDotTypeDotSizeDirective() const {return HasDotTypeDotSizeDirective;}
bool getCOMMDirectiveAlignmentIsInBytes() const { bool getCOMMDirectiveAlignmentIsInBytes() const {
return COMMDirectiveAlignmentIsInBytes; return COMMDirectiveAlignmentIsInBytes;

View File

@@ -304,7 +304,9 @@ namespace llvm {
/// ///
/// @param Symbol - The common symbol to emit. /// @param Symbol - The common symbol to emit.
/// @param Size - The size of the common symbol. /// @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. /// EmitZerofill - Emit the zerofill section and an optional symbol.
/// ///

View File

@@ -290,10 +290,10 @@ void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
// Handle common and BSS local symbols (.lcomm). // Handle common and BSS local symbols (.lcomm).
if (GVKind.isCommon() || GVKind.isBSSLocal()) { if (GVKind.isCommon() || GVKind.isBSSLocal()) {
if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it. if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it.
unsigned Align = 1 << AlignLog;
// Handle common symbols. // Handle common symbols.
if (GVKind.isCommon()) { if (GVKind.isCommon()) {
unsigned Align = 1 << AlignLog;
if (!getObjFileLowering().getCommDirectiveSupportsAlignment()) if (!getObjFileLowering().getCommDirectiveSupportsAlignment())
Align = 0; Align = 0;
@@ -307,17 +307,17 @@ void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
const MCSection *TheSection = const MCSection *TheSection =
getObjFileLowering().SectionForGlobal(GV, GVKind, Mang, TM); getObjFileLowering().SectionForGlobal(GV, GVKind, Mang, TM);
// .zerofill __DATA, __bss, _foo, 400, 5 // .zerofill __DATA, __bss, _foo, 400, 5
OutStreamer.EmitZerofill(TheSection, GVSym, Size, 1 << AlignLog); OutStreamer.EmitZerofill(TheSection, GVSym, Size, Align);
return; return;
} }
if (MAI->hasLCOMMDirective()) { if (MAI->getLCOMMDirectiveType() != LCOMM::None &&
(MAI->getLCOMMDirectiveType() != LCOMM::NoAlignment || Align == 1)) {
// .lcomm _foo, 42 // .lcomm _foo, 42
OutStreamer.EmitLocalCommonSymbol(GVSym, Size); OutStreamer.EmitLocalCommonSymbol(GVSym, Size, Align);
return; return;
} }
unsigned Align = 1 << AlignLog;
if (!getObjFileLowering().getCommDirectiveSupportsAlignment()) if (!getObjFileLowering().getCommDirectiveSupportsAlignment())
Align = 0; Align = 0;

View File

@@ -65,7 +65,7 @@ MCAsmInfo::MCAsmInfo() {
GlobalDirective = "\t.globl\t"; GlobalDirective = "\t.globl\t";
HasSetDirective = true; HasSetDirective = true;
HasAggressiveSymbolFolding = true; HasAggressiveSymbolFolding = true;
HasLCOMMDirective = false; LCOMMDirectiveType = LCOMM::None;
COMMDirectiveAlignmentIsInBytes = true; COMMDirectiveAlignmentIsInBytes = true;
HasDotTypeDotSizeDirective = true; HasDotTypeDotSizeDirective = true;
HasSingleParameterDotFile = true; HasSingleParameterDotFile = true;

View File

@@ -19,7 +19,7 @@ using namespace llvm;
MCAsmInfoCOFF::MCAsmInfoCOFF() { MCAsmInfoCOFF::MCAsmInfoCOFF() {
GlobalPrefix = "_"; GlobalPrefix = "_";
COMMDirectiveAlignmentIsInBytes = false; COMMDirectiveAlignmentIsInBytes = false;
HasLCOMMDirective = true; LCOMMDirectiveType = LCOMM::ByteAlignment;
HasDotTypeDotSizeDirective = false; HasDotTypeDotSizeDirective = false;
HasSingleParameterDotFile = false; HasSingleParameterDotFile = false;
PrivateGlobalPrefix = "L"; // Prefix for private global symbols PrivateGlobalPrefix = "L"; // Prefix for private global symbols

View File

@@ -158,7 +158,9 @@ public:
/// ///
/// @param Symbol - The common symbol to emit. /// @param Symbol - The common symbol to emit.
/// @param Size - The size of the common symbol. /// @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, virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0,
unsigned Size = 0, unsigned ByteAlignment = 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 Symbol - The common symbol to emit.
/// @param Size - The size of the common symbol. /// @param Size - The size of the common symbol.
void MCAsmStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { void MCAsmStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
assert(MAI.hasLCOMMDirective() && "Doesn't have .lcomm, can't emit it!"); unsigned ByteAlign) {
assert(MAI.getLCOMMDirectiveType() != LCOMM::None &&
"Doesn't have .lcomm, can't emit it!");
OS << "\t.lcomm\t" << *Symbol << ',' << Size; OS << "\t.lcomm\t" << *Symbol << ',' << Size;
if (ByteAlign > 1) {
assert(MAI.getLCOMMDirectiveType() == LCOMM::ByteAlignment &&
"Alignment not supported on .lcomm!");
OS << ',' << ByteAlign;
}
EmitEOL(); EmitEOL();
} }

View File

@@ -220,14 +220,14 @@ void MCELFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
SD.setSize(MCConstantExpr::Create(Size, getContext())); 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? // FIXME: Should this be caught and done earlier?
MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol);
MCELF::SetBinding(SD, ELF::STB_LOCAL); MCELF::SetBinding(SD, ELF::STB_LOCAL);
SD.setExternal(false); SD.setExternal(false);
BindingExplicitlySet.insert(Symbol); BindingExplicitlySet.insert(Symbol);
// FIXME: ByteAlignment is not needed here, but is required. EmitCommonSymbol(Symbol, Size, ByteAlignment);
EmitCommonSymbol(Symbol, Size, 1);
} }
void MCELFStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { void MCELFStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) {

View File

@@ -74,7 +74,8 @@ public:
SD.setSize(Value); 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, virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0,
unsigned Size = 0, unsigned ByteAlignment = 0) { unsigned Size = 0, unsigned ByteAlignment = 0) {

View File

@@ -133,9 +133,10 @@ public:
return Child->EmitCommonSymbol(Symbol, Size, ByteAlignment); 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"); LogCall("EmitLocalCommonSymbol");
return Child->EmitLocalCommonSymbol(Symbol, Size); return Child->EmitLocalCommonSymbol(Symbol, Size, ByteAlignment);
} }
virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0,

View File

@@ -67,7 +67,8 @@ public:
virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {
assert(0 && "macho doesn't support this directive"); 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"); assert(0 && "macho doesn't support this directive");
} }
virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0,

View File

@@ -59,8 +59,8 @@ namespace {
virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {} virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {}
virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
unsigned ByteAlignment) {} 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, virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0,
unsigned Size = 0, unsigned ByteAlignment = 0) {} unsigned Size = 0, unsigned ByteAlignment = 0) {}
virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol,

View File

@@ -86,7 +86,8 @@ public:
virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {
report_fatal_error("unsupported directive in pure streamer"); 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"); report_fatal_error("unsupported directive in pure streamer");
} }
virtual void EmitFileDirective(StringRef Filename) { virtual void EmitFileDirective(StringRef Filename) {

View File

@@ -63,7 +63,8 @@ public:
virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value); virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value);
virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
unsigned ByteAlignment); 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, virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol,
unsigned Size,unsigned ByteAlignment); unsigned Size,unsigned ByteAlignment);
virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, 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); 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() assert((Symbol->isInSection()
? Symbol->getSection().getVariant() == MCSection::SV_COFF ? Symbol->getSection().getVariant() == MCSection::SV_COFF
: true) && "Got non COFF section in the COFF backend!"); : 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, void WinCOFFStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol,

View File

@@ -72,7 +72,7 @@ ARMELFMCAsmInfo::ARMELFMCAsmInfo() {
Code32Directive = ".code\t32"; Code32Directive = ".code\t32";
WeakRefDirective = "\t.weak\t"; WeakRefDirective = "\t.weak\t";
HasLCOMMDirective = true; LCOMMDirectiveType = LCOMM::NoAlignment;
HasLEB128 = true; HasLEB128 = true;
SupportsDebugInformation = true; SupportsDebugInformation = true;

View File

@@ -132,7 +132,9 @@ public:
/// ///
/// @param Symbol - The common symbol to emit. /// @param Symbol - The common symbol to emit.
/// @param Size - The size of the common symbol. /// @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, virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0,
unsigned Size = 0, unsigned ByteAlignment = 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, void PTXMCAsmStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
unsigned ByteAlignment) {} 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, void PTXMCAsmStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol,
unsigned Size, unsigned ByteAlignment) {} unsigned Size, unsigned ByteAlignment) {}

View File

@@ -60,7 +60,7 @@ PPCLinuxMCAsmInfo::PPCLinuxMCAsmInfo(bool is64Bit) {
ZeroDirective = "\t.space\t"; ZeroDirective = "\t.space\t";
Data64bitsDirective = is64Bit ? "\t.quad\t" : 0; Data64bitsDirective = is64Bit ? "\t.quad\t" : 0;
HasLCOMMDirective = true; LCOMMDirectiveType = LCOMM::NoAlignment;
AssemblerDialect = 0; // Old-Style mnemonics. AssemblerDialect = 0; // Old-Style mnemonics.
} }

View File

@@ -5,7 +5,7 @@
@dummy = internal global i32 666 @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 @sum = internal global i32 55
@STRIDE = internal global i32 8 @STRIDE = internal global i32 8
@@ -28,8 +28,9 @@
define i32 @main(i32 %argc) nounwind { define i32 @main(i32 %argc) nounwind {
%1 = load i32* @sum, align 4 %1 = load i32* @sum, align 4
%2 = getelementptr [20 x i32]* @array00, i32 0, i32 %argc %2 = getelementptr [80 x i8]* @array00, i32 0, i32 %argc
%3 = load i32* %2, align 4 %3 = load i8* %2
%4 = add i32 %1, %3 %4 = zext i8 %3 to i32
ret i32 %4; %5 = add i32 %1, %4
ret i32 %5
} }

View File

@@ -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))
}

View File

@@ -581,7 +581,8 @@ namespace {
markDefined(*Symbol); markDefined(*Symbol);
} }
virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {} 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, virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol,
uint64_t Size, unsigned ByteAlignment) {} uint64_t Size, unsigned ByteAlignment) {}
virtual void EmitBytes(StringRef Data, unsigned AddrSpace) {} virtual void EmitBytes(StringRef Data, unsigned AddrSpace) {}