Add X86 BEXTR instruction. This instruction uses VEX.vvvv to encode Operand 3 instead...
authorCraig Topper <craig.topper@gmail.com>
Sun, 16 Oct 2011 03:51:13 +0000 (03:51 +0000)
committerCraig Topper <craig.topper@gmail.com>
Sun, 16 Oct 2011 03:51:13 +0000 (03:51 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@142105 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/X86/MCTargetDesc/X86BaseInfo.h
lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
lib/Target/X86/X86InstrInfo.td
test/MC/Disassembler/X86/simple-tests.txt
test/MC/Disassembler/X86/x86-32.txt
test/MC/X86/x86_64-bmi-encoding.s
utils/TableGen/X86RecognizableInstr.cpp
utils/TableGen/X86RecognizableInstr.h

index 555ca17f4251a42d7f89dcdf4a564f8520c4a24b..ce24904f50822dda86cfdb07427097b6232ac757 100644 (file)
@@ -462,7 +462,7 @@ namespace X86II {
   /// is duplicated in the MCInst (e.g. "EAX = addl EAX, [mem]") it is only
   /// counted as one operand.
   ///
-  static inline int getMemoryOperandNo(uint64_t TSFlags) {
+  static inline int getMemoryOperandNo(uint64_t TSFlags, unsigned Opcode) {
     switch (TSFlags & X86II::FormMask) {
     case X86II::MRMInitReg:  assert(0 && "FIXME: Remove this form");
     default: assert(0 && "Unknown FormMask value in getMemoryOperandNo!");
@@ -477,9 +477,12 @@ namespace X86II {
     case X86II::MRMDestMem:
       return 0;
     case X86II::MRMSrcMem: {
+      // FIXME: BEXTR uses VEX.vvvv for Operand 3
+      bool IsBEXTR = (Opcode == X86::BEXTR32rr || Opcode == X86::BEXTR32rm ||
+                      Opcode == X86::BEXTR64rr || Opcode == X86::BEXTR64rm);
       bool HasVEX_4V = (TSFlags >> X86II::VEXShift) & X86II::VEX_4V;
       unsigned FirstMemOp = 1;
-      if (HasVEX_4V)
+      if (HasVEX_4V && !IsBEXTR)
         ++FirstMemOp;// Skip the register source (which is encoded in VEX_VVVV).
 
       // FIXME: Maybe lea should have its own form?  This is a horrible hack.
index 918d4a047430f695cfb84f6dceef86f72ef5f989..55c6010dddeb2cb7420b644195778fd0bf9c72ca 100644 (file)
@@ -447,6 +447,11 @@ void X86MCCodeEmitter::EmitVEXOpcodePrefix(uint64_t TSFlags, unsigned &CurByte,
   //
   unsigned char VEX_PP = 0;
 
+  // FIXME: BEXTR uses VEX.vvvv for Operand 3 instead of Operand 2
+  unsigned Opcode = MI.getOpcode();
+  bool IsBEXTR = (Opcode == X86::BEXTR32rr || Opcode == X86::BEXTR32rm ||
+                  Opcode == X86::BEXTR64rr || Opcode == X86::BEXTR64rm);
+
   // Encode the operand size opcode prefix as needed.
   if (TSFlags & X86II::OpSize)
     VEX_PP = 0x01;
@@ -525,7 +530,8 @@ void X86MCCodeEmitter::EmitVEXOpcodePrefix(uint64_t TSFlags, unsigned &CurByte,
     if (X86II::isX86_64ExtendedReg(MI.getOperand(0).getReg()))
       VEX_R = 0x0;
 
-    if (HasVEX_4V)
+    // FIXME: BEXTR uses VEX.vvvv for Operand 3
+    if (HasVEX_4V && !IsBEXTR)
       VEX_4V = getVEXRegisterEncoding(MI, 1);
 
     if (X86II::isX86_64ExtendedReg(
@@ -534,6 +540,9 @@ void X86MCCodeEmitter::EmitVEXOpcodePrefix(uint64_t TSFlags, unsigned &CurByte,
     if (X86II::isX86_64ExtendedReg(
                MI.getOperand(MemOperand+X86::AddrIndexReg).getReg()))
       VEX_X = 0x0;
+
+    if (IsBEXTR)
+      VEX_4V = getVEXRegisterEncoding(MI, X86::AddrNumOperands+1);
     break;
   case X86II::MRM0m: case X86II::MRM1m:
   case X86II::MRM2m: case X86II::MRM3m:
@@ -563,10 +572,14 @@ void X86MCCodeEmitter::EmitVEXOpcodePrefix(uint64_t TSFlags, unsigned &CurByte,
       VEX_R = 0x0;
     CurOp++;
 
-    if (HasVEX_4V)
+    // FIXME: BEXTR uses VEX.vvvv for Operand 3
+    if (HasVEX_4V && !IsBEXTR)
       VEX_4V = getVEXRegisterEncoding(MI, CurOp++);
     if (X86II::isX86_64ExtendedReg(MI.getOperand(CurOp).getReg()))
       VEX_B = 0x0;
+    CurOp++;
+    if (IsBEXTR)
+      VEX_4V = getVEXRegisterEncoding(MI, CurOp);
     break;
   case X86II::MRMDestReg:
     // MRMDestReg instructions forms:
@@ -872,7 +885,7 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS,
     HasVEX_4V = true;
 
   // Determine where the memory operand starts, if present.
-  int MemoryOperand = X86II::getMemoryOperandNo(TSFlags);
+  int MemoryOperand = X86II::getMemoryOperandNo(TSFlags, Opcode);
   if (MemoryOperand != -1) MemoryOperand += CurOp;
 
   if (!HasVEXPrefix)
@@ -885,6 +898,10 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS,
   if ((TSFlags >> X86II::VEXShift) & X86II::Has3DNow0F0FOpcode)
     BaseOpcode = 0x0F;   // Weird 3DNow! encoding.
 
+  // FIXME: BEXTR uses VEX.vvvv for Operand 3 instead of Operand 2
+  bool IsBEXTR = (Opcode == X86::BEXTR32rr || Opcode == X86::BEXTR32rm ||
+                  Opcode == X86::BEXTR64rr || Opcode == X86::BEXTR64rm);
+
   unsigned SrcRegNum = 0;
   switch (TSFlags & X86II::FormMask) {
   case X86II::MRMInitReg:
@@ -939,18 +956,20 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS,
     EmitByte(BaseOpcode, CurByte, OS);
     SrcRegNum = CurOp + 1;
 
-    if (HasVEX_4V) // Skip 1st src (which is encoded in VEX_VVVV)
+    if (HasVEX_4V && !IsBEXTR) // Skip 1st src (which is encoded in VEX_VVVV)
       SrcRegNum++;
 
     EmitRegModRMByte(MI.getOperand(SrcRegNum),
                      GetX86RegNum(MI.getOperand(CurOp)), CurByte, OS);
     CurOp = SrcRegNum + 1;
+    if (IsBEXTR)
+      ++CurOp;
     break;
 
   case X86II::MRMSrcMem: {
     int AddrOperands = X86::AddrNumOperands;
     unsigned FirstMemOp = CurOp+1;
-    if (HasVEX_4V) {
+    if (HasVEX_4V && !IsBEXTR) {
       ++AddrOperands;
       ++FirstMemOp;  // Skip the register source (which is encoded in VEX_VVVV).
     }
@@ -960,6 +979,8 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS,
     EmitMemModRMByte(MI, FirstMemOp, GetX86RegNum(MI.getOperand(CurOp)),
                      TSFlags, CurByte, OS, Fixups);
     CurOp += AddrOperands + 1;
+    if (IsBEXTR)
+      ++CurOp;
     break;
   }
 
index a9b59d7c42e7916be0a7f91a45f7b823999b803f..fd4ecd4d94fb5a8089f15a6cc62160fe9df41ef5 100644 (file)
@@ -1408,21 +1408,33 @@ let Predicates = [HasBMI], Defs = [EFLAGS] in {
 multiclass bmi_bls<string mnemonic, Format RegMRM, Format MemMRM,
                    RegisterClass RC, X86MemOperand x86memop> {
   def rr : I<0xF3, RegMRM, (outs RC:$dst), (ins RC:$src),
-             !strconcat(mnemonic, "\t{$src, $dst|$dst, $src}"), []>;
+             !strconcat(mnemonic, "\t{$src, $dst|$dst, $src}"), []>, T8, VEX_4V;
   def rm : I<0xF3, MemMRM, (outs RC:$dst), (ins x86memop:$src),
-             !strconcat(mnemonic, "\t{$src, $dst|$dst, $src}"), []>;
+             !strconcat(mnemonic, "\t{$src, $dst|$dst, $src}"), []>, T8, VEX_4V;
 }
 
 let Predicates = [HasBMI], Defs = [EFLAGS] in {
-  defm BLSR32 : bmi_bls<"blsr{l}", MRM1r, MRM1m, GR32, i32mem>, T8, VEX_4V;
-  defm BLSR64 : bmi_bls<"blsr{q}", MRM1r, MRM1m, GR64, i64mem>, T8, VEX_4V,
-                          VEX_W;
-  defm BLSMSK32 : bmi_bls<"blsmsk{l}", MRM2r, MRM2m, GR32, i32mem>, T8, VEX_4V;
-  defm BLSMSK64 : bmi_bls<"blsmsk{q}", MRM2r, MRM2m, GR64, i64mem>, T8, VEX_4V,
-                          VEX_W;
-  defm BLSI32 : bmi_bls<"blsi{l}", MRM3r, MRM3m, GR32, i32mem>, T8, VEX_4V;
-  defm BLSI64 : bmi_bls<"blsi{q}", MRM3r, MRM3m, GR64, i64mem>, T8, VEX_4V,
-                        VEX_W;
+  defm BLSR32 : bmi_bls<"blsr{l}", MRM1r, MRM1m, GR32, i32mem>;
+  defm BLSR64 : bmi_bls<"blsr{q}", MRM1r, MRM1m, GR64, i64mem>, VEX_W;
+  defm BLSMSK32 : bmi_bls<"blsmsk{l}", MRM2r, MRM2m, GR32, i32mem>;
+  defm BLSMSK64 : bmi_bls<"blsmsk{q}", MRM2r, MRM2m, GR64, i64mem>, VEX_W;
+  defm BLSI32 : bmi_bls<"blsi{l}", MRM3r, MRM3m, GR32, i32mem>;
+  defm BLSI64 : bmi_bls<"blsi{q}", MRM3r, MRM3m, GR64, i64mem>, VEX_W;
+}
+
+multiclass bmi_bextr<string mnemonic, RegisterClass RC,
+                     X86MemOperand x86memop> {
+  def rr : I<0xF7, MRMSrcReg, (outs RC:$dst), (ins RC:$src1, RC:$src2),
+             !strconcat(mnemonic, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
+             []>, T8, VEX_4V;
+  def rm : I<0xF7, MRMSrcMem, (outs RC:$dst), (ins x86memop:$src1, RC:$src2),
+             !strconcat(mnemonic, "\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
+             []>, T8, VEX_4V;
+}
+
+let Predicates = [HasBMI], Defs = [EFLAGS] in {
+  defm BEXTR32 : bmi_bextr<"bextr{l}", GR32, i32mem>;
+  defm BEXTR64 : bmi_bextr<"bextr{q}", GR64, i64mem>, VEX_W;
 }
 
 //===----------------------------------------------------------------------===//
index 93154f6a980f911518b049475f255e02531b189b..dc45366f382d928f8077bd33d119d97daaca2b52 100644 (file)
 
 # CHECK: blsiq (%rax), %r15
 0xc4 0xe2 0x80 0xf3 0x18
+
+# CHECK: bextrl %r12d, (%rax), %r10d
+0xc4 0x62 0x18 0xf7 0x10
+
+# CHECK: bextrl %r12d, %r11d, %r10d
+0xc4 0x42 0x18 0xf7 0xd3
+
+# CHECK: bextrq %r12, (%rax), %r10
+0xc4 0x62 0x98 0xf7 0x10
+
+# CHECK: bextrq %r12, %r11, %r10
+0xc4 0x42 0x98 0xf7 0xd3
index 46d93ce717c42bef1237aceb924b804206ad709b..5b00769902b115310850188f106245305f5bbb95 100644 (file)
 
 # CHECK: blsil (%eax), %edi
 0xc4 0xe2 0x40 0xf3 0x18
+
+# CHECK: bextrl %esi, (%eax), %edx
+0xc4 0xe2 0x08 0xf7 0x10
+
+# CHECK: bextrl %esi, %ebx, %edx
+0xc4 0xe2 0x08 0xf7 0xd3
index f02bc0ec48a17ff79e1a2134235e099335c78442..ac08260b11116e33133a6d5297cab83d817467a6 100644 (file)
 // CHECK: andnq  (%rax), %r11, %r10
 // CHECK: encoding: [0xc4,0x62,0xa0,0xf2,0x10]
           andnq  (%rax), %r11, %r10
+
+// CHECK: bextrl %r12d, (%rax), %r10d
+// CHECK: encoding: [0xc4,0x62,0x18,0xf7,0x10]
+          bextrl %r12d, (%rax), %r10d
+
+// CHECK: bextrl %r12d, %r11d, %r10d
+// CHECK: encoding: [0xc4,0x42,0x18,0xf7,0xd3]
+          bextrl %r12d, %r11d, %r10d
+
+// CHECK: bextrq %r12, (%rax), %r10
+// CHECK: encoding: [0xc4,0x62,0x98,0xf7,0x10]
+          bextrq %r12, (%rax), %r10
+
+// CHECK: bextrq %r12, %r11, %r10
+// CHECK: encoding: [0xc4,0x42,0x98,0xf7,0xd3]
+          bextrq %r12, %r11, %r10
index a3647c1f0ec3405a3ee5f55612205e63d72f8316..617a873cac72edc68800dc4604970666f87babb4 100644 (file)
@@ -233,7 +233,7 @@ RecognizableInstr::RecognizableInstr(DisassemblerTables &tables,
                      (Name.find("CRC32") != Name.npos);
   HasFROperands    = hasFROperands();
   HasVEX_LPrefix   = has256BitOperands() || Rec->getValueAsBit("hasVEX_L");
-  
+
   // Check for 64-bit inst which does not require REX
   Is32Bit = false;
   Is64Bit = false;
@@ -265,6 +265,9 @@ RecognizableInstr::RecognizableInstr(DisassemblerTables &tables,
              Rec->getName().find("PUSH64") != Name.npos ||
              Rec->getName().find("POP64") != Name.npos;
 
+  // FIXME: BEXTR uses VEX.vvvv to encode its third operand
+  IsBEXTR = Rec->getName().find("BEXTR") != Name.npos;
+
   ShouldBeEmitted  = true;
 }
   
@@ -695,13 +698,18 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
              "Unexpected number of operands for MRMSrcRegFrm");
   
     HANDLE_OPERAND(roRegister)
-       
-    if (HasVEX_4VPrefix)
+
+    if (HasVEX_4VPrefix && !IsBEXTR)
       // FIXME: In AVX, the register below becomes the one encoded
       // in ModRMVEX and the one above the one in the VEX.VVVV field
       HANDLE_OPERAND(vvvvRegister)
-          
+
     HANDLE_OPERAND(rmRegister)
+
+    // FIXME: BEXTR uses VEX.vvvv for Operand 3
+    if (IsBEXTR)
+      HANDLE_OPERAND(vvvvRegister)
+
     HANDLE_OPTIONAL(immediate)
     break;
   case X86Local::MRMSrcMem:
@@ -719,12 +727,17 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) {
     
     HANDLE_OPERAND(roRegister)
 
-    if (HasVEX_4VPrefix)
+    if (HasVEX_4VPrefix && !IsBEXTR)
       // FIXME: In AVX, the register below becomes the one encoded
       // in ModRMVEX and the one above the one in the VEX.VVVV field
       HANDLE_OPERAND(vvvvRegister)
 
     HANDLE_OPERAND(memory)
+
+    // FIXME: BEXTR uses VEX.vvvv for Operand 3
+    if (IsBEXTR)
+      HANDLE_OPERAND(vvvvRegister)
+
     HANDLE_OPTIONAL(immediate)
     break;
   case X86Local::MRM0r:
index 44415978273f39ab0a2c3f306671a2e0917b25e0..7ed820b80dd13e20dba308c9549f0a136f188393 100644 (file)
@@ -70,7 +70,9 @@ private:
   bool Is64Bit;
   // Whether the instruction has the predicate "In32BitMode"
   bool Is32Bit;
-  
+  // Whether the instruction is BEXTR
+  bool IsBEXTR;
+
   /// The instruction name as listed in the tables
   std::string Name;
   /// The AT&T AsmString for the instruction