[llvm] r325295 - [X86][3DNOW] Teach decoder about AMD 3DNow! instrs

Rafael Auler via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 15 13:20:31 PST 2018


Author: rafauler
Date: Thu Feb 15 13:20:31 2018
New Revision: 325295

URL: http://llvm.org/viewvc/llvm-project?rev=325295&view=rev
Log:
[X86][3DNOW] Teach decoder about AMD 3DNow! instrs

Summary:
This patch makes the decoder understand old AMD 3DNow!
instructions that have never been properly supported in the X86
disassembler, despite being supported in other subsystems. Hopefully
this should make the X86 decoder more complete with respect to binaries
containing legacy code.

Reviewers: craig.topper

Reviewed By: craig.topper

Subscribers: llvm-commits, maksfb, bruno

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

Added:
    llvm/trunk/test/MC/Disassembler/X86/amd3dnow.txt
Modified:
    llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp
    llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h
    llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h
    llvm/trunk/lib/Target/X86/X86Instr3DNow.td
    llvm/trunk/utils/TableGen/X86DisassemblerTables.cpp
    llvm/trunk/utils/TableGen/X86RecognizableInstr.cpp
    llvm/trunk/utils/TableGen/X86RecognizableInstr.h

Modified: llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp?rev=325295&r1=325294&r2=325295&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp (original)
+++ llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp Thu Feb 15 13:20:31 2018
@@ -588,11 +588,44 @@ static int readPrefixes(struct InternalI
                 insn->vectorExtensionPrefix[0], insn->vectorExtensionPrefix[1],
                 insn->vectorExtensionPrefix[2]);
     }
+  } else if (byte == 0x0f) {
+    uint8_t byte1;
+
+    // Check for AMD 3DNow without a REX prefix
+    if (consumeByte(insn, &byte1)) {
+      unconsumeByte(insn);
+    } else {
+      if (byte1 != 0x0f) {
+        unconsumeByte(insn);
+        unconsumeByte(insn);
+      } else {
+        dbgprintf(insn, "Found AMD 3DNow prefix 0f0f");
+        insn->vectorExtensionType = TYPE_3DNOW;
+      }
+    }
   } else if (isREX(insn, byte)) {
     if (lookAtByte(insn, &nextByte))
       return -1;
     insn->rexPrefix = byte;
     dbgprintf(insn, "Found REX prefix 0x%hhx", byte);
+
+    // Check for AMD 3DNow with a REX prefix
+    if (nextByte == 0x0f) {
+      consumeByte(insn, &nextByte);
+      uint8_t byte1;
+
+      if (consumeByte(insn, &byte1)) {
+        unconsumeByte(insn);
+      } else {
+        if (byte1 != 0x0f) {
+          unconsumeByte(insn);
+          unconsumeByte(insn);
+        } else {
+          dbgprintf(insn, "Found AMD 3DNow prefix 0f0f");
+          insn->vectorExtensionType = TYPE_3DNOW;
+        }
+      }
+    }
   } else
     unconsumeByte(insn);
 
@@ -623,6 +656,8 @@ static int readPrefixes(struct InternalI
   return 0;
 }
 
