diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -2497,11 +2497,15 @@ if ((!IsDarwin || NParameters != 0) && NParameters != A.size()) return Error(L, "Wrong number of arguments"); + enum TokenKind { ArgU, AltLocalArg, AltLocalArgU } K; + StringRef LocalArgument; + StringMap LocalSyms; // A macro without parameters is handled differently on Darwin: // gas accepts no arguments and does no substitutions while (!Body.empty()) { // Scan for the next substitution. std::size_t End = Body.size(), Pos = 0; + K = ArgU; for (; Pos != End; ++Pos) { // Check for a substitution or escape. if (IsDarwin && !NParameters) { @@ -2518,103 +2522,152 @@ if (Body[Pos] == '\\' && Pos + 1 != End) break; } + // Handles LOCAL directives in alternative macro mode. + if (AltMacroMode) { + if ((Pos == 0 || !isIdentifierChar(Body[Pos - 1])) && Pos + 6 < End && + Body.substr(Pos, 6) == "LOCAL ") + K = AltLocalArg; + else { + for (const auto &Sym : LocalSyms) { + size_t S = Sym.first().size(); + std::size_t E = Pos + S; + if ((Sym.first() == Body.substr(Pos, S)) && + (Pos == 0 || !isIdentifierChar(Body[Pos - 1])) && + (E >= End || !isIdentifierChar(Body[E]))) { + K = AltLocalArgU; + LocalArgument = Sym.first(); + break; + } + } + } + if (K != ArgU) + break; + } } + if (K == ArgU) { + // Add the prefix. + OS << Body.slice(0, Pos); - // Add the prefix. - OS << Body.slice(0, Pos); - - // Check if we reached the end. - if (Pos == End) - break; - - if (IsDarwin && !NParameters) { - switch (Body[Pos + 1]) { - // $$ => $ - case '$': - OS << '$'; + // Check if we reached the end. + if (Pos == End) break; - // $n => number of arguments - case 'n': - OS << A.size(); - break; - - // $[0-9] => argument - default: { - // Missing arguments are ignored. - unsigned Index = Body[Pos + 1] - '0'; - if (Index >= A.size()) + if (IsDarwin && !NParameters) { + switch (Body[Pos + 1]) { + // $$ => $ + case '$': + OS << '$'; break; - // Otherwise substitute with the token values, with spaces eliminated. - for (const AsmToken &Token : A[Index]) - OS << Token.getString(); - break; - } - } - Pos += 2; - } else { - unsigned I = Pos + 1; - - // Check for the \@ pseudo-variable. - if (EnableAtPseudoVariable && Body[I] == '@' && I + 1 != End) - ++I; - else - while (isIdentifierChar(Body[I]) && I + 1 != End) - ++I; + // $n => number of arguments + case 'n': + OS << A.size(); + break; - const char *Begin = Body.data() + Pos + 1; - StringRef Argument(Begin, I - (Pos + 1)); - unsigned Index = 0; + // $[0-9] => argument + default: { + // Missing arguments are ignored. + unsigned Index = Body[Pos + 1] - '0'; + if (Index >= A.size()) + break; - if (Argument == "@") { - OS << NumOfMacroInstantiations; + // Otherwise substitute with the token values, with spaces eliminated. + for (const AsmToken &Token : A[Index]) + OS << Token.getString(); + break; + } + } Pos += 2; } else { - for (; Index < NParameters; ++Index) - if (Parameters[Index].Name == Argument) - break; + unsigned I = Pos + 1; - if (Index == NParameters) { - if (Body[Pos + 1] == '(' && Body[Pos + 2] == ')') - Pos += 3; - else { - OS << '\\' << Argument; - Pos = I; - } + // 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; + + if (Argument == "@") { + OS << NumOfMacroInstantiations; + Pos += 2; } 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 (AltMacroMode && Token.getString().front() == '%' && - Token.is(AsmToken::Integer)) - // Emit an integer value to the buffer. - OS << Token.getIntVal(); - // Only Token that was validated as a string and begins with '<' - // is considered altMacroString!!! - else if (AltMacroMode && Token.getString().front() == '<' && - Token.is(AsmToken::String)) { - OS << angleBracketString(Token.getStringContents()); + 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; } - // We expect no quotes around the string's contents when - // parsing for varargs. - else if (Token.isNot(AsmToken::String) || VarargParameter) - OS << Token.getString(); - else - OS << Token.getStringContents(); - - Pos += 1 + Argument.size(); + } 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 (AltMacroMode && Token.getString().front() == '%' && + Token.is(AsmToken::Integer)) + // Emit an integer value to the buffer. + OS << Token.getIntVal(); + // Only Token that was validated as a string and begins with '<' + // is considered altMacroString!!! + else if (AltMacroMode && Token.getString().front() == '<' && + Token.is(AsmToken::String)) { + OS << angleBracketString(Token.getStringContents()); + } + // We expect no quotes around the string's contents when + // parsing for varargs. + else if (Token.isNot(AsmToken::String) || VarargParameter) + OS << Token.getString(); + else + OS << Token.getStringContents(); + + Pos += 1 + Argument.size(); + } } } + // Update the scan point. + Body = Body.substr(Pos); + } else if (K == AltLocalArg) { + // Get arguments to the current LOCAL directive + std::size_t I = Pos + 6; + std::size_t E = Body.find('\n', I); + while (I < E) { + while (I < E && !isIdentifierChar(Body[I])) + ++I; + std::size_t B = I; + while (I < E && isIdentifierChar(Body[I])) + ++I; + std::string Sym(Body.data() + B, I - B); + if (LocalSyms.find(Sym) != LocalSyms.end()) + return Error( + L, Sym + " was already used as an argument to a LOCAL directive"); + std::string LocalSym; + do { + static unsigned LocalCnt = 0; + LocalSym = ".LL" + std::to_string(LocalCnt++); + } while (getContext().lookupSymbol(LocalSym)); + LocalSyms[Sym] = LocalSym; + } + OS << Body.slice(0, Pos); + // Update the scan point. + Body = Body.substr(E + 1); + } else { + OS << Body.slice(0, Pos) << LocalSyms[LocalArgument]; + Body = Body.substr(Pos + LocalArgument.size()); } - // Update the scan point. - Body = Body.substr(Pos); } return false; diff --git a/llvm/test/MC/AsmParser/directive_local_alt_macro_mode.s b/llvm/test/MC/AsmParser/directive_local_alt_macro_mode.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/AsmParser/directive_local_alt_macro_mode.s @@ -0,0 +1,44 @@ +// RUN: llvm-mc -triple i386 -filetype=asm %s | FileCheck %s +// RUN: not llvm-mc -triple i386 -filetype=asm --defsym ERR=1 %s -o /dev/null 2>&1 | FileCheck --check-prefix=ERR %s + +.altmacro + +.macro write arg +LOCAL x,y +.set x, \arg +.set y, \arg +.set z, \arg +LOCAL z +.endm + +.macro read +LOCAL foo +foo: +mov x, %eax +mov y, %ebx +mov z, %ecx +jmp foo +.endm + +.macro err +LOCAL x,y +LOCAL x +.endm + +write 16 +read +.ifdef ERR +err +// ERR:[[#@LINE-1]]:4: error: x was already used as an argument to a LOCAL directive +.endif + + +// CHECK: .set .LL0, 16 +// CHECK-NEXT: .set .LL1, 16 +// CHECK-NEXT: .set z, 16 +// CHECK-EMPTY: +// CHECK-NEXT: .LL3: +// CHECK-NEXT: movl x, %eax +// CHECK-NEXT: movl y, %ebx +// CHECK-NEXT: movl 16, %ecx +// CHECK-NEXT: jmp .LL3