OSDN Git Service

[X86][AsmParser] Rework that allows (%dx) to be used in place of %dx with in/out...
authorCraig Topper <craig.topper@intel.com>
Sat, 23 Jun 2018 00:03:20 +0000 (00:03 +0000)
committerCraig Topper <craig.topper@intel.com>
Sat, 23 Jun 2018 00:03:20 +0000 (00:03 +0000)
Previously, to support (%dx) we left a wide open hole in our 16-bit memory address checking. This let this address value be used with any instruction without error in the parser. It would later fail in the encoder with an assertion failure on debug builds and who knows what on release builds.

This patch passes the mnemonic down to the memory operand parsing function so we can allow the (%dx) form only on specific instructions.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@335403 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/X86/AsmParser/X86AsmParser.cpp

index fced1b7..1daa2ed 100644 (file)
@@ -819,8 +819,8 @@ private:
                             std::unique_ptr<llvm::MCParsedAsmOperand> &&Dst);
   bool VerifyAndAdjustOperands(OperandVector &OrigOperands,
                                OperandVector &FinalOperands);
-  std::unique_ptr<X86Operand> ParseOperand();
-  std::unique_ptr<X86Operand> ParseATTOperand();
+  std::unique_ptr<X86Operand> ParseOperand(StringRef Mnemonic);
+  std::unique_ptr<X86Operand> ParseATTOperand(StringRef Mnemonic);
   std::unique_ptr<X86Operand> ParseIntelOperand();
   std::unique_ptr<X86Operand> ParseIntelOffsetOfOperator();
   bool ParseIntelDotOperator(IntelExprStateMachine &SM, SMLoc &End);
@@ -835,7 +835,8 @@ private:
                                      InlineAsmIdentifierInfo &Info,
                                      bool IsUnevaluatedOperand, SMLoc &End);
 
-  std::unique_ptr<X86Operand> ParseMemOperand(unsigned SegReg, SMLoc StartLoc);
+  std::unique_ptr<X86Operand> ParseMemOperand(unsigned SegReg, SMLoc StartLoc,
+                                              StringRef Mnemonic);
 
   bool ParseIntelMemoryOperandSize(unsigned &Size);
   std::unique_ptr<X86Operand>
@@ -988,8 +989,7 @@ static bool CheckBaseRegAndIndexRegAndScale(unsigned BaseReg, unsigned IndexReg,
   // because an unofficial form of in/out instructions uses it.
   if (X86MCRegisterClasses[X86::GR16RegClassID].contains(BaseReg) &&
       (Is64BitMode || (BaseReg != X86::BX && BaseReg != X86::BP &&
-                       BaseReg != X86::SI && BaseReg != X86::DI)) &&
-      BaseReg != X86::DX) {
+                       BaseReg != X86::SI && BaseReg != X86::DI))) {
     ErrMsg = "invalid 16-bit base register";
     return true;
   }
@@ -1302,10 +1302,10 @@ bool X86AsmParser::VerifyAndAdjustOperands(OperandVector &OrigOperands,
   return false;
 }
 
