diff --git a/llvm/lib/MC/MCParser/MasmParser.cpp b/llvm/lib/MC/MCParser/MasmParser.cpp index a5a48d4b1e9d8..beb8c3af34f9b 100644 --- a/llvm/lib/MC/MCParser/MasmParser.cpp +++ b/llvm/lib/MC/MCParser/MasmParser.cpp @@ -389,7 +389,6 @@ class MasmParser : public MCAsmParser { StringRef Name; RedefinableKind Redefinable = REDEFINABLE; bool IsText = false; - int64_t NumericValue = 0; std::string TextValue; }; StringMap Variables; @@ -796,6 +795,34 @@ class MasmParser : public MCAsmParser { /// def_range types parsed by this class. StringMap CVDefRangeTypeMap; + // Generic (target and platform independent) directive parsing. + enum BuiltinSymbol { + BI_NO_SYMBOL, // Placeholder + BI_DATE, + BI_TIME, + BI_VERSION, + BI_FILECUR, + BI_FILENAME, + BI_LINE, + BI_CURSEG, + BI_CPU, + BI_INTERFACE, + BI_CODE, + BI_DATA, + BI_FARDATA, + BI_WORDSIZE, + BI_CODESIZE, + BI_DATASIZE, + BI_MODEL, + BI_STACK, + }; + + /// Maps builtin name --> BuiltinSymbol enum, for builtins handled by this + /// class. + StringMap BuiltinSymbolMap; + + const MCExpr *evaluateBuiltinValue(BuiltinSymbol Symbol, SMLoc StartLoc); + // ".ascii", ".asciz", ".string" bool parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated); @@ -1019,6 +1046,7 @@ class MasmParser : public MCAsmParser { void initializeDirectiveKindMap(); void initializeCVDefRangeTypeMap(); + void initializeBuiltinSymbolMap(); }; } // end anonymous namespace @@ -1057,6 +1085,7 @@ MasmParser::MasmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, initializeDirectiveKindMap(); PlatformParser->Initialize(*this); initializeCVDefRangeTypeMap(); + initializeBuiltinSymbolMap(); NumOfMacroInstantiations = 0; } @@ -1610,6 +1639,19 @@ bool MasmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc, MCSymbol *Sym = getContext().getInlineAsmLabel(SymbolName); if (!Sym) { + // If this is a built-in numeric value, treat it as a constant. + auto BuiltinIt = BuiltinSymbolMap.find(SymbolName.lower()); + const BuiltinSymbol Symbol = (BuiltinIt == BuiltinSymbolMap.end()) + ? BI_NO_SYMBOL + : BuiltinIt->getValue(); + if (Symbol != BI_NO_SYMBOL) { + const MCExpr *Value = evaluateBuiltinValue(Symbol, FirstTokenLoc); + if (Value) { + Res = Value; + return false; + } + } + // Variables use case-insensitive symbol names; if this is a variable, we // find the symbol using its canonical name. auto VarIt = Variables.find(SymbolName.lower()); @@ -1621,14 +1663,14 @@ bool MasmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc, // If this is an absolute variable reference, substitute it now to preserve // semantics in the face of reassignment. if (Sym->isVariable()) { - auto V = Sym->getVariableValue(/*SetUsed*/ false); + auto V = Sym->getVariableValue(/*SetUsed=*/false); bool DoInline = isa(V) && !Variant; if (auto TV = dyn_cast(V)) DoInline = TV->inlineAssignedExpr(); if (DoInline) { if (Variant) return Error(EndLoc, "unexpected modifier on variable reference"); - Res = Sym->getVariableValue(/*SetUsed*/ false); + Res = Sym->getVariableValue(/*SetUsed=*/false); return false; } } @@ -3377,6 +3419,10 @@ bool MasmParser::parseIdentifier(StringRef &Res, /// | name "textequ" text-list (redefinability unspecified) bool MasmParser::parseDirectiveEquate(StringRef IDVal, StringRef Name, DirectiveKind DirKind, SMLoc NameLoc) { + auto BuiltinIt = BuiltinSymbolMap.find(Name.lower()); + if (BuiltinIt != BuiltinSymbolMap.end()) + return Error(NameLoc, "cannot redefine a built-in symbol"); + Variable &Var = Variables[Name.lower()]; if (Var.Name.empty()) { Var.Name = Name; @@ -3429,12 +3475,18 @@ bool MasmParser::parseDirectiveEquate(StringRef IDVal, StringRef Name, SMLoc EndLoc; if (parseExpression(Expr, EndLoc)) return addErrorSuffix(" in '" + Twine(IDVal) + "' directive"); + StringRef ExprAsString = StringRef( + StartLoc.getPointer(), EndLoc.getPointer() - StartLoc.getPointer()); int64_t Value; if (!Expr->evaluateAsAbsolute(Value, getStreamer().getAssemblerPtr())) { + if (DirKind == DK_ASSIGN) + return Error( + StartLoc, + "expected absolute expression; not all symbols have known values", + {StartLoc, EndLoc}); + // Not an absolute expression; define as a text replacement. - StringRef ExprAsString = StringRef( - StartLoc.getPointer(), EndLoc.getPointer() - StartLoc.getPointer()); if (!Var.IsText || Var.TextValue != ExprAsString) { switch (Var.Redefinable) { case Variable::NOT_REDEFINABLE: @@ -3449,29 +3501,40 @@ bool MasmParser::parseDirectiveEquate(StringRef IDVal, StringRef Name, break; } } + Var.IsText = true; Var.TextValue = ExprAsString.str(); - } else { - if (Var.IsText || Var.NumericValue != Value) { - switch (Var.Redefinable) { - case Variable::NOT_REDEFINABLE: - return Error(getTok().getLoc(), "invalid variable redefinition"); - case Variable::WARN_ON_REDEFINITION: - if (Warning(NameLoc, "redefining '" + Name + - "', already defined on the command line")) { - return true; - } - break; - default: - break; + Var.Redefinable = Variable::REDEFINABLE; + + return false; + } + + MCSymbol *Sym = getContext().getOrCreateSymbol(Var.Name); + + const MCConstantExpr *PrevValue = + Sym->isVariable() ? dyn_cast_or_null( + Sym->getVariableValue(/*SetUsed=*/false)) + : nullptr; + if (Var.IsText || !PrevValue || PrevValue->getValue() != Value) { + switch (Var.Redefinable) { + case Variable::NOT_REDEFINABLE: + return Error(getTok().getLoc(), "invalid variable redefinition"); + case Variable::WARN_ON_REDEFINITION: + if (Warning(NameLoc, "redefining '" + Name + + "', already defined on the command line")) { + return true; } + break; + default: + break; } - Var.NumericValue = Value; } + + Var.IsText = false; + Var.TextValue.clear(); Var.Redefinable = (DirKind == DK_ASSIGN) ? Variable::REDEFINABLE : Variable::NOT_REDEFINABLE; - MCSymbol *Sym = getContext().getOrCreateSymbol(Var.Name); Sym->setRedefinable(Var.Redefinable != Variable::NOT_REDEFINABLE); Sym->setVariableValue(Expr); Sym->setExternal(false); @@ -6181,7 +6244,9 @@ bool MasmParser::parseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined) { parseToken(AsmToken::EndOfStatement, "unexpected token in 'ifdef'")) return true; - if (Variables.find(Name.lower()) != Variables.end()) { + if (BuiltinSymbolMap.find(Name.lower()) != BuiltinSymbolMap.end()) { + is_defined = true; + } else if (Variables.find(Name.lower()) != Variables.end()) { is_defined = true; } else { MCSymbol *Sym = getContext().lookupSymbol(Name.lower()); @@ -6303,7 +6368,9 @@ bool MasmParser::parseDirectiveElseIfdef(SMLoc DirectiveLoc, "unexpected token in 'elseifdef'")) return true; - if (Variables.find(Name.lower()) != Variables.end()) { + if (BuiltinSymbolMap.find(Name.lower()) != BuiltinSymbolMap.end()) { + is_defined = true; + } else if (Variables.find(Name.lower()) != Variables.end()) { is_defined = true; } else { MCSymbol *Sym = getContext().lookupSymbol(Name); @@ -6473,7 +6540,9 @@ bool MasmParser::parseDirectiveErrorIfdef(SMLoc DirectiveLoc, if (check(parseIdentifier(Name), "expected identifier after '.errdef'")) return true; - if (Variables.find(Name.lower()) != Variables.end()) { + if (BuiltinSymbolMap.find(Name.lower()) != BuiltinSymbolMap.end()) { + IsDefined = true; + } else if (Variables.find(Name.lower()) != Variables.end()) { IsDefined = true; } else { MCSymbol *Sym = getContext().lookupSymbol(Name); @@ -7520,6 +7589,58 @@ bool MasmParser::parseMSInlineAsm( return false; } +void MasmParser::initializeBuiltinSymbolMap() { + // Numeric built-ins (supported in all versions) + BuiltinSymbolMap["@version"] = BI_VERSION; + BuiltinSymbolMap["@line"] = BI_LINE; + + // Text built-ins (supported in all versions) + // BuiltinSymbolMap["@date"] = BI_DATE; + // BuiltinSymbolMap["@time"] = BI_TIME; + // BuiltinSymbolMap["@filecur"] = BI_FILECUR; + // BuiltinSymbolMap["@filename"] = BI_FILENAME; + // BuiltinSymbolMap["@curseg"] = BI_CURSEG; + + // Some built-ins exist only for MASM32 (32-bit x86) + if (getContext().getSubtargetInfo()->getTargetTriple().getArch() == + Triple::x86) { + // Numeric built-ins + // BuiltinSymbolMap["@cpu"] = BI_CPU; + // BuiltinSymbolMap["@interface"] = BI_INTERFACE; + // BuiltinSymbolMap["@wordsize"] = BI_WORDSIZE; + // BuiltinSymbolMap["@codesize"] = BI_CODESIZE; + // BuiltinSymbolMap["@datasize"] = BI_DATASIZE; + // BuiltinSymbolMap["@model"] = BI_MODEL; + + // Text built-ins + // BuiltinSymbolMap["@code"] = BI_CODE; + // BuiltinSymbolMap["@data"] = BI_DATA; + // BuiltinSymbolMap["@fardata?"] = BI_FARDATA; + // BuiltinSymbolMap["@stack"] = BI_STACK; + } +} + +const MCExpr *MasmParser::evaluateBuiltinValue(BuiltinSymbol Symbol, + SMLoc StartLoc) { + switch (Symbol) { + default: + return nullptr; + case BI_VERSION: + // Match a recent version of ML.EXE. + return MCConstantExpr::create(1427, getContext()); + case BI_LINE: { + int64_t Line; + if (ActiveMacros.empty()) + Line = SrcMgr.FindLineNumber(StartLoc, CurBuffer); + else + Line = SrcMgr.FindLineNumber(ActiveMacros.front()->InstantiationLoc, + ActiveMacros.front()->ExitBuffer); + return MCConstantExpr::create(Line, getContext()); + } + } + llvm_unreachable("unhandled built-in symbol"); +} + /// Create an MCAsmParser instance. MCAsmParser *llvm::createMCMasmParser(SourceMgr &SM, MCContext &C, MCStreamer &Out, const MCAsmInfo &MAI, diff --git a/llvm/test/tools/llvm-ml/builtin_symbols.asm b/llvm/test/tools/llvm-ml/builtin_symbols.asm new file mode 100644 index 0000000000000..844f9f260cb63 --- /dev/null +++ b/llvm/test/tools/llvm-ml/builtin_symbols.asm @@ -0,0 +1,35 @@ +; RUN: llvm-ml -filetype=s %s /Fo /dev/null 2>&1 | FileCheck %s + +version_val TEXTEQU %@Version + +ECHO t1: +%ECHO @Version = version_val +; CHECK-LABEL: t1: +; CHECK-NEXT: 1427 + +ECHO + +ECHO t2: +if @Version gt 510 +ECHO @Version gt 510 +endif +; CHECK-LABEL: t2: +; CHECK-NEXT: @Version gt 510 + +ECHO + +ECHO t3: +if @Version le 510 +ECHO le 510 +endif +; CHECK-LABEL: t3: +; CHECK-NOT: @Version le 510 + +ECHO + +line_val TEXTEQU %@Line + +ECHO t4: +%ECHO @Line = line_val +; CHECK-LABEL: t4: +; CHECK-NEXT: @Line = [[# @LINE - 5]] diff --git a/llvm/test/tools/llvm-ml/variable_redef_errors.asm b/llvm/test/tools/llvm-ml/variable_redef_errors.asm index c5a0844500ef4..faee829ee0fe7 100644 --- a/llvm/test/tools/llvm-ml/variable_redef_errors.asm +++ b/llvm/test/tools/llvm-ml/variable_redef_errors.asm @@ -7,6 +7,12 @@ equated_number equ 3 ; CHECK: :[[# @LINE + 1]]:21: error: invalid variable redefinition equated_number equ 4 +; CHECK: :[[# @LINE + 1]]:1: error: cannot redefine a built-in symbol +@Line equ 5 + +; CHECK: :[[# @LINE + 1]]:1: error: cannot redefine a built-in symbol +@Version equ 6 + .code end