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 @@ -13,6 +13,7 @@ #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" @@ -56,6 +57,7 @@ #include "llvm/Support/MD5.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" @@ -65,6 +67,7 @@ #include #include #include +#include #include #include #include @@ -821,6 +824,9 @@ const MCExpr *evaluateBuiltinValue(BuiltinSymbol Symbol, SMLoc StartLoc); + llvm::Optional evaluateBuiltinTextMacro(BuiltinSymbol Symbol, + SMLoc StartLoc); + // ".ascii", ".asciz", ".string" bool parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated); @@ -1152,22 +1158,9 @@ bool MasmParser::expandCurrentToken() { const AsmToken *tok = &getTok(); - auto it = Variables.find(tok->getIdentifier().lower()); - const llvm::MCAsmMacro *M = - getContext().lookupMacro(tok->getIdentifier().lower()); - if (it != Variables.end() && it->second.IsText) { - std::unique_ptr Instantiation = - MemoryBuffer::getMemBufferCopy(it->second.TextValue, ""); - - // Jump to the macro instantiation and prime the lexer. - CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation), - getTok().getEndLoc()); - Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(), nullptr, - /*EndStatementAtEOF=*/false); - EndStatementAtEOFStack.push_back(false); - Lexer.Lex(); - return false; - } else if (M && M->IsFunction && peekTok().is(AsmToken::LParen)) { + const std::string IDLower = tok->getIdentifier().lower(); + const llvm::MCAsmMacro *M = getContext().lookupMacro(IDLower); + if (M && M->IsFunction && peekTok().is(AsmToken::LParen)) { // This is a macro function invocation; expand it in place. const AsmToken MacroTok = *tok; Lexer.Lex(); @@ -1177,7 +1170,30 @@ } return false; } - return true; + + llvm::Optional ExpandedValue; + auto BuiltinIt = BuiltinSymbolMap.find(IDLower); + auto VarIt = Variables.find(IDLower); + if (BuiltinIt != BuiltinSymbolMap.end()) { + ExpandedValue = + evaluateBuiltinTextMacro(BuiltinIt->getValue(), tok->getLoc()); + } else if (VarIt != Variables.end() && VarIt->getValue().IsText) { + ExpandedValue = VarIt->getValue().TextValue; + } + + if (!ExpandedValue.hasValue()) + return true; + std::unique_ptr Instantiation = + MemoryBuffer::getMemBufferCopy(*ExpandedValue, ""); + + // Jump to the macro instantiation and prime the lexer. + CurBuffer = + SrcMgr.AddNewSourceBuffer(std::move(Instantiation), getTok().getEndLoc()); + Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(), nullptr, + /*EndStatementAtEOF=*/false); + EndStatementAtEOFStack.push_back(false); + Lexer.Lex(); + return false; } const AsmToken &MasmParser::Lex(bool ExpandNextToken) { @@ -2930,16 +2946,17 @@ const char *Begin = Body.data() + Pos; StringRef Argument(Begin, I - Pos); + const std::string ArgumentLower = Argument.lower(); unsigned Index = 0; for (; Index < NParameters; ++Index) - if (Parameters[Index].Name == Argument) + if (Parameters[Index].Name.equals_insensitive(ArgumentLower)) break; if (Index == NParameters) { if (InitialAmpersand) OS << '&'; - auto it = LocalSymbols.find(Argument.lower()); + auto it = LocalSymbols.find(ArgumentLower); if (it != LocalSymbols.end()) OS << it->second; else @@ -3497,9 +3514,9 @@ MCSymbol *Sym = getContext().getOrCreateSymbol(Var.Name); const MCConstantExpr *PrevValue = - Sym->isVariable() - ? dyn_cast_or_null(Sym->getVariableValue()) - : nullptr; + 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: @@ -3587,28 +3604,43 @@ case AsmToken::Identifier: { // This must be a text macro; we need to expand it accordingly. StringRef ID; + SMLoc StartLoc = getTok().getLoc(); if (parseIdentifier(ID)) return true; Data = ID.str(); - auto it = Variables.find(ID.lower()); - if (it == Variables.end()) { - // Not a variable; since we haven't used the token, put it back for better - // error recovery. + auto BuiltinIt = BuiltinSymbolMap.find(ID.lower()); + auto VarIt = Variables.find(ID.lower()); + if (BuiltinIt == BuiltinSymbolMap.end() && VarIt == Variables.end()) { + // Not a variable or built-in text macro; since we haven't used the token, + // put it back for better error recovery. getLexer().UnLex(AsmToken(AsmToken::Identifier, ID)); return true; } - while (it != Variables.end()) { - const Variable &Var = it->second; - if (!Var.IsText) { - // Not a text macro; not usable in TextItem context. Since we haven't - // used the token, put it back for better error recovery. - getLexer().UnLex(AsmToken(AsmToken::Identifier, ID)); - return true; + while (BuiltinIt != BuiltinSymbolMap.end() || VarIt != Variables.end()) { + if (BuiltinIt != BuiltinSymbolMap.end()) { + llvm::Optional BuiltinText = + evaluateBuiltinTextMacro(BuiltinIt->second, StartLoc); + if (!BuiltinText.hasValue()) { + // Not a text macro; not usable in TextItem context. Since we haven't + // used the token, put it back for better error recovery. + getLexer().UnLex(AsmToken(AsmToken::Identifier, ID)); + return true; + } + Data = BuiltinText.getValue(); + } else { + const Variable &Var = VarIt->second; + if (!Var.IsText) { + // Not a text macro; not usable in TextItem context. Since we haven't + // used the token, put it back for better error recovery. + getLexer().UnLex(AsmToken(AsmToken::Identifier, ID)); + return true; + } + Data = Var.TextValue; } - Data = Var.TextValue; - it = Variables.find(StringRef(Data).lower()); + VarIt = Variables.find(StringRef(Data).lower()); + BuiltinIt = BuiltinSymbolMap.find(StringRef(Data).lower()); } return false; } @@ -6842,16 +6874,36 @@ MCAsmMacroParameters Parameters; MCAsmMacroArguments Arguments; + + StringMap BuiltinValues; + for (const auto &S : BuiltinSymbolMap) { + const BuiltinSymbol &Sym = S.getValue(); + if (llvm::Optional Text = evaluateBuiltinTextMacro(Sym, Loc)) { + BuiltinValues[S.getKey().lower()] = std::move(*Text); + } + } + for (const auto &B : BuiltinValues) { + MCAsmMacroParameter P; + MCAsmMacroArgument A; + P.Name = B.getKey(); + P.Required = true; + A.push_back(AsmToken(AsmToken::String, B.getValue())); + + Parameters.push_back(std::move(P)); + Arguments.push_back(std::move(A)); + } + for (const auto &V : Variables) { const Variable &Var = V.getValue(); if (Var.IsText) { - Parameters.emplace_back(); - Arguments.emplace_back(); - MCAsmMacroParameter &P = Parameters.back(); - MCAsmMacroArgument &A = Arguments.back(); + MCAsmMacroParameter P; + MCAsmMacroArgument A; P.Name = Var.Name; P.Required = true; A.push_back(AsmToken(AsmToken::String, Var.TextValue)); + + Parameters.push_back(std::move(P)); + Arguments.push_back(std::move(A)); } } MacroLikeBodies.emplace_back(StringRef(), Body, Parameters); @@ -7580,11 +7632,11 @@ 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; + 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() == @@ -7626,6 +7678,48 @@ llvm_unreachable("unhandled built-in symbol"); } +llvm::Optional +MasmParser::evaluateBuiltinTextMacro(BuiltinSymbol Symbol, SMLoc StartLoc) { + switch (Symbol) { + default: + return {}; + case BI_DATE: { + // Current local date, formatted MM/DD/YY + time_t TT = time(nullptr); + struct tm *TM = localtime(&TT); + SmallString<32> TmpBuffer; + llvm::raw_svector_ostream TmpStream(TmpBuffer); + TmpStream << llvm::format("%02d/%02d/%02d", TM->tm_mon + 1, TM->tm_mday, + TM->tm_year % 100); + return TmpStream.str().str(); + } + case BI_TIME: { + // Current local time, formatted HH:MM:SS + time_t TT = time(nullptr); + struct tm *TM = localtime(&TT); + SmallString<32> TmpBuffer; + llvm::raw_svector_ostream TmpStream(TmpBuffer); + TmpStream << llvm::format("%02d:%02d:%02d", TM->tm_hour, TM->tm_min, + TM->tm_sec); + return TmpStream.str().str(); + } + case BI_FILECUR: + return SrcMgr + .getMemoryBuffer( + ActiveMacros.empty() ? CurBuffer : ActiveMacros.front()->ExitBuffer) + ->getBufferIdentifier() + .str(); + case BI_FILENAME: + return sys::path::stem(sys::path::filename( + SrcMgr.getMemoryBuffer(SrcMgr.getMainFileID()) + ->getBufferIdentifier())) + .upper(); + case BI_CURSEG: + return getStreamer().getCurrentSectionOnly()->getName().str(); + } + 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 --- a/llvm/test/tools/llvm-ml/builtin_symbols.asm +++ b/llvm/test/tools/llvm-ml/builtin_symbols.asm @@ -1,4 +1,6 @@ -; RUN: llvm-ml -filetype=s %s /Fo /dev/null 2>&1 | FileCheck %s +; RUN: llvm-ml -filetype=s %s /I %S /Fo /dev/null 2>&1 | FileCheck %s + +.code version_val TEXTEQU %@Version @@ -33,3 +35,23 @@ %ECHO @Line = line_val ; CHECK-LABEL: t4: ; CHECK-NEXT: @Line = [[# @LINE - 5]] + +ECHO t5: +include builtin_symbols_t5.inc +; CHECK-LABEL: t5: +; CHECK: FileCur = +; CHECK-SAME: builtin_symbols_t5.inc +; CHECK: FileName = +; CHECK-SAME: BUILTIN_SYMBOLS +; CHECK-NOT: T5 + +ECHO t6: +%ECHO Date = @Date +%ECHO Time = @Time + +; CHECK-LABEL: t6: +; CHECK: Date = {{([[:digit:]]{2}/[[:digit:]]{2}/[[:digit:]]{2})}} +; CHECK-NOT: {{[[:digit:]]}} +; CHECK: Time = {{([[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2})}} + +end diff --git a/llvm/test/tools/llvm-ml/builtin_symbols_t5.inc b/llvm/test/tools/llvm-ml/builtin_symbols_t5.inc new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-ml/builtin_symbols_t5.inc @@ -0,0 +1,2 @@ +%echo FileCur = @FileCur +%echo FileName = @FileName