Index: MC/AsmParser/AltMacroExpression.s =================================================================== --- /dev/null +++ MC/AsmParser/AltMacroExpression.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/MCParser/AsmParser.cpp =================================================================== --- MC/MCParser/AsmParser.cpp +++ MC/MCParser/AsmParser.cpp @@ -486,6 +486,12 @@ bool parseDirectiveMacrosOnOff(StringRef Directive); // alternate macro mode directives bool parseDirectiveAltmacro(StringRef Directive); + void setAltMacroMode() { + getLexer().SetAltMacroMode(true); + } + void unSetAltMacroMode() { + getLexer().SetAltMacroMode(false); + } // ".bundle_align_mode" bool parseDirectiveBundleAlignMode(); // ".bundle_lock" @@ -2273,9 +2279,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(); @@ -2446,13 +2461,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()) { @@ -3850,6 +3881,10 @@ bool AsmParser::parseDirectiveAltmacro(StringRef Directive) { if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '" + Directive + "' directive"); + if (Directive == ".altmacro") + setAltMacroMode(); + else + unSetAltMacroMode(); return false; } 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