Index: llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h =================================================================== --- llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h +++ llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoder.h @@ -493,7 +493,8 @@ 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 Index: llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp =================================================================== --- llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp +++ llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoder.cpp @@ -588,11 +588,44 @@ 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 @@ 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 @@ 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 @@ 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 @@ if (lFromXOP3of3(insn->vectorExtensionPrefix[2])) attrMask |= ATTR_VEXL; + } else if (insn->vectorExtensionType == TYPE_3DNOW) { + attrMask |= ATTR_3DNOW; } else { return -1; } Index: llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h =================================================================== --- llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h +++ llvm/trunk/lib/Target/X86/Disassembler/X86DisassemblerDecoderCommon.h @@ -60,7 +60,8 @@ 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_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 { Index: llvm/trunk/lib/Target/X86/X86Instr3DNow.td =================================================================== --- llvm/trunk/lib/Target/X86/X86Instr3DNow.td +++ llvm/trunk/lib/Target/X86/X86Instr3DNow.td @@ -52,8 +52,6 @@ : I3DNow, Has3DNow0F0FOpcode { - // FIXME: The disassembler doesn't support Has3DNow0F0FOpcode yet. - let isAsmParserOnly = 1; let Constraints = "$src1 = $dst"; } @@ -61,10 +59,7 @@ InstrItinClass itin> : I3DNow, - Has3DNow0F0FOpcode { - // FIXME: The disassembler doesn't support Has3DNow0F0FOpcode yet. - let isAsmParserOnly = 1; -} + Has3DNow0F0FOpcode; multiclass I3DNow_binop_rm_int opc, string Mn, OpndItins itins, bit Commutable = 0, string Ver = ""> { Index: llvm/trunk/test/MC/Disassembler/X86/amd3dnow.txt =================================================================== --- llvm/trunk/test/MC/Disassembler/X86/amd3dnow.txt +++ llvm/trunk/test/MC/Disassembler/X86/amd3dnow.txt @@ -0,0 +1,76 @@ +# RUN: llvm-mc --disassemble %s -triple=x86_64-unknown-linux-gnu | FileCheck %s + +# Reference: AMD64 Architecture Programmer's Manual Vol.3 +# Pub no. 24594 - Rev. 3.25 - Dec 2017 - pgs.468-469 + +# CHECK: pfcmpge %mm0, %mm1 +0x0f 0x0f 0xc8 0x90 + +# CHECK: pfcmpgt %mm2, %mm0 +0x0f 0x0f 0xc2 0xa0 + +# CHECK: pfcmpeq %mm5, %mm2 +0x0f 0x0f 0xd5 0xb0 + +# CHECK: pfmin %mm1, %mm0 +0x0f 0x0f 0xc1 0x94 + +# CHECK: pfmax (%rax), %mm0 +0x0f 0x0f 0x00 0xa4 + +# CHECK: pfmul %mm6, %mm0 +0x0f 0x0f 0xc6 0xb4 + +# CHECK: pfrcp (%rbx), %mm1 +0x0f 0x0f 0x0b 0x96 + +# CHECK: pfrcpit1 %mm0, %mm2 +0x0f 0x0f 0xd0 0xa6 + +# CHECK: pfrcpit2 %mm0, %mm1 +0x0f 0x0f 0xc8 0xb6 + +# CHECK: pfrsqrt (%eax), %mm1 +0x67 0x0f 0x0f 0x08 0x97 + +# CHECK: pfrsqit1 (%ebx), %mm4 +0x67 0x0f 0x0f 0x23 0xa7 + +# CHECK: pmulhrw %mm3, %mm0 +0x0f 0x0f 0xc3 0xb7 + +# CHECK: pi2fw %mm1, %mm3 +0x0f 0x0f 0xd9 0x0c + +# CHECK: pf2iw %mm2, %mm4 +0x0f 0x0f 0xe2 0x1c + +# CHECK: pi2fd %mm3, %mm1 +0x0f 0x0f 0xcb 0x0d + +# CHECK: pf2id (%rdi,%r8), %mm1 +0x42 0x0f 0x0f 0x0c 0x07 0x1d + +# CHECK: pfnacc 16(%eax,%ebx,4), %mm0 +0x67 0x0f 0x0f 0x44 0x98 0x10 0x8a + +# CHECK: pfsub %mm1, %mm0 +0x0f 0x0f 0xc1 0x9a + +# CHECK: pfsubr %mm2, %mm1 +0x0f 0x0f 0xca 0xaa + +# CHECK: pswapd %mm1, %mm3 +0x0f 0x0f 0xd9 0xbb + +# CHECK: pfpnacc %mm0, %mm2 +0x0f 0x0f 0xd0 0x8e + +# CHECK: pfadd %mm4, %mm3 +0x0f 0x0f 0xdc 0x9e + +# CHECK: pfacc %mm1, %mm2 +0x0f 0x0f 0xd1 0xae + +# CHECK: pavgusb %mm1, %mm3 +0x0f 0x0f 0xd9 0xbf Index: llvm/trunk/utils/TableGen/X86DisassemblerTables.cpp =================================================================== --- llvm/trunk/utils/TableGen/X86DisassemblerTables.cpp +++ llvm/trunk/utils/TableGen/X86DisassemblerTables.cpp @@ -546,6 +546,8 @@ case IC_EVEX_L2_W_XD_KZ_B: case IC_EVEX_L2_W_OPSIZE_KZ_B: return false; + case IC_3DNOW: + return false; default: errs() << "Unknown instruction class: " << stringForContext((InstructionContext)parent) << "\n"; @@ -888,7 +890,7 @@ } void DisassemblerTables::emitContextTable(raw_ostream &o, unsigned &i) const { - const unsigned int tableSize = 16384; + const unsigned int tableSize = 32768; o.indent(i * 2) << "static const uint8_t " CONTEXTS_STR "[" << tableSize << "] = {\n"; i++; @@ -896,7 +898,9 @@ for (unsigned index = 0; index < tableSize; ++index) { o.indent(i * 2); - if (index & ATTR_EVEX) { + if (index & ATTR_3DNOW) + o << "IC_3DNOW"; + else if (index & ATTR_EVEX) { o << "IC_EVEX"; if (index & ATTR_EVEXL2) o << "_L2"; Index: llvm/trunk/utils/TableGen/X86RecognizableInstr.h =================================================================== --- llvm/trunk/utils/TableGen/X86RecognizableInstr.h +++ llvm/trunk/utils/TableGen/X86RecognizableInstr.h @@ -191,6 +191,8 @@ bool HasEVEX_KZ; /// The hasEVEX_B field from the record bool HasEVEX_B; + /// The has3DNow0F0FOpcode field from the record + bool Has3DNow0F0FOpcode; /// Indicates that the instruction uses the L and L' fields for RC. bool EncodeRC; /// The isCodeGenOnly field from the record @@ -210,12 +212,12 @@ /// Indicates whether the instruction should be emitted into the decode /// tables; regardless, it will be emitted into the instruction info table bool ShouldBeEmitted; - + /// The operands of the instruction, as listed in the CodeGenInstruction. /// They are not one-to-one with operands listed in the MCInst; for example, /// memory operands expand to 5 operands in the MCInst const std::vector* Operands; - + /// The description of the instruction that is emitted into the instruction /// info table InstructionSpecifier* Spec; @@ -283,7 +285,7 @@ /// operand exists. /// @param operandIndex - The index into the generated operand table. /// Incremented by this function one or more - /// times to reflect possible duplicate + /// times to reflect possible duplicate /// operands). /// @param physicalOperandIndex - The index of the current operand into the /// set of non-duplicate ('physical') operands. @@ -314,12 +316,12 @@ bool shouldBeEmitted() const { return ShouldBeEmitted; } - + /// emitInstructionSpecifier - Loads the instruction specifier for the current /// instruction into a DisassemblerTables. /// void emitInstructionSpecifier(); - + /// emitDecodePath - Populates the proper fields in the decode tables /// corresponding to the decode paths for this instruction. /// @@ -349,7 +351,7 @@ const CodeGenInstruction &insn, InstrUID uid); }; - + } // namespace X86Disassembler } // namespace llvm Index: llvm/trunk/utils/TableGen/X86RecognizableInstr.cpp =================================================================== --- llvm/trunk/utils/TableGen/X86RecognizableInstr.cpp +++ llvm/trunk/utils/TableGen/X86RecognizableInstr.cpp @@ -80,19 +80,20 @@ Form = byteFromRec(Rec, "FormBits"); Encoding = byteFromRec(Rec, "OpEncBits"); - OpSize = byteFromRec(Rec, "OpSizeBits"); - AdSize = byteFromRec(Rec, "AdSizeBits"); - HasREX_WPrefix = Rec->getValueAsBit("hasREX_WPrefix"); - HasVEX_4V = Rec->getValueAsBit("hasVEX_4V"); - VEX_WPrefix = byteFromRec(Rec,"VEX_WPrefix"); - IgnoresVEX_L = Rec->getValueAsBit("ignoresVEX_L"); - HasEVEX_L2Prefix = Rec->getValueAsBit("hasEVEX_L2"); - HasEVEX_K = Rec->getValueAsBit("hasEVEX_K"); - HasEVEX_KZ = Rec->getValueAsBit("hasEVEX_Z"); - HasEVEX_B = Rec->getValueAsBit("hasEVEX_B"); - IsCodeGenOnly = Rec->getValueAsBit("isCodeGenOnly"); - ForceDisassemble = Rec->getValueAsBit("ForceDisassemble"); - CD8_Scale = byteFromRec(Rec, "CD8_Scale"); + OpSize = byteFromRec(Rec, "OpSizeBits"); + AdSize = byteFromRec(Rec, "AdSizeBits"); + HasREX_WPrefix = Rec->getValueAsBit("hasREX_WPrefix"); + HasVEX_4V = Rec->getValueAsBit("hasVEX_4V"); + VEX_WPrefix = byteFromRec(Rec,"VEX_WPrefix"); + IgnoresVEX_L = Rec->getValueAsBit("ignoresVEX_L"); + HasEVEX_L2Prefix = Rec->getValueAsBit("hasEVEX_L2"); + HasEVEX_K = Rec->getValueAsBit("hasEVEX_K"); + HasEVEX_KZ = Rec->getValueAsBit("hasEVEX_Z"); + HasEVEX_B = Rec->getValueAsBit("hasEVEX_B"); + Has3DNow0F0FOpcode = Rec->getValueAsBit("has3DNow0F0FOpcode"); + IsCodeGenOnly = Rec->getValueAsBit("isCodeGenOnly"); + ForceDisassemble = Rec->getValueAsBit("ForceDisassemble"); + CD8_Scale = byteFromRec(Rec, "CD8_Scale"); Name = Rec->getName(); @@ -288,6 +289,8 @@ errs() << "Instruction does not use a prefix: " << Name << "\n"; llvm_unreachable("Invalid prefix"); } + } else if (Has3DNow0F0FOpcode) { + insnContext = IC_3DNOW; } else if (Is64Bit || HasREX_WPrefix || AdSize == X86Local::AdSize64) { if (HasREX_WPrefix && (OpSize == X86Local::OpSize16 || OpPrefix == X86Local::PD)) insnContext = IC_64BIT_REXW_OPSIZE;