From: Elena Demikhovsky Date: Wed, 25 Dec 2013 11:40:51 +0000 (+0000) Subject: AVX-512: decoder for AVX-512, made by Alexey Bader. X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=09a63715cea1fc7ba15d0658aac681c4863edf2f;p=oota-llvm.git AVX-512: decoder for AVX-512, made by Alexey Bader. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@198013 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Target/X86/AsmParser/X86AsmParser.cpp b/lib/Target/X86/AsmParser/X86AsmParser.cpp index ef363b8a611..0f8e9f7b4ad 100644 --- a/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -2067,6 +2067,7 @@ ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, return true; } } + // TODO: add parsing of broadcasts {1to8}, {1to16} // Parse "zeroing non-masked" semantic {z} if (getLexer().is(AsmToken::LCurly)) { Operands.push_back(X86Operand::CreateToken("{z}", consumeToken())); diff --git a/lib/Target/X86/Disassembler/X86Disassembler.cpp b/lib/Target/X86/Disassembler/X86Disassembler.cpp index 903e36cfe6c..459ea932c0f 100644 --- a/lib/Target/X86/Disassembler/X86Disassembler.cpp +++ b/lib/Target/X86/Disassembler/X86Disassembler.cpp @@ -418,13 +418,22 @@ static bool translateRMMemory(MCInst &mcInst, InternalInstruction &insn, bool IndexIs256 = (Opcode == X86::VGATHERQPDYrm || Opcode == X86::VGATHERDPSYrm || Opcode == X86::VGATHERQPSYrm || + Opcode == X86::VGATHERDPDZrm || + Opcode == X86::VPGATHERDQZrm || Opcode == X86::VPGATHERQQYrm || Opcode == X86::VPGATHERDDYrm || Opcode == X86::VPGATHERQDYrm); - if (IndexIs128 || IndexIs256) { + bool IndexIs512 = (Opcode == X86::VGATHERQPDZrm || + Opcode == X86::VGATHERDPSZrm || + Opcode == X86::VGATHERQPSZrm || + Opcode == X86::VPGATHERQQZrm || + Opcode == X86::VPGATHERDDZrm || + Opcode == X86::VPGATHERQDZrm); + if (IndexIs128 || IndexIs256 || IndexIs512) { unsigned IndexOffset = insn.sibIndex - (insn.addressSize == 8 ? SIB_INDEX_RAX:SIB_INDEX_EAX); - SIBIndex IndexBase = IndexIs256 ? SIB_INDEX_YMM0 : SIB_INDEX_XMM0; + SIBIndex IndexBase = IndexIs512 ? SIB_INDEX_ZMM0 : + IndexIs256 ? SIB_INDEX_YMM0 : SIB_INDEX_XMM0; insn.sibIndex = (SIBIndex)(IndexBase + (insn.sibIndex == SIB_INDEX_NONE ? 4 : IndexOffset)); } @@ -565,6 +574,9 @@ static bool translateRM(MCInst &mcInst, const OperandSpecifier &operand, case TYPE_XMM128: case TYPE_XMM256: case TYPE_XMM512: + case TYPE_VK1: + case TYPE_VK8: + case TYPE_VK16: case TYPE_DEBUGREG: case TYPE_CONTROLREG: return translateRMRegister(mcInst, insn); @@ -596,7 +608,7 @@ static bool translateRM(MCInst &mcInst, const OperandSpecifier &operand, /// /// @param mcInst - The MCInst to append to. /// @param stackPos - The stack position to translate. -/// @return - 0 on success; nonzero otherwise. +/// @return - false on success; true otherwise. static bool translateFPRegister(MCInst &mcInst, uint8_t stackPos) { if (stackPos >= 8) { @@ -609,6 +621,23 @@ static bool translateFPRegister(MCInst &mcInst, return false; } +/// translateMaskRegister - Translates a 3-bit mask register number to +/// LLVM form, and appends it to an MCInst. +/// +/// @param mcInst - The MCInst to append to. +/// @param maskRegNum - Number of mask register from 0 to 7. +/// @return - false on success; true otherwise. +static bool translateMaskRegister(MCInst &mcInst, + uint8_t maskRegNum) { + if (maskRegNum >= 8) { + debug("Invalid mask register number"); + return true; + } + + mcInst.addOperand(MCOperand::CreateReg(X86::K0 + maskRegNum)); + return false; +} + /// translateOperand - Translates an operand stored in an internal instruction /// to LLVM's format and appends it to an MCInst. /// @@ -626,6 +655,8 @@ static bool translateOperand(MCInst &mcInst, const OperandSpecifier &operand, case ENCODING_REG: translateRegister(mcInst, insn.reg); return false; + case ENCODING_WRITEMASK: + return translateMaskRegister(mcInst, insn.writemask); case ENCODING_RM: return translateRM(mcInst, operand, insn, Dis); case ENCODING_CB: diff --git a/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c b/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c index c81a85755f8..4b97678d0c7 100644 --- a/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c +++ b/lib/Target/X86/Disassembler/X86DisassemblerDecoder.c @@ -40,7 +40,7 @@ * @return - The InstructionContext to use when looking up an * an instruction with these attributes. */ -static InstructionContext contextForAttrs(uint8_t attrMask) { +static InstructionContext contextForAttrs(uint16_t attrMask) { return CONTEXTS_SYM[attrMask]; } @@ -57,7 +57,7 @@ static InstructionContext contextForAttrs(uint8_t attrMask) { */ static int modRMRequired(OpcodeType type, InstructionContext insnContext, - uint8_t opcode) { + uint16_t opcode) { const struct ContextDecision* decision = 0; switch (type) { @@ -444,9 +444,60 @@ static int readPrefixes(struct InternalInstruction* insn) { dbgprintf(insn, "Found prefix 0x%hhx", byte); } - insn->vexXopType = TYPE_NO_VEX_XOP; + insn->vectorExtensionType = TYPE_NO_VEX_XOP; - if (byte == 0xc4) { + if (byte == 0x62) { + uint8_t byte1, byte2; + + if (consumeByte(insn, &byte1)) { + dbgprintf(insn, "Couldn't read second byte of EVEX prefix"); + return -1; + } + + if (lookAtByte(insn, &byte2)) { + dbgprintf(insn, "Couldn't read third byte of EVEX prefix"); + return -1; + } + + if ((insn->mode == MODE_64BIT || (byte1 & 0xc0) == 0xc0) && + ((~byte1 & 0xc) == 0xc) && ((byte2 & 0x4) == 0x4)) { + insn->vectorExtensionType = TYPE_EVEX; + } + else { + unconsumeByte(insn); /* unconsume byte1 */ + unconsumeByte(insn); /* unconsume byte */ + insn->necessaryPrefixLocation = insn->readerCursor - 2; + } + + if (insn->vectorExtensionType == TYPE_EVEX) { + insn->vectorExtensionPrefix[0] = byte; + insn->vectorExtensionPrefix[1] = byte1; + if (consumeByte(insn, &insn->vectorExtensionPrefix[2])) { + dbgprintf(insn, "Couldn't read third byte of EVEX prefix"); + return -1; + } + if (consumeByte(insn, &insn->vectorExtensionPrefix[3])) { + dbgprintf(insn, "Couldn't read fourth byte of EVEX prefix"); + return -1; + } + + /* We simulate the REX prefix for simplicity's sake */ + if (insn->mode == MODE_64BIT) { + insn->rexPrefix = 0x40 + | (wFromEVEX3of4(insn->vectorExtensionPrefix[2]) << 3) + | (rFromEVEX2of4(insn->vectorExtensionPrefix[1]) << 2) + | (xFromEVEX2of4(insn->vectorExtensionPrefix[1]) << 1) + | (bFromEVEX2of4(insn->vectorExtensionPrefix[1]) << 0); + } + + hasOpSize = (VEX_PREFIX_66 == ppFromEVEX3of4(insn->vectorExtensionPrefix[2])); + + dbgprintf(insn, "Found EVEX prefix 0x%hhx 0x%hhx 0x%hhx 0x%hhx", + insn->vectorExtensionPrefix[0], insn->vectorExtensionPrefix[1], + insn->vectorExtensionPrefix[2], insn->vectorExtensionPrefix[3]); + } + } + else if (byte == 0xc4) { uint8_t byte1; if (lookAtByte(insn, &byte1)) { @@ -455,7 +506,7 @@ static int readPrefixes(struct InternalInstruction* insn) { } if (insn->mode == MODE_64BIT || (byte1 & 0xc0) == 0xc0) { - insn->vexXopType = TYPE_VEX_3B; + insn->vectorExtensionType = TYPE_VEX_3B; insn->necessaryPrefixLocation = insn->readerCursor - 1; } else { @@ -463,22 +514,22 @@ static int readPrefixes(struct InternalInstruction* insn) { insn->necessaryPrefixLocation = insn->readerCursor - 1; } - if (insn->vexXopType == TYPE_VEX_3B) { - insn->vexXopPrefix[0] = byte; - consumeByte(insn, &insn->vexXopPrefix[1]); - consumeByte(insn, &insn->vexXopPrefix[2]); + if (insn->vectorExtensionType == TYPE_VEX_3B) { + insn->vectorExtensionPrefix[0] = byte; + consumeByte(insn, &insn->vectorExtensionPrefix[1]); + consumeByte(insn, &insn->vectorExtensionPrefix[2]); /* We simulate the REX prefix for simplicity's sake */ if (insn->mode == MODE_64BIT) { insn->rexPrefix = 0x40 - | (wFromVEX3of3(insn->vexXopPrefix[2]) << 3) - | (rFromVEX2of3(insn->vexXopPrefix[1]) << 2) - | (xFromVEX2of3(insn->vexXopPrefix[1]) << 1) - | (bFromVEX2of3(insn->vexXopPrefix[1]) << 0); + | (wFromVEX3of3(insn->vectorExtensionPrefix[2]) << 3) + | (rFromVEX2of3(insn->vectorExtensionPrefix[1]) << 2) + | (xFromVEX2of3(insn->vectorExtensionPrefix[1]) << 1) + | (bFromVEX2of3(insn->vectorExtensionPrefix[1]) << 0); } - switch (ppFromVEX3of3(insn->vexXopPrefix[2])) + switch (ppFromVEX3of3(insn->vectorExtensionPrefix[2])) { default: break; @@ -488,8 +539,8 @@ static int readPrefixes(struct InternalInstruction* insn) { } dbgprintf(insn, "Found VEX prefix 0x%hhx 0x%hhx 0x%hhx", - insn->vexXopPrefix[0], insn->vexXopPrefix[1], - insn->vexXopPrefix[2]); + insn->vectorExtensionPrefix[0], insn->vectorExtensionPrefix[1], + insn->vectorExtensionPrefix[2]); } } else if (byte == 0xc5) { @@ -501,22 +552,22 @@ static int readPrefixes(struct InternalInstruction* insn) { } if (insn->mode == MODE_64BIT || (byte1 & 0xc0) == 0xc0) { - insn->vexXopType = TYPE_VEX_2B; + insn->vectorExtensionType = TYPE_VEX_2B; } else { unconsumeByte(insn); } - if (insn->vexXopType == TYPE_VEX_2B) { - insn->vexXopPrefix[0] = byte; - consumeByte(insn, &insn->vexXopPrefix[1]); + if (insn->vectorExtensionType == TYPE_VEX_2B) { + insn->vectorExtensionPrefix[0] = byte; + consumeByte(insn, &insn->vectorExtensionPrefix[1]); if (insn->mode == MODE_64BIT) { insn->rexPrefix = 0x40 - | (rFromVEX2of2(insn->vexXopPrefix[1]) << 2); + | (rFromVEX2of2(insn->vectorExtensionPrefix[1]) << 2); } - switch (ppFromVEX2of2(insn->vexXopPrefix[1])) + switch (ppFromVEX2of2(insn->vectorExtensionPrefix[1])) { default: break; @@ -525,7 +576,9 @@ static int readPrefixes(struct InternalInstruction* insn) { break; } - dbgprintf(insn, "Found VEX prefix 0x%hhx 0x%hhx", insn->vexXopPrefix[0], insn->vexXopPrefix[1]); + dbgprintf(insn, "Found VEX prefix 0x%hhx 0x%hhx", + insn->vectorExtensionPrefix[0], + insn->vectorExtensionPrefix[1]); } } else if (byte == 0x8f) { @@ -537,7 +590,7 @@ static int readPrefixes(struct InternalInstruction* insn) { } if ((byte1 & 0x38) != 0x0) { /* 0 in these 3 bits is a POP instruction. */ - insn->vexXopType = TYPE_XOP; + insn->vectorExtensionType = TYPE_XOP; insn->necessaryPrefixLocation = insn->readerCursor - 1; } else { @@ -545,22 +598,22 @@ static int readPrefixes(struct InternalInstruction* insn) { insn->necessaryPrefixLocation = insn->readerCursor - 1; } - if (insn->vexXopType == TYPE_XOP) { - insn->vexXopPrefix[0] = byte; - consumeByte(insn, &insn->vexXopPrefix[1]); - consumeByte(insn, &insn->vexXopPrefix[2]); + if (insn->vectorExtensionType == TYPE_XOP) { + insn->vectorExtensionPrefix[0] = byte; + consumeByte(insn, &insn->vectorExtensionPrefix[1]); + consumeByte(insn, &insn->vectorExtensionPrefix[2]); /* We simulate the REX prefix for simplicity's sake */ if (insn->mode == MODE_64BIT) { insn->rexPrefix = 0x40 - | (wFromXOP3of3(insn->vexXopPrefix[2]) << 3) - | (rFromXOP2of3(insn->vexXopPrefix[1]) << 2) - | (xFromXOP2of3(insn->vexXopPrefix[1]) << 1) - | (bFromXOP2of3(insn->vexXopPrefix[1]) << 0); + | (wFromXOP3of3(insn->vectorExtensionPrefix[2]) << 3) + | (rFromXOP2of3(insn->vectorExtensionPrefix[1]) << 2) + | (xFromXOP2of3(insn->vectorExtensionPrefix[1]) << 1) + | (bFromXOP2of3(insn->vectorExtensionPrefix[1]) << 0); } - switch (ppFromXOP3of3(insn->vexXopPrefix[2])) + switch (ppFromXOP3of3(insn->vectorExtensionPrefix[2])) { default: break; @@ -570,8 +623,8 @@ static int readPrefixes(struct InternalInstruction* insn) { } dbgprintf(insn, "Found XOP prefix 0x%hhx 0x%hhx 0x%hhx", - insn->vexXopPrefix[0], insn->vexXopPrefix[1], - insn->vexXopPrefix[2]); + insn->vectorExtensionPrefix[0], insn->vectorExtensionPrefix[1], + insn->vectorExtensionPrefix[2]); } } else { @@ -646,13 +699,29 @@ static int readOpcode(struct InternalInstruction* insn) { insn->opcodeType = ONEBYTE; - if (insn->vexXopType == TYPE_VEX_3B) + if (insn->vectorExtensionType == TYPE_EVEX) { - switch (mmmmmFromVEX2of3(insn->vexXopPrefix[1])) - { + switch (mmFromEVEX2of4(insn->vectorExtensionPrefix[1])) { + default: + dbgprintf(insn, "Unhandled mm field for instruction (0x%hhx)", + mmFromEVEX2of4(insn->vectorExtensionPrefix[1])); + return -1; + case VEX_LOB_0F: + insn->opcodeType = TWOBYTE; + return consumeByte(insn, &insn->opcode); + case VEX_LOB_0F38: + insn->opcodeType = THREEBYTE_38; + return consumeByte(insn, &insn->opcode); + case VEX_LOB_0F3A: + insn->opcodeType = THREEBYTE_3A; + return consumeByte(insn, &insn->opcode); + } + } + else if (insn->vectorExtensionType == TYPE_VEX_3B) { + switch (mmmmmFromVEX2of3(insn->vectorExtensionPrefix[1])) { default: dbgprintf(insn, "Unhandled m-mmmm field for instruction (0x%hhx)", - mmmmmFromVEX2of3(insn->vexXopPrefix[1])); + mmmmmFromVEX2of3(insn->vectorExtensionPrefix[1])); return -1; case VEX_LOB_0F: insn->opcodeType = TWOBYTE; @@ -665,18 +734,15 @@ static int readOpcode(struct InternalInstruction* insn) { return consumeByte(insn, &insn->opcode); } } - else if (insn->vexXopType == TYPE_VEX_2B) - { + else if (insn->vectorExtensionType == TYPE_VEX_2B) { insn->opcodeType = TWOBYTE; return consumeByte(insn, &insn->opcode); } - else if (insn->vexXopType == TYPE_XOP) - { - switch (mmmmmFromXOP2of3(insn->vexXopPrefix[1])) - { + else if (insn->vectorExtensionType == TYPE_XOP) { + switch (mmmmmFromXOP2of3(insn->vectorExtensionPrefix[1])) { default: dbgprintf(insn, "Unhandled m-mmmm field for instruction (0x%hhx)", - mmmmmFromVEX2of3(insn->vexXopPrefix[1])); + mmmmmFromVEX2of3(insn->vectorExtensionPrefix[1])); return -1; case XOP_MAP_SELECT_8: insn->opcodeType = XOP8_MAP; @@ -760,10 +826,10 @@ static int readModRM(struct InternalInstruction* insn); */ static int getIDWithAttrMask(uint16_t* instructionID, struct InternalInstruction* insn, - uint8_t attrMask) { + uint16_t attrMask) { BOOL hasModRMExtension; - uint8_t instructionClass; + uint16_t instructionClass; instructionClass = contextForAttrs(attrMask); @@ -826,7 +892,7 @@ static BOOL is16BitEquivalent(const char* orig, const char* equiv) { * nonzero otherwise. */ static int getID(struct InternalInstruction* insn, const void *miiArg) { - uint8_t attrMask; + uint16_t attrMask; uint16_t instructionID; dbgprintf(insn, "getID()"); @@ -836,11 +902,35 @@ static int getID(struct InternalInstruction* insn, const void *miiArg) { if (insn->mode == MODE_64BIT) attrMask |= ATTR_64BIT; - if (insn->vexXopType != TYPE_NO_VEX_XOP) { - attrMask |= ATTR_VEX; + if (insn->vectorExtensionType != TYPE_NO_VEX_XOP) { + attrMask |= (insn->vectorExtensionType == TYPE_EVEX) ? ATTR_EVEX : ATTR_VEX; + + if (insn->vectorExtensionType == TYPE_EVEX) { + switch (ppFromEVEX3of4(insn->vectorExtensionPrefix[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 (insn->vexXopType == TYPE_VEX_3B) { - switch (ppFromVEX3of3(insn->vexXopPrefix[2])) { + if (zFromEVEX4of4(insn->vectorExtensionPrefix[3])) + attrMask |= ATTR_EVEXKZ; + if (bFromEVEX4of4(insn->vectorExtensionPrefix[3])) + attrMask |= ATTR_EVEXB; + if (aaaFromEVEX4of4(insn->vectorExtensionPrefix[3])) + attrMask |= ATTR_EVEXK; + if (lFromEVEX4of4(insn->vectorExtensionPrefix[3])) + attrMask |= ATTR_EVEXL; + if (l2FromEVEX4of4(insn->vectorExtensionPrefix[3])) + attrMask |= ATTR_EVEXL2; + } + else if (insn->vectorExtensionType == TYPE_VEX_3B) { + switch (ppFromVEX3of3(insn->vectorExtensionPrefix[2])) { case VEX_PREFIX_66: attrMask |= ATTR_OPSIZE; break; @@ -852,11 +942,11 @@ static int getID(struct InternalInstruction* insn, const void *miiArg) { break; } - if (lFromVEX3of3(insn->vexXopPrefix[2])) + if (lFromVEX3of3(insn->vectorExtensionPrefix[2])) attrMask |= ATTR_VEXL; } - else if (insn->vexXopType == TYPE_VEX_2B) { - switch (ppFromVEX2of2(insn->vexXopPrefix[1])) { + else if (insn->vectorExtensionType == TYPE_VEX_2B) { + switch (ppFromVEX2of2(insn->vectorExtensionPrefix[1])) { case VEX_PREFIX_66: attrMask |= ATTR_OPSIZE; break; @@ -868,11 +958,11 @@ static int getID(struct InternalInstruction* insn, const void *miiArg) { break; } - if (lFromVEX2of2(insn->vexXopPrefix[1])) + if (lFromVEX2of2(insn->vectorExtensionPrefix[1])) attrMask |= ATTR_VEXL; } - else if (insn->vexXopType == TYPE_XOP) { - switch (ppFromXOP3of3(insn->vexXopPrefix[2])) { + else if (insn->vectorExtensionType == TYPE_XOP) { + switch (ppFromXOP3of3(insn->vectorExtensionPrefix[2])) { case VEX_PREFIX_66: attrMask |= ATTR_OPSIZE; break; @@ -884,7 +974,7 @@ static int getID(struct InternalInstruction* insn, const void *miiArg) { break; } - if (lFromXOP3of3(insn->vexXopPrefix[2])) + if (lFromXOP3of3(insn->vectorExtensionPrefix[2])) attrMask |= ATTR_VEXL; } else { @@ -1033,6 +1123,8 @@ static int readSIB(struct InternalInstruction* insn) { return -1; index = indexFromSIB(insn->sib) | (xFromREX(insn->rexPrefix) << 3); + if (insn->vectorExtensionType == TYPE_EVEX) + index |= v2FromEVEX4of4(insn->vectorExtensionPrefix[3]) << 4; switch (index) { case 0x4: @@ -1183,6 +1275,10 @@ static int readModRM(struct InternalInstruction* insn) { reg |= rFromREX(insn->rexPrefix) << 3; rm |= bFromREX(insn->rexPrefix) << 3; + if (insn->vectorExtensionType == TYPE_EVEX) { + reg |= r2FromEVEX2of4(insn->vectorExtensionPrefix[1]) << 4; + rm |= xFromEVEX2of4(insn->vectorExtensionPrefix[1]) << 4; + } insn->reg = (Reg)(insn->regBase + reg); @@ -1229,6 +1325,7 @@ static int readModRM(struct InternalInstruction* insn) { case 0x0: insn->eaDisplacement = EA_DISP_NONE; /* readSIB may override this */ switch (rm) { + case 0x14: case 0x4: case 0xc: /* in case REXW.b is set */ insn->eaBase = (insn->addressSize == 4 ? @@ -1252,6 +1349,7 @@ static int readModRM(struct InternalInstruction* insn) { case 0x2: insn->eaDisplacement = (mod == 0x1 ? EA_DISP_8 : EA_DISP_32); switch (rm) { + case 0x14: case 0x4: case 0xc: /* in case REXW.b is set */ insn->eaBase = EA_BASE_sib; @@ -1312,6 +1410,10 @@ static int readModRM(struct InternalInstruction* insn) { case TYPE_XMM32: \ case TYPE_XMM: \ return prefix##_XMM0 + index; \ + case TYPE_VK1: \ + case TYPE_VK8: \ + case TYPE_VK16: \ + return prefix##_K0 + index; \ case TYPE_MM64: \ case TYPE_MM32: \ case TYPE_MM: \ @@ -1550,12 +1652,14 @@ static int readImmediate(struct InternalInstruction* insn, uint8_t size) { static int readVVVV(struct InternalInstruction* insn) { dbgprintf(insn, "readVVVV()"); - 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]); + if (insn->vectorExtensionType == TYPE_EVEX) + insn->vvvv = vvvvFromEVEX3of4(insn->vectorExtensionPrefix[2]); + else if (insn->vectorExtensionType == TYPE_VEX_3B) + insn->vvvv = vvvvFromVEX3of3(insn->vectorExtensionPrefix[2]); + else if (insn->vectorExtensionType == TYPE_VEX_2B) + insn->vvvv = vvvvFromVEX2of2(insn->vectorExtensionPrefix[1]); + else if (insn->vectorExtensionType == TYPE_XOP) + insn->vvvv = vvvvFromXOP3of3(insn->vectorExtensionPrefix[2]); else return -1; @@ -1565,6 +1669,23 @@ static int readVVVV(struct InternalInstruction* insn) { return 0; } +/* + * readMaskRegister - Reads an mask register from the opcode field of an + * instruction. + * + * @param insn - The instruction whose opcode field is to be read. + * @return - 0 on success; nonzero otherwise. + */ +static int readMaskRegister(struct InternalInstruction* insn) { + dbgprintf(insn, "readMaskRegister()"); + + if (insn->vectorExtensionType != TYPE_EVEX) + return -1; + + insn->writemask = aaaFromEVEX4of4(insn->vectorExtensionPrefix[3]); + return 0; +} + /* * readOperands - Consults the specifier for an instruction and consumes all * operands for that instruction, interpreting them as it goes. @@ -1675,6 +1796,10 @@ static int readOperands(struct InternalInstruction* insn) { if (fixupReg(insn, &x86OperandSets[insn->spec->operands][index])) return -1; break; + case ENCODING_WRITEMASK: + if (readMaskRegister(insn)) + return -1; + break; case ENCODING_DUP: break; default: diff --git a/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h b/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h index 6d03d5ca5f3..294c47688ff 100644 --- a/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h +++ b/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h @@ -45,6 +45,21 @@ extern "C" { #define xFromREX(rex) (((rex) & 0x2) >> 1) #define bFromREX(rex) ((rex) & 0x1) +#define rFromEVEX2of4(evex) (((~(evex)) & 0x80) >> 7) +#define xFromEVEX2of4(evex) (((~(evex)) & 0x40) >> 6) +#define bFromEVEX2of4(evex) (((~(evex)) & 0x20) >> 5) +#define r2FromEVEX2of4(evex) (((~(evex)) & 0x10) >> 4) +#define mmFromEVEX2of4(evex) ((evex) & 0x3) +#define wFromEVEX3of4(evex) (((evex) & 0x80) >> 7) +#define vvvvFromEVEX3of4(evex) (((~(evex)) & 0x78) >> 3) +#define ppFromEVEX3of4(evex) ((evex) & 0x3) +#define zFromEVEX4of4(evex) (((evex) & 0x80) >> 7) +#define l2FromEVEX4of4(evex) (((evex) & 0x40) >> 6) +#define lFromEVEX4of4(evex) (((evex) & 0x20) >> 5) +#define bFromEVEX4of4(evex) (((evex) & 0x10) >> 4) +#define v2FromEVEX4of4(evex) (((~evex) & 0x8) >> 3) +#define aaaFromEVEX4of4(evex) ((evex) & 0x7) + #define rFromVEX2of3(vex) (((~(vex)) & 0x80) >> 7) #define xFromVEX2of3(vex) (((~(vex)) & 0x40) >> 6) #define bFromVEX2of3(vex) (((~(vex)) & 0x20) >> 5) @@ -314,6 +329,16 @@ extern "C" { ENTRY(ZMM30) \ ENTRY(ZMM31) +#define REGS_MASKS \ + ENTRY(K0) \ + ENTRY(K1) \ + ENTRY(K2) \ + ENTRY(K3) \ + ENTRY(K4) \ + ENTRY(K5) \ + ENTRY(K6) \ + ENTRY(K7) + #define REGS_SEGMENT \ ENTRY(ES) \ ENTRY(CS) \ @@ -361,6 +386,7 @@ extern "C" { REGS_XMM \ REGS_YMM \ REGS_ZMM \ + REGS_MASKS \ REGS_SEGMENT \ REGS_DEBUG \ REGS_CONTROL \ @@ -463,7 +489,7 @@ typedef enum { } XOPMapSelect; /* - * VEXPrefixCode - Possible values for the VEX.pp field + * VEXPrefixCode - Possible values for the VEX.pp/EVEX.pp field */ typedef enum { @@ -474,11 +500,12 @@ typedef enum { } VEXPrefixCode; typedef enum { - TYPE_NO_VEX_XOP = 0x0, - TYPE_VEX_2B = 0x1, - TYPE_VEX_3B = 0x2, - TYPE_XOP = 0x3 -} VEXXOPType; + TYPE_NO_VEX_XOP = 0x0, + TYPE_VEX_2B = 0x1, + TYPE_VEX_3B = 0x2, + TYPE_EVEX = 0x3, + TYPE_XOP = 0x4 +} VectorExtensionType; typedef uint8_t BOOL; @@ -536,10 +563,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/XOP prefix, if present */ - uint8_t vexXopPrefix[3]; - /* The length of the VEX prefix (0 if not present) */ - VEXXOPType vexXopType; + /* The value of the vector extention prefix(EVEX/VEX/XOP), if present */ + uint8_t vectorExtensionPrefix[4]; + /* The type of the vector extension prefix */ + VectorExtensionType vectorExtensionType; /* 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 @@ -585,6 +612,9 @@ struct InternalInstruction { instructions */ Reg vvvv; + /* The writemask for AVX-512 instructions which is contained in EVEX.aaa */ + Reg writemask; + /* The ModR/M byte, which contains most register operands and some portion of all memory operands */ BOOL consumedModRM; diff --git a/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h b/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h index 44d61294d46..7afe088c6bd 100644 --- a/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h +++ b/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h @@ -53,16 +53,22 @@ * processed correctly. Most of these indicate the presence of particular * prefixes, but ATTR_64BIT is simply an attribute of the decoding context. */ -#define ATTRIBUTE_BITS \ - ENUM_ENTRY(ATTR_NONE, 0x00) \ - ENUM_ENTRY(ATTR_64BIT, 0x01) \ - ENUM_ENTRY(ATTR_XS, 0x02) \ - ENUM_ENTRY(ATTR_XD, 0x04) \ - ENUM_ENTRY(ATTR_REXW, 0x08) \ - ENUM_ENTRY(ATTR_OPSIZE, 0x10) \ - ENUM_ENTRY(ATTR_ADSIZE, 0x20) \ - ENUM_ENTRY(ATTR_VEX, 0x40) \ - ENUM_ENTRY(ATTR_VEXL, 0x80) +#define ATTRIBUTE_BITS \ + ENUM_ENTRY(ATTR_NONE, 0x00) \ + ENUM_ENTRY(ATTR_64BIT, (0x1 << 0)) \ + ENUM_ENTRY(ATTR_XS, (0x1 << 1)) \ + ENUM_ENTRY(ATTR_XD, (0x1 << 2)) \ + ENUM_ENTRY(ATTR_REXW, (0x1 << 3)) \ + ENUM_ENTRY(ATTR_OPSIZE, (0x1 << 4)) \ + ENUM_ENTRY(ATTR_ADSIZE, (0x1 << 5)) \ + ENUM_ENTRY(ATTR_VEX, (0x1 << 6)) \ + ENUM_ENTRY(ATTR_VEXL, (0x1 << 7)) \ + ENUM_ENTRY(ATTR_EVEX, (0x1 << 8)) \ + ENUM_ENTRY(ATTR_EVEXL, (0x1 << 9)) \ + ENUM_ENTRY(ATTR_EVEXL2, (0x1 << 10)) \ + ENUM_ENTRY(ATTR_EVEXK, (0x1 << 11)) \ + ENUM_ENTRY(ATTR_EVEXKZ, (0x1 << 12)) \ + ENUM_ENTRY(ATTR_EVEXB, (0x1 << 13)) #define ENUM_ENTRY(n, v) n = v, enum attributeBits { @@ -73,7 +79,7 @@ enum attributeBits { /* * Combinations of the above attributes that are relevant to instruction - * decode. Although other combinations are possible, they can be reduced to + * decode. Although other combinations are possible, they can be reduced to * these without affecting the ultimately decoded instruction. */ @@ -198,38 +204,38 @@ enum attributeBits { ENUM_ENTRY(IC_EVEX_L2_W_XS_B, 4, "requires EVEX_B, L2, W and XS prefix") \ ENUM_ENTRY(IC_EVEX_L2_W_XD_B, 4, "requires EVEX_B, L2, W and XD prefix") \ ENUM_ENTRY(IC_EVEX_L2_W_OPSIZE_B, 4, "requires EVEX_B, L2, W and OpSize") \ - ENUM_ENTRY(IC_EVEX_K_B, 1, "requires EVEX_B and EVEX_K prefix") \ - ENUM_ENTRY(IC_EVEX_XS_K_B, 2, "requires EVEX_B, EVEX_K and the XS prefix") \ - ENUM_ENTRY(IC_EVEX_XD_K_B, 2, "requires EVEX_B, EVEX_K and the XD prefix") \ - ENUM_ENTRY(IC_EVEX_OPSIZE_K_B, 2, "requires EVEX_B, EVEX_K and the OpSize prefix") \ - ENUM_ENTRY(IC_EVEX_W_K_B, 3, "requires EVEX_B, EVEX_K and the W prefix") \ - ENUM_ENTRY(IC_EVEX_W_XS_K_B, 4, "requires EVEX_B, EVEX_K, W, and XS prefix") \ - ENUM_ENTRY(IC_EVEX_W_XD_K_B, 4, "requires EVEX_B, EVEX_K, W, and XD prefix") \ - ENUM_ENTRY(IC_EVEX_W_OPSIZE_K_B, 4, "requires EVEX_B, EVEX_K, W, and OpSize") \ - ENUM_ENTRY(IC_EVEX_L_K_B, 3, "requires EVEX_B, EVEX_K and the L prefix") \ - ENUM_ENTRY(IC_EVEX_L_XS_K_B, 4, "requires EVEX_B, EVEX_K and the L and XS prefix")\ - ENUM_ENTRY(IC_EVEX_L_XD_K_B, 4, "requires EVEX_B, EVEX_K and the L and XD prefix")\ - ENUM_ENTRY(IC_EVEX_L_OPSIZE_K_B, 4, "requires EVEX_B, EVEX_K, L, and OpSize") \ - ENUM_ENTRY(IC_EVEX_L_W_K_B, 3, "requires EVEX_B, EVEX_K, L and W") \ - ENUM_ENTRY(IC_EVEX_L_W_XS_K_B, 4, "requires EVEX_B, EVEX_K, L, W and XS prefix") \ - ENUM_ENTRY(IC_EVEX_L_W_XD_K_B, 4, "requires EVEX_B, EVEX_K, L, W and XD prefix") \ - ENUM_ENTRY(IC_EVEX_L_W_OPSIZE_K_B, 4, "requires EVEX_B, EVEX_K, L, W and OpSize") \ - ENUM_ENTRY(IC_EVEX_L2_K_B, 3, "requires EVEX_B, EVEX_K and the L2 prefix") \ - ENUM_ENTRY(IC_EVEX_L2_XS_K_B, 4, "requires EVEX_B, EVEX_K and the L2 and XS prefix")\ - ENUM_ENTRY(IC_EVEX_L2_XD_K_B, 4, "requires EVEX_B, EVEX_K and the L2 and XD prefix")\ - ENUM_ENTRY(IC_EVEX_L2_OPSIZE_K_B, 4, "requires EVEX_B, EVEX_K, L2, and OpSize") \ - ENUM_ENTRY(IC_EVEX_L2_W_K_B, 3, "requires EVEX_B, EVEX_K, L2 and W") \ - ENUM_ENTRY(IC_EVEX_L2_W_XS_K_B, 4, "requires EVEX_B, EVEX_K, L2, W and XS prefix") \ - ENUM_ENTRY(IC_EVEX_L2_W_XD_K_B, 4, "requires EVEX_B, EVEX_K, L2, W and XD prefix") \ - ENUM_ENTRY(IC_EVEX_L2_W_OPSIZE_K_B, 4, "requires EVEX_B, EVEX_K, L2, W and OpSize") \ - ENUM_ENTRY(IC_EVEX_KZ_B, 1, "requires EVEX_B and EVEX_KZ prefix") \ - ENUM_ENTRY(IC_EVEX_XS_KZ_B, 2, "requires EVEX_B, EVEX_KZ and the XS prefix") \ - ENUM_ENTRY(IC_EVEX_XD_KZ_B, 2, "requires EVEX_B, EVEX_KZ and the XD prefix") \ - ENUM_ENTRY(IC_EVEX_OPSIZE_KZ_B, 2, "requires EVEX_B, EVEX_KZ and the OpSize prefix") \ - ENUM_ENTRY(IC_EVEX_W_KZ_B, 3, "requires EVEX_B, EVEX_KZ and the W prefix") \ - ENUM_ENTRY(IC_EVEX_W_XS_KZ_B, 4, "requires EVEX_B, EVEX_KZ, W, and XS prefix") \ - ENUM_ENTRY(IC_EVEX_W_XD_KZ_B, 4, "requires EVEX_B, EVEX_KZ, W, and XD prefix") \ - ENUM_ENTRY(IC_EVEX_W_OPSIZE_KZ_B, 4, "requires EVEX_B, EVEX_KZ, W, and OpSize") \ + ENUM_ENTRY(IC_EVEX_K_B, 1, "requires EVEX_B and EVEX_K prefix") \ + ENUM_ENTRY(IC_EVEX_XS_K_B, 2, "requires EVEX_B, EVEX_K and the XS prefix") \ + ENUM_ENTRY(IC_EVEX_XD_K_B, 2, "requires EVEX_B, EVEX_K and the XD prefix") \ + ENUM_ENTRY(IC_EVEX_OPSIZE_K_B, 2, "requires EVEX_B, EVEX_K and the OpSize prefix") \ + ENUM_ENTRY(IC_EVEX_W_K_B, 3, "requires EVEX_B, EVEX_K and the W prefix") \ + ENUM_ENTRY(IC_EVEX_W_XS_K_B, 4, "requires EVEX_B, EVEX_K, W, and XS prefix") \ + ENUM_ENTRY(IC_EVEX_W_XD_K_B, 4, "requires EVEX_B, EVEX_K, W, and XD prefix") \ + ENUM_ENTRY(IC_EVEX_W_OPSIZE_K_B, 4, "requires EVEX_B, EVEX_K, W, and OpSize") \ + ENUM_ENTRY(IC_EVEX_L_K_B, 3, "requires EVEX_B, EVEX_K and the L prefix") \ + ENUM_ENTRY(IC_EVEX_L_XS_K_B, 4, "requires EVEX_B, EVEX_K and the L and XS prefix")\ + ENUM_ENTRY(IC_EVEX_L_XD_K_B, 4, "requires EVEX_B, EVEX_K and the L and XD prefix")\ + ENUM_ENTRY(IC_EVEX_L_OPSIZE_K_B, 4, "requires EVEX_B, EVEX_K, L, and OpSize") \ + ENUM_ENTRY(IC_EVEX_L_W_K_B, 3, "requires EVEX_B, EVEX_K, L and W") \ + ENUM_ENTRY(IC_EVEX_L_W_XS_K_B, 4, "requires EVEX_B, EVEX_K, L, W and XS prefix") \ + ENUM_ENTRY(IC_EVEX_L_W_XD_K_B, 4, "requires EVEX_B, EVEX_K, L, W and XD prefix") \ + ENUM_ENTRY(IC_EVEX_L_W_OPSIZE_K_B,4, "requires EVEX_B, EVEX_K, L, W and OpSize") \ + ENUM_ENTRY(IC_EVEX_L2_K_B, 3, "requires EVEX_B, EVEX_K and the L2 prefix") \ + ENUM_ENTRY(IC_EVEX_L2_XS_K_B, 4, "requires EVEX_B, EVEX_K and the L2 and XS prefix")\ + ENUM_ENTRY(IC_EVEX_L2_XD_K_B, 4, "requires EVEX_B, EVEX_K and the L2 and XD prefix")\ + ENUM_ENTRY(IC_EVEX_L2_OPSIZE_K_B, 4, "requires EVEX_B, EVEX_K, L2, and OpSize") \ + ENUM_ENTRY(IC_EVEX_L2_W_K_B, 3, "requires EVEX_B, EVEX_K, L2 and W") \ + ENUM_ENTRY(IC_EVEX_L2_W_XS_K_B, 4, "requires EVEX_B, EVEX_K, L2, W and XS prefix") \ + ENUM_ENTRY(IC_EVEX_L2_W_XD_K_B, 4, "requires EVEX_B, EVEX_K, L2, W and XD prefix") \ + ENUM_ENTRY(IC_EVEX_L2_W_OPSIZE_K_B,4, "requires EVEX_B, EVEX_K, L2, W and OpSize") \ + ENUM_ENTRY(IC_EVEX_KZ_B, 1, "requires EVEX_B and EVEX_KZ prefix") \ + ENUM_ENTRY(IC_EVEX_XS_KZ_B, 2, "requires EVEX_B, EVEX_KZ and the XS prefix") \ + ENUM_ENTRY(IC_EVEX_XD_KZ_B, 2, "requires EVEX_B, EVEX_KZ and the XD prefix") \ + ENUM_ENTRY(IC_EVEX_OPSIZE_KZ_B, 2, "requires EVEX_B, EVEX_KZ and the OpSize prefix") \ + ENUM_ENTRY(IC_EVEX_W_KZ_B, 3, "requires EVEX_B, EVEX_KZ and the W prefix") \ + ENUM_ENTRY(IC_EVEX_W_XS_KZ_B, 4, "requires EVEX_B, EVEX_KZ, W, and XS prefix") \ + ENUM_ENTRY(IC_EVEX_W_XD_KZ_B, 4, "requires EVEX_B, EVEX_KZ, W, and XD prefix") \ + ENUM_ENTRY(IC_EVEX_W_OPSIZE_KZ_B, 4, "requires EVEX_B, EVEX_KZ, W, and OpSize") \ ENUM_ENTRY(IC_EVEX_L_KZ_B, 3, "requires EVEX_B, EVEX_KZ and the L prefix") \ ENUM_ENTRY(IC_EVEX_L_XS_KZ_B, 4, "requires EVEX_B, EVEX_KZ and the L and XS prefix")\ ENUM_ENTRY(IC_EVEX_L_XD_KZ_B, 4, "requires EVEX_B, EVEX_KZ and the L and XD prefix")\ diff --git a/test/MC/Disassembler/X86/avx-512.txt b/test/MC/Disassembler/X86/avx-512.txt new file mode 100644 index 00000000000..e5ad2a9e441 --- /dev/null +++ b/test/MC/Disassembler/X86/avx-512.txt @@ -0,0 +1,59 @@ +# RUN: llvm-mc --disassemble %s -triple=x86_64-apple-darwin9 -mcpu=knl | FileCheck %s + +# CHECK: vpbroadcastd %xmm18, %zmm28 {%k7} {z} +0x62 0x22 0x7d 0xcf 0x58 0xe2 + +# CHECK: vbroadcastss (%rsp), %zmm28 +0x62 0x62 0x7d 0x48 0x18 0x24 0x24 + +# CHECK: vblendmpd (%rsi), %zmm2, %zmm8 {%k7} +0x62 0x72 0xed 0x4f 0x65 0x06 + +# CHECK: vpermpd (%rsi,%r10,4), %zmm2, %zmm8 +0x62 0x32 0xed 0x48 0x16 0x04 0x96 + +# CHECK: vpbroadcastmw2d %k2, %zmm8 +0x62 0xd2 0x7e 0x48 0x3a 0xd0 + +# CHECK: vpbroadcastq (%r9,%rax), %zmm28 +0x62 0x42 0xfd 0x48 0x59 0x24 0x01 + +# CHECK: vbroadcastss %xmm0, %zmm1 +0x62 0xf2 0x7d 0x48 0x18 0xc8 + +# CHECK: vextracti32x4 $4, %zmm0, (%r10) +0x62 0xd3 0x7d 0x48 0x39 0x02 0x04 + +# CHECK: vextracti32x4 $4, %zmm0, %xmm1 +0x62 0xf3 0x7d 0x48 0x39 0xc1 0x04 + +# CHECK: vinserti32x4 $1, %xmm21, %zmm5, %zmm17 +0x62 0xa3 0x55 0x48 0x38 0xcd 0x01 + +# CHECK: vmovaps %zmm21, %zmm5 {%k3} +0x62 0xb1 0x7c 0x4b 0x28 0xed + +# CHECK: vgatherdps (%rsi,%zmm0,4), %zmm1 {%k2} +0x62 0xf2 0x7d 0x4a 0x92 0x0c 0x86 + +# CHECK: vgatherdpd (%rsi,%ymm0,4), %zmm1 {%k2} +0x62 0xf2 0xfd 0x4a 0x92 0x0c 0x86 + +##################################################### +# MASK INSTRUCTIONS # +##################################################### + +# CHECK: kshiftlw $3, %k1, %k2 +0xc4 0xe3 0xf9 0x32 0xd1 0x03 + +# CHECK: kmovw (%rdi), %k1 +0xc5 0xf8 0x90 0x0f + +# CHECK: kmovw %k1, %eax +0xc5 0xf8 0x93 0xc1 + +# CHECK: kandw %k1, %k2, %k3 +0xc5 0xec 0x41 0xd9 + +# CHECK: kmovw %k5, %k1 +0xc5 0xf8 0x90 0xcd diff --git a/utils/TableGen/X86DisassemblerTables.cpp b/utils/TableGen/X86DisassemblerTables.cpp index bdb47931859..7d2c9c7fe88 100644 --- a/utils/TableGen/X86DisassemblerTables.cpp +++ b/utils/TableGen/X86DisassemblerTables.cpp @@ -636,14 +636,36 @@ void DisassemblerTables::emitInstructionInfo(raw_ostream &o, } void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const { + const unsigned int tableSize = 16384; o.indent(i * 2) << "static const uint8_t " CONTEXTS_STR - "[256] = {\n"; + "[" << tableSize << "] = {\n"; i++; - for (unsigned index = 0; index < 256; ++index) { + for (unsigned index = 0; index < tableSize; ++index) { o.indent(i * 2); - if ((index & ATTR_VEXL) && (index & ATTR_REXW) && (index & ATTR_OPSIZE)) + if (index & ATTR_EVEX) { + o << "IC_EVEX"; + if (index & ATTR_EVEXL2) + o << "_L2"; + else if (index & ATTR_EVEXL) + o << "_L"; + if (index & ATTR_REXW) + o << "_W"; + if (index & ATTR_OPSIZE) + o << "_OPSIZE"; + else if (index & ATTR_XD) + o << "_XD"; + else if (index & ATTR_XS) + o << "_XS"; + if (index & ATTR_EVEXKZ) + o << "_KZ"; + else if (index & ATTR_EVEXK) + o << "_K"; + if (index & ATTR_EVEXB) + o << "_B"; + } + else if ((index & ATTR_VEXL) && (index & ATTR_REXW) && (index & ATTR_OPSIZE)) o << "IC_VEX_L_W_OPSIZE"; else if ((index & ATTR_VEXL) && (index & ATTR_REXW) && (index & ATTR_XD)) o << "IC_VEX_L_W_XD"; @@ -713,7 +735,7 @@ void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const { else o << "IC"; - if (index < 255) + if (index < tableSize - 1) o << ","; else o << " ";