diff --git a/llvm/lib/MC/MCParser/MasmParser.cpp b/llvm/lib/MC/MCParser/MasmParser.cpp --- a/llvm/lib/MC/MCParser/MasmParser.cpp +++ b/llvm/lib/MC/MCParser/MasmParser.cpp @@ -389,7 +389,6 @@ StringRef Name; RedefinableKind Redefinable = REDEFINABLE; bool IsText = false; - int64_t NumericValue = 0; std::string TextValue; }; StringMap Variables; @@ -794,6 +793,34 @@ /// 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); @@ -1017,6 +1044,7 @@ void initializeDirectiveKindMap(); void initializeCVDefRangeTypeMap(); + void initializeBuiltinSymbolMap(); }; } // end anonymous namespace @@ -1055,6 +1083,7 @@ initializeDirectiveKindMap(); PlatformParser->Initialize(*this); initializeCVDefRangeTypeMap(); + initializeBuiltinSymbolMap(); NumOfMacroInstantiations = 0; } @@ -1602,6 +1631,19 @@ 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()); @@ -3418,12 +3460,18 @@ 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: @@ -3438,29 +3486,40 @@ 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()) + : 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); @@ -6170,7 +6229,9 @@ 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()); @@ -6292,7 +6353,9 @@ "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); @@ -6462,7 +6525,9 @@ 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); @@ -7509,6 +7574,58 @@ 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 --- /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]]