[ms] [llvm-ml] Support MASM's relational operators (EQ, LT, etc.)
authorEric Astor <epastor@google.com>
Mon, 9 Nov 2020 18:22:37 +0000 (13:22 -0500)
committerEric Astor <epastor@google.com>
Mon, 9 Nov 2020 19:01:36 +0000 (14:01 -0500)
Support the named relational operators (EQ, LT, etc.).

Reviewed By: thakis

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

llvm/lib/MC/MCParser/MasmParser.cpp
llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
llvm/test/tools/llvm-ml/named_bitwise_operators.test [deleted file]
llvm/test/tools/llvm-ml/named_operators.test [new file with mode: 0644]

index ad961bc..036551e 100644 (file)
@@ -1831,13 +1831,17 @@ bool MasmParser::parseBinOpRHS(unsigned Precedence, const MCExpr *&Res,
   while (true) {
     AsmToken::TokenKind TokKind = Lexer.getKind();
     if (Lexer.getKind() == AsmToken::Identifier) {
-      StringRef Identifier = Lexer.getTok().getString();
-      if (Identifier.equals_lower("and"))
-        TokKind = AsmToken::Amp;
-      else if (Identifier.equals_lower("not"))
-        TokKind = AsmToken::Exclaim;
-      else if (Identifier.equals_lower("or"))
-        TokKind = AsmToken::Pipe;
+      TokKind = StringSwitch<AsmToken::TokenKind>(Lexer.getTok().getString())
+                    .CaseLower("and", AsmToken::Amp)
+                    .CaseLower("not", AsmToken::Exclaim)
+                    .CaseLower("or", AsmToken::Pipe)
+                    .CaseLower("eq", AsmToken::EqualEqual)
+                    .CaseLower("ne", AsmToken::ExclaimEqual)
+                    .CaseLower("lt", AsmToken::Less)
+                    .CaseLower("le", AsmToken::LessEqual)
+                    .CaseLower("gt", AsmToken::Greater)
+                    .CaseLower("ge", AsmToken::GreaterEqual)
+                    .Default(TokKind);
     }
     MCBinaryExpr::Opcode Kind = MCBinaryExpr::Add;
     unsigned TokPrec = getBinOpPrecedence(TokKind, Kind);
index fd7beea..03956de 100644 (file)
@@ -57,22 +57,28 @@ static bool checkScale(unsigned Scale, StringRef &ErrMsg) {
 namespace {
 
 static const char OpPrecedence[] = {
-  0, // IC_OR
-  1, // IC_XOR
-  2, // IC_AND
-  3, // IC_LSHIFT
-  3, // IC_RSHIFT
-  4, // IC_PLUS
-  4, // IC_MINUS
-  5, // IC_MULTIPLY
-  5, // IC_DIVIDE
-  5, // IC_MOD
-  6, // IC_NOT
-  7, // IC_NEG
-  8, // IC_RPAREN
-  9, // IC_LPAREN
-  0, // IC_IMM
-  0  // IC_REGISTER
+    0,  // IC_OR
+    1,  // IC_XOR
+    2,  // IC_AND
+    4,  // IC_LSHIFT
+    4,  // IC_RSHIFT
+    5,  // IC_PLUS
+    5,  // IC_MINUS
+    6,  // IC_MULTIPLY
+    6,  // IC_DIVIDE
+    6,  // IC_MOD
+    7,  // IC_NOT
+    8,  // IC_NEG
+    9,  // IC_RPAREN
+    10, // IC_LPAREN
+    0,  // IC_IMM
+    0,  // IC_REGISTER
+    3,  // IC_EQ
+    3,  // IC_NE
+    3,  // IC_LT
+    3,  // IC_LE
+    3,  // IC_GT
+    3   // IC_GE
 };
 
 class X86AsmParser : public MCTargetAsmParser {
@@ -143,7 +149,13 @@ private:
     IC_RPAREN,
     IC_LPAREN,
     IC_IMM,
-    IC_REGISTER
+    IC_REGISTER,
+    IC_EQ,
+    IC_NE,
+    IC_LT,
+    IC_LE,
+    IC_GT,
+    IC_GE
   };
 
   enum IntelOperatorKind {
@@ -332,6 +344,44 @@ private:
             Val = Op1.second >> Op2.second;
             OperandStack.push_back(std::make_pair(IC_IMM, Val));
             break;
+          case IC_EQ:
+            assert(Op1.first == IC_IMM && Op2.first == IC_IMM &&
+                   "Equals operation with an immediate and a register!");
+            Val = (Op1.second == Op2.second) ? -1 : 0;
+            OperandStack.push_back(std::make_pair(IC_IMM, Val));
+            break;
+          case IC_NE:
+            assert(Op1.first == IC_IMM && Op2.first == IC_IMM &&
+                   "Not-equals operation with an immediate and a register!");
+            Val = (Op1.second != Op2.second) ? -1 : 0;
+            OperandStack.push_back(std::make_pair(IC_IMM, Val));
+            break;
+          case IC_LT:
+            assert(Op1.first == IC_IMM && Op2.first == IC_IMM &&
+                   "Less-than operation with an immediate and a register!");
+            Val = (Op1.second < Op2.second) ? -1 : 0;
+            OperandStack.push_back(std::make_pair(IC_IMM, Val));
+            break;
+          case IC_LE:
+            assert(Op1.first == IC_IMM && Op2.first == IC_IMM &&
+                   "Less-than-or-equal operation with an immediate and a "
+                   "register!");
+            Val = (Op1.second <= Op2.second) ? -1 : 0;
+            OperandStack.push_back(std::make_pair(IC_IMM, Val));
+            break;
+          case IC_GT:
+            assert(Op1.first == IC_IMM && Op2.first == IC_IMM &&
+                   "Greater-than operation with an immediate and a register!");
+            Val = (Op1.second > Op2.second) ? -1 : 0;
+            OperandStack.push_back(std::make_pair(IC_IMM, Val));
+            break;
+          case IC_GE:
+            assert(Op1.first == IC_IMM && Op2.first == IC_IMM &&
+                   "Greater-than-or-equal operation with an immediate and a "
+                   "register!");
+            Val = (Op1.second >= Op2.second) ? -1 : 0;
+            OperandStack.push_back(std::make_pair(IC_IMM, Val));
+            break;
           }
         }
       }
@@ -345,6 +395,12 @@ private:
     IES_OR,
     IES_XOR,
     IES_AND,
+    IES_EQ,
+    IES_NE,
+    IES_LT,
+    IES_LE,
+    IES_GT,
+    IES_GE,
     IES_LSHIFT,
     IES_RSHIFT,
     IES_PLUS,
@@ -461,6 +517,96 @@ private:
       }
       PrevState = CurrState;
     }
