Index: MC/AsmParser/altmacro_expression.s =================================================================== --- /dev/null +++ MC/AsmParser/altmacro_expression.s @@ -0,0 +1,65 @@ +# RUN: llvm-mc %s| FileCheck %s + +# Checking that the '%' was evaluated as a string first +# In a fail scenario: The asmprint will print: addl $%(1+4), %eax + +# CHECK: addl $5, %eax +.altmacro +.macro percent_expr arg + addl $\arg, %eax +.endm + +percent_expr %(1+4) + + +# Checking that the second '%' acts as modulo operator +# The altmacro percent '%' must be located before the first argument +# If a percent is located in the middle of the estimated argument without any +# '%' in the beginning , error will be generated. +# The second percent '%' after the first altmacro percent '%' is a regular operator. + +#CHECK: addl $1, %eax +.macro inner_percent arg + addl $\arg, %eax +.endm + +inner_percent %(1%4) + + +# Checking for nested macro +# The first argument use is for the calling function and the second use is for the evaluation. + +#CHECK: addl $1, %eax +.macro macro_call_0 number + addl $\number, %eax +.endm + +.macro macro_call_1 number + macro_call_\number %(\number + 1) +.endm + +macro_call_1 %(1-1) + + +# Checking the ability to pass a number of arguments. +# The arguments can be separated by ',' or not. + +#CHECK: label013: +#CHECK: addl $0, %eax +#CHECK: addl $1, %eax +#CHECK: addl $3, %eax + +#CHECK: label014: +#CHECK: addl $0, %eax +#CHECK: addl $1, %eax +#CHECK: addl $4, %eax + +.macro multi_args_macro arg1 arg2 arg3 + label\arg1\arg2\arg3: + addl $\arg1, %eax + addl $\arg2, %eax + addl $\arg3, %eax +.endm + +multi_args_macro %(1+4-5) 1 %2+1 +multi_args_macro %(1+4-5),1,%4%10 Index: MC/AsmParser/negativ_altmacro_expression.s =================================================================== --- /dev/null +++ MC/AsmParser/negativ_altmacro_expression.s @@ -0,0 +1,32 @@ +# RUN: not llvm-mc %s 2>&1 | FileCheck %s + +# This test is a negative test for the altmacro expression. +# In this test we check the '.noaltmacro' directive. +# We expect that '.altmacro' and '.noaltmacro' will act as a switch on/off directives to the alternate macro mode. +# .noaltmacro returns the format into a regular macro handling. + +.altmacro +.noaltmacro +# CHECK: error: unknown token in expression +# CHECK-NEXT: addl $%(1%4), %eax +.macro inner_percent arg + addl $\arg, %eax +.endm + +inner_percent %(1%4) + + # CHECK: multi_args_macro %(1+4-5) 1 %2+1 + # CHECK: error: unknown token in expression + # CHECK-NEXT: addl $%(1+4-5), %eax + + + # CHECK: multi_args_macro %(1+4-5),1,%4%10 + # CHECK: error: unknown token in expression + # CHECK-NEXT: addl $%(1+4-5), %eax + .macro multi_args_macro arg1 arg2 arg3 + label\arg1\arg2\arg3: + addl $\arg1, %eax +.endm + +multi_args_macro %(1+4-5) 1 %2+1 +multi_args_macro %(1+4-5),1,%4%10 Index: MC/MCParser/AsmParser.cpp =================================================================== --- MC/MCParser/AsmParser.cpp +++ MC/MCParser/AsmParser.cpp @@ -412,7 +412,7 @@ DK_CFI_REMEMBER_STATE, DK_CFI_RESTORE_STATE, DK_CFI_SAME_VALUE, DK_CFI_RESTORE, DK_CFI_ESCAPE, DK_CFI_SIGNAL_FRAME, DK_CFI_UNDEFINED, DK_CFI_REGISTER, DK_CFI_WINDOW_SAVE, - DK_MACROS_ON, DK_MACROS_OFF, + DK_MACROS_ON, DK_MACROS_OFF, DK_ALTMACRO, DK_NOALTMACRO, DK_MACRO, DK_EXITM, DK_ENDM, DK_ENDMACRO, DK_PURGEM, DK_SLEB128, DK_ULEB128, DK_ERR, DK_ERROR, DK_WARNING, @@ -484,7 +484,8 @@ bool parseDirectiveEndMacro(StringRef Directive); bool parseDirectiveMacro(SMLoc DirectiveLoc); bool parseDirectiveMacrosOnOff(StringRef Directive); - + // alternate macro mode directives + bool parseDirectiveAltmacro(StringRef Directive); // ".bundle_align_mode" bool parseDirectiveBundleAlignMode(); // ".bundle_lock" @@ -1921,6 +1922,9 @@ return parseDirectiveMacrosOnOff(IDVal); case DK_MACRO: return parseDirectiveMacro(IDLoc); + case DK_ALTMACRO: + case DK_NOALTMACRO: + return parseDirectiveAltmacro(IDVal); case DK_EXITM: return parseDirectiveExitMacro(IDVal); case DK_ENDM: @@ -2269,9 +2273,18 @@ } else { bool VarargParameter = HasVararg && Index == (NParameters - 1); for (const AsmToken &Token : A[Index]) + // For altmacro mode, you can write '%expr'. + // The prefix '%' evaluates the expression 'expr' + // and uses the result as a string (e.g. replace %(1+2) with the string "3"). + // Here, we identify the integer token which is the result of the + // absolute expression evaluation and replace it with its string representation. + if ((Lexer.IsaAltMacroMode()) && + (*(Token.getString().begin()) == '%') && Token.is(AsmToken::Integer)) + // Emit an integer value to the buffer. + OS << Token.getIntVal(); // We expect no quotes around the string's contents when // parsing for varargs. - if (Token.getKind() != AsmToken::String || VarargParameter) + else if (Token.isNot(AsmToken::String) || VarargParameter) OS << Token.getString(); else OS << Token.getStringContents(); @@ -2442,13 +2455,29 @@ NamedParametersFound = true; } + bool Vararg = HasVararg && Parameter == (NParameters - 1); if (NamedParametersFound && FA.Name.empty()) return Error(IDLoc, "cannot mix positional and keyword arguments"); - bool Vararg = HasVararg && Parameter == (NParameters - 1); - if (parseMacroArgument(FA.Value, Vararg)) - return true; + if (Lexer.IsaAltMacroMode() && Lexer.is(AsmToken::Percent)) { + SMLoc StrLoc = Lexer.getLoc(); + SMLoc EndLoc; + const MCExpr *AbsoluteExp; + int64_t Value; + /// Eat '%' + Lex(); + if (parseExpression(AbsoluteExp, EndLoc)) + return false; + if (!AbsoluteExp->evaluateAsAbsolute(Value)) + return Error(StrLoc, "expected absolute expression"); + const char *StrChar = StrLoc.getPointer(); + const char *EndChar = EndLoc.getPointer(); + AsmToken newToken(AsmToken::Integer, StringRef(StrChar , EndChar - StrChar), Value); + FA.Value.push_back(newToken); + } + else if(parseMacroArgument(FA.Value, Vararg)) + return true; unsigned PI = Parameter; if (!FA.Name.empty()) { @@ -3840,6 +3869,19 @@ return false; } +/// parseDirectiveAltmacro +/// ::= .altmacro +/// ::= .noaltmacro +bool AsmParser::parseDirectiveAltmacro(StringRef Directive) { + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '" + Directive + "' directive"); + if (Directive == ".altmacro") + getLexer().SetAltMacroMode(true); + else + getLexer().SetAltMacroMode(false); + return false; +} + /// parseDirectiveMacrosOnOff /// ::= .macros_on /// ::= .macros_off @@ -4937,6 +4979,8 @@ DirectiveKindMap[".err"] = DK_ERR; DirectiveKindMap[".error"] = DK_ERROR; DirectiveKindMap[".warning"] = DK_WARNING; + DirectiveKindMap[".altmacro"] = DK_ALTMACRO; + DirectiveKindMap[".noaltmacro"] = DK_NOALTMACRO; DirectiveKindMap[".reloc"] = DK_RELOC; DirectiveKindMap[".dc"] = DK_DC; DirectiveKindMap[".dc.a"] = DK_DC_A; Index: MC/MCParser/MCAsmLexer.cpp =================================================================== --- MC/MCParser/MCAsmLexer.cpp +++ MC/MCParser/MCAsmLexer.cpp @@ -13,7 +13,7 @@ using namespace llvm; -MCAsmLexer::MCAsmLexer() { +MCAsmLexer::MCAsmLexer() : AltMacroMode(false) { CurTok.emplace_back(AsmToken::Space, StringRef()); } Index: llvm/MC/MCParser/MCAsmLexer.h =================================================================== --- llvm/MC/MCParser/MCAsmLexer.h +++ llvm/MC/MCParser/MCAsmLexer.h @@ -161,6 +161,7 @@ bool IsAtStartOfStatement = true; AsmCommentConsumer *CommentConsumer = nullptr; + bool AltMacroMode; MCAsmLexer(); virtual AsmToken LexToken() = 0; @@ -175,6 +176,14 @@ MCAsmLexer &operator=(const MCAsmLexer &) = delete; virtual ~MCAsmLexer(); + bool IsaAltMacroMode() { + return AltMacroMode; + } + + void SetAltMacroMode(bool AltMacroSet) { + AltMacroMode = AltMacroSet; + } + /// Consume the next token from the input stream and return it. /// /// The lexer will continuosly return the end-of-file token once the end of