Implement support for the bizarre 3DNow! encoding (which is unlike anything
authorChris Lattner <sabre@nondot.org>
Sun, 3 Oct 2010 18:08:05 +0000 (18:08 +0000)
committerChris Lattner <sabre@nondot.org>
Sun, 3 Oct 2010 18:08:05 +0000 (18:08 +0000)
else in X86), and add support for pavgusb.  This is apparently the
only instruction (other than movsx) that is preventing ffmpeg from building
with clang.

If someone else is interested in banging out the rest of the 3DNow!
instructions, it should be quite easy now.

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

lib/Target/X86/X86Instr3DNow.td
lib/Target/X86/X86InstrFormats.td
lib/Target/X86/X86InstrInfo.h
lib/Target/X86/X86InstrInfo.td
lib/Target/X86/X86MCCodeEmitter.cpp
test/MC/X86/3DNow.s [new file with mode: 0644]

index 7615f845a46faf641e9a1e3cd9266d2aba50efb0..9efa2a6cd3321bcfe82a438472235ac42feb225b 100644 (file)
 // floating point and also adds a few more random instructions for good measure.
 //
 //===----------------------------------------------------------------------===//
+
+// FIXME: We don't support any intrinsics for these instructions yet.
+
+class I3DNow<bits<8> o, Format F, dag outs, dag ins, string asm, 
+             list<dag> pattern>
+      : I<o, F, outs, ins, asm, pattern>, TB, Requires<[Has3DNow]>,
+        Has3DNow0F0FOpcode {
+  // FIXME: The disassembler doesn't support 3DNow! yet.
+  let isAsmParserOnly = 1;
+}
+
+
+let Constraints = "$src1 = $dst" in {
+  // MMXI_binop_rm_int - Simple MMX binary operator based on intrinsic.
+  // When this is cleaned up, remove the FIXME from X86RecognizableInstr.cpp.
+  multiclass I3DNow_binop_rm<bits<8> opc, string Mnemonic> {
+    def rr : I3DNow<opc, MRMSrcReg, (outs VR64:$dst),
+                    (ins VR64:$src1, VR64:$src2),
+                    !strconcat(Mnemonic, "\t{$src2, $dst|$dst, $src2}"), []>;
+    def rm : I3DNow<opc, MRMSrcMem, (outs VR64:$dst),
+                    (ins VR64:$src1, i64mem:$src2),
+                    !strconcat(Mnemonic, "\t{$src2, $dst|$dst, $src2}"), []>;
+  }
+}
+
+defm PAVGUSB : I3DNow_binop_rm<0xBF, "pavgusb">;
+
+
+
+
+// TODO: Add support for the rest of the 3DNow! and "3DNowA" instructions.
index 2e4f4cafccc3393f8156757cd4c7374c9eb68a7d..ce85e3a49dc2c274546f5497eaf8668d7583a785 100644 (file)
@@ -109,6 +109,7 @@ class VEX_W  { bit hasVEX_WPrefix = 1; }
 class VEX_4V : VEX { bit hasVEX_4VPrefix = 1; }
 class VEX_I8IMM { bit hasVEX_i8ImmReg = 1; }
 class VEX_L  { bit hasVEX_L = 1; }
+class Has3DNow0F0FOpcode  { bit has3DNow0F0FOpcode = 1; }
 
 class X86Inst<bits<8> opcod, Format f, ImmType i, dag outs, dag ins,
               string AsmStr, Domain d = GenericDomain>
@@ -142,6 +143,7 @@ class X86Inst<bits<8> opcod, Format f, ImmType i, dag outs, dag ins,
   bit hasVEX_i8ImmReg = 0;  // Does this inst requires the last source register
                             // to be encoded in a immediate field?
   bit hasVEX_L = 0;         // Does this inst uses large (256-bit) registers?
+  bit has3DNow0F0FOpcode =0;// Wacky 3dNow! encoding?
 
   // TSFlags layout should be kept in sync with X86InstrInfo.h.
   let TSFlags{5-0}   = FormBits;
@@ -160,6 +162,7 @@ class X86Inst<bits<8> opcod, Format f, ImmType i, dag outs, dag ins,
   let TSFlags{34}    = hasVEX_4VPrefix;
   let TSFlags{35}    = hasVEX_i8ImmReg;
   let TSFlags{36}    = hasVEX_L;
+  let TSFlags{37}    = has3DNow0F0FOpcode;
 }
 
 class I<bits<8> o, Format f, dag outs, dag ins, string asm,