+    void onEq() {
+      IntelExprState CurrState = State;
+      switch (State) {
+      default:
+        State = IES_ERROR;
+        break;
+      case IES_INTEGER:
+      case IES_RPAREN:
+      case IES_REGISTER:
+        State = IES_EQ;
+        IC.pushOperator(IC_EQ);
+        break;
+      }
+      PrevState = CurrState;
+    }
+    void onNE() {
+      IntelExprState CurrState = State;
+      switch (State) {
+      default:
+        State = IES_ERROR;
+        break;
+      case IES_INTEGER:
+      case IES_RPAREN:
+      case IES_REGISTER:
+        State = IES_NE;
+        IC.pushOperator(IC_NE);
+        break;
+      }
+      PrevState = CurrState;
+    }
+    void onLT() {
+      IntelExprState CurrState = State;
+      switch (State) {
+      default:
+        State = IES_ERROR;
+        break;
+      case IES_INTEGER:
+      case IES_RPAREN:
+      case IES_REGISTER:
+        State = IES_LT;
+        IC.pushOperator(IC_LT);
+        break;
+      }
+      PrevState = CurrState;
+    }
+    void onLE() {
+      IntelExprState CurrState = State;
+      switch (State) {
+      default:
+        State = IES_ERROR;
+        break;
+      case IES_INTEGER:
+      case IES_RPAREN:
+      case IES_REGISTER:
+        State = IES_LE;
+        IC.pushOperator(IC_LE);
+        break;
+      }
+      PrevState = CurrState;
+    }
+    void onGT() {
+      IntelExprState CurrState = State;
+      switch (State) {
+      default:
+        State = IES_ERROR;
+        break;
+      case IES_INTEGER:
+      case IES_RPAREN:
+      case IES_REGISTER:
+        State = IES_GT;
+        IC.pushOperator(IC_GT);
+        break;
+      }
+      PrevState = CurrState;
+    }
+    void onGE() {
+      IntelExprState CurrState = State;
+      switch (State) {
+      default:
+        State = IES_ERROR;
+        break;
+      case IES_INTEGER:
+      case IES_RPAREN:
+      case IES_REGISTER:
+        State = IES_GE;
+        IC.pushOperator(IC_GE);
+        break;
+      }
+      PrevState = CurrState;
+    }
     void onLShift() {
       IntelExprState CurrState = State;
       switch (State) {
@@ -531,6 +677,12 @@ private:
       case IES_OR:
       case IES_XOR:
       case IES_AND:
+      case IES_EQ:
+      case IES_NE:
+      case IES_LT:
+      case IES_LE:
+      case IES_GT:
+      case IES_GE:
       case IES_LSHIFT:
       case IES_RSHIFT:
       case IES_PLUS:
@@ -586,6 +738,12 @@ private:
       case IES_OR:
       case IES_XOR:
       case IES_AND:
+      case IES_EQ:
+      case IES_NE:
+      case IES_LT:
+      case IES_LE:
+      case IES_GT:
+      case IES_GE:
       case IES_LSHIFT:
       case IES_RSHIFT:
       case IES_PLUS:
@@ -686,6 +844,12 @@ private:
       case IES_OR:
       case IES_XOR:
       case IES_AND:
+      case IES_EQ:
+      case IES_NE:
+      case IES_LT:
+      case IES_LE:
+      case IES_GT:
+      case IES_GE:
       case IES_LSHIFT:
       case IES_RSHIFT:
       case IES_DIVIDE:
@@ -822,6 +986,12 @@ private:
       case IES_OR:
       case IES_XOR:
       case IES_AND:
+      case IES_EQ:
+      case IES_NE:
+      case IES_LT:
+      case IES_LE:
+      case IES_GT:
+      case IES_GE:
       case IES_LSHIFT:
       case IES_RSHIFT:
       case IES_MULTIPLY:
@@ -932,6 +1102,8 @@ private:
   bool ParseRoundingModeOp(SMLoc Start, OperandVector &Operands);
   bool ParseIntelNamedOperator(StringRef Name, IntelExprStateMachine &SM,
                                bool &ParseError, SMLoc &End);
+  bool ParseMasmNamedOperator(StringRef Name, IntelExprStateMachine &SM,
+                              bool &ParseError, SMLoc &End);
   void RewriteIntelExpression(IntelExprStateMachine &SM, SMLoc Start,
                               SMLoc End);
   bool ParseIntelExpression(IntelExprStateMachine &SM, SMLoc &End);
@@ -1608,8 +1780,10 @@ bool X86AsmParser::CreateMemForMSInlineAsm(
 bool X86AsmParser::ParseIntelNamedOperator(StringRef Name,
                                            IntelExprStateMachine &SM,
                                            bool &ParseError, SMLoc &End) {
-  // A named operator should be either lower or upper case, but not a mix
-  if (Name.compare(Name.lower()) && Name.compare(Name.upper()))
+  // A named operator should be either lower or upper case, but not a mix...
+  // except in MASM, which uses full case-insensitivity.
+  if (Name.compare(Name.lower()) && Name.compare(Name.upper()) &&
+      !getParser().isParsingMasm())
     return false;
   if (Name.equals_lower("not")) {
     SM.onNot();
@@ -1645,6 +1819,27 @@ bool X86AsmParser::ParseIntelNamedOperator(StringRef Name,
     End = consumeToken();
   return true;
 }
+bool X86AsmParser::ParseMasmNamedOperator(StringRef Name,
+                                          IntelExprStateMachine &SM,
+                                          bool &ParseError, SMLoc &End) {
+  if (Name.equals_lower("eq")) {
+    SM.onEq();
+  } else if (Name.equals_lower("ne")) {
+    SM.onNE();
+  } else if (Name.equals_lower("lt")) {
+    SM.onLT();
+  } else if (Name.equals_lower("le")) {
+    SM.onLE();
+  } else if (Name.equals_lower("gt")) {
+    SM.onGT();
+  } else if (Name.equals_lower("ge")) {
+    SM.onGE();
+  } else {
+    return false;
+  }
+  End = consumeToken();
+  return true;
+}
 
 bool X86AsmParser::ParseIntelExpression(IntelExprStateMachine &SM, SMLoc &End) {
   MCAsmParser &Parser = getParser();
@@ -1787,6 +1982,12 @@ bool X86AsmParser::ParseIntelExpression(IntelExprStateMachine &SM, SMLoc &End) {
           return true;
         break;
       }
+      if (Parser.isParsingMasm() &&
+          ParseMasmNamedOperator(Identifier, SM, ParseError, End)) {
+        if (ParseError)
+          return true;
+        break;
+      }
       // Symbol reference, when parsing assembly content
       InlineAsmIdentifierInfo Info;
       AsmFieldInfo FieldInfo;
diff --git a/llvm/test/tools/llvm-ml/named_bitwise_operators.test b/llvm/test/tools/llvm-ml/named_bitwise_operators.test
deleted file mode 100644 (file)
index f122dbe..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-; RUN: llvm-ml -filetype=asm %s | FileCheck %s
-
-.data
-
-t1 BYTE NOT 1
-; CHECK: t1:
-; CHECK-NEXT: .byte -2
-
-t2 BYTE 1 OR 2
-; CHECK: t2:
-; CHECK-NEXT: .byte 3
-
-t3 BYTE 6 AND 10
-; CHECK: t3:
-; CHECK-NEXT: .byte 2
-
-.code
-xor eax, eax
-
-END
diff --git a/llvm/test/tools/llvm-ml/named_operators.test b/llvm/test/tools/llvm-ml/named_operators.test
new file mode 100644 (file)
index 0000000..1eb9453
--- /dev/null
@@ -0,0 +1,143 @@
+; RUN: llvm-ml -filetype=asm %s | FileCheck %s
+
+.data
+
+t1 BYTE NOT 1
+; CHECK-LABEL: t1:
+; CHECK-NEXT: .byte -2
+; CHECK-NOT: .byte
+
+t2 BYTE 1 OR 2
+; CHECK-LABEL: t2:
+; CHECK-NEXT: .byte 3
+
+t3 BYTE 6 AND 10
+; CHECK-LABEL: t3:
+; CHECK-NEXT: .byte 2
+
+t4 BYTE 5 EQ 6
+   BYTE 6 EQ 6
+   BYTE 7 EQ 6
+; CHECK-LABEL: t4:
+; CHECK-NEXT: .byte 0
+; CHECK: .byte -1
+; CHECK: .byte 0
+; CHECK-NOT: .byte
+
+t5 BYTE 5 NE 6
+   BYTE 6 NE 6
+   BYTE 7 NE 6
+; CHECK-LABEL: t5:
+; CHECK-NEXT: .byte -1
+; CHECK: .byte 0
+; CHECK: .byte -1
+; CHECK-NOT: .byte
+
+t6 BYTE 5 LT 6
+   BYTE 6 LT 6
+   BYTE 7 LT 6
+; CHECK-LABEL: t6:
+; CHECK-NEXT: .byte -1
+; CHECK: .byte 0
+; CHECK: .byte 0
+; CHECK-NOT: .byte
+
+t7 BYTE 5 LE 6
+   BYTE 6 LE 6
+   BYTE 7 LE 6
+; CHECK-LABEL: t7:
+; CHECK-NEXT: .byte -1
+; CHECK: .byte -1
+; CHECK: .byte 0
+; CHECK-NOT: .byte
+
+t8 BYTE 5 GT 6
+   BYTE 6 GT 6
+   BYTE 7 GT 6
+; CHECK-LABEL: t8:
+; CHECK-NEXT: .byte 0
+; CHECK: .byte 0
+; CHECK: .byte -1
+; CHECK-NOT: .byte
+
+t9 BYTE 5 GE 6
+   BYTE 6 GE 6
+   BYTE 7 GE 6
+; CHECK-LABEL: t9:
+; CHECK-NEXT: .byte 0
+; CHECK: .byte -1
+; CHECK: .byte -1
+; CHECK-NOT: .byte
+
+.code
+
+t10:
+xor eax, Not 1
+; CHECK-LABEL: t10:
+; CHECK-NEXT: xor eax, -2
+
+t11:
+xor eax, 1 oR 2
+; CHECK-LABEL: t11:
+; CHECK-NEXT: xor eax, 3
+
+t12:
+xor eax, 6 ANd 10
+; CHECK-LABEL: t12:
+; CHECK-NEXT: xor eax, 2
+
+t13:
+xor eax, 5 Eq 6
+xor eax, 6 eQ 6
+xor eax, 7 eq 6
+; CHECK-LABEL: t13:
+; CHECK-NEXT: xor eax, 0
+; CHECK-NEXT: xor eax, -1
+; CHECK-NEXT: xor eax, 0
+
+t14:
+xor eax, 5 Ne 6
+xor eax, 6 nE 6
+xor eax, 7 ne 6
+; CHECK-LABEL: t14:
+; CHECK-NEXT: xor eax, -1
+; CHECK-NEXT: xor eax, 0
+; CHECK-NEXT: xor eax, -1
+
+t15:
+xor eax, 5 Lt 6
+xor eax, 6 lT 6
+xor eax, 7 lt 6
+; CHECK-LABEL: t15:
+; CHECK-NEXT: xor eax, -1
+; CHECK-NEXT: xor eax, 0
+; CHECK-NEXT: xor eax, 0
+
+t16:
+xor eax, 5 Le 6
+xor eax, 6 lE 6
+xor eax, 7 le 6
+; CHECK-LABEL: t16:
+; CHECK-NEXT: xor eax, -1
+; CHECK-NEXT: xor eax, -1
+; CHECK-NEXT: xor eax, 0
+
+t17:
+xor eax, 5 Gt 6
+xor eax, 6 gT 6
+xor eax, 7 gt 6
+; CHECK-LABEL: t17:
+; CHECK-NEXT: xor eax, 0
+; CHECK-NEXT: xor eax, 0
+; CHECK-NEXT: xor eax, -1
+
+t18:
+xor eax, 5 Ge 6
+xor eax, 6 gE 6
+xor eax, 7 ge 6
+; CHECK-LABEL: t18:
+; CHECK-NEXT: xor eax, 0
+; CHECK-NEXT: xor eax, -1
+; CHECK-NEXT: xor eax, -1
+
+END