diff options
-rw-r--r-- | lib/Target/X86/Disassembler/X86DisassemblerDecoder.c | 172 | ||||
-rw-r--r-- | lib/Target/X86/Disassembler/X86DisassemblerDecoder.h | 30 | ||||
-rw-r--r-- | lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h | 11 | ||||
-rw-r--r-- | lib/Target/X86/X86InstrInfo.td | 4 | ||||
-rw-r--r-- | lib/Target/X86/X86InstrXOP.td | 146 | ||||
-rw-r--r-- | test/MC/Disassembler/X86/simple-tests.txt | 72 | ||||
-rw-r--r-- | test/MC/X86/avx512-encodings.s | 2 | ||||
-rw-r--r-- | utils/TableGen/X86DisassemblerTables.cpp | 3 | ||||
-rw-r--r-- | utils/TableGen/X86DisassemblerTables.h | 5 | ||||
-rw-r--r-- | utils/TableGen/X86RecognizableInstr.cpp | 67 |
10 files changed, 383 insertions, 129 deletions
diff --git a/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c b/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c index c26cfb5..480a869 100644 --- a/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c +++ b/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c @@ -81,6 +81,15 @@ static int modRMRequired(OpcodeType type, case THREEBYTE_A7: decision = &THREEBYTEA7_SYM; break; + case XOP8_MAP: + decision = &XOP8_MAP_SYM; + break; + case XOP9_MAP: + decision = &XOP9_MAP_SYM; + break; + case XOPA_MAP: + decision = &XOPA_MAP_SYM; + break; } return decision->opcodeDecisions[insnContext].modRMDecisions[opcode]. @@ -122,6 +131,15 @@ static InstrUID decode(OpcodeType type, case THREEBYTE_A7: dec = &THREEBYTEA7_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode]; break; + case XOP8_MAP: + dec = &XOP8_MAP_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode]; + break; + case XOP9_MAP: + dec = &XOP9_MAP_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode]; + break; + case XOPA_MAP: + dec = &XOPA_MAP_SYM.opcodeDecisions[insnContext].modRMDecisions[opcode]; + break; } switch (dec->modrm_type) { @@ -428,7 +446,7 @@ static int readPrefixes(struct InternalInstruction* insn) { dbgprintf(insn, "Found prefix 0x%hhx", byte); } - insn->vexSize = 0; + insn->vexXopType = TYPE_NO_VEX_XOP; if (byte == 0xc4) { uint8_t byte1; @@ -439,7 +457,7 @@ static int readPrefixes(struct InternalInstruction* insn) { } if (insn->mode == MODE_64BIT || (byte1 & 0xc0) == 0xc0) { - insn->vexSize = 3; + insn->vexXopType = TYPE_VEX_3B; insn->necessaryPrefixLocation = insn->readerCursor - 1; } else { @@ -447,22 +465,22 @@ static int readPrefixes(struct InternalInstruction* insn) { insn->necessaryPrefixLocation = insn->readerCursor - 1; } - if (insn->vexSize == 3) { - insn->vexPrefix[0] = byte; - consumeByte(insn, &insn->vexPrefix[1]); - consumeByte(insn, &insn->vexPrefix[2]); + if (insn->vexXopType == TYPE_VEX_3B) { + insn->vexXopPrefix[0] = byte; + consumeByte(insn, &insn->vexXopPrefix[1]); + consumeByte(insn, &insn->vexXopPrefix[2]); /* We simulate the REX prefix for simplicity's sake */ if (insn->mode == MODE_64BIT) { insn->rexPrefix = 0x40 - | (wFromVEX3of3(insn->vexPrefix[2]) << 3) - | (rFromVEX2of3(insn->vexPrefix[1]) << 2) - | (xFromVEX2of3(insn->vexPrefix[1]) << 1) - | (bFromVEX2of3(insn->vexPrefix[1]) << 0); + | (wFromVEX3of3(insn->vexXopPrefix[2]) << 3) + | (rFromVEX2of3(insn->vexXopPrefix[1]) << 2) + | (xFromVEX2of3(insn->vexXopPrefix[1]) << 1) + | (bFromVEX2of3(insn->vexXopPrefix[1]) << 0); } - switch (ppFromVEX3of3(insn->vexPrefix[2])) + switch (ppFromVEX3of3(insn->vexXopPrefix[2])) { default: break; @@ -471,7 +489,9 @@ static int readPrefixes(struct InternalInstruction* insn) { break; } - dbgprintf(insn, "Found VEX prefix 0x%hhx 0x%hhx 0x%hhx", insn->vexPrefix[0], insn->vexPrefix[1], insn->vexPrefix[2]); + dbgprintf(insn, "Found VEX prefix 0x%hhx 0x%hhx 0x%hhx", + insn->vexXopPrefix[0], insn->vexXopPrefix[1], + insn->vexXopPrefix[2]); } } else if (byte == 0xc5) { @@ -483,22 +503,66 @@ static int readPrefixes(struct InternalInstruction* insn) { } if (insn->mode == MODE_64BIT || (byte1 & 0xc0) == 0xc0) { - insn->vexSize = 2; + insn->vexXopType = TYPE_VEX_2B; + } + else { + unconsumeByte(insn); + } + + if (insn->vexXopType == TYPE_VEX_2B) { + insn->vexXopPrefix[0] = byte; + consumeByte(insn, &insn->vexXopPrefix[1]); + + if (insn->mode == MODE_64BIT) { + insn->rexPrefix = 0x40 + | (rFromVEX2of2(insn->vexXopPrefix[1]) << 2); + } + + switch (ppFromVEX2of2(insn->vexXopPrefix[1])) + { + default: + break; + case VEX_PREFIX_66: + hasOpSize = TRUE; + break; + } + + dbgprintf(insn, "Found VEX prefix 0x%hhx 0x%hhx", insn->vexXopPrefix[0], insn->vexXopPrefix[1]); + } + } + else if (byte == 0x8f) { + uint8_t byte1; + + if (lookAtByte(insn, &byte1)) { + dbgprintf(insn, "Couldn't read second byte of XOP"); + return -1; + } + + if ((byte1 & 0x38) != 0x0) { // 0 in these 3 bits is a POP instruction. + insn->vexXopType = TYPE_XOP; + insn->necessaryPrefixLocation = insn->readerCursor - 1; } else { unconsumeByte(insn); + insn->necessaryPrefixLocation = insn->readerCursor - 1; } - if (insn->vexSize == 2) { - insn->vexPrefix[0] = byte; - consumeByte(insn, &insn->vexPrefix[1]); + if (insn->vexXopType == TYPE_XOP) { + insn->vexXopPrefix[0] = byte; + consumeByte(insn, &insn->vexXopPrefix[1]); + consumeByte(insn, &insn->vexXopPrefix[2]); + + /* We simulate the REX prefix for simplicity's sake */ if (insn->mode == MODE_64BIT) { insn->rexPrefix = 0x40 - | (rFromVEX2of2(insn->vexPrefix[1]) << 2); + | (wFromXOP3of3(insn->vexXopPrefix[2]) << 3) + | (rFromXOP2of3(insn->vexXopPrefix[1]) << 2) + | (xFromXOP2of3(insn->vexXopPrefix[1]) << 1) + | (bFromXOP2of3(insn->vexXopPrefix[1]) << 0); } - switch (ppFromVEX2of2(insn->vexPrefix[1])) + switch (ppFromXOP3of3(insn->vexXopPrefix[2])) { default: break; @@ -507,7 +571,9 @@ static int readPrefixes(struct InternalInstruction* insn) { break; } - dbgprintf(insn, "Found VEX prefix 0x%hhx 0x%hhx", insn->vexPrefix[0], insn->vexPrefix[1]); + dbgprintf(insn, "Found XOP prefix 0x%hhx 0x%hhx 0x%hhx", + insn->vexXopPrefix[0], insn->vexXopPrefix[1], + insn->vexXopPrefix[2]); } } else { @@ -582,12 +648,13 @@ static int readOpcode(struct InternalInstruction* insn) { insn->opcodeType = ONEBYTE; - if (insn->vexSize == 3) + if (insn->vexXopType == TYPE_VEX_3B) { - switch (mmmmmFromVEX2of3(insn->vexPrefix[1])) + switch (mmmmmFromVEX2of3(insn->vexXopPrefix[1])) { default: - dbgprintf(insn, "Unhandled m-mmmm field for instruction (0x%hhx)", mmmmmFromVEX2of3(insn->vexPrefix[1])); + dbgprintf(insn, "Unhandled m-mmmm field for instruction (0x%hhx)", + mmmmmFromVEX2of3(insn->vexXopPrefix[1])); return -1; case VEX_LOB_0F: insn->opcodeType = TWOBYTE; @@ -600,11 +667,30 @@ static int readOpcode(struct InternalInstruction* insn) { return consumeByte(insn, &insn->opcode); } } - else if (insn->vexSize == 2) + else if (insn->vexXopType == TYPE_VEX_2B) { insn->opcodeType = TWOBYTE; return consumeByte(insn, &insn->opcode); } + else if (insn->vexXopType == TYPE_XOP) + { + switch (mmmmmFromXOP2of3(insn->vexXopPrefix[1])) + { + default: + dbgprintf(insn, "Unhandled m-mmmm field for instruction (0x%hhx)", + mmmmmFromVEX2of3(insn->vexXopPrefix[1])); + return -1; + case XOP_MAP_SELECT_8: + insn->opcodeType = XOP8_MAP; + return consumeByte(insn, &insn->opcode); + case XOP_MAP_SELECT_9: + insn->opcodeType = XOP9_MAP; + return consumeByte(insn, &insn->opcode); + case XOP_MAP_SELECT_A: + insn->opcodeType = XOPA_MAP; + return consumeByte(insn, &insn->opcode); + } + } if (consumeByte(insn, ¤t)) return -1; @@ -752,11 +838,27 @@ static int getID(struct InternalInstruction* insn, const void *miiArg) { if (insn->mode == MODE_64BIT) attrMask |= ATTR_64BIT; - if (insn->vexSize) { + if (insn->vexXopType != TYPE_NO_VEX_XOP) { attrMask |= ATTR_VEX; - if (insn->vexSize == 3) { - switch (ppFromVEX3of3(insn->vexPrefix[2])) { + if (insn->vexXopType == TYPE_VEX_3B) { + switch (ppFromVEX3of3(insn->vexXopPrefix[2])) { + case VEX_PREFIX_66: + attrMask |= ATTR_OPSIZE; + break; + case VEX_PREFIX_F3: + attrMask |= ATTR_XS; + break; + case VEX_PREFIX_F2: + attrMask |= ATTR_XD; + break; + } + + if (lFromVEX3of3(insn->vexXopPrefix[2])) + attrMask |= ATTR_VEXL; + } + else if (insn->vexXopType == TYPE_VEX_2B) { + switch (ppFromVEX2of2(insn->vexXopPrefix[1])) { case VEX_PREFIX_66: attrMask |= ATTR_OPSIZE; break; @@ -768,11 +870,11 @@ static int getID(struct InternalInstruction* insn, const void *miiArg) { break; } - if (lFromVEX3of3(insn->vexPrefix[2])) + if (lFromVEX2of2(insn->vexXopPrefix[1])) attrMask |= ATTR_VEXL; } - else if (insn->vexSize == 2) { - switch (ppFromVEX2of2(insn->vexPrefix[1])) { + else if (insn->vexXopType == TYPE_XOP) { + switch (ppFromXOP3of3(insn->vexXopPrefix[2])) { case VEX_PREFIX_66: attrMask |= ATTR_OPSIZE; break; @@ -784,7 +886,7 @@ static int getID(struct InternalInstruction* insn, const void *miiArg) { break; } - if (lFromVEX2of2(insn->vexPrefix[1])) + if (lFromXOP3of3(insn->vexXopPrefix[2])) attrMask |= ATTR_VEXL; } else { @@ -1450,10 +1552,12 @@ static int readImmediate(struct InternalInstruction* insn, uint8_t size) { static int readVVVV(struct InternalInstruction* insn) { dbgprintf(insn, "readVVVV()"); - if (insn->vexSize == 3) - insn->vvvv = vvvvFromVEX3of3(insn->vexPrefix[2]); - else if (insn->vexSize == 2) - insn->vvvv = vvvvFromVEX2of2(insn->vexPrefix[1]); + if (insn->vexXopType == TYPE_VEX_3B) + insn->vvvv = vvvvFromVEX3of3(insn->vexXopPrefix[2]); + else if (insn->vexXopType == TYPE_VEX_2B) + insn->vvvv = vvvvFromVEX2of2(insn->vexXopPrefix[1]); + else if (insn->vexXopType == TYPE_XOP) + insn->vvvv = vvvvFromXOP3of3(insn->vexXopPrefix[2]); else return -1; diff --git a/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h b/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h index 4fd8fb7..bd9a651 100644 --- a/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h +++ b/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h @@ -59,6 +59,15 @@ extern "C" { #define lFromVEX2of2(vex) (((vex) & 0x4) >> 2) #define ppFromVEX2of2(vex) ((vex) & 0x3) +#define rFromXOP2of3(xop) (((~(xop)) & 0x80) >> 7) +#define xFromXOP2of3(xop) (((~(xop)) & 0x40) >> 6) +#define bFromXOP2of3(xop) (((~(xop)) & 0x20) >> 5) +#define mmmmmFromXOP2of3(xop) ((xop) & 0x1f) +#define wFromXOP3of3(xop) (((xop) & 0x80) >> 7) +#define vvvvFromXOP3of3(vex) (((~(vex)) & 0x78) >> 3) +#define lFromXOP3of3(xop) (((xop) & 0x4) >> 2) +#define ppFromXOP3of3(xop) ((xop) & 0x3) + /* * These enums represent Intel registers for use by the decoder. */ @@ -444,9 +453,15 @@ typedef enum { typedef enum { VEX_LOB_0F = 0x1, VEX_LOB_0F38 = 0x2, - VEX_LOB_0F3A = 0x3 + VEX_LOB_0F3A = 0x3, } VEXLeadingOpcodeByte; +typedef enum { + XOP_MAP_SELECT_8 = 0x8, + XOP_MAP_SELECT_9 = 0x9, + XOP_MAP_SELECT_A = 0xA +} XOPMapSelect; + /* * VEXPrefixCode - Possible values for the VEX.pp field */ @@ -458,6 +473,13 @@ typedef enum { VEX_PREFIX_F2 = 0x3 } VEXPrefixCode; +typedef enum { + TYPE_NO_VEX_XOP = 0x0, + TYPE_VEX_2B = 0x1, + TYPE_VEX_3B = 0x2, + TYPE_XOP = 0x3 +} VEXXOPType; + typedef uint8_t BOOL; /* @@ -514,10 +536,10 @@ struct InternalInstruction { uint8_t prefixPresent[0x100]; /* contains the location (for use with the reader) of the prefix byte */ uint64_t prefixLocations[0x100]; - /* The value of the VEX prefix, if present */ - uint8_t vexPrefix[3]; + /* The value of the VEX/XOP prefix, if present */ + uint8_t vexXopPrefix[3]; /* The length of the VEX prefix (0 if not present) */ - uint8_t vexSize; + VEXXOPType vexXopType; /* The value of the REX prefix, if present */ uint8_t rexPrefix; /* The location where a mandatory prefix would have to be (i.e., right before diff --git a/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h b/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h index b2f053b..86a90ee 100644 --- a/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h +++ b/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h @@ -32,6 +32,9 @@ #define THREEBYTE3A_SYM x86DisassemblerThreeByte3AOpcodes #define THREEBYTEA6_SYM x86DisassemblerThreeByteA6Opcodes #define THREEBYTEA7_SYM x86DisassemblerThreeByteA7Opcodes +#define XOP8_MAP_SYM x86DisassemblerXOP8Opcodes +#define XOP9_MAP_SYM x86DisassemblerXOP9Opcodes +#define XOPA_MAP_SYM x86DisassemblerXOPAOpcodes #define INSTRUCTIONS_STR "x86DisassemblerInstrSpecifiers" #define CONTEXTS_STR "x86DisassemblerContexts" @@ -41,6 +44,9 @@ #define THREEBYTE3A_STR "x86DisassemblerThreeByte3AOpcodes" #define THREEBYTEA6_STR "x86DisassemblerThreeByteA6Opcodes" #define THREEBYTEA7_STR "x86DisassemblerThreeByteA7Opcodes" +#define XOP8_MAP_STR "x86DisassemblerXOP8Opcodes" +#define XOP9_MAP_STR "x86DisassemblerXOP9Opcodes" +#define XOPA_MAP_STR "x86DisassemblerXOPAOpcodes" /* * Attributes of an instruction that must be known before the opcode can be @@ -234,7 +240,10 @@ typedef enum { THREEBYTE_38 = 2, THREEBYTE_3A = 3, THREEBYTE_A6 = 4, - THREEBYTE_A7 = 5 + THREEBYTE_A7 = 5, + XOP8_MAP = 6, + XOP9_MAP = 7, + XOPA_MAP = 8 } OpcodeType; /* diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index b63fbe9..be35187 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -1912,7 +1912,7 @@ let Predicates = [HasBMI2] in { //===----------------------------------------------------------------------===// // TBM Instructions // -let isAsmParserOnly = 1, Predicates = [HasTBM], Defs = [EFLAGS] in { +let Predicates = [HasTBM], Defs = [EFLAGS] in { multiclass tbm_ternary_imm_intr<bits<8> opc, RegisterClass RC, string OpcodeStr, X86MemOperand x86memop, PatFrag ld_frag, @@ -1987,7 +1987,7 @@ defm T1MSKC : tbm_binary_intr<0x01, "t1mskc", MRM7r, MRM7m, defm TZMSK : tbm_binary_intr<0x01, "tzmsk", MRM4r, MRM4m, int_x86_tbm_tzmsk_u32, int_x86_tbm_tzmsk_u64>; -} // isAsmParserOnly, HasTBM, EFLAGS +} // HasTBM, EFLAGS //===----------------------------------------------------------------------===// // Pattern fragments to auto generate TBM instructions. diff --git a/lib/Target/X86/X86InstrXOP.td b/lib/Target/X86/X86InstrXOP.td index 2aa08fa..2b6ee5c 100644 --- a/lib/Target/X86/X86InstrXOP.td +++ b/lib/Target/X86/X86InstrXOP.td @@ -20,23 +20,21 @@ multiclass xop2op<bits<8> opc, string OpcodeStr, Intrinsic Int, PatFrag memop> { [(set VR128:$dst, (Int (bitconvert (memop addr:$src))))]>, VEX; } -let isAsmParserOnly = 1 in { - defm VPHSUBWD : xop2op<0xE2, "vphsubwd", int_x86_xop_vphsubwd, memopv2i64>; - defm VPHSUBDQ : xop2op<0xE3, "vphsubdq", int_x86_xop_vphsubdq, memopv2i64>; - defm VPHSUBBW : xop2op<0xE1, "vphsubbw", int_x86_xop_vphsubbw, memopv2i64>; - defm VPHADDWQ : xop2op<0xC7, "vphaddwq", int_x86_xop_vphaddwq, memopv2i64>; - defm VPHADDWD : xop2op<0xC6, "vphaddwd", int_x86_xop_vphaddwd, memopv2i64>; - defm VPHADDUWQ : xop2op<0xD7, "vphadduwq", int_x86_xop_vphadduwq, memopv2i64>; - defm VPHADDUWD : xop2op<0xD6, "vphadduwd", int_x86_xop_vphadduwd, memopv2i64>; - defm VPHADDUDQ : xop2op<0xDB, "vphaddudq", int_x86_xop_vphaddudq, memopv2i64>; - defm VPHADDUBW : xop2op<0xD1, "vphaddubw", int_x86_xop_vphaddubw, memopv2i64>; - defm VPHADDUBQ : xop2op<0xD3, "vphaddubq", int_x86_xop_vphaddubq, memopv2i64>; - defm VPHADDUBD : xop2op<0xD2, "vphaddubd", int_x86_xop_vphaddubd, memopv2i64>; - defm VPHADDDQ : xop2op<0xCB, "vphadddq", int_x86_xop_vphadddq, memopv2i64>; - defm VPHADDBW : xop2op<0xC1, "vphaddbw", int_x86_xop_vphaddbw, memopv2i64>; - defm VPHADDBQ : xop2op<0xC3, "vphaddbq", int_x86_xop_vphaddbq, memopv2i64>; - defm VPHADDBD : xop2op<0xC2, "vphaddbd", int_x86_xop_vphaddbd, memopv2i64>; -} +defm VPHSUBWD : xop2op<0xE2, "vphsubwd", int_x86_xop_vphsubwd, memopv2i64>; +defm VPHSUBDQ : xop2op<0xE3, "vphsubdq", int_x86_xop_vphsubdq, memopv2i64>; +defm VPHSUBBW : xop2op<0xE1, "vphsubbw", int_x86_xop_vphsubbw, memopv2i64>; +defm VPHADDWQ : xop2op<0xC7, "vphaddwq", int_x86_xop_vphaddwq, memopv2i64>; +defm VPHADDWD : xop2op<0xC6, "vphaddwd", int_x86_xop_vphaddwd, memopv2i64>; +defm VPHADDUWQ : xop2op<0xD7, "vphadduwq", int_x86_xop_vphadduwq, memopv2i64>; +defm VPHADDUWD : xop2op<0xD6, "vphadduwd", int_x86_xop_vphadduwd, memopv2i64>; +defm VPHADDUDQ : xop2op<0xDB, "vphaddudq", int_x86_xop_vphaddudq, memopv2i64>; +defm VPHADDUBW : xop2op<0xD1, "vphaddubw", int_x86_xop_vphaddubw, memopv2i64>; +defm VPHADDUBQ : xop2op<0xD3, "vphaddubq", int_x86_xop_vphaddubq, memopv2i64>; +defm VPHADDUBD : xop2op<0xD2, "vphaddubd", int_x86_xop_vphaddubd, memopv2i64>; +defm VPHADDDQ : xop2op<0xCB, "vphadddq", int_x86_xop_vphadddq, memopv2i64>; +defm VPHADDBW : xop2op<0xC1, "vphaddbw", int_x86_xop_vphaddbw, memopv2i64>; +defm VPHADDBQ : xop2op<0xC3, "vphaddbq", int_x86_xop_vphaddbq, memopv2i64>; +defm VPHADDBD : xop2op<0xC2, "vphaddbd", int_x86_xop_vphaddbd, memopv2i64>; // Scalar load 2 addr operand instructions multiclass xop2opsld<bits<8> opc, string OpcodeStr, Intrinsic Int, @@ -49,12 +47,10 @@ multiclass xop2opsld<bits<8> opc, string OpcodeStr, Intrinsic Int, [(set VR128:$dst, (Int (bitconvert mem_cpat:$src)))]>, VEX; } -let isAsmParserOnly = 1 in { - defm VFRCZSS : xop2opsld<0x82, "vfrczss", int_x86_xop_vfrcz_ss, - ssmem, sse_load_f32>; - defm VFRCZSD : xop2opsld<0x83, "vfrczsd", int_x86_xop_vfrcz_sd, - sdmem, sse_load_f64>; -} +defm VFRCZSS : xop2opsld<0x82, "vfrczss", int_x86_xop_vfrcz_ss, + ssmem, sse_load_f32>; +defm VFRCZSD : xop2opsld<0x83, "vfrczsd", int_x86_xop_vfrcz_sd, + sdmem, sse_load_f64>; multiclass xop2op128<bits<8> opc, string OpcodeStr, Intrinsic Int, PatFrag memop> { @@ -66,10 +62,8 @@ multiclass xop2op128<bits<8> opc, string OpcodeStr, Intrinsic Int, [(set VR128:$dst, (Int (bitconvert (memop addr:$src))))]>, VEX; } -let isAsmParserOnly = 1 in { - defm VFRCZPS : xop2op128<0x80, "vfrczps", int_x86_xop_vfrcz_ps, memopv4f32>; - defm VFRCZPD : xop2op128<0x81, "vfrczpd", int_x86_xop_vfrcz_pd, memopv2f64>; -} +defm VFRCZPS : xop2op128<0x80, "vfrczps", int_x86_xop_vfrcz_ps, memopv4f32>; +defm VFRCZPD : xop2op128<0x81, "vfrczpd", int_x86_xop_vfrcz_pd, memopv2f64>; multiclass xop2op256<bits<8> opc, string OpcodeStr, Intrinsic Int, PatFrag memop> { @@ -81,12 +75,8 @@ multiclass xop2op256<bits<8> opc, string OpcodeStr, Intrinsic Int, [(set VR256:$dst, (Int (bitconvert (memop addr:$src))))]>, VEX, VEX_L; } -let isAsmParserOnly = 1 in { - defm VFRCZPS : xop2op256<0x80, "vfrczps", int_x86_xop_vfrcz_ps_256, - memopv8f32>; - defm VFRCZPD : xop2op256<0x81, "vfrczpd", int_x86_xop_vfrcz_pd_256, - memopv4f64>; -} +defm VFRCZPS : xop2op256<0x80, "vfrczps", int_x86_xop_vfrcz_ps_256, memopv8f32>; +defm VFRCZPD : xop2op256<0x81, "vfrczpd", int_x86_xop_vfrcz_pd_256, memopv4f64>; multiclass xop3op<bits<8> opc, string OpcodeStr, Intrinsic Int> { def rr : IXOP<opc, MRMSrcReg, (outs VR128:$dst), @@ -107,20 +97,18 @@ multiclass xop3op<bits<8> opc, string OpcodeStr, Intrinsic Int> { VEX_4VOp3; } -let isAsmParserOnly = 1 in { - defm VPSHLW : xop3op<0x95, "vpshlw", int_x86_xop_vpshlw>; - defm VPSHLQ : xop3op<0x97, "vpshlq", int_x86_xop_vpshlq>; - defm VPSHLD : xop3op<0x96, "vpshld", int_x86_xop_vpshld>; - defm VPSHLB : xop3op<0x94, "vpshlb", int_x86_xop_vpshlb>; - defm VPSHAW : xop3op<0x99, "vpshaw", int_x86_xop_vpshaw>; - defm VPSHAQ : xop3op<0x9B, "vpshaq", int_x86_xop_vpshaq>; - defm VPSHAD : xop3op<0x9A, "vpshad", int_x86_xop_vpshad>; - defm VPSHAB : xop3op<0x98, "vpshab", int_x86_xop_vpshab>; - defm VPROTW : xop3op<0x91, "vprotw", int_x86_xop_vprotw>; - defm VPROTQ : xop3op<0x93, "vprotq", int_x86_xop_vprotq>; - defm VPROTD : xop3op<0x92, "vprotd", int_x86_xop_vprotd>; - defm VPROTB : xop3op<0x90, "vprotb", int_x86_xop_vprotb>; -} +defm VPSHLW : xop3op<0x95, "vpshlw", int_x86_xop_vpshlw>; +defm VPSHLQ : xop3op<0x97, "vpshlq", int_x86_xop_vpshlq>; +defm VPSHLD : xop3op<0x96, "vpshld", int_x86_xop_vpshld>; +defm VPSHLB : xop3op<0x94, "vpshlb", int_x86_xop_vpshlb>; +defm VPSHAW : xop3op<0x99, "vpshaw", int_x86_xop_vpshaw>; +defm VPSHAQ : xop3op<0x9B, "vpshaq", int_x86_xop_vpshaq>; +defm VPSHAD : xop3op<0x9A, "vpshad", int_x86_xop_vpshad>; +defm VPSHAB : xop3op<0x98, "vpshab", int_x86_xop_vpshab>; +defm VPROTW : xop3op<0x91, "vprotw", int_x86_xop_vprotw>; +defm VPROTQ : xop3op<0x93, "vprotq", int_x86_xop_vprotq>; +defm VPROTD : xop3op<0x92, "vprotd", int_x86_xop_vprotd>; +defm VPROTB : xop3op<0x90, "vprotb", int_x86_xop_vprotb>; multiclass xop3opimm<bits<8> opc, string OpcodeStr, Intrinsic Int> { def ri : IXOPi8<opc, MRMSrcReg, (outs VR128:$dst), @@ -134,12 +122,10 @@ multiclass xop3opimm<bits<8> opc, string OpcodeStr, Intrinsic Int> { (Int (bitconvert (memopv2i64 addr:$src1)), imm:$src2))]>, VEX; } -let isAsmParserOnly = 1 in { - defm VPROTW : xop3opimm<0xC1, "vprotw", int_x86_xop_vprotwi>; - defm VPROTQ : xop3opimm<0xC3, "vprotq", int_x86_xop_vprotqi>; - defm VPROTD : xop3opimm<0xC2, "vprotd", int_x86_xop_vprotdi>; - defm VPROTB : xop3opimm<0xC0, "vprotb", int_x86_xop_vprotbi>; -} +defm VPROTW : xop3opimm<0xC1, "vprotw", int_x86_xop_vprotwi>; +defm VPROTQ : xop3opimm<0xC3, "vprotq", int_x86_xop_vprotqi>; +defm VPROTD : xop3opimm<0xC2, "vprotd", int_x86_xop_vprotdi>; +defm VPROTB : xop3opimm<0xC0, "vprotb", int_x86_xop_vprotbi>; // Instruction where second source can be memory, but third must be register multiclass xop4opm2<bits<8> opc, string OpcodeStr, Intrinsic Int> { @@ -158,20 +144,18 @@ multiclass xop4opm2<bits<8> opc, string OpcodeStr, Intrinsic Int> { VR128:$src3))]>, VEX_4V, VEX_I8IMM; } -let isAsmParserOnly = 1 in { - defm VPMADCSWD : xop4opm2<0xB6, "vpmadcswd", int_x86_xop_vpmadcswd>; - defm VPMADCSSWD : xop4opm2<0xA6, "vpmadcsswd", int_x86_xop_vpmadcsswd>; - defm VPMACSWW : xop4opm2<0x95, "vpmacsww", int_x86_xop_vpmacsww>; - defm VPMACSWD : xop4opm2<0x96, "vpmacswd", int_x86_xop_vpmacswd>; - defm VPMACSSWW : xop4opm2<0x85, "vpmacssww", int_x86_xop_vpmacssww>; - defm VPMACSSWD : xop4opm2<0x86, "vpmacsswd", int_x86_xop_vpmacsswd>; - defm VPMACSSDQL : xop4opm2<0x87, "vpmacssdql", int_x86_xop_vpmacssdql>; - defm VPMACSSDQH : xop4opm2<0x8F, "vpmacssdqh", int_x86_xop_vpmacssdqh>; - defm VPMACSSDD : xop4opm2<0x8E, "vpmacssdd", int_x86_xop_vpmacssdd>; - defm VPMACSDQL : xop4opm2<0x97, "vpmacsdql", int_x86_xop_vpmacsdql>; - defm VPMACSDQH : xop4opm2<0x9F, "vpmacsdqh", int_x86_xop_vpmacsdqh>; - defm VPMACSDD : xop4opm2<0x9E, "vpmacsdd", int_x86_xop_vpmacsdd>; -} +defm VPMADCSWD : xop4opm2<0xB6, "vpmadcswd", int_x86_xop_vpmadcswd>; +defm VPMADCSSWD : xop4opm2<0xA6, "vpmadcsswd", int_x86_xop_vpmadcsswd>; +defm VPMACSWW : xop4opm2<0x95, "vpmacsww", int_x86_xop_vpmacsww>; +defm VPMACSWD : xop4opm2<0x96, "vpmacswd", int_x86_xop_vpmacswd>; +defm VPMACSSWW : xop4opm2<0x85, "vpmacssww", int_x86_xop_vpmacssww>; +defm VPMACSSWD : xop4opm2<0x86, "vpmacsswd", int_x86_xop_vpmacsswd>; +defm VPMACSSDQL : xop4opm2<0x87, "vpmacssdql", int_x86_xop_vpmacssdql>; +defm VPMACSSDQH : xop4opm2<0x8F, "vpmacssdqh", int_x86_xop_vpmacssdqh>; +defm VPMACSSDD : xop4opm2<0x8E, "vpmacssdd", int_x86_xop_vpmacssdd>; +defm VPMACSDQL : xop4opm2<0x97, "vpmacsdql", int_x86_xop_vpmacsdql>; +defm VPMACSDQH : xop4opm2<0x9F, "vpmacsdqh", int_x86_xop_vpmacsdqh>; +defm VPMACSDD : xop4opm2<0x9E, "vpmacsdd", int_x86_xop_vpmacsdd>; // Instruction where second source can be memory, third must be imm8 multiclass xop4opimm<bits<8> opc, string OpcodeStr, Intrinsic Int> { @@ -190,16 +174,14 @@ multiclass xop4opimm<bits<8> opc, string OpcodeStr, Intrinsic Int> { imm:$src3))]>, VEX_4V; } -let isAsmParserOnly = 1 in { - defm VPCOMB : xop4opimm<0xCC, "vpcomb", int_x86_xop_vpcomb>; - defm VPCOMW : xop4opimm<0xCD, "vpcomw", int_x86_xop_vpcomw>; - defm VPCOMD : xop4opimm<0xCE, "vpcomd", int_x86_xop_vpcomd>; - defm VPCOMQ : xop4opimm<0xCF, "vpcomq", int_x86_xop_vpcomq>; - defm VPCOMUB : xop4opimm<0xEC, "vpcomub", int_x86_xop_vpcomub>; - defm VPCOMUW : xop4opimm<0xED, "vpcomuw", int_x86_xop_vpcomuw>; - defm VPCOMUD : xop4opimm<0xEE, "vpcomud", int_x86_xop_vpcomud>; - defm VPCOMUQ : xop4opimm<0xEF, "vpcomuq", int_x86_xop_vpcomuq>; -} +defm VPCOMB : xop4opimm<0xCC, "vpcomb", int_x86_xop_vpcomb>; +defm VPCOMW : xop4opimm<0xCD, "vpcomw", int_x86_xop_vpcomw>; +defm VPCOMD : xop4opimm<0xCE, "vpcomd", int_x86_xop_vpcomd>; +defm VPCOMQ : xop4opimm<0xCF, "vpcomq", int_x86_xop_vpcomq>; +defm VPCOMUB : xop4opimm<0xEC, "vpcomub", int_x86_xop_vpcomub>; +defm VPCOMUW : xop4opimm<0xED, "vpcomuw", int_x86_xop_vpcomuw>; +defm VPCOMUD : xop4opimm<0xEE, "vpcomud", int_x86_xop_vpcomud>; +defm VPCOMUQ : xop4opimm<0xEF, "vpcomuq", int_x86_xop_vpcomuq>; // Instruction where either second or third source can be memory multiclass xop4op<bits<8> opc, string OpcodeStr, Intrinsic Int> { @@ -227,10 +209,8 @@ multiclass xop4op<bits<8> opc, string OpcodeStr, Intrinsic Int> { VEX_4V, VEX_I8IMM; } -let isAsmParserOnly = 1 in { - defm VPPERM : xop4op<0xA3, "vpperm", int_x86_xop_vpperm>; - defm VPCMOV : xop4op<0xA2, "vpcmov", int_x86_xop_vpcmov>; -} +defm VPPERM : xop4op<0xA3, "vpperm", int_x86_xop_vpperm>; +defm VPCMOV : xop4op<0xA2, "vpcmov", int_x86_xop_vpcmov>; multiclass xop4op256<bits<8> opc, string OpcodeStr, Intrinsic Int> { def rrY : IXOPi8<opc, MRMSrcReg, (outs VR256:$dst), @@ -257,9 +237,7 @@ multiclass xop4op256<bits<8> opc, string OpcodeStr, Intrinsic Int> { VEX_4V, VEX_I8IMM, VEX_L; } -let isAsmParserOnly = 1 in { - defm VPCMOV : xop4op256<0xA2, "vpcmov", int_x86_xop_vpcmov_256>; -} +defm VPCMOV : xop4op256<0xA2, "vpcmov", int_x86_xop_vpcmov_256>; multiclass xop5op<bits<8> opc, string OpcodeStr, Intrinsic Int128, Intrinsic Int256, PatFrag ld_128, PatFrag ld_256> { diff --git a/test/MC/Disassembler/X86/simple-tests.txt b/test/MC/Disassembler/X86/simple-tests.txt index 9934812..7ca0874 100644 --- a/test/MC/Disassembler/X86/simple-tests.txt +++ b/test/MC/Disassembler/X86/simple-tests.txt @@ -770,9 +770,24 @@ # CHECK: vfmaddps %ymm2, %ymm1, %ymm0, %ymm0 0xc4 0xe3 0xfd 0x68 0xc2 0x10 +# CHECK: vpermil2ps $0, %xmm4, %xmm3, %xmm2, %xmm1 +0xc4 0xe3 0x69 0x48 0xcb 0x40 + # CHECK: vpermil2ps $1, 4(%rax), %xmm2, %xmm3, %xmm0 0xc4 0xe3 0xe1 0x48 0x40 0x04 0x21 +# CHECK: vpermil2ps $2, (%rax), %ymm1, %ymm5, %ymm6 +0xc4 0xe3 0xd5 0x48 0x30 0x12 + +# CHECK: vpermil2ps $3, %xmm1, (%rax), %xmm3, %xmm4 +0xc4 0xe3 0x61 0x48 0x20 0x13 + +# CHECK: vpermil2ps $0, %ymm4, %ymm4, %ymm2, %ymm2 +0xc4 0xe3 0x6d 0x48 0xd4 0x40 + +# CHECK: vpermil2pd $1, %ymm1, 4(%rax), %ymm1, %ymm0 +0xc4 0xe3 0x75 0x49 0x40 0x04 0x11 + # CHECK: vgatherdpd %xmm0, (%rdi,%xmm1,2), %xmm2 0xc4 0xe2 0xf9 0x92 0x14 0x4f @@ -844,3 +859,60 @@ # CHECK: xacquire # CHECK-NEXT: xchgl %ebx, (%rax) 0xf2 0x87 0x18 + +# CHECK: bextr $2814, %edi, %eax +0x8f 0xea 0x78 0x10 0xc7 0xfe 0x0a 0x00 0x00 + +# CHECK: blci %rdi, %rax +0x8f 0xe9 0xf8 0x02 0xf7 + +# CHECK: vpcmov %xmm1, %xmm2, %xmm3, %xmm4 +0x8f 0xe8 0x60 0xa2 0xe2 0x10 + +# CHECK: vpcmov (%rax), %xmm2, %xmm3, %xmm4 +0x8f 0xe8 0xe0 0xa2 0x20 0x20 + +# CHECK: vpcmov %xmm1, (%rax), %xmm3, %xmm4 +0x8f 0xe8 0x60 0xa2 0x20 0x10 + +# CHECK: vpcmov %ymm1, %ymm2, %ymm3, %ymm4 +0x8f 0xe8 0x64 0xa2 0xe2 0x10 + +# CHECK: vpcmov (%rax), %ymm2, %ymm3, %ymm4 +0x8f 0xe8 0xe4 0xa2 0x20 0x20 + +# CHECK: vpcmov %ymm1, (%rax), %ymm3, %ymm4 +0x8f 0xe8 0x64 0xa2 0x20 0x10 + +# CHECK: vpcomb $55, %xmm6, %xmm4, %xmm2 +0x8f 0xe8 0x58 0xcc 0xd6 0x37 + +# CHECK: vpcomb $56, 8(%rax), %xmm3, %xmm2 +0x8f 0xe8 0x60 0xcc 0x50 0x08 0x38 + +# CHECK: vpmacsdd %xmm4, %xmm6, %xmm4, %xmm2 +0x8f 0xe8 0x58 0x9e 0xd6 0x40 +# CHECK: vpmacsdd %xmm4, (%rax,%rcx), %xmm4, %xmm3 +0x8f 0xe8 0x58 0x9e 0x1c 0x08 0x40 + +# CHECK: vprotd (%rax), %xmm0, %xmm3 +0x8f 0xe9 0xf8 0x92 0x18 +# CHECK: vprotd %xmm2, (%rax,%rcx), %xmm4 +0x8f 0xe9 0x68 0x92 0x24 0x08 +# CHECK: vprotd %xmm5, %xmm3, %xmm2 +0x8f 0xe9 0x50 0x92 0xd3 +# CHECK: vprotd $43, (%rcx), %xmm6 +0x8f 0xe8 0x78 0xc2 0x31 0x2b +# CHECK: vprotd $44, (%rax,%rcx), %xmm7 +0x8f 0xe8 0x78 0xc2 0x3c 0x08 0x2c +# CHECK: vprotd $45, %xmm4, %xmm4 +0x8f 0xe8 0x78 0xc2 0xe4 0x2d + +# CHECK: vfrczps 4(%rax), %xmm3 +0x8f 0xe9 0x78 0x80 0x58 0x04 +# CHECK: vfrczps %xmm6, %xmm5 +0x8f 0xe9 0x78 0x80 0xee +# CHECK: vfrczps (%rcx), %xmm1 +0x8f 0xe9 0x78 0x80 0x09 +# CHECK: vfrczps %ymm2, %ymm4 +0x8f 0xe9 0x7c 0x80 0xe2 diff --git a/test/MC/X86/avx512-encodings.s b/test/MC/X86/avx512-encodings.s index 09dff8c..38f9190 100644 --- a/test/MC/X86/avx512-encodings.s +++ b/test/MC/X86/avx512-encodings.s @@ -42,4 +42,4 @@ vpbroadcastd %xmm0, %zmm1 {%k1} {z} // CHECK: vmovdqu64 {{.*}} {%k3} // CHECK: encoding: [0x62,0xf1,0xfe,0x4b,0x6f,0xc8] -vmovdqu64 %zmm0, %zmm1 {%k3}
\ No newline at end of file +vmovdqu64 %zmm0, %zmm1 {%k3} diff --git a/utils/TableGen/X86DisassemblerTables.cpp b/utils/TableGen/X86DisassemblerTables.cpp index 98a4797..026870e 100644 --- a/utils/TableGen/X86DisassemblerTables.cpp +++ b/utils/TableGen/X86DisassemblerTables.cpp @@ -707,6 +707,9 @@ void DisassemblerTables::emitContextDecisions(raw_ostream &o1, raw_ostream &o2, emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[3], THREEBYTE3A_STR); emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[4], THREEBYTEA6_STR); emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[5], THREEBYTEA7_STR); + emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[6], XOP8_MAP_STR); + emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[7], XOP9_MAP_STR); + emitContextDecision(o1, o2, i1, i2, ModRMTableNum, *Tables[8], XOPA_MAP_STR); } void DisassemblerTables::emit(raw_ostream &o) const { diff --git a/utils/TableGen/X86DisassemblerTables.h b/utils/TableGen/X86DisassemblerTables.h index 3861b74..bf8b127 100644 --- a/utils/TableGen/X86DisassemblerTables.h +++ b/utils/TableGen/X86DisassemblerTables.h @@ -40,7 +40,10 @@ private: /// [3] three-byte opcodes of the form 0f 3a __ /// [4] three-byte opcodes of the form 0f a6 __ /// [5] three-byte opcodes of the form 0f a7 __ - ContextDecision* Tables[6]; + /// [6] XOP8 map opcode + /// [7] XOP9 map opcode + /// [8] XOPA map opcode + ContextDecision* Tables[9]; // Table of ModRM encodings. typedef std::map<std::vector<unsigned>, unsigned> ModRMMapTy; diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index d2675d7..7c8b84e 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -79,7 +79,8 @@ namespace X86Local { DC = 7, DD = 8, DE = 9, DF = 10, XD = 11, XS = 12, T8 = 13, P_TA = 14, - A6 = 15, A7 = 16, T8XD = 17, T8XS = 18, TAXD = 19 + A6 = 15, A7 = 16, T8XD = 17, T8XS = 18, TAXD = 19, + XOP8 = 20, XOP9 = 21, XOPA = 22 }; } @@ -134,6 +135,10 @@ namespace X86Local { #define THREE_BYTE_38_EXTENSION_TABLES \ EXTENSION_TABLE(F3) +#define XOP9_MAP_EXTENSION_TABLES \ + EXTENSION_TABLE(01) \ + EXTENSION_TABLE(02) + using namespace X86Disassembler; /// needsModRMForDecode - Indicates whether a particular instruction requires a @@ -908,6 +913,7 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const { uint8_t opcodeToSet = 0; switch (Prefix) { + default: llvm_unreachable("Invalid prefix!"); // Extended two-byte opcodes can start with f2 0f, f3 0f, or 0f case X86Local::XD: case X86Local::XS: @@ -1021,6 +1027,63 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const { filter = new DumbFilter(); opcodeToSet = Opcode; break; + case X86Local::XOP8: + opcodeType = XOP8_MAP; + if (needsModRMForDecode(Form)) + filter = new ModFilter(isRegFormat(Form)); + else + filter = new DumbFilter(); + opcodeToSet = Opcode; + break; + case X86Local::XOP9: + opcodeType = XOP9_MAP; + switch (Opcode) { + default: + if (needsModRMForDecode(Form)) + filter = new ModFilter(isRegFormat(Form)); + else + filter = new DumbFilter(); + break; +#define EXTENSION_TABLE(n) case 0x##n: + XOP9_MAP_EXTENSION_TABLES +#undef EXTENSION_TABLE + switch (Form) { + default: + llvm_unreachable("Unhandled XOP9 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::XOPA: + opcodeType = XOPA_MAP; + if (needsModRMForDecode(Form)) + filter = new ModFilter(isRegFormat(Form)); + else + filter = new DumbFilter(); + opcodeToSet = Opcode; + break; case X86Local::D8: case X86Local::D9: case X86Local::DA: @@ -1041,7 +1104,7 @@ void RecognizableInstr::emitDecodePath(DisassemblerTables &tables) const { opcodeToSet = 0xd8 + (Prefix - X86Local::D8); break; case X86Local::REP: - default: + case 0: opcodeType = ONEBYTE; switch (Opcode) { #define EXTENSION_TABLE(n) case 0x##n: |