[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