[llvm] bf027da - [ms] [llvm-ml] Enable support for MASM-style macro procedures
Eric Astor via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 4 07:30:38 PST 2020
Author: Eric Astor
Date: 2020-11-04T10:29:57-05:00
New Revision: bf027da04c4159fda2403038f9b4a97454a3b625
URL: https://github.com/llvm/llvm-project/commit/bf027da04c4159fda2403038f9b4a97454a3b625
DIFF: https://github.com/llvm/llvm-project/commit/bf027da04c4159fda2403038f9b4a97454a3b625.diff
LOG: [ms] [llvm-ml] Enable support for MASM-style macro procedures
Allows the MACRO directive to define macro procedures with parameters and macro-local symbols.
Supports required and optional parameters (including default values), and matches ml64.exe for its macro-local symbol handling (up to 65536 macro-local symbols in any translation unit).
Reviewed By: thakis
Differential Revision: https://reviews.llvm.org/D89729
Added:
llvm/test/tools/llvm-ml/macro.test
llvm/test/tools/llvm-ml/macro_errors.test
Modified:
llvm/include/llvm/MC/MCAsmMacro.h
llvm/lib/MC/MCAsmMacro.cpp
llvm/lib/MC/MCParser/MasmParser.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/MC/MCAsmMacro.h b/llvm/include/llvm/MC/MCAsmMacro.h
index 7eecce0faf64..1177853fec96 100644
--- a/llvm/include/llvm/MC/MCAsmMacro.h
+++ b/llvm/include/llvm/MC/MCAsmMacro.h
@@ -143,10 +143,14 @@ struct MCAsmMacro {
StringRef Name;
StringRef Body;
MCAsmMacroParameters Parameters;
+ std::vector<std::string> Locals;
public:
MCAsmMacro(StringRef N, StringRef B, MCAsmMacroParameters P)
: Name(N), Body(B), Parameters(std::move(P)) {}
+ MCAsmMacro(StringRef N, StringRef B, MCAsmMacroParameters P,
+ std::vector<std::string> L)
+ : Name(N), Body(B), Parameters(std::move(P)), Locals(std::move(L)) {}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void dump() const { dump(dbgs()); }
diff --git a/llvm/lib/MC/MCAsmMacro.cpp b/llvm/lib/MC/MCAsmMacro.cpp
index 186a68b02a29..bc95f98f2957 100644
--- a/llvm/lib/MC/MCAsmMacro.cpp
+++ b/llvm/lib/MC/MCAsmMacro.cpp
@@ -38,6 +38,11 @@ void MCAsmMacro::dump(raw_ostream &OS) const {
OS << " ";
P.dump();
}
+ if (!Locals.empty()) {
+ OS << " Locals:\n";
+ for (StringRef L : Locals)
+ OS << " " << L << '\n';
+ }
OS << " (BEGIN BODY)" << Body << "(END BODY)\n";
}
#endif
diff --git a/llvm/lib/MC/MCParser/MasmParser.cpp b/llvm/lib/MC/MCParser/MasmParser.cpp
index c574b8715b16..6bddbe6ef50a 100644
--- a/llvm/lib/MC/MCParser/MasmParser.cpp
+++ b/llvm/lib/MC/MCParser/MasmParser.cpp
@@ -51,6 +51,7 @@
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -432,12 +433,12 @@ class MasmParser : public MCAsmParser {
/// Did we already inform the user about inconsistent MD5 usage?
bool ReportedInconsistentMD5 = false;
- // Is alt macro mode enabled.
- bool AltMacroMode = false;
-
// Current <...> expression depth.
unsigned AngleBracketDepth = 0U;
+ // Number of locals defined.
+ uint16_t LocalCounter = 0;
+
public:
MasmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out,
const MCAsmInfo &MAI, unsigned CB);
@@ -541,8 +542,8 @@ class MasmParser : public MCAsmParser {
ArrayRef<MCAsmMacroParameter> Parameters);
bool expandMacro(raw_svector_ostream &OS, StringRef Body,
ArrayRef<MCAsmMacroParameter> Parameters,
- ArrayRef<MCAsmMacroArgument> A, bool EnableAtPseudoVariable,
- SMLoc L);
+ ArrayRef<MCAsmMacroArgument> A,
+ const std::vector<std::string> &Locals, SMLoc L);
/// Are we inside a macro instantiation?
bool isInsideMacroInstantiation() {return !ActiveMacros.empty();}
@@ -706,8 +707,6 @@ class MasmParser : public MCAsmParser {
DK_CFI_REGISTER,
DK_CFI_WINDOW_SAVE,
DK_CFI_B_KEY_FRAME,
- DK_ALTMACRO,
- DK_NOALTMACRO,
DK_MACRO,
DK_EXITM,
DK_ENDM,
@@ -889,9 +888,7 @@ class MasmParser : public MCAsmParser {
bool parseDirectivePurgeMacro(SMLoc DirectiveLoc);
bool parseDirectiveExitMacro(StringRef Directive);
bool parseDirectiveEndMacro(StringRef Directive);
- bool parseDirectiveMacro(SMLoc DirectiveLoc);
- // alternate macro mode directives
- bool parseDirectiveAltmacro(StringRef Directive);
+ bool parseDirectiveMacro(StringRef Name, SMLoc NameLoc);
bool parseDirectiveStruct(StringRef Directive, DirectiveKind DirKind,
StringRef Name, SMLoc NameLoc);
@@ -1615,11 +1612,6 @@ bool MasmParser::parseExpression(const MCExpr *&Res) {
/// If the function returns a 'true' value,
/// the End argument will be filled with the last location pointed to the '>'
/// character.
-
-/// There is a gap between the AltMacro's documentation and the single quote
-/// implementation. GCC does not fully support this feature and so we will not
-/// support it.
-/// TODO: Adding single quote as a string.
static bool isAngleBracketString(SMLoc &StrLoc, SMLoc &EndLoc) {
assert((StrLoc.getPointer() != nullptr) &&
"Argument to the function cannot be a NULL value");
@@ -1638,12 +1630,12 @@ static bool isAngleBracketString(SMLoc &StrLoc, SMLoc &EndLoc) {
}
/// creating a string without the escape characters '!'.
-static std::string angleBracketString(StringRef AltMacroStr) {
+static std::string angleBracketString(StringRef BracketContents) {
std::string Res;
- for (size_t Pos = 0; Pos < AltMacroStr.size(); Pos++) {
- if (AltMacroStr[Pos] == '!')
+ for (size_t Pos = 0; Pos < BracketContents.size(); Pos++) {
+ if (BracketContents[Pos] == '!')
Pos++;
- Res += AltMacroStr[Pos];
+ Res += BracketContents[Pos];
}
return Res;
}
@@ -2252,11 +2244,6 @@ bool MasmParser::parseStatement(ParseStatementInfo &Info,
return parseDirectiveCFIRegister(IDLoc);
case DK_CFI_WINDOW_SAVE:
return parseDirectiveCFIWindowSave();
- case DK_MACRO:
- return parseDirectiveMacro(IDLoc);
- case DK_ALTMACRO:
- case DK_NOALTMACRO:
- return parseDirectiveAltmacro(IDVal);
case DK_EXITM:
return parseDirectiveExitMacro(IDVal);
case DK_ENDM:
@@ -2396,6 +2383,9 @@ bool MasmParser::parseStatement(ParseStatementInfo &Info,
case DK_ENDS:
Lex();
return parseDirectiveEnds(IDVal, IDLoc);
+ case DK_MACRO:
+ Lex();
+ return parseDirectiveMacro(IDVal, IDLoc);
}
// Finally, we check if this is allocating a variable with user-defined type.
@@ -2601,33 +2591,29 @@ static bool isIdentifierChar(char c) {
bool MasmParser::expandMacro(raw_svector_ostream &OS, StringRef Body,
ArrayRef<MCAsmMacroParameter> Parameters,
ArrayRef<MCAsmMacroArgument> A,
- bool EnableAtPseudoVariable, SMLoc L) {
+ const std::vector<std::string> &Locals, SMLoc L) {
unsigned NParameters = Parameters.size();
bool HasVararg = NParameters ? Parameters.back().Vararg : false;
- if ((!IsDarwin || NParameters != 0) && NParameters != A.size())
+ if (NParameters != A.size())
return Error(L, "Wrong number of arguments");
+ StringMap<std::string> LocalSymbols;
+ std::string Name;
+ Name.reserve(6);
+ for (StringRef Local : Locals) {
+ raw_string_ostream LocalName(Name);
+ LocalName << "??"
+ << format_hex_no_prefix(LocalCounter++, 4, /*Upper=*/true);
+ LocalSymbols.insert({Local, LocalName.str()});
+ Name.clear();
+ }
- // A macro without parameters is handled
diff erently 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;
for (; Pos != End; ++Pos) {
- // Check for a substitution or escape.
- if (IsDarwin && !NParameters) {
- // This macro has no parameters, look for $0, $1, etc.
- if (Body[Pos] != '$' || Pos + 1 == End)
- continue;
-
- char Next = Body[Pos + 1];
- if (Next == '$' || Next == 'n' ||
- isdigit(static_cast<unsigned char>(Next)))
- break;
- } else {
- // This macro has parameters, look for \foo, \bar, etc.
- if (Body[Pos] == '\\' && Pos + 1 != End)
- break;
- }
+ // Find the next possible identifier
+ if (Body[Pos] == '&' || isIdentifierChar(Body[Pos]))
+ break;
}
// Add the prefix.
@@ -2637,90 +2623,56 @@ bool MasmParser::expandMacro(raw_svector_ostream &OS, StringRef Body,
if (Pos == End)
break;
- if (IsDarwin && !NParameters) {
- switch (Body[Pos + 1]) {
- // $$ => $
- case '$':
- OS << '$';
- break;
-
- // $n => number of arguments
- case 'n':
- OS << A.size();
- break;
+ unsigned I = Pos;
+ bool InitialAmpersand = (Body[I] == '&');
+ if (InitialAmpersand) {
+ ++I;
+ ++Pos;
+ }
+ while (isIdentifierChar(Body[I]) && I + 1 != End)
+ ++I;
- // $[0-9] => argument
- default: {
- // Missing arguments are ignored.
- unsigned Index = Body[Pos + 1] - '0';
- if (Index >= A.size())
- break;
+ const char *Begin = Body.data() + Pos;
+ StringRef Argument(Begin, I - Pos);
+ unsigned Index = 0;
- // Otherwise substitute with the token values, with spaces eliminated.
- for (const AsmToken &Token : A[Index])
- OS << Token.getString();
+ for (; Index < NParameters; ++Index)
+ if (Parameters[Index].Name == Argument)
break;
- }
- }
- Pos += 2;
- } else {
- unsigned I = Pos + 1;
- // Check for the \@ pseudo-variable.
- if (EnableAtPseudoVariable && Body[I] == '@' && I + 1 != End)
- ++I;
+ if (Index == NParameters) {
+ if (InitialAmpersand)
+ OS << '&';
+ auto it = LocalSymbols.find(Argument.lower());
+ if (it != LocalSymbols.end())
+ OS << it->second;
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;
+ OS << Argument;
+ Pos = I;
+ } else {
+ bool VarargParameter = HasVararg && Index == (NParameters - 1);
+ for (const AsmToken &Token : A[Index]) {
+ // In MASM, 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 (Token.getString().front() == '%' && 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.
+ else if (Token.isNot(AsmToken::String) || VarargParameter)
+ OS << Token.getString();
+ else
+ OS << Token.getStringContents();
+ }
- if (Argument == "@") {
- OS << NumOfMacroInstantiations;
- Pos += 2;
- } else {
- 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;
- }
- } 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();
- }
+ Pos += Argument.size();
+ if (Pos < End && Body[Pos] == '&') {
+ ++Pos;
}
}
// Update the scan point.
@@ -2779,7 +2731,6 @@ class AsmLexerSkipSpaceRAII {
} // end anonymous namespace
bool MasmParser::parseMacroArgument(MCAsmMacroArgument &MA, bool Vararg) {
-
if (Vararg) {
if (Lexer.isNot(AsmToken::EndOfStatement)) {
StringRef Str = parseStringToEndOfStatement();
@@ -2788,6 +2739,17 @@ bool MasmParser::parseMacroArgument(MCAsmMacroArgument &MA, bool Vararg) {
return false;
}
+ SMLoc StrLoc = Lexer.getLoc(), EndLoc;
+ if (Lexer.is(AsmToken::Less) && isAngleBracketString(StrLoc, EndLoc)) {
+ const char *StrChar = StrLoc.getPointer();
+ const char *EndChar = EndLoc.getPointer();
+ jumpToLoc(EndLoc, CurBuffer);
+ /// Eat from '<' to '>'.
+ Lex();
+ MA.emplace_back(AsmToken::String, StringRef(StrChar, EndChar - StrChar));
+ return false;
+ }
+
unsigned ParenLevel = 0;
// Darwin doesn't use spaces to delmit arguments.
@@ -2801,7 +2763,6 @@ bool MasmParser::parseMacroArgument(MCAsmMacroArgument &MA, bool Vararg) {
return TokError("unexpected token in macro instantiation");
if (ParenLevel == 0) {
-
if (Lexer.is(AsmToken::Comma))
break;
@@ -2887,7 +2848,7 @@ bool MasmParser::parseMacroArguments(const MCAsmMacro *M,
SMLoc StrLoc = Lexer.getLoc();
SMLoc EndLoc;
- if (AltMacroMode && Lexer.is(AsmToken::Percent)) {
+ if (Lexer.is(AsmToken::Percent)) {
const MCExpr *AbsoluteExp;
int64_t Value;
/// Eat '%'.
@@ -2902,17 +2863,7 @@ bool MasmParser::parseMacroArguments(const MCAsmMacro *M,
AsmToken newToken(AsmToken::Integer,
StringRef(StrChar, EndChar - StrChar), Value);
FA.Value.push_back(newToken);
- } else if (AltMacroMode && Lexer.is(AsmToken::Less) &&
- isAngleBracketString(StrLoc, EndLoc)) {
- const char *StrChar = StrLoc.getPointer();
- const char *EndChar = EndLoc.getPointer();
- jumpToLoc(EndLoc, CurBuffer);
- /// Eat from '<' to '>'.
- Lex();
- AsmToken newToken(AsmToken::String,
- StringRef(StrChar, EndChar - StrChar));
- FA.Value.push_back(newToken);
- } else if(parseMacroArgument(FA.Value, Vararg))
+ } else if (parseMacroArgument(FA.Value, Vararg))
return true;
unsigned PI = Parameter;
@@ -2992,12 +2943,12 @@ bool MasmParser::handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc) {
StringRef Body = M->Body;
raw_svector_ostream OS(Buf);
- if (expandMacro(OS, Body, M->Parameters, A, true, getTok().getLoc()))
+ if (expandMacro(OS, Body, M->Parameters, A, M->Locals, getTok().getLoc()))
return true;
- // We include the .endmacro in the buffer as our cue to exit the macro
+ // We include the endm in the buffer as our cue to exit the macro
// instantiation.
- OS << ".endmacro\n";
+ OS << "endm\n";
std::unique_ptr<MemoryBuffer> Instantiation =
MemoryBuffer::getMemBufferCopy(OS.str(), "<instantiation>");
@@ -5312,76 +5263,60 @@ bool MasmParser::parseDirectiveCFIUndefined(SMLoc DirectiveLoc) {
return false;
}
-/// parseDirectiveAltmacro
-/// ::= .altmacro
-/// ::= .noaltmacro
-bool MasmParser::parseDirectiveAltmacro(StringRef Directive) {
- if (getLexer().isNot(AsmToken::EndOfStatement))
- return TokError("unexpected token in '" + Directive + "' directive");
- AltMacroMode = (Directive == ".altmacro");
- return false;
-}
-
/// parseDirectiveMacro
-/// ::= .macro name[,] [parameters]
-bool MasmParser::parseDirectiveMacro(SMLoc DirectiveLoc) {
- StringRef Name;
- if (parseIdentifier(Name))
- return TokError("expected identifier in '.macro' directive");
-
- if (getLexer().is(AsmToken::Comma))
- Lex();
-
+/// ::= name macro [parameters]
+/// ["LOCAL" identifiers]
+/// parameters ::= parameter [, parameter]*
+/// parameter ::= name ":" qualifier
+/// qualifier ::= "req" | "vararg" | "=" macro_argument
+bool MasmParser::parseDirectiveMacro(StringRef Name, SMLoc NameLoc) {
MCAsmMacroParameters Parameters;
while (getLexer().isNot(AsmToken::EndOfStatement)) {
-
if (!Parameters.empty() && Parameters.back().Vararg)
return Error(Lexer.getLoc(),
"Vararg parameter '" + Parameters.back().Name +
- "' should be last one in the list of parameters.");
+ "' should be last in the list of parameters");
MCAsmMacroParameter Parameter;
if (parseIdentifier(Parameter.Name))
- return TokError("expected identifier in '.macro' directive");
+ return TokError("expected identifier in 'macro' directive");
// Emit an error if two (or more) named parameters share the same name.
for (const MCAsmMacroParameter& CurrParam : Parameters)
- if (CurrParam.Name.equals(Parameter.Name))
+ if (CurrParam.Name.equals_lower(Parameter.Name))
return TokError("macro '" + Name + "' has multiple parameters"
" named '" + Parameter.Name + "'");
if (Lexer.is(AsmToken::Colon)) {
Lex(); // consume ':'
- SMLoc QualLoc;
- StringRef Qualifier;
+ if (parseOptionalToken(AsmToken::Equal)) {
+ // Default value
+ SMLoc ParamLoc;
- QualLoc = Lexer.getLoc();
- if (parseIdentifier(Qualifier))
- return Error(QualLoc, "missing parameter qualifier for "
- "'" + Parameter.Name + "' in macro '" + Name + "'");
-
- if (Qualifier == "req")
- Parameter.Required = true;
- else if (Qualifier == "vararg")
- Parameter.Vararg = true;
- else
- return Error(QualLoc, Qualifier + " is not a valid parameter qualifier "
- "for '" + Parameter.Name + "' in macro '" + Name + "'");
- }
-
- if (getLexer().is(AsmToken::Equal)) {
- Lex();
-
- SMLoc ParamLoc;
-
- ParamLoc = Lexer.getLoc();
- if (parseMacroArgument(Parameter.Value, /*Vararg=*/false ))
- return true;
-
- if (Parameter.Required)
- Warning(ParamLoc, "pointless default value for required parameter "
- "'" + Parameter.Name + "' in macro '" + Name + "'");
+ ParamLoc = Lexer.getLoc();
+ if (parseMacroArgument(Parameter.Value, /*Vararg=*/false))
+ return true;
+ } else {
+ SMLoc QualLoc;
+ StringRef Qualifier;
+
+ QualLoc = Lexer.getLoc();
+ if (parseIdentifier(Qualifier))
+ return Error(QualLoc, "missing parameter qualifier for "
+ "'" +
+ Parameter.Name + "' in macro '" + Name +
+ "'");
+
+ if (Qualifier.equals_lower("req"))
+ Parameter.Required = true;
+ else if (Qualifier.equals_lower("vararg"))
+ Parameter.Vararg = true;
+ else
+ return Error(QualLoc,
+ Qualifier + " is not a valid parameter qualifier for '" +
+ Parameter.Name + "' in macro '" + Name + "'");
+ }
}
Parameters.push_back(std::move(Parameter));
@@ -5393,6 +5328,24 @@ bool MasmParser::parseDirectiveMacro(SMLoc DirectiveLoc) {
// Eat just the end of statement.
Lexer.Lex();
+ std::vector<std::string> Locals;
+ if (getTok().is(AsmToken::Identifier) &&
+ getTok().getIdentifier().equals_lower("local")) {
+ Lex(); // Eat the LOCAL directive.
+
+ StringRef ID;
+ while (true) {
+ if (parseIdentifier(ID))
+ return true;
+ Locals.push_back(ID.lower());
+
+ // If we see a comma, continue (and allow line continuation).
+ if (!parseOptionalToken(AsmToken::Comma))
+ break;
+ parseOptionalToken(AsmToken::EndOfStatement);
+ }
+ }
+
// Consuming deferred text, so use Lexer.Lex to ignore Lexing Errors.
AsmToken EndToken, StartToken = getTok();
unsigned MacroDepth = 0;
@@ -5405,12 +5358,11 @@ bool MasmParser::parseDirectiveMacro(SMLoc DirectiveLoc) {
// Check whether we have reached the end of the file.
if (getLexer().is(AsmToken::Eof))
- return Error(DirectiveLoc, "no matching '.endmacro' in definition");
+ return Error(NameLoc, "no matching 'endm' in definition");
- // Otherwise, check whether we have reach the .endmacro.
+ // Otherwise, check whether we have reach the 'endm'.
if (getLexer().is(AsmToken::Identifier)) {
- if (getTok().getIdentifier() == ".endm" ||
- getTok().getIdentifier() == ".endmacro") {
+ if (getTok().getIdentifier().equals_lower("endm")) {
if (MacroDepth == 0) { // Outermost macro.
EndToken = getTok();
Lexer.Lex();
@@ -5422,10 +5374,14 @@ bool MasmParser::parseDirectiveMacro(SMLoc DirectiveLoc) {
// Otherwise we just found the end of an inner macro.
--MacroDepth;
}
- } else if (getTok().getIdentifier() == ".macro") {
- // We allow nested macros. Those aren't instantiated until the outermost
- // macro is expanded so just ignore them for now.
- ++MacroDepth;
+ } else {
+ const AsmToken NextTok = getLexer().peekTok();
+ if (NextTok.is(AsmToken::Identifier) &&
+ NextTok.getIdentifier().equals_lower("macro")) {
+ // We allow nested macros. Those aren't instantiated until the
+ // outermost macro is expanded so just ignore them for now.
+ ++MacroDepth;
+ }
}
}
@@ -5434,14 +5390,14 @@ bool MasmParser::parseDirectiveMacro(SMLoc DirectiveLoc) {
}
if (getContext().lookupMacro(Name)) {
- return Error(DirectiveLoc, "macro '" + Name + "' is already defined");
+ return Error(NameLoc, "macro '" + Name + "' is already defined");
}
const char *BodyStart = StartToken.getLoc().getPointer();
const char *BodyEnd = EndToken.getLoc().getPointer();
StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart);
- checkForBadMacro(DirectiveLoc, Name, Body, Parameters);
- MCAsmMacro Macro(Name, Body, std::move(Parameters));
+ checkForBadMacro(NameLoc, Name, Body, Parameters);
+ MCAsmMacro Macro(Name, Body, std::move(Parameters), std::move(Locals));
DEBUG_WITH_TYPE("asm-macros", dbgs() << "Defining new macro:\n";
Macro.dump());
getContext().defineMacro(Name, std::move(Macro));
@@ -5551,7 +5507,7 @@ void MasmParser::checkForBadMacro(SMLoc DirectiveLoc, StringRef Name,
}
/// parseDirectiveExitMacro
-/// ::= .exitm
+/// ::= exitm
bool MasmParser::parseDirectiveExitMacro(StringRef Directive) {
if (parseToken(AsmToken::EndOfStatement,
"unexpected token in '" + Directive + "' directive"))
@@ -6365,9 +6321,9 @@ void MasmParser::initializeDirectiveKindMap() {
// DirectiveKindMap[".cfi_register"] = DK_CFI_REGISTER;
// DirectiveKindMap[".cfi_window_save"] = DK_CFI_WINDOW_SAVE;
// DirectiveKindMap[".cfi_b_key_frame"] = DK_CFI_B_KEY_FRAME;
- // DirectiveKindMap[".macro"] = DK_MACRO;
- // DirectiveKindMap[".exitm"] = DK_EXITM;
- // DirectiveKindMap[".endm"] = DK_ENDM;
+ DirectiveKindMap["macro"] = DK_MACRO;
+ DirectiveKindMap["exitm"] = DK_EXITM;
+ DirectiveKindMap["endm"] = DK_ENDM;
// DirectiveKindMap[".purgem"] = DK_PURGEM;
DirectiveKindMap[".err"] = DK_ERR;
DirectiveKindMap[".errb"] = DK_ERRB;
@@ -6386,8 +6342,6 @@ void MasmParser::initializeDirectiveKindMap() {
DirectiveKindMap[".savexmm128"] = DK_SAVEXMM128;
DirectiveKindMap[".setframe"] = DK_SETFRAME;
DirectiveKindMap[".radix"] = DK_RADIX;
- // DirectiveKindMap[".altmacro"] = DK_ALTMACRO;
- // DirectiveKindMap[".noaltmacro"] = DK_NOALTMACRO;
DirectiveKindMap["db"] = DK_DB;
DirectiveKindMap["dd"] = DK_DD;
DirectiveKindMap["df"] = DK_DF;
@@ -6494,8 +6448,7 @@ bool MasmParser::parseDirectiveRept(SMLoc DirectiveLoc, StringRef Dir) {
SmallString<256> Buf;
raw_svector_ostream OS(Buf);
while (Count--) {
- // Note that the AtPseudoVariable is disabled for instantiations of .rep(t).
- if (expandMacro(OS, M->Body, None, None, false, getTok().getLoc()))
+ if (expandMacro(OS, M->Body, None, None, M->Locals, getTok().getLoc()))
return true;
}
instantiateMacroLikeBody(M, DirectiveLoc, OS);
@@ -6526,9 +6479,7 @@ bool MasmParser::parseDirectiveIrp(SMLoc DirectiveLoc) {
raw_svector_ostream OS(Buf);
for (const MCAsmMacroArgument &Arg : A) {
- // 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, Arg, true, getTok().getLoc()))
+ if (expandMacro(OS, M->Body, Parameter, Arg, M->Locals, getTok().getLoc()))
return true;
}
@@ -6571,9 +6522,7 @@ bool MasmParser::parseDirectiveIrpc(SMLoc DirectiveLoc) {
MCAsmMacroArgument Arg;
Arg.emplace_back(AsmToken::Identifier, Values.slice(I, I + 1));
- // 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()))
+ if (expandMacro(OS, M->Body, Parameter, Arg, M->Locals, getTok().getLoc()))
return true;
}
diff --git a/llvm/test/tools/llvm-ml/macro.test b/llvm/test/tools/llvm-ml/macro.test
new file mode 100644
index 000000000000..1703ae3d0b0f
--- /dev/null
+++ b/llvm/test/tools/llvm-ml/macro.test
@@ -0,0 +1,106 @@
+; RUN: llvm-ml -m64 -filetype=asm %s | FileCheck %s
+
+.data
+
+x1 DWORD ?
+x2 DWORD ?
+xa1 DWORD ?
+
+.code
+
+substitution_macro macro a1:req, a2:=<7>
+ mov eax, a1
+ mov eax, a1&
+ mov eax, &a1
+ mov eax, &a1&
+
+ mov eax, xa1
+ mov eax, x&a1
+ mov eax, x&a1&
+
+ mov eax, a2
+ mov eax, a2&
+ mov eax, &a2
+ mov eax, &a2&
+endm
+
+substitution_test_with_default PROC
+; CHECK-LABEL: substitution_test_with_default:
+
+ substitution_macro 1
+; CHECK: mov eax, 1
+; CHECK-NEXT: mov eax, 1
+; CHECK-NEXT: mov eax, 1
+; CHECK-NEXT: mov eax, 1
+; CHECK: mov eax, dword ptr [rip + xa1]
+; CHECK-NEXT: mov eax, dword ptr [rip + x1]
+; CHECK-NEXT: mov eax, dword ptr [rip + x1]
+; CHECK: mov eax, 7
+; CHECK-NEXT: mov eax, 7
+; CHECK-NEXT: mov eax, 7
+; CHECK-NEXT: mov eax, 7
+
+ ret
+substitution_test_with_default ENDP
+
+substitution_test_with_value PROC
+; CHECK-LABEL: substitution_test_with_value:
+
+ substitution_macro 2, 8
+; CHECK: mov eax, 2
+; CHECK-NEXT: mov eax, 2
+; CHECK-NEXT: mov eax, 2
+; CHECK-NEXT: mov eax, 2
+; CHECK: mov eax, dword ptr [rip + xa1]
+; CHECK-NEXT: mov eax, dword ptr [rip + x2]
+; CHECK-NEXT: mov eax, dword ptr [rip + x2]
+; CHECK: mov eax, 8
+; CHECK-NEXT: mov eax, 8
+; CHECK-NEXT: mov eax, 8
+; CHECK-NEXT: mov eax, 8
+
+ ret
+substitution_test_with_value ENDP
+
+optional_parameter_macro MACRO a1:req, a2
+ mov eax, a1
+IFNB <a2>
+ mov eax, a2
+ENDIF
+ ret
+ENDM
+
+optional_parameter_test PROC
+; CHECK-LABEL: optional_parameter_test:
+
+ optional_parameter_macro 4
+; CHECK: mov eax, 4
+; CHECK: ret
+
+ optional_parameter_macro 5, 9
+; CHECK: mov eax, 5
+; CHECK: mov eax, 9
+; CHECK: ret
+optional_parameter_test ENDP
+
+local_symbol_macro MACRO
+ LOCAL a
+a: ret
+ jmp a
+ENDM
+
+local_symbol_test PROC
+; CHECK-LABEL: local_symbol_test:
+
+ local_symbol_macro
+; CHECK: "??0000":
+; CHECK-NEXT: ret
+; CHECK-NEXT: jmp "??0000"
+
+ local_symbol_macro
+; CHECK: "??0001":
+; CHECK-NEXT: ret
+; CHECK-NEXT: jmp "??0001"
+local_symbol_test ENDP
+
+END
diff --git a/llvm/test/tools/llvm-ml/macro_errors.test b/llvm/test/tools/llvm-ml/macro_errors.test
new file mode 100644
index 000000000000..d5ef5c903b00
--- /dev/null
+++ b/llvm/test/tools/llvm-ml/macro_errors.test
@@ -0,0 +1,24 @@
+; RUN: not llvm-ml -filetype=asm %s 2>&1 | FileCheck %s --implicit-check-not=error:
+
+.code
+
+; CHECK: error: Vararg parameter 'param' should be last in the list of parameters
+; CHECK: error: unexpected 'ENDM' in file, no current macro definition
+early_vararg_macro MACRO param:vararg, trailing_param
+ENDM
+
+; CHECK: error: macro 'colliding_parameters_macro' has multiple parameters named 'paRAM'
+; CHECK: error: unexpected 'ENDM' in file, no current macro definition
+colliding_parameters_macro MACRO Param, paRAM
+ENDM
+
+; CHECK: error: missing parameter qualifier for 'param' in macro 'missing_qualifier_macro'
+; CHECK: error: unexpected 'ENDM' in file, no current macro definition
+missing_qualifier_macro MACRO param:
+ENDM
+
+
+; CHECK: error: no matching 'endm' in definition
+missing_end_macro MACRO
+
+end
More information about the llvm-commits
mailing list