index 2e7e0636378df8a7fee742ec7903bab97864757b..b58984fce64a640ff903df7dda5ab855272413b4 100644 (file)
@@ -449,28 +449,36 @@ namespace X86II {
     OpcodeMask    = 0xFF << OpcodeShift,
 
     //===------------------------------------------------------------------===//
-    // VEX - The opcode prefix used by AVX instructions
+    /// VEX - The opcode prefix used by AVX instructions
     VEX         = 1U << 0,
 
-    // VEX_W - Has a opcode specific functionality, but is used in the same
-    // way as REX_W is for regular SSE instructions.
+    /// VEX_W - Has a opcode specific functionality, but is used in the same
+    /// way as REX_W is for regular SSE instructions.
     VEX_W       = 1U << 1,
 
-    // VEX_4V - Used to specify an additional AVX/SSE register. Several 2
-    // address instructions in SSE are represented as 3 address ones in AVX
-    // and the additional register is encoded in VEX_VVVV prefix.
+    /// VEX_4V - Used to specify an additional AVX/SSE register. Several 2
+    /// address instructions in SSE are represented as 3 address ones in AVX
+    /// and the additional register is encoded in VEX_VVVV prefix.
     VEX_4V      = 1U << 2,
 
-    // VEX_I8IMM - Specifies that the last register used in a AVX instruction,
-    // must be encoded in the i8 immediate field. This usually happens in
-    // instructions with 4 operands.
+    /// VEX_I8IMM - Specifies that the last register used in a AVX instruction,
+    /// must be encoded in the i8 immediate field. This usually happens in
+    /// instructions with 4 operands.
     VEX_I8IMM   = 1U << 3,
 
-    // VEX_L - Stands for a bit in the VEX opcode prefix meaning the current
-    // instruction uses 256-bit wide registers. This is usually auto detected if
-    // a VR256 register is used, but some AVX instructions also have this field
-    // marked when using a f256 memory references.
-    VEX_L       = 1U << 4
+    /// VEX_L - Stands for a bit in the VEX opcode prefix meaning the current
+    /// instruction uses 256-bit wide registers. This is usually auto detected
+    /// if a VR256 register is used, but some AVX instructions also have this
+    /// field marked when using a f256 memory references.
+    VEX_L       = 1U << 4,
+    
+    /// Has3DNow0F0FOpcode - This flag indicates that the instruction uses the
+    /// wacky 0x0F 0x0F prefix for 3DNow! instructions.  The manual documents
+    /// this as having a 0x0F prefix with a 0x0F opcode, and each instruction
+    /// storing a classifier in the imm8 field.  To simplify our implementation,
+    /// we handle this by storeing the classifier in the opcode field and using
+    /// this flag to indicate that the encoder should do the wacky 3DNow! thing.
+    Has3DNow0F0FOpcode = 1U << 5
   };
   
   // getBaseOpcodeFor - This function returns the "base" X86 opcode for the
index cfe7fed0669b13ab41c17554c790359e952c7568..3835ddc7b14f97f7695be9a8a16a8f6f6e8482c3 100644 (file)
@@ -349,6 +349,8 @@ def NoCMov       : Predicate<"!Subtarget->hasCMov()">;
 // no AVX version of the desired intructions is present, this is better for
 // incremental dev (without fallbacks it's easier to spot what's missing)
 def HasMMX       : Predicate<"Subtarget->hasMMX() && !Subtarget->hasAVX()">;
+def Has3DNow     : Predicate<"Subtarget->has3DNow()">;
+def Has3DNowA    : Predicate<"Subtarget->has3DNowA()">;
 def HasSSE1      : Predicate<"Subtarget->hasSSE1() && !Subtarget->hasAVX()">;
 def HasSSE2      : Predicate<"Subtarget->hasSSE2() && !Subtarget->hasAVX()">;
 def HasSSE3      : Predicate<"Subtarget->hasSSE3() && !Subtarget->hasAVX()">;
index cdc8a1d431d0996ea5c9fdc1be59d2399824f08e..d5cab49c0d6afa3a162b351af734363037ada463 100644 (file)
@@ -822,6 +822,7 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS,
   if ((TSFlags >> 32) & X86II::VEX_4V)
     HasVEX_4V = true;
 
+  
   // Determine where the memory operand starts, if present.
   int MemoryOperand = X86II::getMemoryOperandNo(TSFlags);
   if (MemoryOperand != -1) MemoryOperand += CurOp;
@@ -831,7 +832,12 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS,
   else
     EmitVEXOpcodePrefix(TSFlags, CurByte, MemoryOperand, MI, Desc, OS);
 
+  
   unsigned char BaseOpcode = X86II::getBaseOpcodeFor(TSFlags);
+  
+  if ((TSFlags >> 32) & X86II::Has3DNow0F0FOpcode)
+    BaseOpcode = 0x0F;   // Weird 3DNow! encoding.
+  
   unsigned SrcRegNum = 0;
   switch (TSFlags & X86II::FormMask) {
   case X86II::MRMInitReg:
@@ -998,6 +1004,9 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS,
     }
   }
 
+  if ((TSFlags >> 32) & X86II::Has3DNow0F0FOpcode)
+    EmitByte(X86II::getBaseOpcodeFor(TSFlags), CurByte, OS);
+  
 
 #ifndef NDEBUG
   // FIXME: Verify.
diff --git a/test/MC/X86/3DNow.s b/test/MC/X86/3DNow.s
new file mode 100644 (file)
index 0000000..e5c9f7d
--- /dev/null
@@ -0,0 +1,11 @@
+// RUN: llvm-mc -triple i386-unknown-unknown --show-encoding %s | FileCheck %s
+
+// PR8283
+
+// CHECK: pavgusb %mm2, %mm1  # encoding: [0x0f,0x0f,0xca,0xbf]
+pavgusb        %mm2, %mm1
+
+// CHECK: pavgusb 9(%esi,%edx), %mm3 # encoding: [0x0f,0x0f,0x5c,0x16,0x09,0
+pavgusb        9(%esi,%edx), %mm3
+
+