diff options
Diffstat (limited to 'llvm/lib')
4 files changed, 50 insertions, 11 deletions
diff --git a/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp b/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp index 843d037ad3c..50d10feaae3 100644 --- a/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp +++ b/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp @@ -588,11 +588,44 @@ static int readPrefixes(struct InternalInstruction* insn) { insn->vectorExtensionPrefix[0], insn->vectorExtensionPrefix[1], insn->vectorExtensionPrefix[2]); } + } else if (byte == 0x0f) { + uint8_t byte1; + + // Check for AMD 3DNow without a REX prefix + if (consumeByte(insn, &byte1)) { + unconsumeByte(insn); + } else { + if (byte1 != 0x0f) { + unconsumeByte(insn); + unconsumeByte(insn); + } else { + dbgprintf(insn, "Found AMD 3DNow prefix 0f0f"); + insn->vectorExtensionType = TYPE_3DNOW; + } + } } else if (isREX(insn, byte)) { if (lookAtByte(insn, &nextByte)) return -1; insn->rexPrefix = byte; dbgprintf(insn, "Found REX prefix 0x%hhx", byte); + + // Check for AMD 3DNow with a REX prefix + if (nextByte == 0x0f) { + consumeByte(insn, &nextByte); + uint8_t byte1; + + if (consumeByte(insn, &byte1)) { + unconsumeByte(insn); + } else { + if (byte1 != 0x0f) { + unconsumeByte(insn); + unconsumeByte(insn); + } else { + dbgprintf(insn, "Found AMD 3DNow prefix 0f0f"); + insn->vectorExtensionType = TYPE_3DNOW; + } + } + } } else unconsumeByte(insn); @@ -623,6 +656,8 @@ static int readPrefixes(struct InternalInstruction* insn) { return 0; } +static int readModRM(struct InternalInstruction* insn); + /* * readOpcode - Reads the opcode (excepting the ModR/M byte in the case of * extended or escape opcodes). @@ -690,6 +725,12 @@ static int readOpcode(struct InternalInstruction* insn) { insn->opcodeType = XOPA_MAP; return consumeByte(insn, &insn->opcode); } + } else if (insn->vectorExtensionType == TYPE_3DNOW) { + // Consume operands before the opcode to comply with the 3DNow encoding + if (readModRM(insn)) + return -1; + insn->opcodeType = TWOBYTE; + return consumeByte(insn, &insn->opcode); } if (consumeByte(insn, ¤t)) @@ -735,8 +776,6 @@ static int readOpcode(struct InternalInstruction* insn) { return 0; } -static int readModRM(struct InternalInstruction* insn); - /* * getIDWithAttrMask - Determines the ID of an instruction, consuming * the ModR/M byte as appropriate for extended and escape opcodes, @@ -912,6 +951,8 @@ static int getID(struct InternalInstruction* insn, const void *miiArg) { if (lFromXOP3of3(insn->vectorExtensionPrefix[2])) attrMask |= ATTR_VEXL; + } else if (insn->vectorExtensionType == TYPE_3DNOW) { + attrMask |= ATTR_3DNOW; } else { return -1; } diff --git a/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h b/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h index ecd9d8dccaf..1be3c43a6d3 100644 --- a/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h +++ b/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h @@ -493,7 +493,8 @@ enum VectorExtensionType { TYPE_VEX_2B = 0x1, TYPE_VEX_3B = 0x2, TYPE_EVEX = 0x3, - TYPE_XOP = 0x4 + TYPE_XOP = 0x4, + TYPE_3DNOW = 0x5 }; /// \brief Type for the byte reader that the consumer must provide to diff --git a/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h b/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h index ad1404860fb..ffac6c9c440 100644 --- a/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h +++ b/llvm/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h @@ -60,7 +60,8 @@ namespace X86Disassembler { ENUM_ENTRY(ATTR_EVEXL2, (0x1 << 10)) \ ENUM_ENTRY(ATTR_EVEXK, (0x1 << 11)) \ ENUM_ENTRY(ATTR_EVEXKZ, (0x1 << 12)) \ - ENUM_ENTRY(ATTR_EVEXB, (0x1 << 13)) + ENUM_ENTRY(ATTR_EVEXB, (0x1 << 13)) \ + ENUM_ENTRY(ATTR_3DNOW, (0x1 << 14)) #define ENUM_ENTRY(n, v) n = v, enum attributeBits { @@ -270,7 +271,8 @@ enum attributeBits { ENUM_ENTRY(IC_EVEX_L2_W_KZ, 3, "requires EVEX_KZ, L2 and W") \ ENUM_ENTRY(IC_EVEX_L2_W_XS_KZ, 4, "requires EVEX_KZ, L2, W and XS prefix") \ ENUM_ENTRY(IC_EVEX_L2_W_XD_KZ, 4, "requires EVEX_KZ, L2, W and XD prefix") \ - ENUM_ENTRY(IC_EVEX_L2_W_OPSIZE_KZ, 4, "requires EVEX_KZ, L2, W and OpSize") + ENUM_ENTRY(IC_EVEX_L2_W_OPSIZE_KZ, 4, "requires EVEX_KZ, L2, W and OpSize") \ + ENUM_ENTRY(IC_3DNOW, 8, "requires AMD 3DNow prefix 0f0f") #define ENUM_ENTRY(n, r, d) n, enum InstructionContext { diff --git a/llvm/lib/Target/X86/X86Instr3DNow.td b/llvm/lib/Target/X86/X86Instr3DNow.td index d2e5980718e..edb7dd619fb 100644 --- a/llvm/lib/Target/X86/X86Instr3DNow.td +++ b/llvm/lib/Target/X86/X86Instr3DNow.td @@ -52,8 +52,6 @@ class I3DNow_binop<bits<8> o, Format F, dag ins, string Mnemonic, list<dag> pat, : I3DNow<o, F, (outs VR64:$dst), ins, !strconcat(Mnemonic, "\t{$src2, $dst|$dst, $src2}"), pat, itin>, Has3DNow0F0FOpcode { - // FIXME: The disassembler doesn't support Has3DNow0F0FOpcode yet. - let isAsmParserOnly = 1; let Constraints = "$src1 = $dst"; } @@ -61,10 +59,7 @@ class I3DNow_conv<bits<8> o, Format F, dag ins, string Mnemonic, list<dag> pat, InstrItinClass itin> : I3DNow<o, F, (outs VR64:$dst), ins, !strconcat(Mnemonic, "\t{$src, $dst|$dst, $src}"), pat, itin>, - Has3DNow0F0FOpcode { - // FIXME: The disassembler doesn't support Has3DNow0F0FOpcode yet. - let isAsmParserOnly = 1; -} + Has3DNow0F0FOpcode; multiclass I3DNow_binop_rm_int<bits<8> opc, string Mn, OpndItins itins, bit Commutable = 0, string Ver = ""> { |