aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/llvm/MC/MCStreamer.h2
-rw-r--r--lib/MC/MCAsmStreamer.cpp14
-rw-r--r--test/MC/AsmParser/directive_align.s16
-rw-r--r--tools/llvm-mc/AsmParser.cpp98
-rw-r--r--tools/llvm-mc/AsmParser.h2
5 files changed, 124 insertions, 8 deletions
diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h
index bb85d2d..793af5d 100644
--- a/include/llvm/MC/MCStreamer.h
+++ b/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/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp
index d00638c..314e525 100644
--- a/lib/MC/MCAsmStreamer.cpp
+++ b/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/test/MC/AsmParser/directive_align.s b/test/MC/AsmParser/directive_align.s
new file mode 100644
index 0000000..5715cb3
--- /dev/null
+++ b/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/tools/llvm-mc/AsmParser.cpp b/tools/llvm-mc/AsmParser.cpp
index 4cb515b..29222d4 100644
--- a/tools/llvm-mc/AsmParser.cpp
+++ b/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/tools/llvm-mc/AsmParser.h b/tools/llvm-mc/AsmParser.h
index 326d0e7..aa885e6 100644
--- a/tools/llvm-mc/AsmParser.h
+++ b/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);
};