diff options
author | Craig Topper <craig.topper@gmail.com> | 2014-10-07 07:29:50 +0000 |
---|---|---|
committer | Craig Topper <craig.topper@gmail.com> | 2014-10-07 07:29:50 +0000 |
commit | 0676b902ad242537eb9d9914477dea4c36388ffd (patch) | |
tree | 56a535627f6030b642b0f1cd607ee74719a842bc /llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp | |
parent | 273515eb1215ef0001092eba6f6298b20ee0226c (diff) | |
download | bcm5719-llvm-0676b902ad242537eb9d9914477dea4c36388ffd.tar.gz bcm5719-llvm-0676b902ad242537eb9d9914477dea4c36388ffd.zip |
[X86] Fix a bug where the disassembler was ignoring the VEX.W bit in 32-bit mode for certain instructions it shouldn't.
Unfortunately, this isn't easy to fix since there's no simple way to figure out from the disassembler tables whether the W-bit is being used to select a 64-bit GPR or if its a required part of the opcode. The fix implemented here just looks for "64" in the instruction name and ignores the W-bit in 32-bit mode if its present.
Fixes PR21169.
llvm-svn: 219194
Diffstat (limited to 'llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp')
-rw-r--r-- | llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp b/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp index d6667aa2819..98b344096aa 100644 --- a/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp +++ b/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp @@ -852,6 +852,22 @@ static bool is16BitEquivalent(const char* orig, const char* equiv) { } /* + * is64Bit - Determines whether this instruction is a 64-bit instruction. + * + * @param name - The instruction that is not 16-bit + */ +static bool is64Bit(const char* name) { + off_t i; + + for (i = 0;; ++i) { + if (name[i] == '\0') + return false; + if (name[i] == '6' && name[i+1] == '4') + return true; + } +} + +/* * getID - Determines the ID of an instruction, consuming the ModR/M byte as * appropriate for extended and escape opcodes. Determines the attributes and * context for the instruction before doing so. @@ -983,6 +999,37 @@ static int getID(struct InternalInstruction* insn, const void *miiArg) { /* The following clauses compensate for limitations of the tables. */ + if (insn->mode != MODE_64BIT && + insn->vectorExtensionType != TYPE_NO_VEX_XOP) { + /* + * The tables can't distinquish between cases where the W-bit is used to + * select register size and cases where its a required part of the opcode. + */ + if ((insn->vectorExtensionType == TYPE_EVEX && + wFromEVEX3of4(insn->vectorExtensionPrefix[2])) || + (insn->vectorExtensionType == TYPE_VEX_3B && + wFromVEX3of3(insn->vectorExtensionPrefix[2])) || + (insn->vectorExtensionType == TYPE_XOP && + wFromXOP3of3(insn->vectorExtensionPrefix[2]))) { + + uint16_t instructionIDWithREXW; + if (getIDWithAttrMask(&instructionIDWithREXW, + insn, attrMask | ATTR_REXW)) { + insn->instructionID = instructionID; + insn->spec = specifierForUID(instructionID); + return 0; + } + + const char *SpecName = GetInstrName(instructionIDWithREXW, miiArg); + // If not a 64-bit instruction. Switch the opcode. + if (!is64Bit(SpecName)) { + insn->instructionID = instructionIDWithREXW; + insn->spec = specifierForUID(instructionIDWithREXW); + return 0; + } + } + } + if ((insn->mode == MODE_16BIT || insn->prefixPresent[0x66]) && !(attrMask & ATTR_OPSIZE)) { /* |