From: Craig Topper Date: Sun, 16 Oct 2011 03:51:13 +0000 (+0000) Subject: Add X86 BEXTR instruction. This instruction uses VEX.vvvv to encode Operand 3 instead... X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=17730847d59c919d97f097d46a3fcba1888e5300;p=oota-llvm.git Add X86 BEXTR instruction. This instruction uses VEX.vvvv to encode Operand 3 instead of Operand 2 so needs special casing in the disassembler and code emitter. Ultimately, should pass this information from tablegen git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@142105 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Target/X86/MCTargetDesc/X86BaseInfo.h b/lib/Target/X86/MCTargetDesc/X86BaseInfo.h index 555ca17f425..ce24904f508 100644 --- a/lib/Target/X86/MCTargetDesc/X86BaseInfo.h +++ b/lib/Target/X86/MCTargetDesc/X86BaseInfo.h @@ -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. diff --git a/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp b/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp index 918d4a04743..55c6010ddde 100644 --- a/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp +++ b/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp @@ -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; } diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index a9b59d7c42e..fd4ecd4d94f 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -1408,21 +1408,33 @@ let Predicates = [HasBMI], Defs = [EFLAGS] in { multiclass bmi_bls { 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 { + 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; } //===----------------------------------------------------------------------===// diff --git a/test/MC/Disassembler/X86/simple-tests.txt b/test/MC/Disassembler/X86/simple-tests.txt index 93154f6a980..dc45366f382 100644 --- a/test/MC/Disassembler/X86/simple-tests.txt +++ b/test/MC/Disassembler/X86/simple-tests.txt @@ -536,3 +536,15 @@ # 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 diff --git a/test/MC/Disassembler/X86/x86-32.txt b/test/MC/Disassembler/X86/x86-32.txt index 46d93ce717c..5b00769902b 100644 --- a/test/MC/Disassembler/X86/x86-32.txt +++ b/test/MC/Disassembler/X86/x86-32.txt @@ -504,3 +504,9 @@ # 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 diff --git a/test/MC/X86/x86_64-bmi-encoding.s b/test/MC/X86/x86_64-bmi-encoding.s index f02bc0ec48a..ac08260b111 100644 --- a/test/MC/X86/x86_64-bmi-encoding.s +++ b/test/MC/X86/x86_64-bmi-encoding.s @@ -55,3 +55,19 @@ // 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 diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index a3647c1f0ec..617a873cac7 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -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: diff --git a/utils/TableGen/X86RecognizableInstr.h b/utils/TableGen/X86RecognizableInstr.h index 44415978273..7ed820b80dd 100644 --- a/utils/TableGen/X86RecognizableInstr.h +++ b/utils/TableGen/X86RecognizableInstr.h @@ -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