+static int readModRM(struct InternalInstruction* insn);
+
 /*
  * readOpcode - Reads the opcode (excepting the ModR/M byte in the case of
  *   extended or escape opcodes).
@@ -690,6 +725,12 @@ static int readOpcode(struct InternalIns
       insn->opcodeType = XOPA_MAP;
       return consumeByte(insn, &insn->opcode);
     }
+  } else if (insn->vectorExtensionType == TYPE_3DNOW) {
+    // Consume operands before the opcode to comply with the 3DNow encoding
+    if (readModRM(insn))
+      return -1;
+    insn->opcodeType = TWOBYTE;
+    return consumeByte(insn, &insn->opcode);
   }
 
   if (consumeByte(insn, &current))
@@ -735,8 +776,6 @@ static int readOpcode(struct InternalIns
   return 0;
 }
 
-static int readModRM(struct InternalInstruction* insn);
-
 /*
  * getIDWithAttrMask - Determines the ID of an instruction, consuming
  *   the ModR/M byte as appropriate for extended and escape opcodes,
@@ -912,6 +951,8 @@ static int getID(struct InternalInstruct
 
       if (lFromXOP3of3(insn->vectorExtensionPrefix[2]))
         attrMask |= ATTR_VEXL;
+    } else if (insn->vectorExtensionType == TYPE_3DNOW) {
+      attrMask |= ATTR_3DNOW;
     } else {
       return -1;
     }

Modified: llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h?rev=325295&r1=325294&r2=325295&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h (original)
+++ llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h Thu Feb 15 13:20:31 2018
@@ -493,7 +493,8 @@ enum VectorExtensionType {
   TYPE_VEX_2B       = 0x1,
   TYPE_VEX_3B       = 0x2,
   TYPE_EVEX         = 0x3,
-  TYPE_XOP          = 0x4
+  TYPE_XOP          = 0x4,
+  TYPE_3DNOW        = 0x5
 };
 
 /// \brief Type for the byte reader that the consumer must provide to

Modified: llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h?rev=325295&r1=325294&r2=325295&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h (original)
+++ llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h Thu Feb 15 13:20:31 2018
@@ -60,7 +60,8 @@ namespace X86Disassembler {
   ENUM_ENTRY(ATTR_EVEXL2, (0x1 << 10))  \
   ENUM_ENTRY(ATTR_EVEXK,  (0x1 << 11))  \
   ENUM_ENTRY(ATTR_EVEXKZ, (0x1 << 12))  \
-  ENUM_ENTRY(ATTR_EVEXB,  (0x1 << 13))
+  ENUM_ENTRY(ATTR_EVEXB,  (0x1 << 13))  \
+  ENUM_ENTRY(ATTR_3DNOW,  (0x1 << 14))
 
 #define ENUM_ENTRY(n, v) n = v,
 enum attributeBits {
@@ -270,7 +271,8 @@ enum attributeBits {
   ENUM_ENTRY(IC_EVEX_L2_W_KZ,        3,  "requires EVEX_KZ, L2 and W")               \
   ENUM_ENTRY(IC_EVEX_L2_W_XS_KZ,     4,  "requires EVEX_KZ, L2, W and XS prefix")    \
   ENUM_ENTRY(IC_EVEX_L2_W_XD_KZ,     4,  "requires EVEX_KZ, L2, W and XD prefix")    \
-  ENUM_ENTRY(IC_EVEX_L2_W_OPSIZE_KZ, 4,  "requires EVEX_KZ, L2, W and OpSize")
+  ENUM_ENTRY(IC_EVEX_L2_W_OPSIZE_KZ, 4,  "requires EVEX_KZ, L2, W and OpSize")       \
+  ENUM_ENTRY(IC_3DNOW,               8,  "requires AMD 3DNow prefix 0f0f")
 
 #define ENUM_ENTRY(n, r, d) n,
 enum InstructionContext {

Modified: llvm/trunk/lib/Target/X86/X86Instr3DNow.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86Instr3DNow.td?rev=325295&r1=325294&r2=325295&view=diff
==============================================================================
--- llvm/trunk/lib/Target/X86/X86Instr3DNow.td (original)
+++ llvm/trunk/lib/Target/X86/X86Instr3DNow.td Thu Feb 15 13:20:31 2018
@@ -52,8 +52,6 @@ class I3DNow_binop<bits<8> o, Format F,
       : I3DNow<o, F, (outs VR64:$dst), ins,
           !strconcat(Mnemonic, "\t{$src2, $dst|$dst, $src2}"), pat, itin>,
         Has3DNow0F0FOpcode {
-  // FIXME: The disassembler doesn't support Has3DNow0F0FOpcode yet.
-  let isAsmParserOnly = 1;
   let Constraints = "$src1 = $dst";
 }
 
@@ -61,10 +59,7 @@ class I3DNow_conv<bits<8> o, Format F, d
                   InstrItinClass itin>
       : I3DNow<o, F, (outs VR64:$dst), ins,
           !strconcat(Mnemonic, "\t{$src, $dst|$dst, $src}"), pat, itin>,
-        Has3DNow0F0FOpcode {
-  // FIXME: The disassembler doesn't support Has3DNow0F0FOpcode yet.
-  let isAsmParserOnly = 1;
-}
+        Has3DNow0F0FOpcode;
 
 multiclass I3DNow_binop_rm_int<bits<8> opc, string Mn, OpndItins itins,
                                bit Commutable = 0, string Ver = ""> {

Added: llvm/trunk/test/MC/Disassembler/X86/amd3dnow.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/Disassembler/X86/amd3dnow.txt?rev=325295&view=auto
==============================================================================
--- llvm/trunk/test/MC/Disassembler/X86/amd3dnow.txt (added)
+++ llvm/trunk/test/MC/Disassembler/X86/amd3dnow.txt Thu Feb 15 13:20:31 2018
@@ -0,0 +1,76 @@
+# RUN: llvm-mc --disassemble %s -triple=x86_64-unknown-linux-gnu | FileCheck %s
+
+# Reference: AMD64 Architecture Programmer's Manual Vol.3
+# Pub no. 24594 - Rev. 3.25 - Dec 2017 - pgs.468-469
+
+# CHECK: pfcmpge     %mm0, %mm1
+0x0f 0x0f 0xc8 0x90
+
+# CHECK: pfcmpgt     %mm2, %mm0
+0x0f 0x0f 0xc2 0xa0
+
+# CHECK: pfcmpeq     %mm5, %mm2
+0x0f 0x0f 0xd5 0xb0
+
+# CHECK: pfmin       %mm1, %mm0
+0x0f 0x0f 0xc1 0x94
+
+# CHECK: pfmax       (%rax), %mm0
+0x0f 0x0f 0x00 0xa4
+
+# CHECK: pfmul       %mm6, %mm0
+0x0f 0x0f 0xc6 0xb4
+
+# CHECK: pfrcp       (%rbx), %mm1
+0x0f 0x0f 0x0b 0x96
+
+# CHECK: pfrcpit1    %mm0, %mm2
+0x0f 0x0f 0xd0 0xa6
+
+# CHECK: pfrcpit2    %mm0, %mm1
+0x0f 0x0f 0xc8 0xb6
+
+# CHECK: pfrsqrt     (%eax), %mm1
+0x67 0x0f 0x0f 0x08 0x97
+
+# CHECK: pfrsqit1    (%ebx), %mm4
+0x67 0x0f 0x0f 0x23 0xa7
+
+# CHECK: pmulhrw     %mm3, %mm0
+0x0f 0x0f 0xc3 0xb7
+
+# CHECK: pi2fw       %mm1, %mm3
+0x0f 0x0f 0xd9 0x0c
+
+# CHECK: pf2iw       %mm2, %mm4
+0x0f 0x0f 0xe2 0x1c
+
+# CHECK: pi2fd       %mm3, %mm1
+0x0f 0x0f 0xcb 0x0d
+
+# CHECK: pf2id       (%rdi,%r8), %mm1
+0x42 0x0f 0x0f 0x0c 0x07 0x1d
+
+# CHECK: pfnacc      16(%eax,%ebx,4), %mm0
+0x67 0x0f 0x0f 0x44 0x98 0x10 0x8a
+
+# CHECK: pfsub       %mm1, %mm0
+0x0f 0x0f 0xc1 0x9a
+
+# CHECK: pfsubr      %mm2, %mm1
+0x0f 0x0f 0xca 0xaa
+
+# CHECK: pswapd      %mm1, %mm3
+0x0f 0x0f 0xd9 0xbb
+
+# CHECK: pfpnacc     %mm0, %mm2
+0x0f 0x0f 0xd0 0x8e
+
+# CHECK: pfadd       %mm4, %mm3
+0x0f 0x0f 0xdc 0x9e
+
+# CHECK: pfacc       %mm1, %mm2
+0x0f 0x0f 0xd1 0xae
+
+# CHECK: pavgusb     %mm1, %mm3
+0x0f 0x0f 0xd9 0xbf

Modified: llvm/trunk/utils/TableGen/X86DisassemblerTables.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/X86DisassemblerTables.cpp?rev=325295&r1=325294&r2=325295&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/X86DisassemblerTables.cpp (original)
+++ llvm/trunk/utils/TableGen/X86DisassemblerTables.cpp Thu Feb 15 13:20:31 2018
@@ -546,6 +546,8 @@ static inline bool inheritsFrom(Instruct
   case IC_EVEX_L2_W_XD_KZ_B:
   case IC_EVEX_L2_W_OPSIZE_KZ_B:
     return false;
+  case IC_3DNOW:
+    return false;
   default:
     errs() << "Unknown instruction class: " <<
       stringForContext((InstructionContext)parent) << "\n";
@@ -888,7 +890,7 @@ void DisassemblerTables::emitInstruction
 }
 
 void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const {
-  const unsigned int tableSize = 16384;
+  const unsigned int tableSize = 32768;
   o.indent(i * 2) << "static const uint8_t " CONTEXTS_STR
                      "[" << tableSize << "] = {\n";
   i++;
@@ -896,7 +898,9 @@ void DisassemblerTables::emitContextTabl
   for (unsigned index = 0; index < tableSize; ++index) {
     o.indent(i * 2);
 
-    if (index & ATTR_EVEX) {
+    if (index & ATTR_3DNOW)
+      o << "IC_3DNOW";
+    else if (index & ATTR_EVEX) {
       o << "IC_EVEX";
       if (index & ATTR_EVEXL2)
         o << "_L2";

Modified: llvm/trunk/utils/TableGen/X86RecognizableInstr.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/X86RecognizableInstr.cpp?rev=325295&r1=325294&r2=325295&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/X86RecognizableInstr.cpp (original)
+++ llvm/trunk/utils/TableGen/X86RecognizableInstr.cpp Thu Feb 15 13:20:31 2018
@@ -80,19 +80,20 @@ RecognizableInstr::RecognizableInstr(Dis
   Form     = byteFromRec(Rec, "FormBits");
   Encoding = byteFromRec(Rec, "OpEncBits");
 
-  OpSize           = byteFromRec(Rec, "OpSizeBits");
-  AdSize           = byteFromRec(Rec, "AdSizeBits");
-  HasREX_WPrefix   = Rec->getValueAsBit("hasREX_WPrefix");
-  HasVEX_4V        = Rec->getValueAsBit("hasVEX_4V");
-  VEX_WPrefix      = byteFromRec(Rec,"VEX_WPrefix");
-  IgnoresVEX_L     = Rec->getValueAsBit("ignoresVEX_L");
-  HasEVEX_L2Prefix = Rec->getValueAsBit("hasEVEX_L2");
-  HasEVEX_K        = Rec->getValueAsBit("hasEVEX_K");
-  HasEVEX_KZ       = Rec->getValueAsBit("hasEVEX_Z");
-  HasEVEX_B        = Rec->getValueAsBit("hasEVEX_B");
-  IsCodeGenOnly    = Rec->getValueAsBit("isCodeGenOnly");
-  ForceDisassemble = Rec->getValueAsBit("ForceDisassemble");
-  CD8_Scale        = byteFromRec(Rec, "CD8_Scale");
+  OpSize             = byteFromRec(Rec, "OpSizeBits");
+  AdSize             = byteFromRec(Rec, "AdSizeBits");
+  HasREX_WPrefix     = Rec->getValueAsBit("hasREX_WPrefix");
+  HasVEX_4V          = Rec->getValueAsBit("hasVEX_4V");
+  VEX_WPrefix        = byteFromRec(Rec,"VEX_WPrefix");
+  IgnoresVEX_L       = Rec->getValueAsBit("ignoresVEX_L");
+  HasEVEX_L2Prefix   = Rec->getValueAsBit("hasEVEX_L2");
+  HasEVEX_K          = Rec->getValueAsBit("hasEVEX_K");
+  HasEVEX_KZ         = Rec->getValueAsBit("hasEVEX_Z");
+  HasEVEX_B          = Rec->getValueAsBit("hasEVEX_B");
+  Has3DNow0F0FOpcode = Rec->getValueAsBit("has3DNow0F0FOpcode");
+  IsCodeGenOnly      = Rec->getValueAsBit("isCodeGenOnly");
+  ForceDisassemble   = Rec->getValueAsBit("ForceDisassemble");
+  CD8_Scale          = byteFromRec(Rec, "CD8_Scale");
 
   Name      = Rec->getName();
 
@@ -288,6 +289,8 @@ InstructionContext RecognizableInstr::in
       errs() << "Instruction does not use a prefix: " << Name << "\n";
       llvm_unreachable("Invalid prefix");
     }
+  } else if (Has3DNow0F0FOpcode) {
+    insnContext = IC_3DNOW;
   } else if (Is64Bit || HasREX_WPrefix || AdSize == X86Local::AdSize64) {
     if (HasREX_WPrefix && (OpSize == X86Local::OpSize16 || OpPrefix == X86Local::PD))
       insnContext = IC_64BIT_REXW_OPSIZE;

Modified: llvm/trunk/utils/TableGen/X86RecognizableInstr.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/X86RecognizableInstr.h?rev=325295&r1=325294&r2=325295&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/X86RecognizableInstr.h (original)
+++ llvm/trunk/utils/TableGen/X86RecognizableInstr.h Thu Feb 15 13:20:31 2018
@@ -191,6 +191,8 @@ private:
   bool HasEVEX_KZ;
   /// The hasEVEX_B field from the record
   bool HasEVEX_B;
+  /// The has3DNow0F0FOpcode field from the record
+  bool Has3DNow0F0FOpcode;
   /// Indicates that the instruction uses the L and L' fields for RC.
   bool EncodeRC;
   /// The isCodeGenOnly field from the record
@@ -210,12 +212,12 @@ private:
   /// Indicates whether the instruction should be emitted into the decode
   /// tables; regardless, it will be emitted into the instruction info table
   bool ShouldBeEmitted;
-  
+
   /// The operands of the instruction, as listed in the CodeGenInstruction.
   /// They are not one-to-one with operands listed in the MCInst; for example,
   /// memory operands expand to 5 operands in the MCInst
   const std::vector<CGIOperandList::OperandInfo>* Operands;
-  
+
   /// The description of the instruction that is emitted into the instruction
   /// info table
   InstructionSpecifier* Spec;
@@ -283,7 +285,7 @@ private:
   ///                               operand exists.
   /// @param operandIndex         - The index into the generated operand table.
   ///                               Incremented by this function one or more
-  ///                               times to reflect possible duplicate 
+  ///                               times to reflect possible duplicate
   ///                               operands).
   /// @param physicalOperandIndex - The index of the current operand into the
   ///                               set of non-duplicate ('physical') operands.
@@ -314,12 +316,12 @@ private:
   bool shouldBeEmitted() const {
     return ShouldBeEmitted;
   }
-  
+
   /// emitInstructionSpecifier - Loads the instruction specifier for the current
   ///   instruction into a DisassemblerTables.
   ///
   void emitInstructionSpecifier();
-  
+
   /// emitDecodePath - Populates the proper fields in the decode tables
   ///   corresponding to the decode paths for this instruction.
   ///
@@ -349,7 +351,7 @@ public:
                            const CodeGenInstruction &insn,
                            InstrUID uid);
 };
-  
+
 } // namespace X86Disassembler
 
 } // namespace llvm




More information about the llvm-commits mailing list