From: Craig Topper Date: Sat, 15 Oct 2011 20:46:47 +0000 (+0000) Subject: Add support for X86 blsr, blsmsk, and blsi instructions. Required extra work because... X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=566f233ba64c0bb2773b5717cb18753c7564f4b7;p=oota-llvm.git Add support for X86 blsr, blsmsk, and blsi instructions. Required extra work because these are the first VEX encoded instructions to use the reg field as an opcode extension. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@142082 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Target/X86/MCTargetDesc/X86BaseInfo.h b/lib/Target/X86/MCTargetDesc/X86BaseInfo.h index e6ba705d4d8..555ca17f425 100644 --- a/lib/Target/X86/MCTargetDesc/X86BaseInfo.h +++ b/lib/Target/X86/MCTargetDesc/X86BaseInfo.h @@ -495,8 +495,13 @@ namespace X86II { case X86II::MRM0m: case X86II::MRM1m: case X86II::MRM2m: case X86II::MRM3m: case X86II::MRM4m: case X86II::MRM5m: - case X86II::MRM6m: case X86II::MRM7m: - return 0; + case X86II::MRM6m: case X86II::MRM7m: { + bool HasVEX_4V = (TSFlags >> X86II::VEXShift) & X86II::VEX_4V; + unsigned FirstMemOp = 0; + if (HasVEX_4V) + ++FirstMemOp;// Skip the register dest (which is encoded in VEX_VVVV). + return FirstMemOp; + } case X86II::MRM_C1: case X86II::MRM_C2: case X86II::MRM_C3: diff --git a/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp b/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp index 2eee1128119..918d4a04743 100644 --- a/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp +++ b/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp @@ -63,9 +63,8 @@ public: unsigned OpNum) { unsigned SrcReg = MI.getOperand(OpNum).getReg(); unsigned SrcRegNum = GetX86RegNum(MI.getOperand(OpNum)); - if ((SrcReg >= X86::XMM8 && SrcReg <= X86::XMM15) || - (SrcReg >= X86::YMM8 && SrcReg <= X86::YMM15)) - SrcRegNum += 8; + if (X86II::isX86_64ExtendedReg(SrcReg)) + SrcRegNum |= 8; // The registers represented through VEX_VVVV should // be encoded in 1's complement form. @@ -516,7 +515,7 @@ void X86MCCodeEmitter::EmitVEXOpcodePrefix(uint64_t TSFlags, unsigned &CurByte, VEX_R = 0x0; break; } - case X86II::MRMSrcMem: { + case X86II::MRMSrcMem: // MRMSrcMem instructions forms: // src1(ModR/M), MemAddr // src1(ModR/M), src2(VEX_4V), MemAddr @@ -526,31 +525,34 @@ void X86MCCodeEmitter::EmitVEXOpcodePrefix(uint64_t TSFlags, unsigned &CurByte, if (X86II::isX86_64ExtendedReg(MI.getOperand(0).getReg())) VEX_R = 0x0; - unsigned MemAddrOffset = 1; - if (HasVEX_4V) { + if (HasVEX_4V) VEX_4V = getVEXRegisterEncoding(MI, 1); - MemAddrOffset++; - } if (X86II::isX86_64ExtendedReg( - MI.getOperand(MemAddrOffset+X86::AddrBaseReg).getReg())) + MI.getOperand(MemOperand+X86::AddrBaseReg).getReg())) VEX_B = 0x0; if (X86II::isX86_64ExtendedReg( - MI.getOperand(MemAddrOffset+X86::AddrIndexReg).getReg())) + MI.getOperand(MemOperand+X86::AddrIndexReg).getReg())) VEX_X = 0x0; break; - } case X86II::MRM0m: case X86II::MRM1m: case X86II::MRM2m: case X86II::MRM3m: case X86II::MRM4m: case X86II::MRM5m: - case X86II::MRM6m: case X86II::MRM7m: + case X86II::MRM6m: case X86II::MRM7m: { // MRM[0-9]m instructions forms: // MemAddr - if (X86II::isX86_64ExtendedReg(MI.getOperand(X86::AddrBaseReg).getReg())) + // src1(VEX_4V), MemAddr + if (HasVEX_4V) + VEX_4V = getVEXRegisterEncoding(MI, 0); + + if (X86II::isX86_64ExtendedReg( + MI.getOperand(MemOperand+X86::AddrBaseReg).getReg())) VEX_B = 0x0; - if (X86II::isX86_64ExtendedReg(MI.getOperand(X86::AddrIndexReg).getReg())) + if (X86II::isX86_64ExtendedReg( + MI.getOperand(MemOperand+X86::AddrIndexReg).getReg())) VEX_X = 0x0; break; + } case X86II::MRMSrcReg: // MRMSrcReg instructions forms: // dst(ModR/M), src1(VEX_4V), src2(ModR/M), src3(VEX_I8IMM) @@ -976,6 +978,8 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS, case X86II::MRM2m: case X86II::MRM3m: case X86II::MRM4m: case X86II::MRM5m: case X86II::MRM6m: case X86II::MRM7m: + if (HasVEX_4V) // Skip the register dst (which is encoded in VEX_VVVV). + CurOp++; EmitByte(BaseOpcode, CurByte, OS); EmitMemModRMByte(MI, CurOp, (TSFlags & X86II::FormMask)-X86II::MRM0m, TSFlags, CurByte, OS, Fixups); diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index d54bf275c04..a9b59d7c42e 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -1375,7 +1375,7 @@ let Predicates = [HasLZCNT], Defs = [EFLAGS] in { } //===----------------------------------------------------------------------===// -// TZCNT Instruction +// BMI Instructions // let Predicates = [HasBMI], Defs = [EFLAGS] in { def TZCNT16rr : I<0xBC, MRMSrcReg, (outs GR16:$dst), (ins GR16:$src), @@ -1405,6 +1405,26 @@ let Predicates = [HasBMI], Defs = [EFLAGS] in { (implicit EFLAGS)]>, XS; } +multiclass bmi_bls { + def rr : I<0xF3, RegMRM, (outs RC:$dst), (ins RC:$src), + !strconcat(mnemonic, "\t{$src, $dst|$dst, $src}"), []>; + def rm : I<0xF3, MemMRM, (outs RC:$dst), (ins x86memop:$src), + !strconcat(mnemonic, "\t{$src, $dst|$dst, $src}"), []>; +} + +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; +} + //===----------------------------------------------------------------------===// // Subsystems. //===----------------------------------------------------------------------===// diff --git a/test/MC/Disassembler/X86/simple-tests.txt b/test/MC/Disassembler/X86/simple-tests.txt index 2dc918cb0dc..93154f6a980 100644 --- a/test/MC/Disassembler/X86/simple-tests.txt +++ b/test/MC/Disassembler/X86/simple-tests.txt @@ -518,3 +518,21 @@ # CHECK: andnq (%rax), %r15, %rax 0xc4 0xe2 0x80 0xf2 0x00 + +# CHECK: blsrl (%rax), %r15d +0xc4 0xe2 0x00 0xf3 0x08 + +# CHECK: blsrq (%rax), %r15 +0xc4 0xe2 0x80 0xf3 0x08 + +# CHECK: blsmskl (%rax), %r15d +0xc4 0xe2 0x00 0xf3 0x10 + +# CHECK: blsmskq (%rax), %r15 +0xc4 0xe2 0x80 0xf3 0x10 + +# CHECK: blsil (%rax), %r15d +0xc4 0xe2 0x00 0xf3 0x18 + +# CHECK: blsiq (%rax), %r15 +0xc4 0xe2 0x80 0xf3 0x18 diff --git a/test/MC/Disassembler/X86/x86-32.txt b/test/MC/Disassembler/X86/x86-32.txt index c4437ba35d7..46d93ce717c 100644 --- a/test/MC/Disassembler/X86/x86-32.txt +++ b/test/MC/Disassembler/X86/x86-32.txt @@ -495,3 +495,12 @@ # CHECK: andnl (%eax), %edi, %eax 0xc4 0xe2 0x80 0xf2 0x00 + +# CHECK: blsrl (%eax), %edi +0xc4 0xe2 0x40 0xf3 0x08 + +# CHECK: blsmskl (%eax), %edi +0xc4 0xe2 0x40 0xf3 0x10 + +# CHECK: blsil (%eax), %edi +0xc4 0xe2 0x40 0xf3 0x18 diff --git a/test/MC/X86/x86_64-bmi-encoding.s b/test/MC/X86/x86_64-bmi-encoding.s new file mode 100644 index 00000000000..f02bc0ec48a --- /dev/null +++ b/test/MC/X86/x86_64-bmi-encoding.s @@ -0,0 +1,57 @@ +// RUN: llvm-mc -triple x86_64-unknown-unknown --show-encoding %s | FileCheck %s + +// CHECK: blsmskl %r11d, %r10d +// CHECK: encoding: [0xc4,0xc2,0x28,0xf3,0xd3] + blsmskl %r11d, %r10d + +// CHECK: blsmskq %r11, %r10 +// CHECK: encoding: [0xc4,0xc2,0xa8,0xf3,0xd3] + blsmskq %r11, %r10 + +// CHECK: blsmskl (%rax), %r10d +// CHECK: encoding: [0xc4,0xe2,0x28,0xf3,0x10] + blsmskl (%rax), %r10d + +// CHECK: blsmskq (%rax), %r10 +// CHECK: encoding: [0xc4,0xe2,0xa8,0xf3,0x10] + blsmskq (%rax), %r10 + +// CHECK: blsil %r11d, %r10d +// CHECK: encoding: [0xc4,0xc2,0x28,0xf3,0xdb] + blsil %r11d, %r10d + +// CHECK: blsiq %r11, %r10 +// CHECK: encoding: [0xc4,0xc2,0xa8,0xf3,0xdb] + blsiq %r11, %r10 + +// CHECK: blsil (%rax), %r10d +// CHECK: encoding: [0xc4,0xe2,0x28,0xf3,0x18] + blsil (%rax), %r10d + +// CHECK: blsiq (%rax), %r10 +// CHECK: encoding: [0xc4,0xe2,0xa8,0xf3,0x18] + blsiq (%rax), %r10 + +// CHECK: blsrl %r11d, %r10d +// CHECK: encoding: [0xc4,0xc2,0x28,0xf3,0xcb] + blsrl %r11d, %r10d + +// CHECK: blsrq %r11, %r10 +// CHECK: encoding: [0xc4,0xc2,0xa8,0xf3,0xcb] + blsrq %r11, %r10 + +// CHECK: blsrl (%rax), %r10d +// CHECK: encoding: [0xc4,0xe2,0x28,0xf3,0x08] + blsrl (%rax), %r10d + +// CHECK: blsrq (%rax), %r10 +// CHECK: encoding: [0xc4,0xe2,0xa8,0xf3,0x08] + blsrq (%rax), %r10 + +// CHECK: andnl (%rax), %r11d, %r10d +// CHECK: encoding: [0xc4,0x62,0x20,0xf2,0x10] + andnl (%rax), %r11d, %r10d + +// CHECK: andnq (%rax), %r11, %r10 +// CHECK: encoding: [0xc4,0x62,0xa0,0xf2,0x10] + andnq (%rax), %r11, %r10 diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index cae82374924..a3647c1f0ec 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -119,6 +119,9 @@ namespace X86Local { EXTENSION_TABLE(ba) \ EXTENSION_TABLE(c7) +#define THREE_BYTE_38_EXTENSION_TABLES \ + EXTENSION_TABLE(F3) + using namespace X86Disassembler; /// needsModRMForDecode - Indicates whether a particular instruction requires a @@ -736,12 +739,12 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) { // Operand 2 (optional) is an immediate or relocation. if (HasVEX_4VPrefix) assert(numPhysicalOperands <= 3 && - "Unexpected number of operands for MRMSrcMemFrm with VEX_4V"); + "Unexpected number of operands for MRMnRFrm with VEX_4V"); else assert(numPhysicalOperands <= 2 && "Unexpected number of operands for MRMnRFrm"); if (HasVEX_4VPrefix) - HANDLE_OPERAND(vvvvRegister); + HANDLE_OPERAND(vvvvRegister) HANDLE_OPTIONAL(rmRegister) HANDLE_OPTIONAL(relocation) break; @@ -755,8 +758,14 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) { case X86Local::MRM7m: // Operand 1 is a memory operand (possibly SIB-extended) // Operand 2 (optional) is an immediate or relocation. - assert(numPhysicalOperands >= 1 && numPhysicalOperands <= 2 && - "Unexpected number of operands for MRMnMFrm"); + if (HasVEX_4VPrefix) + assert(numPhysicalOperands >= 2 && numPhysicalOperands <= 3 && + "Unexpected number of operands for MRMnMFrm"); + else + assert(numPhysicalOperands >= 1 && numPhysicalOperands <= 2 && + "Unexpected number of operands for MRMnMFrm"); + if (HasVEX_4VPrefix) + HANDLE_OPERAND(vvvvRegister) HANDLE_OPERAND(memory) HANDLE_OPTIONAL(relocation) break; @@ -845,10 +854,43 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const { case X86Local::T8: case X86Local::TF: opcodeType = THREEBYTE_38; - if (needsModRMForDecode(Form)) - filter = new ModFilter(isRegFormat(Form)); - else - filter = new DumbFilter(); + switch (Opcode) { + default: + if (needsModRMForDecode(Form)) + filter = new ModFilter(isRegFormat(Form)); + else + filter = new DumbFilter(); + break; +#define EXTENSION_TABLE(n) case 0x##n: + THREE_BYTE_38_EXTENSION_TABLES +#undef EXTENSION_TABLE + switch (Form) { + default: + llvm_unreachable("Unhandled two-byte extended opcode"); + case X86Local::MRM0r: + case X86Local::MRM1r: + case X86Local::MRM2r: + case X86Local::MRM3r: + case X86Local::MRM4r: + case X86Local::MRM5r: + case X86Local::MRM6r: + case X86Local::MRM7r: + filter = new ExtendedFilter(true, Form - X86Local::MRM0r); + break; + case X86Local::MRM0m: + case X86Local::MRM1m: + case X86Local::MRM2m: + case X86Local::MRM3m: + case X86Local::MRM4m: + case X86Local::MRM5m: + case X86Local::MRM6m: + case X86Local::MRM7m: + filter = new ExtendedFilter(false, Form - X86Local::MRM0m); + break; + MRM_MAPPING + } // switch (Form) + break; + } // switch (Opcode) opcodeToSet = Opcode; break; case X86Local::P_TA: