[llvm] 00ebbed - [ms] [llvm-ml] Make variable redefinition match ML.EXE

Eric Astor via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 10 05:36:39 PDT 2021


Author: Eric Astor
Date: 2021-06-10T08:36:15-04:00
New Revision: 00ebbedd1c92f7461f81e79bd1474e894fd25378

URL: https://github.com/llvm/llvm-project/commit/00ebbedd1c92f7461f81e79bd1474e894fd25378
DIFF: https://github.com/llvm/llvm-project/commit/00ebbedd1c92f7461f81e79bd1474e894fd25378.diff

LOG: [ms] [llvm-ml] Make variable redefinition match ML.EXE

MASM specifies that all variable definitions are redefinable, except for EQU definitions to expressions. (TEXTEQU is unspecified, but appears to be fully redefinable as well.)

Also, in practice, ML.EXE allows redefinitions where the value doesn't change.

Make variable redefinition possible for text macros, suppressing expansion if written as the first argument to an EQU or TEXTEQU directive.

Reviewed By: thakis

Differential Revision: https://reviews.llvm.org/D103993

Added: 
    llvm/test/tools/llvm-ml/variable_redef.asm
    llvm/test/tools/llvm-ml/variable_redef_errors.asm

Modified: 
    llvm/lib/MC/MCParser/MasmParser.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/MC/MCParser/MasmParser.cpp b/llvm/lib/MC/MCParser/MasmParser.cpp
index 2c0e3a2acaf12..9d5f33e8883dd 100644
--- a/llvm/lib/MC/MCParser/MasmParser.cpp
+++ b/llvm/lib/MC/MCParser/MasmParser.cpp
@@ -1122,8 +1122,22 @@ const AsmToken &MasmParser::Lex() {
   }
 
   const AsmToken *tok = &Lexer.Lex();
