[MC][X86] Enhance X86 Register expression handling to more closely match GCC.

Allow the comparison of x86 registers in the evaluation of assembler
directives. This generalizes and simplifies the extension from r334022
to catch another case found in the Linux kernel.

Reviewers: rnk, void

Reviewed By: rnk

Subscribers: hiraditya, nickdesaulniers, llvm-commits

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

llvm-svn: 339895
diff --git a/llvm/lib/MC/MCExpr.cpp b/llvm/lib/MC/MCExpr.cpp
index e3a6f8e7..638cb35 100644
--- a/llvm/lib/MC/MCExpr.cpp
+++ b/llvm/lib/MC/MCExpr.cpp
@@ -751,8 +751,22 @@
     if (!ABE->getLHS()->evaluateAsRelocatableImpl(LHSValue, Asm, Layout, Fixup,
                                                   Addrs, InSet) ||
         !ABE->getRHS()->evaluateAsRelocatableImpl(RHSValue, Asm, Layout, Fixup,
-                                                  Addrs, InSet))
+                                                  Addrs, InSet)) {
+      // Check if both are Target Expressions, see if we can compare them.
+      if (const MCTargetExpr *L = dyn_cast<MCTargetExpr>(ABE->getLHS()))
+        if (const MCTargetExpr *R = cast<MCTargetExpr>(ABE->getRHS())) {
+          switch (ABE->getOpcode()) {
+          case MCBinaryExpr::EQ:
+            Res = MCValue::get((L->isEqualTo(R)) ? -1 : 0);
+            return true;
+          case MCBinaryExpr::NE:
+            Res = MCValue::get((R->isEqualTo(R)) ? 0 : -1);
+            return true;
+          default: {}
+          }
+        }
       return false;
+    }
 
     // We only support a few operations on non-constant expressions, handle
     // those first.
diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp
index 39a7608..b43babb 100644
--- a/llvm/lib/MC/MCParser/AsmParser.cpp
+++ b/llvm/lib/MC/MCParser/AsmParser.cpp
@@ -337,7 +337,7 @@
   StringRef parseStringToComma();
 
   bool parseAssignment(StringRef Name, bool allow_redef,
-                       bool NoDeadStrip = false, bool AllowExtendedExpr = false);
+                       bool NoDeadStrip = false);
 
   unsigned getBinOpPrecedence(AsmToken::TokenKind K,
                               MCBinaryExpr::Opcode &Kind);
@@ -1363,7 +1363,8 @@
 bool AsmParser::parseExpression(const MCExpr *&Res, SMLoc &EndLoc) {
   // Parse the expression.
   Res = nullptr;
-  if (parsePrimaryExpr(Res, EndLoc) || parseBinOpRHS(1, Res, EndLoc))
+  if (getTargetParser().parsePrimaryExpr(Res, EndLoc) ||
+      parseBinOpRHS(1, Res, EndLoc))
     return true;
 
   // As a special case, we support 'a op b @ modifier' by rewriting the
@@ -1617,7 +1618,7 @@
 
     // Eat the next primary expression.
     const MCExpr *RHS;
-    if (parsePrimaryExpr(RHS, EndLoc))
+    if (getTargetParser().parsePrimaryExpr(RHS, EndLoc))
       return true;
 
     // If BinOp binds less tightly with RHS than the operator after RHS, let
@@ -1826,7 +1827,7 @@
     // identifier '=' ... -> assignment statement
     Lex();
 
-    return parseAssignment(IDVal, true, /*NoDeadStrip*/ false, /*AllowExtendedExpr*/true);
+    return parseAssignment(IDVal, true);
 
   default: // Normal instruction or directive.
     break;
@@ -2766,11 +2767,11 @@
 }
 
 bool AsmParser::parseAssignment(StringRef Name, bool allow_redef,
-                                bool NoDeadStrip, bool AllowExtendedExpr) {
+                                bool NoDeadStrip) {
   MCSymbol *Sym;
   const MCExpr *Value;
   if (MCParserUtils::parseAssignmentExpression(Name, allow_redef, *this, Sym,
-                                               Value, AllowExtendedExpr))
+                                               Value))
     return true;
 
   if (!Sym) {
@@ -5839,17 +5840,13 @@
 
 bool parseAssignmentExpression(StringRef Name, bool allow_redef,
                                MCAsmParser &Parser, MCSymbol *&Sym,
-                               const MCExpr *&Value, bool AllowExtendedExpr) {
+                               const MCExpr *&Value) {
 
   // FIXME: Use better location, we should use proper tokens.
   SMLoc EqualLoc = Parser.getTok().getLoc();
   SMLoc EndLoc;
-  if (AllowExtendedExpr) {
-    if (Parser.getTargetParser().parseAssignmentExpression(Value, EndLoc)) {
-      return Parser.TokError("missing expression");
-    }
-  } else if (Parser.parseExpression(Value, EndLoc))
-      return Parser.TokError("missing expression");
+  if (Parser.parseExpression(Value))
+    return Parser.TokError("missing expression");
 
   // Note: we don't count b as used in "a = b". This is to allow
   // a = b
diff --git a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
index fafbed0..b02e4d8 100644
--- a/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
+++ b/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
@@ -955,7 +955,7 @@
 
   void SetFrameRegister(unsigned RegNo) override;
 
-  bool parseAssignmentExpression(const MCExpr *&Res, SMLoc &EndLoc) override;
+  bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) override;
 
   bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
                         SMLoc NameLoc, OperandVector &Operands) override;
@@ -2260,15 +2260,17 @@
   return X86Operand::CreateMem(getPointerWidth(), Disp, MemStart, MemEnd);
 }
 
-// Parse either a standard expression or a register.
-bool X86AsmParser::parseAssignmentExpression(const MCExpr *&Res,
-                                             SMLoc &EndLoc) {
+// Parse either a standard primary expression or a register.
+bool X86AsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) {
   MCAsmParser &Parser = getParser();
-  if (Parser.parseExpression(Res, EndLoc)) {
+  if (Parser.parsePrimaryExpr(Res, EndLoc)) {
     SMLoc StartLoc = Parser.getTok().getLoc();
     // Normal Expression parse fails, check if it could be a register.
     unsigned RegNo;
-    if (Parser.getTargetParser().ParseRegister(RegNo, StartLoc, EndLoc))
+    bool TryRegParse =
+        getTok().is(AsmToken::Percent) ||
+        (isParsingIntelSyntax() && getTok().is(AsmToken::Identifier));
+    if (!TryRegParse || ParseRegister(RegNo, StartLoc, EndLoc))
       return true;
     // Clear previous parse error and return correct expression.
     Parser.clearPendingErrors();
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86MCExpr.h b/llvm/lib/Target/X86/MCTargetDesc/X86MCExpr.h
index f1438cd..1070f70 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86MCExpr.h
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86MCExpr.h
@@ -48,7 +48,7 @@
   /// @}
 
   void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override {
-    if (MAI->getAssemblerDialect() == 0)
+    if (!MAI || MAI->getAssemblerDialect() == 0)
       OS << '%';
     OS << X86ATTInstPrinter::getRegisterName(RegNo);
   }
@@ -59,6 +59,11 @@
   }
   // Register values should be inlined as they are not valid .set expressions.
   bool inlineAssignedExpr() const override { return true; }
+  bool isEqualTo(const MCExpr *X) const override {
+    if (auto *E = dyn_cast<X86MCExpr>(X))
+      return getRegNo() == E->getRegNo();
+    return false;
+  }
   void visitUsedExpr(MCStreamer &Streamer) const override{};
   MCFragment *findAssociatedFragment() const override { return nullptr; }