-std::unique_ptr<X86Operand> X86AsmParser::ParseOperand() {
+std::unique_ptr<X86Operand> X86AsmParser::ParseOperand(StringRef Mnemonic) {
   if (isParsingIntelSyntax())
     return ParseIntelOperand();
-  return ParseATTOperand();
+  return ParseATTOperand(Mnemonic);
 }
 
 std::unique_ptr<X86Operand> X86AsmParser::CreateMemForInlineAsm(
@@ -1891,12 +1891,12 @@ std::unique_ptr<X86Operand> X86AsmParser::ParseIntelOperand() {
                                BaseReg, IndexReg, Scale, Start, End, Size);
 }
 
-std::unique_ptr<X86Operand> X86AsmParser::ParseATTOperand() {
+std::unique_ptr<X86Operand> X86AsmParser::ParseATTOperand(StringRef Mnemonic) {
   MCAsmParser &Parser = getParser();
   switch (getLexer().getKind()) {
   default:
     // Parse a memory operand with no segment register.
-    return ParseMemOperand(0, Parser.getTok().getLoc());
+    return ParseMemOperand(0, Parser.getTok().getLoc(), Mnemonic);
   case AsmToken::Percent: {
     // Read the register.
     unsigned RegNo;
@@ -1922,7 +1922,7 @@ std::unique_ptr<X86Operand> X86AsmParser::ParseATTOperand() {
       return ErrorOperand(Start, "invalid segment register");
 
     getParser().Lex(); // Eat the colon.
-    return ParseMemOperand(RegNo, Start);
+    return ParseMemOperand(RegNo, Start, Mnemonic);
   }
   case AsmToken::Dollar: {
     // $42 -> immediate.
@@ -2048,7 +2048,8 @@ bool X86AsmParser::HandleAVX512Operand(OperandVector &Operands,
 /// ParseMemOperand: segment: disp(basereg, indexreg, scale).  The '%ds:' prefix
 /// has already been parsed if present.
 std::unique_ptr<X86Operand> X86AsmParser::ParseMemOperand(unsigned SegReg,
-                                                          SMLoc MemStart) {
+                                                          SMLoc MemStart,
+                                                          StringRef Mnemonic) {
 
   MCAsmParser &Parser = getParser();
   // We have to disambiguate a parenthesized expression "(4+5)" from the start
@@ -2198,6 +2199,22 @@ std::unique_ptr<X86Operand> X86AsmParser::ParseMemOperand(unsigned SegReg,
   if (parseToken(AsmToken::RParen, "unexpected token in memory operand"))
     return nullptr;
 
+  // This is a terrible hack to handle "out[s]?[bwl]? %al, (%dx)" ->
+  // "outb %al, %dx".  Out doesn't take a memory form, but this is a widely
+  // documented form in various unofficial manuals, so a lot of code uses it.
+  if (BaseReg == X86::DX && IndexReg == 0 && Scale == 1 &&
+      SegReg == 0 && isa<MCConstantExpr>(Disp) &&
+      cast<MCConstantExpr>(Disp)->getValue() == 0 &&
+      (Mnemonic == "outb" || Mnemonic == "outsb" ||
+       Mnemonic == "outw" || Mnemonic == "outsw" ||
+       Mnemonic == "outl" || Mnemonic == "outsl" ||
+       Mnemonic == "out" || Mnemonic == "outs" ||
+       Mnemonic == "inb" || Mnemonic == "insb" ||
+       Mnemonic == "inw" || Mnemonic == "insw" ||
+       Mnemonic == "inl" || Mnemonic == "insl" ||
+       Mnemonic == "in" || Mnemonic == "ins"))
+    return X86Operand::CreateReg(BaseReg, BaseLoc, BaseLoc);
+
   StringRef ErrMsg;
   if (CheckBaseRegAndIndexRegAndScale(BaseReg, IndexReg, Scale, is64BitMode(),
                                       ErrMsg)) {
@@ -2459,7 +2476,7 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
 
     // Read the operands.
     while(1) {
-      if (std::unique_ptr<X86Operand> Op = ParseOperand()) {
+      if (std::unique_ptr<X86Operand> Op = ParseOperand(Name)) {
         Operands.push_back(std::move(Op));
         if (HandleAVX512Operand(Operands, *Operands.back()))
           return true;
@@ -2529,35 +2546,6 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
     }
   }
 
-  // This is a terrible hack to handle "out[s]?[bwl]? %al, (%dx)" ->
-  // "outb %al, %dx".  Out doesn't take a memory form, but this is a widely
-  // documented form in various unofficial manuals, so a lot of code uses it.
-  if ((Name == "outb" || Name == "outsb" || Name == "outw" || Name == "outsw" ||
-       Name == "outl" || Name == "outsl" || Name == "out" || Name == "outs") &&
-      Operands.size() == 3) {
-    X86Operand &Op = (X86Operand &)*Operands.back();
-    if (Op.isMem() && Op.Mem.SegReg == 0 &&
-        isa<MCConstantExpr>(Op.Mem.Disp) &&
-        cast<MCConstantExpr>(Op.Mem.Disp)->getValue() == 0 &&
-        Op.Mem.BaseReg == MatchRegisterName("dx") && Op.Mem.IndexReg == 0) {
-      SMLoc Loc = Op.getEndLoc();
-      Operands.back() = X86Operand::CreateReg(Op.Mem.BaseReg, Loc, Loc);
-    }
-  }
-  // Same hack for "in[s]?[bwl]? (%dx), %al" -> "inb %dx, %al".
-  if ((Name == "inb" || Name == "insb" || Name == "inw" || Name == "insw" ||
-       Name == "inl" || Name == "insl" || Name == "in" || Name == "ins") &&
-      Operands.size() == 3) {
-    X86Operand &Op = (X86Operand &)*Operands[1];
-    if (Op.isMem() && Op.Mem.SegReg == 0 &&
-        isa<MCConstantExpr>(Op.Mem.Disp) &&
-        cast<MCConstantExpr>(Op.Mem.Disp)->getValue() == 0 &&
-        Op.Mem.BaseReg == MatchRegisterName("dx") && Op.Mem.IndexReg == 0) {
-      SMLoc Loc = Op.getEndLoc();
-      Operands[1] = X86Operand::CreateReg(Op.Mem.BaseReg, Loc, Loc);
-    }
-  }
-
   SmallVector<std::unique_ptr<MCParsedAsmOperand>, 2> TmpOperands;
   bool HadVerifyError = false;