diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index 12b9cf561a8..fe8b8844366 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -147,6 +147,9 @@ private: /// Boolean tracking whether macro substitution is enabled. unsigned MacrosEnabledFlag : 1; + /// \brief Keeps track of how many .macro's have been instantiated. + unsigned NumOfMacroInstantiations; + /// Flag tracking whether any errors have been encountered. unsigned HadError : 1; @@ -251,7 +254,7 @@ private: ArrayRef Parameters); bool expandMacro(raw_svector_ostream &OS, StringRef Body, ArrayRef Parameters, - ArrayRef A, + ArrayRef A, bool EnableAtPseudoVariable, const SMLoc &L); /// \brief Are macros enabled in the parser? @@ -519,6 +522,8 @@ AsmParser::AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, PlatformParser->Initialize(*this); initializeDirectiveKindMap(); + + NumOfMacroInstantiations = 0; } AsmParser::~AsmParser() { @@ -1764,7 +1769,8 @@ static bool isIdentifierChar(char c) { bool AsmParser::expandMacro(raw_svector_ostream &OS, StringRef Body, ArrayRef Parameters, - ArrayRef A, const SMLoc &L) { + ArrayRef A, + bool EnableAtPseudoVariable, const SMLoc &L) { unsigned NParameters = Parameters.size(); bool HasVararg = NParameters ? Parameters.back().Vararg : false; if ((!IsDarwin || NParameters != 0) && NParameters != A.size()) @@ -1830,36 +1836,47 @@ bool AsmParser::expandMacro(raw_svector_ostream &OS, StringRef Body, Pos += 2; } else { unsigned I = Pos + 1; - while (isIdentifierChar(Body[I]) && I + 1 != End) + + // Check for the \@ pseudo-variable. + if (EnableAtPseudoVariable && Body[I] == '@' && I + 1 != End) ++I; + else + while (isIdentifierChar(Body[I]) && I + 1 != End) + ++I; const char *Begin = Body.data() + Pos + 1; StringRef Argument(Begin, I - (Pos + 1)); unsigned Index = 0; - for (; Index < NParameters; ++Index) - if (Parameters[Index].Name == Argument) - break; - if (Index == NParameters) { - if (Body[Pos + 1] == '(' && Body[Pos + 2] == ')') - Pos += 3; - else { - OS << '\\' << Argument; - Pos = I; - } + if (Argument == "@") { + OS << NumOfMacroInstantiations; + Pos += 2; } else { - bool VarargParameter = HasVararg && Index == (NParameters - 1); - for (MCAsmMacroArgument::const_iterator it = A[Index].begin(), - ie = A[Index].end(); - it != ie; ++it) - // We expect no quotes around the string's contents when - // parsing for varargs. - if (it->getKind() != AsmToken::String || VarargParameter) - OS << it->getString(); - else - OS << it->getStringContents(); + for (; Index < NParameters; ++Index) + if (Parameters[Index].Name == Argument) + break; - Pos += 1 + Argument.size(); + if (Index == NParameters) { + if (Body[Pos + 1] == '(' && Body[Pos + 2] == ')') + Pos += 3; + else { + OS << '\\' << Argument; + Pos = I; + } + } else { + bool VarargParameter = HasVararg && Index == (NParameters - 1); + for (MCAsmMacroArgument::const_iterator it = A[Index].begin(), + ie = A[Index].end(); + it != ie; ++it) + // We expect no quotes around the string's contents when + // parsing for varargs. + if (it->getKind() != AsmToken::String || VarargParameter) + OS << it->getString(); + else + OS << it->getStringContents(); + + Pos += 1 + Argument.size(); + } } } // Update the scan point. @@ -2117,7 +2134,7 @@ bool AsmParser::handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc) { StringRef Body = M->Body; raw_svector_ostream OS(Buf); - if (expandMacro(OS, Body, M->Parameters, A, getTok().getLoc())) + if (expandMacro(OS, Body, M->Parameters, A, true, getTok().getLoc())) return true; // We include the .endmacro in the buffer as our cue to exit the macro @@ -2133,6 +2150,8 @@ bool AsmParser::handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc) { NameLoc, CurBuffer, getTok().getLoc(), TheCondStack.size()); ActiveMacros.push_back(MI); + ++NumOfMacroInstantiations; + // Jump to the macro instantiation and prime the lexer. CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation), SMLoc()); Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer()); @@ -4378,7 +4397,8 @@ bool AsmParser::parseDirectiveRept(SMLoc DirectiveLoc, StringRef Dir) { SmallString<256> Buf; raw_svector_ostream OS(Buf); while (Count--) { - if (expandMacro(OS, M->Body, None, None, getTok().getLoc())) + // Note that the AtPseudoVariable is disabled for instantiations of .rep(t). + if (expandMacro(OS, M->Body, None, None, false, getTok().getLoc())) return true; } instantiateMacroLikeBody(M, DirectiveLoc, OS); @@ -4417,7 +4437,9 @@ bool AsmParser::parseDirectiveIrp(SMLoc DirectiveLoc) { raw_svector_ostream OS(Buf); for (MCAsmMacroArguments::iterator i = A.begin(), e = A.end(); i != e; ++i) { - if (expandMacro(OS, M->Body, Parameter, *i, getTok().getLoc())) + // Note that the AtPseudoVariable is enabled for instantiations of .irp. + // This is undocumented, but GAS seems to support it. + if (expandMacro(OS, M->Body, Parameter, *i, true, getTok().getLoc())) return true; } @@ -4464,7 +4486,9 @@ bool AsmParser::parseDirectiveIrpc(SMLoc DirectiveLoc) { MCAsmMacroArgument Arg; Arg.push_back(AsmToken(AsmToken::Identifier, Values.slice(I, I + 1))); - if (expandMacro(OS, M->Body, Parameter, Arg, getTok().getLoc())) + // Note that the AtPseudoVariable is enabled for instantiations of .irpc. + // This is undocumented, but GAS seems to support it. + if (expandMacro(OS, M->Body, Parameter, Arg, true, getTok().getLoc())) return true; } diff --git a/test/MC/AsmParser/at-pseudo-variable-bad.s b/test/MC/AsmParser/at-pseudo-variable-bad.s new file mode 100644 index 00000000000..885f18b2d4f --- /dev/null +++ b/test/MC/AsmParser/at-pseudo-variable-bad.s @@ -0,0 +1,23 @@ +# RUN: not llvm-mc -triple i386-unknown-unknown < %s 2>&1 | FileCheck %s + +add $1\@, %eax +# CHECK: :[[@LINE-1]]:8: error: unexpected token in argument list + +.macro A @ + mov %eax, %eax +.endm +# CHECK: :[[@LINE-3]]:11: error: expected identifier in '.macro' directive + +.rept 2 + addi $8, $8, \@ +.endr +# CHECK: error: unknown token in expression +# CHECK: :[[@LINE-4]]:1: note: while in macro instantiation +# CHECK-NEXT: .rept 2 + +.rep 3 + addi $9, $9, \@ +.endr +# CHECK: error: unknown token in expression +# CHECK: :[[@LINE-4]]:1: note: while in macro instantiation +# CHECK-NEXT: .rep 3 diff --git a/test/MC/AsmParser/at-pseudo-variable.s b/test/MC/AsmParser/at-pseudo-variable.s new file mode 100644 index 00000000000..b0966e13717 --- /dev/null +++ b/test/MC/AsmParser/at-pseudo-variable.s @@ -0,0 +1,64 @@ +# RUN: llvm-mc -triple i386-unknown-unknown %s | FileCheck %s + +.macro A + add $1\@, %eax +.endm + +.macro B + sub $1\@, %eax +.endm + + A +# CHECK: addl $10, %eax + A +# CHECK: addl $11, %eax + B +# CHECK: subl $12, %eax + B +# CHECK: subl $13, %eax + +# The following uses of \@ are undocumented, but valid: +.irpc foo,234 + add $\foo\@, %eax +.endr +# CHECK: addl $24, %eax +# CHECK: addl $34, %eax +# CHECK: addl $44, %eax + +.irp reg,%eax,%ebx + sub $2\@, \reg +.endr +# CHECK: subl $24, %eax +# CHECK: subl $24, %ebx + +# Test that .irp(c) and .rep(t) do not increase \@. +# Only the use of A should increase \@, so we can test that it increases by 1 +# each time. + +.irpc foo,123 + sub $\foo, %eax +.endr + + A +# CHECK: addl $14, %eax + +.irp reg,%eax,%ebx + sub $4, \reg +.endr + + A +# CHECK: addl $15, %eax + +.rept 2 + sub $5, %eax +.endr + + A +# CHECK: addl $16, %eax + +.rep 3 + sub $6, %eax +.endr + + A +# CHECK: addl $17, %eax