[llvm] 5fba605 - [ms] [llvm-ml] Support built-in text macros
Eric Astor via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 21 08:46:05 PDT 2021
Author: Eric Astor
Date: 2021-07-21T11:44:09-04:00
New Revision: 5fba6058965c6b2cd2fe17335bb1fb78d99815bd
URL: https://github.com/llvm/llvm-project/commit/5fba6058965c6b2cd2fe17335bb1fb78d99815bd
DIFF: https://github.com/llvm/llvm-project/commit/5fba6058965c6b2cd2fe17335bb1fb78d99815bd.diff
LOG: [ms] [llvm-ml] Support built-in text macros
Add support for all built-in text macros supported by ML64:
@Date, @Time, @FileName, @FileCur, and @CurSeg.
Reviewed By: thakis
Differential Revision: https://reviews.llvm.org/D104965
Added:
llvm/test/tools/llvm-ml/builtin_symbols_t5.inc
Modified:
llvm/include/llvm/MC/MCParser/MCAsmParser.h
llvm/lib/MC/MCParser/MasmParser.cpp
llvm/test/tools/llvm-ml/builtin_symbols.asm
llvm/tools/llvm-ml/Opts.td
llvm/tools/llvm-ml/llvm-ml.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/MC/MCParser/MCAsmParser.h b/llvm/include/llvm/MC/MCParser/MCAsmParser.h
index c9b3ab3256da8..dbb76bd36591d 100644
--- a/llvm/include/llvm/MC/MCParser/MCAsmParser.h
+++ b/llvm/include/llvm/MC/MCParser/MCAsmParser.h
@@ -18,6 +18,7 @@
#include "llvm/MC/MCParser/MCAsmLexer.h"
#include "llvm/Support/SMLoc.h"
#include <cstdint>
+#include <ctime>
#include <string>
#include <utility>
@@ -348,7 +349,7 @@ MCAsmParser *createMCAsmParser(SourceMgr &, MCContext &, MCStreamer &,
/// Create an MCAsmParser instance for parsing Microsoft MASM-style assembly
MCAsmParser *createMCMasmParser(SourceMgr &, MCContext &, MCStreamer &,
- const MCAsmInfo &, unsigned CB = 0);
+ const MCAsmInfo &, struct tm, unsigned CB = 0);
} // end namespace llvm
diff --git a/llvm/lib/MC/MCParser/MasmParser.cpp b/llvm/lib/MC/MCParser/MasmParser.cpp
index beb8c3af34f9b..92ec178e34085 100644
--- 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 <climits>
#include <cstddef>
#include <cstdint>
+#include <ctime>
#include <deque>
#include <memory>
#include <sstream>
@@ -372,6 +375,10 @@ class MasmParser : public MCAsmParser {
/// This is the current buffer index we're lexing from as managed by the
/// SourceMgr object.
unsigned CurBuffer;
+
+ /// time of assembly
+ struct tm TM;
+
std::vector<bool> EndStatementAtEOFStack;
AsmCond TheCondState;
@@ -448,7 +455,7 @@ class MasmParser : public MCAsmParser {
public:
MasmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out,
- const MCAsmInfo &MAI, unsigned CB);
+ const MCAsmInfo &MAI, struct tm TM, unsigned CB = 0);
MasmParser(const MasmParser &) = delete;
MasmParser &operator=(const MasmParser &) = delete;
~MasmParser() override;
@@ -823,6 +830,9 @@ class MasmParser : public MCAsmParser {
const MCExpr *evaluateBuiltinValue(BuiltinSymbol Symbol, SMLoc StartLoc);
+ llvm::Optional<std::string> evaluateBuiltinTextMacro(BuiltinSymbol Symbol,
+ SMLoc StartLoc);
+
// ".ascii", ".asciz", ".string"
bool parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated);
@@ -1060,9 +1070,9 @@ extern MCAsmParserExtension *createCOFFMasmParser();
enum { DEFAULT_ADDRSPACE = 0 };
MasmParser::MasmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out,
- const MCAsmInfo &MAI, unsigned CB = 0)
+ const MCAsmInfo &MAI, struct tm TM, unsigned CB)
: Lexer(MAI), Ctx(Ctx), Out(Out), MAI(MAI), SrcMgr(SM),
- CurBuffer(CB ? CB : SM.getMainFileID()) {
+ CurBuffer(CB ? CB : SM.getMainFileID()), TM(TM) {
HadError = false;
// Save the old handler.
SavedDiagHandler = SrcMgr.getDiagHandler();
@@ -1154,25 +1164,9 @@ void MasmParser::jumpToLoc(SMLoc Loc, unsigned InBuffer,
bool MasmParser::expandMacros() {
const AsmToken &Tok = getTok();
+ const std::string IDLower = Tok.getIdentifier().lower();
- auto VarIt = Variables.find(Tok.getIdentifier().lower());
- if (VarIt != Variables.end() && VarIt->second.IsText) {
- std::unique_ptr<MemoryBuffer> Instantiation =
- MemoryBuffer::getMemBufferCopy(VarIt->second.TextValue,
- "<instantiation>");
-
- // Jump to the macro instantiation and prime the lexer.
- CurBuffer =
- SrcMgr.AddNewSourceBuffer(std::move(Instantiation), Tok.getEndLoc());
- Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(), nullptr,
- /*EndStatementAtEOF=*/false);
- EndStatementAtEOFStack.push_back(false);
- Lexer.Lex();
- return false;
- }
-
- const llvm::MCAsmMacro *M =
- getContext().lookupMacro(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 SMLoc MacroLoc = Tok.getLoc();
@@ -1185,7 +1179,31 @@ bool MasmParser::expandMacros() {
return false;
}
- return true;
+ llvm::Optional<std::string> ExpandedValue;
+ auto BuiltinIt = BuiltinSymbolMap.find(IDLower);
+ if (BuiltinIt != BuiltinSymbolMap.end()) {
+ ExpandedValue =
+ evaluateBuiltinTextMacro(BuiltinIt->getValue(), Tok.getLoc());
+ } else {
+ auto VarIt = Variables.find(IDLower);
+ if (VarIt != Variables.end() && VarIt->getValue().IsText) {
+ ExpandedValue = VarIt->getValue().TextValue;
+ }
+ }
+
+ if (!ExpandedValue.hasValue())
+ return true;
+ std::unique_ptr<MemoryBuffer> Instantiation =
+ MemoryBuffer::getMemBufferCopy(*ExpandedValue, "<instantiation>");
+
+ // Jump to the macro instantiation and prime the lexer.
+ CurBuffer =
+ SrcMgr.AddNewSourceBuffer(std::move(Instantiation), Tok.getEndLoc());
+ Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(), nullptr,
+ /*EndStatementAtEOF=*/false);
+ EndStatementAtEOFStack.push_back(false);
+ Lexer.Lex();
+ return false;
}
const AsmToken &MasmParser::Lex(ExpandKind ExpandNextToken) {
@@ -2938,16 +2956,17 @@ bool MasmParser::expandMacro(raw_svector_ostream &OS, StringRef Body,
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
@@ -3602,28 +3621,50 @@ bool MasmParser::parseTextItem(std::string &Data) {
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.
- getLexer().UnLex(AsmToken(AsmToken::Identifier, ID));
- return true;
- }
+ bool Expanded = false;
+ while (true) {
+ // Try to resolve as a built-in text macro
+ auto BuiltinIt = BuiltinSymbolMap.find(ID.lower());
+ if (BuiltinIt != BuiltinSymbolMap.end()) {
+ llvm::Optional<std::string> BuiltinText =
+ evaluateBuiltinTextMacro(BuiltinIt->getValue(), StartLoc);
+ if (!BuiltinText.hasValue()) {
+ // Not a text macro; break without substituting
+ break;
+ }
+ Data = std::move(*BuiltinText);
+ ID = StringRef(Data);
+ Expanded = true;
+ continue;
+ }
- 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;
+ // Try to resolve as a variable text macro
+ auto VarIt = Variables.find(ID.lower());
+ if (VarIt != Variables.end()) {
+ const Variable &Var = VarIt->getValue();
+ if (!Var.IsText) {
+ // Not a text macro; break without substituting
+ break;
+ }
+ Data = Var.TextValue;
+ ID = StringRef(Data);
+ Expanded = true;
+ continue;
}
- Data = Var.TextValue;
- it = Variables.find(StringRef(Data).lower());
+
+ break;
+ }
+
+ if (!Expanded) {
+ // 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;
}
return false;
}
@@ -6857,16 +6898,36 @@ bool MasmParser::expandStatement(SMLoc Loc) {
MCAsmMacroParameters Parameters;
MCAsmMacroArguments Arguments;
+
+ StringMap<std::string> BuiltinValues;
+ for (const auto &S : BuiltinSymbolMap) {
+ const BuiltinSymbol &Sym = S.getValue();
+ if (llvm::Optional<std::string> 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);
@@ -7595,11 +7656,11 @@ void MasmParser::initializeBuiltinSymbolMap() {
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() ==
@@ -7641,9 +7702,42 @@ const MCExpr *MasmParser::evaluateBuiltinValue(BuiltinSymbol Symbol,
llvm_unreachable("unhandled built-in symbol");
}
+llvm::Optional<std::string>
+MasmParser::evaluateBuiltinTextMacro(BuiltinSymbol Symbol, SMLoc StartLoc) {
+ switch (Symbol) {
+ default:
+ return {};
+ case BI_DATE: {
+ // Current local date, formatted MM/DD/YY
+ char TmpBuffer[sizeof("mm/dd/yy")];
+ const size_t Len = strftime(TmpBuffer, sizeof(TmpBuffer), "%D", &TM);
+ return std::string(TmpBuffer, Len);
+ }
+ case BI_TIME: {
+ // Current local time, formatted HH:MM:SS (24-hour clock)
+ char TmpBuffer[sizeof("hh:mm:ss")];
+ const size_t Len = strftime(TmpBuffer, sizeof(TmpBuffer), "%T", &TM);
+ return std::string(TmpBuffer, Len);
+ }
+ case BI_FILECUR:
+ return SrcMgr
+ .getMemoryBuffer(
+ ActiveMacros.empty() ? CurBuffer : ActiveMacros.front()->ExitBuffer)
+ ->getBufferIdentifier()
+ .str();
+ case BI_FILENAME:
+ return sys::path::stem(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,
- unsigned CB) {
- return new MasmParser(SM, C, Out, MAI, CB);
+ struct tm TM, unsigned CB) {
+ return new MasmParser(SM, C, Out, MAI, TM, CB);
}
diff --git a/llvm/test/tools/llvm-ml/builtin_symbols.asm b/llvm/test/tools/llvm-ml/builtin_symbols.asm
index 844f9f260cb63..81442c49d7ec7 100644
--- a/llvm/test/tools/llvm-ml/builtin_symbols.asm
+++ b/llvm/test/tools/llvm-ml/builtin_symbols.asm
@@ -1,4 +1,7 @@
-; 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 --check-prefixes=CHECK,CHECK-REALTIME
+; RUN: llvm-ml -filetype=s %s /I %S /Fo /dev/null --timestamp=0 --utc 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-FIXEDTIME
+
+.code
version_val TEXTEQU %@Version
@@ -33,3 +36,24 @@ ECHO t4:
%ECHO @Line = line_val
; CHECK-LABEL: t4:
; CHECK-NEXT: @Line = [[# @LINE - 5]]
+
+ECHO t5:
+include builtin_symbols_t5.inc
+; CHECK-LABEL: t5:
+; CHECK: FileCur = {{.*}}builtin_symbols_t5.inc
+; CHECK: FileName = BUILTIN_SYMBOLS
+; CHECK-NOT: _T5
+
+ECHO t6:
+%ECHO Date = @Date
+%ECHO Time = @Time
+
+; CHECK-LABEL: t6:
+; CHECK-REALTIME: Date = {{([[:digit:]]{2}/[[:digit:]]{2}/[[:digit:]]{2})}}
+; CHECK-FIXEDTIME: Date = 01/01/70
+; CHECK-NOT: {{[[:digit:]]}}
+; CHECK-REALTIME: Time = {{([[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2})}}
+; CHECK-FIXEDTIME: Time = 00:00:00
+; CHECK-NOT: {{[[:digit:]]}}
+
+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
index 0000000000000..4a08674bd7569
--- /dev/null
+++ b/llvm/test/tools/llvm-ml/builtin_symbols_t5.inc
@@ -0,0 +1,2 @@
+%echo FileCur = @FileCur
+%echo FileName = @FileName
diff --git a/llvm/tools/llvm-ml/Opts.td b/llvm/tools/llvm-ml/Opts.td
index 06871b49ad0d9..631c8566e2a7f 100644
--- a/llvm/tools/llvm-ml/Opts.td
+++ b/llvm/tools/llvm-ml/Opts.td
@@ -51,6 +51,12 @@ def preserve_comments : LLVMFlag<"preserve-comments">,
HelpText<"Preserve comments in output assembly">;
def save_temp_labels : LLVMFlag<"save-temp-labels">,
HelpText<"Don't discard temporary labels">;
+def timestamp : LLVMJoined<"timestamp=">,
+ HelpText<"Specify the assembly timestamp (used for @Date and "
+ "@Time built-ins)">;
+def utc : LLVMFlag<"utc">,
+ HelpText<"Render @Date and @Time built-ins in GMT/UTC">;
+def gmtime : LLVMFlag<"gmtime">, Alias<utc>;
def help : MLFlag<"?">,
HelpText<"Display available options">;
diff --git a/llvm/tools/llvm-ml/llvm-ml.cpp b/llvm/tools/llvm-ml/llvm-ml.cpp
index dee5f6ff4e513..0e6b055837863 100644
--- a/llvm/tools/llvm-ml/llvm-ml.cpp
+++ b/llvm/tools/llvm-ml/llvm-ml.cpp
@@ -42,6 +42,7 @@
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/WithColor.h"
+#include <ctime>
using namespace llvm;
using namespace llvm::opt;
@@ -130,8 +131,31 @@ static int AssembleInput(StringRef ProgName, const Target *TheTarget,
MCAsmInfo &MAI, MCSubtargetInfo &STI,
MCInstrInfo &MCII, MCTargetOptions &MCOptions,
const opt::ArgList &InputArgs) {
+ struct tm TM;
+ time_t Timestamp;
+ if (InputArgs.hasArg(OPT_timestamp)) {
+ StringRef TimestampStr = InputArgs.getLastArgValue(OPT_timestamp);
+ int64_t IntTimestamp;
+ if (TimestampStr.getAsInteger(10, IntTimestamp)) {
+ WithColor::error(errs(), ProgName)
+ << "invalid timestamp '" << TimestampStr
+ << "'; must be expressed in seconds since the UNIX epoch.\n";
+ return 1;
+ }
+ Timestamp = IntTimestamp;
+ } else {
+ Timestamp = time(nullptr);
+ }
+ if (InputArgs.hasArg(OPT_utc)) {
+ // Not thread-safe.
+ TM = *gmtime(&Timestamp);
+ } else {
+ // Not thread-safe.
+ TM = *localtime(&Timestamp);
+ }
+
std::unique_ptr<MCAsmParser> Parser(
- createMCMasmParser(SrcMgr, Ctx, Str, MAI, 0));
+ createMCMasmParser(SrcMgr, Ctx, Str, MAI, TM, 0));
std::unique_ptr<MCTargetAsmParser> TAP(
TheTarget->createMCAsmParser(STI, *Parser, MCII, MCOptions));
More information about the llvm-commits
mailing list