diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h index 54de8a31076..bc3dd738ee3 100644 --- a/include/llvm/MC/MCStreamer.h +++ b/include/llvm/MC/MCStreamer.h @@ -115,6 +115,15 @@ namespace llvm { virtual void EmitSymbolAttribute(MCSymbol *Symbol, SymbolAttr Attribute) = 0; + /// EmitCommonSymbol - Emit a common symbol of @param Size with the @param + /// Pow2Alignment if non-zero. + /// + /// @param Symbol - The common symbol to emit. + /// @param Size - The size of the common symbol. + /// @param Pow2Alignment - The alignment of the common symbol if non-zero. + virtual void EmitCommonSymbol(MCSymbol *Symbol, unsigned Size, + unsigned Pow2Alignment) = 0; + /// @} /// @name Generating Data /// @{ diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp index 7d944644488..f4aeaf39f33 100644 --- a/lib/MC/MCAsmStreamer.cpp +++ b/lib/MC/MCAsmStreamer.cpp @@ -41,6 +41,9 @@ namespace { virtual void EmitSymbolAttribute(MCSymbol *Symbol, SymbolAttr Attribute); + virtual void EmitCommonSymbol(MCSymbol *Symbol, unsigned Size, + unsigned Pow2Alignment); + virtual void EmitBytes(const char *Data, unsigned Length); virtual void EmitValue(const MCValue &Value, unsigned Size); @@ -142,6 +145,15 @@ void MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, OS << ' ' << Symbol->getName() << '\n'; } +void MCAsmStreamer::EmitCommonSymbol(MCSymbol *Symbol, unsigned Size, + unsigned Pow2Alignment) { + OS << ".comm"; + OS << ' ' << Symbol->getName() << ',' << Size; + if (Pow2Alignment != 0) + OS << ',' << Pow2Alignment; + OS << '\n'; +} + void MCAsmStreamer::EmitBytes(const char *Data, unsigned Length) { assert(CurSection && "Cannot emit contents before setting section!"); for (unsigned i = 0; i != Length; ++i) diff --git a/test/MC/AsmParser/directive_comm.s b/test/MC/AsmParser/directive_comm.s new file mode 100644 index 00000000000..ed493746185 --- /dev/null +++ b/test/MC/AsmParser/directive_comm.s @@ -0,0 +1,8 @@ +# RUN: llvm-mc %s > %t + +# RUN: grep -A 3 TEST0 %t > %t2 +# RUN: grep ".comm a,6,2" %t2 | count 1 +# RUN: grep ".comm b,8" %t2 | count 1 +TEST0: + .comm a, 4+2, 2 + .comm b,8 diff --git a/tools/llvm-mc/AsmParser.cpp b/tools/llvm-mc/AsmParser.cpp index f5bf5892012..1a3543aac77 100644 --- a/tools/llvm-mc/AsmParser.cpp +++ b/tools/llvm-mc/AsmParser.cpp @@ -520,6 +520,9 @@ bool AsmParser::ParseStatement() { if (!strcmp(IDVal, ".weak_reference")) return ParseDirectiveSymbolAttribute(MCStreamer::WeakReference); + if (!strcmp(IDVal, ".comm")) + return ParseDirectiveComm(); + Warning(IDLoc, "ignoring directive for now"); EatToEndOfStatement(); return false; @@ -896,3 +899,59 @@ bool AsmParser::ParseDirectiveSymbolAttribute(MCStreamer::SymbolAttr Attr) { Lexer.Lex(); return false; } + +/// ParseDirectiveComm +/// ::= .comm identifier , size_expression [ , align_expression ] +bool AsmParser::ParseDirectiveComm() { + if (Lexer.isNot(asmtok::Identifier)) + return TokError("expected identifier in directive"); + + // handle the identifier as the key symbol. + SMLoc IDLoc = Lexer.getLoc(); + MCSymbol *Sym = Ctx.GetOrCreateSymbol(Lexer.getCurStrVal()); + Lexer.Lex(); + + if (Lexer.isNot(asmtok::Comma)) + return TokError("unexpected token in directive"); + Lexer.Lex(); + + int64_t Size; + SMLoc SizeLoc = Lexer.getLoc(); + if (ParseAbsoluteExpression(Size)) + return true; + + int64_t Pow2Alignment = 0; + SMLoc Pow2AlignmentLoc; + if (Lexer.is(asmtok::Comma)) { + Lexer.Lex(); + Pow2AlignmentLoc = Lexer.getLoc(); + if (ParseAbsoluteExpression(Pow2Alignment)) + return true; + } + + if (Lexer.isNot(asmtok::EndOfStatement)) + return TokError("unexpected token in '.comm' directive"); + + Lexer.Lex(); + + // NOTE: a size of zero should create a undefined symbol + if (Size < 0) + return Error(SizeLoc, "invalid '.comm' size, can't be less than zero"); + + // NOTE: The alignment in the directive is a power of 2 value, the assember + // may internally end up wanting an alignment in bytes. + // FIXME: Diagnose overflow. + if (Pow2Alignment < 0) + return Error(Pow2AlignmentLoc, "invalid '.comm' alignment, can't be less " + "than zero"); + + // TODO: Symbol must be undefined or it is a error to re-defined the symbol + if (Sym->getSection() || Ctx.GetSymbolValue(Sym)) + return Error(IDLoc, "invalid symbol redefinition"); + + // TODO: Symbol to be made into a common with this Size and Pow2Alignment + + Out.EmitCommonSymbol(Sym, Size, Pow2Alignment); + + return false; +} diff --git a/tools/llvm-mc/AsmParser.h b/tools/llvm-mc/AsmParser.h index 333b284eac9..bafdfb76a0e 100644 --- a/tools/llvm-mc/AsmParser.h +++ b/tools/llvm-mc/AsmParser.h @@ -109,6 +109,8 @@ private: /// ParseDirectiveSymbolAttribute - Parse a directive like ".globl" which /// accepts a single symbol (which should be a label or an external). bool ParseDirectiveSymbolAttribute(MCStreamer::SymbolAttr Attr); + + bool ParseDirectiveComm(); // ".comm" };