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);
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).
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))
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,
if (lFromXOP3of3(insn->vectorExtensionPrefix[2]))
attrMask |= ATTR_VEXL;
+ } else if (insn->vectorExtensionType == TYPE_3DNOW) {
+ attrMask |= ATTR_3DNOW;
} else {
return -1;
}
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
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 {
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 {
: 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";
}
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 = ""> {
--- /dev/null
+# 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
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";
}
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++;
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";
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();
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;
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
/// 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<CGIOperandList::OperandInfo>* Operands;
-
+
/// The description of the instruction that is emitted into the instruction
/// info table
InstructionSpecifier* Spec;
/// 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.
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.
///
const CodeGenInstruction &insn,
InstrUID uid);
};
-
+
} // namespace X86Disassembler
} // namespace llvm