diff --git a/test/MC/AsmParser/dg.exp b/test/MC/AsmParser/dg.exp new file mode 100644 index 00000000000..ebd84187f52 --- /dev/null +++ b/test/MC/AsmParser/dg.exp @@ -0,0 +1,3 @@ +load_lib llvm.exp + +RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{s}]] diff --git a/test/MC/AsmParser/directive_ascii.s b/test/MC/AsmParser/directive_ascii.s new file mode 100644 index 00000000000..95e194a3768 --- /dev/null +++ b/test/MC/AsmParser/directive_ascii.s @@ -0,0 +1,25 @@ +# RUN: llvm-mc %s > %t + +# RUN: grep -A 1 TEST0 %t > %t2 +# RUN: not grep ".byte" %t2 +TEST0: + .ascii + +# RUN: grep -A 1 TEST1 %t > %t2 +# RUN: not grep "byte" %t2 +TEST1: + .asciz + +# RUN: grep -A 2 TEST2 %t > %t2 +# RUN: grep ".byte 65" %t2 | count 1 +TEST2: + .ascii "A" + +# RUN: grep -A 5 TEST3 %t > %t2 +# RUN: grep ".byte 66" %t2 | count 1 +# RUN: grep ".byte 67" %t2 | count 1 +# RUN: grep ".byte 0" %t2 | count 2 +TEST3: + .asciz "B", "C" + + \ No newline at end of file diff --git a/test/MC/AsmParser/directive_fill.s b/test/MC/AsmParser/directive_fill.s new file mode 100644 index 00000000000..ec8bdf27c71 --- /dev/null +++ b/test/MC/AsmParser/directive_fill.s @@ -0,0 +1,11 @@ +# RUN: llvm-mc %s > %t + +# RUN: grep -A 2 TEST0 %t > %t2 +# RUN: grep ".byte 10" %t2 | count 1 +TEST0: + .fill 1, 1, 10 + +# RUN: grep -A 3 TEST1 %t > %t2 +# RUN: grep ".short 3" %t2 | count 2 +TEST1: + .fill 2, 2, 3 diff --git a/test/MC/AsmParser/directive_space.s b/test/MC/AsmParser/directive_space.s new file mode 100644 index 00000000000..6159775de4b --- /dev/null +++ b/test/MC/AsmParser/directive_space.s @@ -0,0 +1,11 @@ +# RUN: llvm-mc %s > %t + +# RUN: grep -A 2 TEST0 %t > %t2 +# RUN: grep ".byte 0" %t2 | count 1 +TEST0: + .space 1 + +# RUN: grep -A 3 TEST1 %t > %t2 +# RUN: grep ".byte 3" %t2 | count 2 +TEST1: + .space 2, 3 diff --git a/test/MC/AsmParser/directive_values.s b/test/MC/AsmParser/directive_values.s new file mode 100644 index 00000000000..39ba0689234 --- /dev/null +++ b/test/MC/AsmParser/directive_values.s @@ -0,0 +1,21 @@ +# RUN: llvm-mc %s > %t + +# RUN: grep -A 2 TEST0 %t > %t2 +# RUN: grep ".byte 0" %t2 | count 1 +TEST0: + .byte 0 + +# RUN: grep -A 2 TEST1 %t > %t2 +# RUN: grep ".short 3" %t2 | count 1 +TEST1: + .short 3 + +# RUN: grep -A 2 TEST2 %t > %t2 +# RUN: grep ".long 8" %t2 | count 1 +TEST2: + .long 8 + +# RUN: grep -A 2 TEST3 %t > %t2 +# RUN: grep ".quad 9" %t2 | count 1 +TEST3: + .quad 9 diff --git a/tools/llvm-mc/AsmParser.cpp b/tools/llvm-mc/AsmParser.cpp index e493812e887..d9e14458fd2 100644 --- a/tools/llvm-mc/AsmParser.cpp +++ b/tools/llvm-mc/AsmParser.cpp @@ -291,7 +291,27 @@ bool AsmParser::ParseStatement() { if (!strcmp(IDVal, ".objc_selector_strs")) return ParseDirectiveSectionSwitch("__OBJC,__selector_strs"); - + // Data directives + + if (!strcmp(IDVal, ".ascii")) + return ParseDirectiveAscii(false); + if (!strcmp(IDVal, ".asciz")) + return ParseDirectiveAscii(true); + + // FIXME: Target hooks for size? Also for "word", "hword". + if (!strcmp(IDVal, ".byte")) + return ParseDirectiveValue(1); + if (!strcmp(IDVal, ".short")) + return ParseDirectiveValue(2); + if (!strcmp(IDVal, ".long")) + return ParseDirectiveValue(4); + if (!strcmp(IDVal, ".quad")) + return ParseDirectiveValue(8); + if (!strcmp(IDVal, ".fill")) + return ParseDirectiveFill(); + if (!strcmp(IDVal, ".space")) + return ParseDirectiveSpace(); + Lexer.PrintMessage(IDLoc, "warning: ignoring directive for now"); EatToEndOfStatement(); return false; @@ -361,3 +381,131 @@ bool AsmParser::ParseDirectiveSectionSwitch(const char *Section, Out.SwitchSection(Ctx.GetSection(Section)); return false; } + +/// ParseDirectiveAscii: +/// ::= ( .ascii | .asciiz ) [ "string" ( , "string" )* ] +bool AsmParser::ParseDirectiveAscii(bool ZeroTerminated) { + if (Lexer.isNot(asmtok::EndOfStatement)) { + for (;;) { + if (Lexer.isNot(asmtok::String)) + return TokError("expected string in '.ascii' or '.asciz' directive"); + + // FIXME: This shouldn't use a const char* + strlen, the string could have + // embedded nulls. + // FIXME: Should have accessor for getting string contents. + const char *Str = Lexer.getCurStrVal(); + Out.EmitBytes(Str + 1, strlen(Str) - 2); + if (ZeroTerminated) + Out.EmitBytes("\0", 1); + + Lexer.Lex(); + + if (Lexer.is(asmtok::EndOfStatement)) + break; + + if (Lexer.isNot(asmtok::Comma)) + return TokError("unexpected token in '.ascii' or '.asciz' directive"); + Lexer.Lex(); + } + } + + Lexer.Lex(); + return false; +} + +/// ParseDirectiveValue +/// ::= (.byte | .short | ... ) [ expression (, expression)* ] +bool AsmParser::ParseDirectiveValue(unsigned Size) { + if (Lexer.isNot(asmtok::EndOfStatement)) { + for (;;) { + int64_t Expr; + if (ParseExpression(Expr)) + return true; + + Out.EmitValue(MCValue::get(Expr), Size); + + if (Lexer.is(asmtok::EndOfStatement)) + break; + + // FIXME: Improve diagnostic. + if (Lexer.isNot(asmtok::Comma)) + return TokError("unexpected token in directive"); + Lexer.Lex(); + } + } + + Lexer.Lex(); + return false; +} + +/// ParseDirectiveSpace +/// ::= .space expression [ , expression ] +bool AsmParser::ParseDirectiveSpace() { + int64_t NumBytes; + if (ParseExpression(NumBytes)) + return true; + + int64_t FillExpr = 0; + bool HasFillExpr = false; + if (Lexer.isNot(asmtok::EndOfStatement)) { + if (Lexer.isNot(asmtok::Comma)) + return TokError("unexpected token in '.space' directive"); + Lexer.Lex(); + + if (ParseExpression(FillExpr)) + return true; + + HasFillExpr = true; + + if (Lexer.isNot(asmtok::EndOfStatement)) + return TokError("unexpected token in '.space' directive"); + } + + Lexer.Lex(); + + if (NumBytes <= 0) + return TokError("invalid number of bytes in '.space' directive"); + + // FIXME: Sometimes the fill expr is 'nop' if it isn't supplied, instead of 0. + for (uint64_t i = 0, e = NumBytes; i != e; ++i) + Out.EmitValue(MCValue::get(FillExpr), 1); + + return false; +} + +/// ParseDirectiveFill +/// ::= .fill expression , expression , expression +bool AsmParser::ParseDirectiveFill() { + int64_t NumValues; + if (ParseExpression(NumValues)) + return true; + + if (Lexer.isNot(asmtok::Comma)) + return TokError("unexpected token in '.fill' directive"); + Lexer.Lex(); + + int64_t FillSize; + if (ParseExpression(FillSize)) + return true; + + if (Lexer.isNot(asmtok::Comma)) + return TokError("unexpected token in '.fill' directive"); + Lexer.Lex(); + + int64_t FillExpr; + if (ParseExpression(FillExpr)) + return true; + + if (Lexer.isNot(asmtok::EndOfStatement)) + return TokError("unexpected token in '.fill' directive"); + + Lexer.Lex(); + + if (FillSize != 1 && FillSize != 2 && FillSize != 4) + return TokError("invalid '.fill' size, expected 1, 2, or 4"); + + for (uint64_t i = 0, e = NumValues; i != e; ++i) + Out.EmitValue(MCValue::get(FillExpr), FillSize); + + return false; +} diff --git a/tools/llvm-mc/AsmParser.h b/tools/llvm-mc/AsmParser.h index c793d782b8f..d0cc0eef2f6 100644 --- a/tools/llvm-mc/AsmParser.h +++ b/tools/llvm-mc/AsmParser.h @@ -57,6 +57,10 @@ private: bool ParseDirectiveDarwinSection(); // Darwin specific ".section". bool ParseDirectiveSectionSwitch(const char *Section, const char *Directives = 0); + bool ParseDirectiveAscii(bool ZeroTerminated); // ".ascii", ".asciiz" + bool ParseDirectiveValue(unsigned Size); // ".byte", ".long", ... + bool ParseDirectiveFill(); // ".fill" + bool ParseDirectiveSpace(); // ".space" }; diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp index b999109f0bc..4100cb14de1 100644 --- a/tools/llvm-mc/llvm-mc.cpp +++ b/tools/llvm-mc/llvm-mc.cpp @@ -141,6 +141,10 @@ static int AssembleInput(const char *ProgName) { MCContext Ctx; OwningPtr Str(createAsmStreamer(Ctx, outs())); + + // FIXME: Target hook & command line option for initial section. + Str.get()->SwitchSection(Ctx.GetSection("__TEXT,__text,regular,pure_instructions")); + AsmParser Parser(SrcMgr, Ctx, *Str.get()); return Parser.Run(); }