+  bool StartOfStatement = Lexer.isAtStartOfStatement();
 
   while (tok->is(AsmToken::Identifier)) {
+    if (StartOfStatement) {
+      AsmToken NextTok;
+
+      MutableArrayRef<AsmToken> Buf(NextTok);
+      size_t ReadCount = Lexer.peekTokens(Buf);
+      if (ReadCount && NextTok.is(AsmToken::Identifier) &&
+          (NextTok.getString().equals_lower("equ") ||
+           NextTok.getString().equals_lower("textequ"))) {
+        // This looks like an EQU or TEXTEQU directive; don't expand the
+        // identifier, allowing for redefinitions.
+        break;
+      }
+    }
     auto it = Variables.find(tok->getIdentifier().lower());
     const llvm::MCAsmMacro *M =
         getContext().lookupMacro(tok->getIdentifier().lower());
@@ -3327,35 +3341,38 @@ bool MasmParser::parseIdentifier(StringRef &Res) {
 ///  ::= name "=" expression
 ///    | name "equ" expression    (not redefinable)
 ///    | name "equ" text-list
-///    | name "textequ" text-list
+///    | name "textequ" text-list (redefinability unspecified)
 bool MasmParser::parseDirectiveEquate(StringRef IDVal, StringRef Name,
                                       DirectiveKind DirKind) {
   Variable &Var = Variables[Name.lower()];
   if (Var.Name.empty()) {
     Var.Name = Name;
-  } else if (!Var.Redefinable) {
-    return TokError("invalid variable redefinition");
   }
-  Var.Redefinable = (DirKind != DK_EQU);
 
   SMLoc StartLoc = Lexer.getLoc();
   if (DirKind == DK_EQU || DirKind == DK_TEXTEQU) {
     // "equ" and "textequ" both allow text expressions.
     std::string Value;
-    if (!parseTextItem(Value)) {
-      Var.IsText = true;
-      Var.TextValue = Value;
+    std::string TextItem;
+    if (!parseTextItem(TextItem)) {
+      Value += TextItem;
 
       // Accept a text-list, not just one text-item.
       auto parseItem = [&]() -> bool {
-        if (parseTextItem(Value))
+        if (parseTextItem(TextItem))
           return TokError("expected text item");
-        Var.TextValue += Value;
+        Value += TextItem;
         return false;
       };
       if (parseOptionalToken(AsmToken::Comma) && parseMany(parseItem))
         return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");
 
+      if (!Var.Redefinable && (!Var.IsText || Var.TextValue != Value))
+        return Error(getTok().getLoc(), "invalid variable redefinition");
+      Var.IsText = true;
+      Var.TextValue = Value;
+      Var.Redefinable = true;
+
       return false;
     }
   }
@@ -3367,19 +3384,28 @@ bool MasmParser::parseDirectiveEquate(StringRef IDVal, StringRef Name,
   SMLoc EndLoc;
   if (parseExpression(Expr, EndLoc))
     return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");
+
+  int64_t Value;
+  if (!Expr->evaluateAsAbsolute(Value, getStreamer().getAssemblerPtr())) {
+    // Not an absolute expression; define as a text replacement.
+    StringRef ExprAsString = StringRef(
+        StartLoc.getPointer(), EndLoc.getPointer() - StartLoc.getPointer());
+    if (!Var.Redefinable && (!Var.IsText && Var.TextValue != ExprAsString))
+      return Error(getTok().getLoc(), "invalid variable redefinition");
+    Var.IsText = true;
+    Var.TextValue = ExprAsString.str();
+  } else {
+    if (!Var.Redefinable && (Var.IsText || Var.NumericValue != Value))
+      return Error(getTok().getLoc(), "invalid variable redefinition");
+    Var.NumericValue = Value;
+  }
+  Var.Redefinable = (DirKind == DK_ASSIGN);
+
   MCSymbol *Sym = getContext().getOrCreateSymbol(Var.Name);
   Sym->setRedefinable(Var.Redefinable);
   Sym->setVariableValue(Expr);
   Sym->setExternal(false);
 
-  if (Expr->evaluateAsAbsolute(Var.NumericValue,
-                               getStreamer().getAssemblerPtr()))
-    return false;
-
-  // Not an absolute expression; define as a text replacement.
-  Var.IsText = true;
-  Var.TextValue = StringRef(StartLoc.getPointer(),
-                            EndLoc.getPointer() - StartLoc.getPointer()).str();
   return false;
 }
 

diff  --git a/llvm/test/tools/llvm-ml/variable_redef.asm b/llvm/test/tools/llvm-ml/variable_redef.asm
new file mode 100644
index 0000000000000..f21f8f7eb0f34
--- /dev/null
+++ b/llvm/test/tools/llvm-ml/variable_redef.asm
@@ -0,0 +1,76 @@
+; RUN: llvm-ml -filetype=s %s /Fo - | FileCheck %s
+
+.data
+
+; <var> = <expression> can be redefined at any time.
+assigned_number = 1
+t1_original BYTE assigned_number
+assigned_number = 1
+t1_reset BYTE assigned_number
+assigned_number = 2
+t1_changed BYTE assigned_number
+
+; CHECK-LABEL: t1_original:
+; CHECK-NEXT: .byte 1
+
+; CHECK-LABEL: t1_reset:
+; CHECK-NEXT: .byte 1
+
+; CHECK-LABEL: t1_changed:
+; CHECK-NEXT: .byte 2
+
+; <var> EQU <expression> can be redundantly set, but can't be changed.
+equated_number equ 3
+t2_original BYTE equated_number
+equated_number equ 3
+t2_reset BYTE equated_number
+
+; CHECK-LABEL: t2_original:
+; CHECK-NEXT: .byte 3
+
+; CHECK-LABEL: t2_reset:
+; CHECK-NEXT: .byte 3
+
+; <var> EQU <text> can be redefined at any time.
+equated_text equ <4, 5>
+t3_original BYTE equated_text
+equated_text equ <4, 5>
+t3_reset BYTE equated_text
+equated_text equ <5, 6>
+t3_changed BYTE equated_text
+
+; CHECK-LABEL: t3_original:
+; CHECK-NEXT: .byte 4
+; CHECK-NEXT: .byte 5
+
+; CHECK-LABEL: t3_reset:
+; CHECK-NEXT: .byte 4
+; CHECK-NEXT: .byte 5
+
+; CHECK-LABEL: t3_changed:
+; CHECK-NEXT: .byte 5
+; CHECK-NEXT: .byte 6
+
+; <var> TEXTEQU <text> can be redefined at any time.
+textequated_text textequ <7, 8>
+t4_original BYTE textequated_text
+textequated_text textequ <7, 8>
+t4_reset BYTE textequated_text
+textequated_text textequ <9, 10>
+t4_changed BYTE textequated_text
+
+; CHECK-LABEL: t4_original:
+; CHECK-NEXT: .byte 7
+; CHECK-NEXT: .byte 8
+
+; CHECK-LABEL: t4_reset:
+; CHECK-NEXT: .byte 7
+; CHECK-NEXT: .byte 8
+
+; CHECK-LABEL: t4_changed:
+; CHECK-NEXT: .byte 9
+; CHECK-NEXT: .byte 10
+
+.code
+
+end

diff  --git a/llvm/test/tools/llvm-ml/variable_redef_errors.asm b/llvm/test/tools/llvm-ml/variable_redef_errors.asm
new file mode 100644
index 0000000000000..c5a0844500ef4
--- /dev/null
+++ b/llvm/test/tools/llvm-ml/variable_redef_errors.asm
@@ -0,0 +1,12 @@
+; RUN: not llvm-ml -filetype=s %s /Fo - 2>&1 | FileCheck %s --implicit-check-not=error:
+
+.data
+
+; <var> EQU <expression> can't be redefined to a new value
+equated_number equ 3
+; CHECK: :[[# @LINE + 1]]:21: error: invalid variable redefinition
+equated_number equ 4
+
+.code
+
+end


        


More information about the llvm-commits mailing list