diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h index bb85d2d55474..793af5d4c090 100644 --- a/llvm/include/llvm/MC/MCStreamer.h +++ b/llvm/include/llvm/MC/MCStreamer.h @@ -135,7 +135,7 @@ namespace llvm { /// This used to implement the .align assembler directive. /// /// @param ByteAlignment - The alignment to reach. This must be a power of - /// two. + /// two on some targets. /// @param Value - The value to use when filling bytes. /// @param Size - The size of the integer (in bytes) to emit for @param /// Value. This must match a native machine width. diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp index d00638c516dd..314e52568142 100644 --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -105,6 +105,7 @@ void MCAsmStreamer::EmitLabel(MCSymbol *Symbol) { OS << Symbol->getName() << ":\n"; Symbol->setSection(CurSection); + Symbol->setExternal(false); } void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCValue &Value, @@ -164,20 +165,23 @@ void MCAsmStreamer::EmitValue(const MCValue &Value, unsigned Size) { void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, unsigned ValueSize, unsigned MaxBytesToEmit) { + // Some assemblers don't support .balign, so we always emit as .p2align if + // this is a power of two. Otherwise we assume the client knows the target + // supports .balign and use that. unsigned Pow2 = Log2_32(ByteAlignment); - assert((1U << Pow2) == ByteAlignment && "Invalid alignment!"); + bool IsPow2 = (1U << Pow2) == ByteAlignment; switch (ValueSize) { default: assert(0 && "Invalid size for machine code value!"); case 8: assert(0 && "Unsupported alignment size!"); - case 1: OS << ".p2align"; break; - case 2: OS << ".p2alignw"; break; - case 4: OS << ".p2alignl"; break; + case 1: OS << (IsPow2 ? ".p2align" : ".balign"); break; + case 2: OS << (IsPow2 ? ".p2alignw" : ".balignw"); break; + case 4: OS << (IsPow2 ? ".p2alignl" : ".balignl"); break; } - OS << ' ' << Pow2; + OS << ' ' << (IsPow2 ? Pow2 : ByteAlignment); OS << ", " << truncateToSize(Value, ValueSize); if (MaxBytesToEmit) diff --git a/llvm/test/MC/AsmParser/directive_align.s b/llvm/test/MC/AsmParser/directive_align.s new file mode 100644 index 000000000000..5715cb3fc05f --- /dev/null +++ b/llvm/test/MC/AsmParser/directive_align.s @@ -0,0 +1,16 @@ +# RUN: llvm-mc %s > %t + +# RUN: grep -A 2 TEST0 %t > %t2 +# RUN: grep ".p2align 1, 0" %t2 | count 1 +TEST0: + .align 1 + +# RUN: grep -A 2 TEST1 %t > %t2 +# RUN: grep ".p2alignl 3, 0, 2" %t2 | count 1 +TEST1: + .align32 3,,2 + +# RUN: grep -A 2 TEST2 %t > %t2 +# RUN: grep ".balign 3, 10" %t2 | count 1 +TEST2: + .balign 3,10 diff --git a/llvm/tools/llvm-mc/AsmParser.cpp b/llvm/tools/llvm-mc/AsmParser.cpp index 4cb515b5ad03..29222d4c0f6b 100644 --- a/llvm/tools/llvm-mc/AsmParser.cpp +++ b/llvm/tools/llvm-mc/AsmParser.cpp @@ -429,10 +429,30 @@ bool AsmParser::ParseStatement() { return ParseDirectiveValue(4); if (!strcmp(IDVal, ".quad")) return ParseDirectiveValue(8); - if (!strcmp(IDVal, ".fill")) - return ParseDirectiveFill(); + + // FIXME: Target hooks for IsPow2. + if (!strcmp(IDVal, ".align")) + return ParseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/1); + if (!strcmp(IDVal, ".align32")) + return ParseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/4); + if (!strcmp(IDVal, ".balign")) + return ParseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/1); + if (!strcmp(IDVal, ".balignw")) + return ParseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/2); + if (!strcmp(IDVal, ".balignl")) + return ParseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/4); + if (!strcmp(IDVal, ".p2align")) + return ParseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/1); + if (!strcmp(IDVal, ".p2alignw")) + return ParseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/2); + if (!strcmp(IDVal, ".p2alignl")) + return ParseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/4); + if (!strcmp(IDVal, ".org")) return ParseDirectiveOrg(); + + if (!strcmp(IDVal, ".fill")) + return ParseDirectiveFill(); if (!strcmp(IDVal, ".space")) return ParseDirectiveSpace(); @@ -708,3 +728,77 @@ bool AsmParser::ParseDirectiveOrg() { return false; } + +/// ParseDirectiveAlign +/// ::= {.align, ...} expression [ , expression [ , expression ]] +bool AsmParser::ParseDirectiveAlign(bool IsPow2, unsigned ValueSize) { + int64_t Alignment; + if (ParseAbsoluteExpression(Alignment)) + return true; + + SMLoc MaxBytesLoc; + bool HasFillExpr = false; + int64_t FillExpr = 0; + int64_t MaxBytesToFill = 0; + if (Lexer.isNot(asmtok::EndOfStatement)) { + if (Lexer.isNot(asmtok::Comma)) + return TokError("unexpected token in directive"); + Lexer.Lex(); + + // The fill expression can be omitted while specifying a maximum number of + // alignment bytes, e.g: + // .align 3,,4 + if (Lexer.isNot(asmtok::Comma)) { + HasFillExpr = true; + if (ParseAbsoluteExpression(FillExpr)) + return true; + } + + if (Lexer.isNot(asmtok::EndOfStatement)) { + if (Lexer.isNot(asmtok::Comma)) + return TokError("unexpected token in directive"); + Lexer.Lex(); + + MaxBytesLoc = Lexer.getLoc(); + if (ParseAbsoluteExpression(MaxBytesToFill)) + return true; + + if (Lexer.isNot(asmtok::EndOfStatement)) + return TokError("unexpected token in directive"); + } + } + + Lexer.Lex(); + + if (!HasFillExpr) { + // FIXME: Sometimes fill with nop. + FillExpr = 0; + } + + // Compute alignment in bytes. + if (IsPow2) { + // FIXME: Diagnose overflow. + Alignment = 1 << Alignment; + } + + // Diagnose non-sensical max bytes to fill. + if (MaxBytesLoc.isValid()) { + if (MaxBytesToFill < 1) { + Lexer.PrintMessage(MaxBytesLoc, "warning: alignment directive can never " + "be satisfied in this many bytes, ignoring"); + return false; + } + + if (MaxBytesToFill >= Alignment) { + Lexer.PrintMessage(MaxBytesLoc, "warning: maximum bytes expression " + "exceeds alignment and has no effect"); + MaxBytesToFill = 0; + } + } + + // FIXME: Target specific behavior about how the "extra" bytes are filled. + Out.EmitValueToAlignment(Alignment, FillExpr, ValueSize, MaxBytesToFill); + + return false; +} + diff --git a/llvm/tools/llvm-mc/AsmParser.h b/llvm/tools/llvm-mc/AsmParser.h index 326d0e74b8d4..aa885e639937 100644 --- a/llvm/tools/llvm-mc/AsmParser.h +++ b/llvm/tools/llvm-mc/AsmParser.h @@ -79,6 +79,8 @@ private: bool ParseDirectiveSpace(); // ".space" bool ParseDirectiveSet(); // ".set" bool ParseDirectiveOrg(); // ".org" + // ".align{,32}", ".p2align{,w,l}" + bool ParseDirectiveAlign(bool IsPow2, unsigned ValueSize); };