From 2c84821ee0d9807d20ea82b8550edde09426a867 Mon Sep 17 00:00:00 2001 From: iximeow Date: Sun, 4 Jul 2021 12:55:21 -0700 Subject: add real-mode decoder --- src/real_mode/display.rs | 3729 ++++++++++++++++ src/real_mode/evex.rs | 18 + src/real_mode/mod.rs | 10677 ++++++++++++++++++++++++++++++++++++++++++++- src/real_mode/uarch.rs | 226 + src/real_mode/vex.rs | 3356 ++++++++++++++ 5 files changed, 18005 insertions(+), 1 deletion(-) create mode 100644 src/real_mode/display.rs create mode 100644 src/real_mode/evex.rs create mode 100644 src/real_mode/uarch.rs create mode 100644 src/real_mode/vex.rs (limited to 'src/real_mode') diff --git a/src/real_mode/display.rs b/src/real_mode/display.rs new file mode 100644 index 0000000..a6e0a32 --- /dev/null +++ b/src/real_mode/display.rs @@ -0,0 +1,3729 @@ +extern crate yaxpeax_arch; + +use MEM_SIZE_STRINGS; + +use core::fmt; + +use yaxpeax_arch::{Colorize, ShowContextual, NoColors, YaxColors}; +use yaxpeax_arch::display::*; + +use crate::real_mode::{RegSpec, Opcode, Operand, MergeMode, InstDecoder, Instruction, Segment, PrefixVex, OperandSpec}; + +impl fmt::Display for InstDecoder { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self == &InstDecoder::default() { + return write!(f, ""); + } else if self == &InstDecoder::minimal() { + return write!(f, ""); + } + if self.sse3() { write!(f, "sse3 ")? } + if self.ssse3() { write!(f, "ssse3 ")? } + if self.monitor() { write!(f, "monitor ")? } + if self.vmx() { write!(f, "vmx ")? } + if self.fma3() { write!(f, "fma3 ")? } + if self.cmpxchg16b() { write!(f, "cmpxchg16b ")? } + if self.sse4_1() { write!(f, "sse4_1 ")? } + if self.sse4_2() { write!(f, "sse4_2 ")? } + if self.movbe() { write!(f, "movbe ")? } + if self.popcnt() { write!(f, "popcnt ")? } + if self.aesni() { write!(f, "aesni ")? } + if self.xsave() { write!(f, "xsave ")? } + if self.rdrand() { write!(f, "rdrand ")? } + if self.sgx() { write!(f, "sgx ")? } + if self.bmi1() { write!(f, "bmi1 ")? } + if self.avx2() { write!(f, "avx2 ")? } + if self.bmi2() { write!(f, "bmi2 ")? } + if self.invpcid() { write!(f, "invpcid ")? } + if self.mpx() { write!(f, "mpx ")? } + if self.avx512_f() { write!(f, "avx512_f ")? } + if self.avx512_dq() { write!(f, "avx512_dq ")? } + if self.rdseed() { write!(f, "rdseed ")? } + if self.adx() { write!(f, "adx ")? } + if self.avx512_fma() { write!(f, "avx512_fma ")? } + if self.pcommit() { write!(f, "pcommit ")? } + if self.clflushopt() { write!(f, "clflushopt ")? } + if self.clwb() { write!(f, "clwb ")? } + if self.avx512_pf() { write!(f, "avx512_pf ")? } + if self.avx512_er() { write!(f, "avx512_er ")? } + if self.avx512_cd() { write!(f, "avx512_cd ")? } + if self.sha() { write!(f, "sha ")? } + if self.avx512_bw() { write!(f, "avx512_bw ")? } + if self.avx512_vl() { write!(f, "avx512_vl ")? } + if self.prefetchwt1() { write!(f, "prefetchwt1 ")? } + if self.avx512_vbmi() { write!(f, "avx512_vbmi ")? } + if self.avx512_vbmi2() { write!(f, "avx512_vbmi2 ")? } + if self.gfni() { write!(f, "gfni ")? } + if self.vaes() { write!(f, "vaes ")? } + if self.pclmulqdq() { write!(f, "pclmulqdq ")? } + if self.avx_vnni() { write!(f, "avx_vnni ")? } + if self.avx512_bitalg() { write!(f, "avx512_bitalg ")? } + if self.avx512_vpopcntdq() { write!(f, "avx512_vpopcntdq ")? } + if self.avx512_4vnniw() { write!(f, "avx512_4vnniw ")? } + if self.avx512_4fmaps() { write!(f, "avx512_4fmaps ")? } + if self.cx8() { write!(f, "cx8 ")? } + if self.syscall() { write!(f, "syscall ")? } + if self.rdtscp() { write!(f, "rdtscp ")? } + if self.abm() { write!(f, "abm ")? } + if self.sse4a() { write!(f, "sse4a ")? } + if self._3dnowprefetch() { write!(f, "_3dnowprefetch ")? } + if self.xop() { write!(f, "xop ")? } + if self.skinit() { write!(f, "skinit ")? } + if self.tbm() { write!(f, "tbm ")? } + if self.intel_quirks() { write!(f, "intel_quirks ")? } + if self.amd_quirks() { write!(f, "amd_quirks ")? } + if self.avx() { write!(f, "avx ")? } + Ok(()) + } +} + +impl fmt::Display for PrefixVex { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.present() { + write!(f, "vex:{}{}{}{}", + if self.w() { "w" } else { "-" }, + if self.r() { "r" } else { "-" }, + if self.x() { "x" } else { "-" }, + if self.b() { "b" } else { "-" }, + ) + } else { + write!(f, "vex:none") + } + } +} + +impl fmt::Display for Segment { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Segment::CS => write!(f, "cs"), + Segment::DS => write!(f, "ds"), + Segment::ES => write!(f, "es"), + Segment::FS => write!(f, "fs"), + Segment::GS => write!(f, "gs"), + Segment::SS => write!(f, "ss"), + } + } +} + +// register names are grouped by indices scaled by 16. +// xmm, ymm, zmm all get two indices. +const REG_NAMES: &[&'static str] = &[ + "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", + "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", + "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh", + "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", + "dr0", "dr1", "dr2", "dr3", "dr4", "dr5", "dr6", "dr7", + "es", "cs", "ss", "ds", "fs", "gs", "", "", + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15", + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15", + "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7", "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15", + "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7", "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15", + "zmm0", "zmm1", "zmm2", "zmm3", "zmm4", "zmm5", "zmm6", "zmm7", "zmm8", "zmm9", "zmm10", "zmm11", "zmm12", "zmm13", "zmm14", "zmm15", "zmm16", "zmm17", "zmm18", "zmm19", "zmm20", "zmm21", "zmm22", "zmm23", "zmm24", "zmm25", "zmm26", "zmm27", "zmm28", "zmm29", "zmm30", "zmm31", + "st(0)", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)", + "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", + "k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7", + "eip", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", + "eflags", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", +]; + +pub(crate) fn regspec_label(spec: &RegSpec) -> &'static str { + unsafe { REG_NAMES.get_unchecked((spec.num as u16 + ((spec.bank as u16) << 3)) as usize) } +} + +impl fmt::Display for RegSpec { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(regspec_label(self)) + } +} + +impl fmt::Display for Operand { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + self.colorize(&NoColors, fmt) + } +} + +impl Colorize for Operand { + fn colorize(&self, colors: &Y, f: &mut T) -> fmt::Result { + match self { + &Operand::ImmediateU8(imm) => { + write!(f, "{}", colors.number(u8_hex(imm))) + } + &Operand::ImmediateI8(imm) => { + write!(f, "{}", + colors.number(signed_i8_hex(imm))) + }, + &Operand::ImmediateU16(imm) => { + write!(f, "{}", colors.number(u16_hex(imm))) + } + &Operand::ImmediateI16(imm) => { + write!(f, "{}", + colors.number(signed_i16_hex(imm))) + }, + &Operand::ImmediateU32(imm) => { + write!(f, "{}", colors.number(u32_hex(imm))) + } + &Operand::ImmediateI32(imm) => { + write!(f, "{}", + colors.number(signed_i32_hex(imm))) + }, + &Operand::Register(ref spec) => { + f.write_str(regspec_label(spec)) + } + &Operand::RegisterMaskMerge(ref spec, ref mask, merge_mode) => { + f.write_str(regspec_label(spec))?; + if mask.num != 0 { + f.write_str("{")?; + f.write_str(regspec_label(mask))?; + f.write_str("}")?; + } + if let MergeMode::Zero = merge_mode { + f.write_str("{z}")?; + } + Ok(()) + } + &Operand::RegisterMaskMergeSae(ref spec, ref mask, merge_mode, sae_mode) => { + f.write_str(regspec_label(spec))?; + if mask.num != 0 { + f.write_str("{")?; + f.write_str(regspec_label(mask))?; + f.write_str("}")?; + } + if let MergeMode::Zero = merge_mode { + f.write_str("{z}")?; + } + f.write_str(sae_mode.label())?; + Ok(()) + } + &Operand::RegisterMaskMergeSaeNoround(ref spec, ref mask, merge_mode) => { + f.write_str(regspec_label(spec))?; + if mask.num != 0 { + f.write_str("{")?; + f.write_str(regspec_label(mask))?; + f.write_str("}")?; + } + if let MergeMode::Zero = merge_mode { + f.write_str("{z}")?; + } + f.write_str("{sae}")?; + Ok(()) + } + &Operand::DisplacementU16(imm) => { + write!(f, "[{}]", colors.address(u16_hex(imm))) + } + &Operand::DisplacementU32(imm) => { + write!(f, "[{}]", colors.address(u32_hex(imm))) + } + &Operand::RegDisp(ref spec, disp) => { + write!(f, "[{} ", regspec_label(spec))?; + format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?; + write!(f, "]") + }, + &Operand::RegDeref(ref spec) => { + f.write_str("[")?; + f.write_str(regspec_label(spec))?; + f.write_str("]") + }, + &Operand::RegScale(ref spec, scale) => { + write!(f, "[{} * {}]", + regspec_label(spec), + colors.number(scale) + ) + }, + &Operand::RegScaleDisp(ref spec, scale, disp) => { + write!(f, "[{} * {} ", + regspec_label(spec), + colors.number(scale), + )?; + format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?; + write!(f, "]") + }, + &Operand::RegIndexBase(ref base, ref index) => { + f.write_str("[")?; + f.write_str(regspec_label(base))?; + f.write_str(" + ")?; + f.write_str(regspec_label(index))?; + f.write_str("]") + } + &Operand::RegIndexBaseDisp(ref base, ref index, disp) => { + write!(f, "[{} + {} ", + regspec_label(base), + regspec_label(index), + )?; + format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?; + write!(f, "]") + }, + &Operand::RegIndexBaseScale(ref base, ref index, scale) => { + write!(f, "[{} + {} * {}]", + regspec_label(base), + regspec_label(index), + colors.number(scale) + ) + } + &Operand::RegIndexBaseScaleDisp(ref base, ref index, scale, disp) => { + write!(f, "[{} + {} * {} ", + regspec_label(base), + regspec_label(index), + colors.number(scale), + )?; + format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?; + write!(f, "]") + }, + &Operand::RegDispMasked(ref spec, disp, ref mask_reg) => { + write!(f, "[{} ", regspec_label(spec))?; + format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?; + write!(f, "]")?; + write!(f, "{{{}}}", regspec_label(mask_reg)) + }, + &Operand::RegDerefMasked(ref spec, ref mask_reg) => { + f.write_str("[")?; + f.write_str(regspec_label(spec))?; + f.write_str("]")?; + write!(f, "{{{}}}", regspec_label(mask_reg)) + }, + &Operand::RegScaleMasked(ref spec, scale, ref mask_reg) => { + write!(f, "[{} * {}]", + regspec_label(spec), + colors.number(scale) + )?; + write!(f, "{{{}}}", regspec_label(mask_reg)) + }, + &Operand::RegScaleDispMasked(ref spec, scale, disp, ref mask_reg) => { + write!(f, "[{} * {} ", + regspec_label(spec), + colors.number(scale), + )?; + format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?; + write!(f, "]")?; + write!(f, "{{{}}}", regspec_label(mask_reg)) + }, + &Operand::RegIndexBaseMasked(ref base, ref index, ref mask_reg) => { + f.write_str("[")?; + f.write_str(regspec_label(base))?; + f.write_str(" + ")?; + f.write_str(regspec_label(index))?; + f.write_str("]")?; + write!(f, "{{{}}}", regspec_label(mask_reg)) + } + &Operand::RegIndexBaseDispMasked(ref base, ref index, disp, ref mask_reg) => { + write!(f, "[{} + {} ", + regspec_label(base), + regspec_label(index), + )?; + format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?; + write!(f, "]")?; + write!(f, "{{{}}}", regspec_label(mask_reg)) + }, + &Operand::RegIndexBaseScaleMasked(ref base, ref index, scale, ref mask_reg) => { + write!(f, "[{} + {} * {}]", + regspec_label(base), + regspec_label(index), + colors.number(scale) + )?; + write!(f, "{{{}}}", regspec_label(mask_reg)) + } + &Operand::RegIndexBaseScaleDispMasked(ref base, ref index, scale, disp, ref mask_reg) => { + write!(f, "[{} + {} * {} ", + regspec_label(base), + regspec_label(index), + colors.number(scale), + )?; + format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?; + write!(f, "]")?; + write!(f, "{{{}}}", regspec_label(mask_reg)) + }, + &Operand::Nothing => { Ok(()) }, + } + } +} + +impl fmt::Display for Opcode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(self.name()) + } +} + +const MNEMONICS: &[&'static str] = &[ + "invalid", + "add", + "or", + "adc", + "sbb", + "and", + "xor", + "sub", + "cmp", + "xadd", + "bt", + "bts", + "btc", + "btr", + "bsf", + "bsr", + "tzcnt", + "movss", + "addss", + "subss", + "mulss", + "divss", + "minss", + "maxss", + "sqrtss", + "movsd", + "sqrtsd", + "addsd", + "subsd", + "mulsd", + "divsd", + "minsd", + "maxsd", + "movsldup", + "movshdup", + "movddup", + "haddps", + "hsubps", + "addsubpd", + "addsubps", + "cvtsi2ss", + "cvtsi2sd", + "cvttsd2si", + "cvttps2dq", + "cvtpd2dq", + "cvtpd2ps", + "cvtps2dq", + "cvtsd2si", + "cvtsd2ss", + "cvttss2si", + "cvtss2si", + "cvtss2sd", + "cvtdq2pd", + "lddqu", + "movzx", + "movsx", + "movsxd", + "sar", + "sal", + "shr", + "shrd", + "shl", + "rcr", + "rcl", + "ror", + "rol", + "inc", + "dec", + "hlt", + "call", + "callf", + "jmp", + "jmpf", + "push", + "pop", + "lea", + "nop", + "prefetchnta", + "prefetch0", + "prefetch1", + "prefetch2", + "xchg", + "popf", + "int", + "into", + "iret", + "iretd", + "iretq", + "retf", + "enter", + "leave", + "mov", + "ret", + "pushf", + "wait", + "cbw", + "cwde", + "cdqe", + "cwd", + "cdq", + "cqo", + "lods", + "stos", + "lahf", + "sahf", + "cmps", + "scas", + "movs", + "test", + "ins", + "in", + "outs", + "out", + "imul", + "jo", + "jno", + "jb", + "jnb", + "jz", + "jnz", + "ja", + "jna", + "js", + "jns", + "jp", + "jnp", + "jl", + "jge", + "jle", + "jg", + "cmova", + "cmovb", + "cmovg", + "cmovge", + "cmovl", + "cmovle", + "cmovna", + "cmovnb", + "cmovno", + "cmovnp", + "cmovns", + "cmovnz", + "cmovo", + "cmovp", + "cmovs", + "cmovz", + "div", + "idiv", + "mul", + "neg", + "not", + "cmpxchg", + "seto", + "setno", + "setb", + "setae", + "setz", + "setnz", + "setbe", + "seta", + "sets", + "setns", + "setp", + "setnp", + "setl", + "setge", + "setle", + "setg", + "cpuid", + "ud0", + "ud1", + "ud2", + "wbinvd", + "invd", + "sysret", + "clts", + "syscall", + "lsl", + "lar", + "les", + "lds", + "sgdt", + "sidt", + "lgdt", + "lidt", + "smsw", + "lmsw", + "swapgs", + "rdtscp", + "invlpg", + "fxsave", + "fxrstor", + "ldmxcsr", + "stmxcsr", + "xsave", + "xrstor", + "xsaveopt", + "lfence", + "mfence", + "sfence", + "clflush", + "clflushopt", + "clwb", + "wrmsr", + "rdtsc", + "rdmsr", + "rdpmc", + "sldt", + "str", + "lldt", + "ltr", + "verr", + "verw", + "cmc", + "clc", + "stc", + "cli", + "sti", + "cld", + "std", + "jmpe", + "popcnt", + "movdqu", + "movdqa", + "movq", + "cmpss", + "cmpsd", + "unpcklps", + "unpcklpd", + "unpckhps", + "unpckhpd", + "pshufhw", + "pshuflw", + "movups", + "movq2dq", + "movdq2q", + "rsqrtss", + "rcpss", + "andn", + "bextr", + "blsi", + "blsmsk", + "blsr", + "vmclear", + "vmxon", + "vmcall", + "vmlaunch", + "vmresume", + "vmxoff", + "pconfig", + "monitor", + "mwait", + "monitorx", + "mwaitx", + "clac", + "stac", + "encls", + "enclv", + "xgetbv", + "xsetbv", + "vmfunc", + "xabort", + "xbegin", + "xend", + "xtest", + "enclu", + "rdpkru", + "wrpkru", + "rdpru", + "clzero", + "rdseed", + "rdrand", + "addps", + "addpd", + "andnps", + "andnpd", + "andps", + "andpd", + "bswap", + "cmppd", + "cmpps", + "comisd", + "comiss", + "cvtdq2ps", + "cvtpi2ps", + "cvtpi2pd", + "cvtps2pd", + "cvtps2pi", + "cvtpd2pi", + "cvttps2pi", + "cvttpd2pi", + "cvttpd2dq", + "divps", + "divpd", + "emms", + "getsec", + "lfs", + "lgs", + "lss", + "maskmovq", + "maskmovdqu", + "maxps", + "maxpd", + "minps", + "minpd", + "movaps", + "movapd", + "movd", + "movlps", + "movlpd", + "movhps", + "movhpd", + "movlhps", + "movhlps", + "movupd", + "movmskps", + "movmskpd", + "movnti", + "movntps", + "movntpd", + "extrq", + "insertq", + "movntss", + "movntsd", + "movntq", + "movntdq", + "mulps", + "mulpd", + "orps", + "orpd", + "packssdw", + "packsswb", + "packuswb", + "paddb", + "paddd", + "paddq", + "paddsb", + "paddsw", + "paddusb", + "paddusw", + "paddw", + "pand", + "pandn", + "pavgb", + "pavgw", + "pcmpeqb", + "pcmpeqd", + "pcmpeqw", + "pcmpgtb", + "pcmpgtd", + "pcmpgtw", + "pinsrw", + "pmaddwd", + "pmaxsw", + "pmaxub", + "pminsw", + "pminub", + "pmovmskb", + "pmulhuw", + "pmulhw", + "pmullw", + "pmuludq", + "por", + "psadbw", + "pshufw", + "pshufd", + "pslld", + "pslldq", + "psllq", + "psllw", + "psrad", + "psraw", + "psrld", + "psrldq", + "psrlq", + "psrlw", + "psubb", + "psubd", + "psubq", + "psubsb", + "psubsw", + "psubusb", + "psubusw", + "psubw", + "punpckhbw", + "punpckhdq", + "punpckhwd", + "punpcklbw", + "punpckldq", + "punpcklwd", + "punpcklqdq", + "punpckhqdq", + "pxor", + "rcpps", + "rsm", + "rsqrtps", + "shld", + "shufpd", + "shufps", + "slhd", + "sqrtps", + "sqrtpd", + "subps", + "subpd", + "sysenter", + "sysexit", + "ucomisd", + "ucomiss", + "vmread", + "vmwrite", + "xorps", + "xorpd", + "vmovddup", + "vpshuflw", + "vpshufhw", + "vhaddps", + "vhsubps", + "vaddsubps", + "vcvtpd2dq", + "vlddqu", + "vcomisd", + "vcomiss", + "vucomisd", + "vucomiss", + "vaddpd", + "vaddps", + "vaddsd", + "vaddss", + "vaddsubpd", + "vaesdec", + "vaesdeclast", + "vaesenc", + "vaesenclast", + "vaesimc", + "vaeskeygenassist", + "vblendpd", + "vblendps", + "vblendvpd", + "vblendvps", + "vbroadcastf128", + "vbroadcasti128", + "vbroadcastsd", + "vbroadcastss", + "vcmpsd", + "vcmpss", + "vcmppd", + "vcmpps", + "vcvtdq2pd", + "vcvtdq2ps", + "vcvtpd2ps", + "vcvtph2ps", + "vcvtps2dq", + "vcvtps2pd", + "vcvtss2sd", + "vcvtsi2ss", + "vcvtsi2sd", + "vcvtsd2si", + "vcvtsd2ss", + "vcvtps2ph", + "vcvtss2si", + "vcvttpd2dq", + "vcvttps2dq", + "vcvttss2si", + "vcvttsd2si", + "vdivpd", + "vdivps", + "vdivsd", + "vdivss", + "vdppd", + "vdpps", + "vextractf128", + "vextracti128", + "vextractps", + "vfmadd132pd", + "vfmadd132ps", + "vfmadd132sd", + "vfmadd132ss", + "vfmadd213pd", + "vfmadd213ps", + "vfmadd213sd", + "vfmadd213ss", + "vfmadd231pd", + "vfmadd231ps", + "vfmadd231sd", + "vfmadd231ss", + "vfmaddsub132pd", + "vfmaddsub132ps", + "vfmaddsub213pd", + "vfmaddsub213ps", + "vfmaddsub231pd", + "vfmaddsub231ps", + "vfmsub132pd", + "vfmsub132ps", + "vfmsub132sd", + "vfmsub132ss", + "vfmsub213pd", + "vfmsub213ps", + "vfmsub213sd", + "vfmsub213ss", + "vfmsub231pd", + "vfmsub231ps", + "vfmsub231sd", + "vfmsub231ss", + "vfmsubadd132pd", + "vfmsubadd132ps", + "vfmsubadd213pd", + "vfmsubadd213ps", + "vfmsubadd231pd", + "vfmsubadd231ps", + "vfnmadd132pd", + "vfnmadd132ps", + "vfnmadd132sd", + "vfnmadd132ss", + "vfnmadd213pd", + "vfnmadd213ps", + "vfnmadd213sd", + "vfnmadd213ss", + "vfnmadd231pd", + "vfnmadd231ps", + "vfnmadd231sd", + "vfnmadd231ss", + "vfnmsub132pd", + "vfnmsub132ps", + "vfnmsub132sd", + "vfnmsub132ss", + "vfnmsub213pd", + "vfnmsub213ps", + "vfnmsub213sd", + "vfnmsub213ss", + "vfnmsub231pd", + "vfnmsub231ps", + "vfnmsub231sd", + "vfnmsub231ss", + "vgatherdpd", + "vgatherdps", + "vgatherqpd", + "vgatherqps", + "vhaddpd", + "vhsubpd", + "vinsertf128", + "vinserti128", + "vinsertps", + "vmaskmovdqu", + "vmaskmovpd", + "vmaskmovps", + "vmaxpd", + "vmaxps", + "vmaxsd", + "vmaxss", + "vminpd", + "vminps", + "vminsd", + "vminss", + "vmovapd", + "vmovaps", + "vmovd", + "vmovdqa", + "vmovdqu", + "vmovhlps", + "vmovhpd", + "vmovhps", + "vmovlhps", + "vmovlpd", + "vmovlps", + "vmovmskpd", + "vmovmskps", + "vmovntdq", + "vmovntdqa", + "vmovntpd", + "vmovntps", + "vmovq", + "vmovss", + "vmovsd", + "vmovshdup", + "vmovsldup", + "vmovupd", + "vmovups", + "vmpsadbw", + "vmulpd", + "vmulps", + "vmulsd", + "vmulss", + "vpabsb", + "vpabsd", + "vpabsw", + "vpackssdw", + "vpackusdw", + "vpacksswb", + "vpackuswb", + "vpaddb", + "vpaddd", + "vpaddq", + "vpaddsb", + "vpaddsw", + "vpaddusb", + "vpaddusw", + "vpaddw", + "vpalignr", + "vandpd", + "vandps", + "vorpd", + "vorps", + "vandnpd", + "vandnps", + "vpand", + "vpandn", + "vpavgb", + "vpavgw", + "vpblendd", + "vpblendvb", + "vpblendw", + "vpbroadcastb", + "vpbroadcastd", + "vpbroadcastq", + "vpbroadcastw", + "vpclmulqdq", + "vpcmpeqb", + "vpcmpeqd", + "vpcmpeqq", + "vpcmpeqw", + "vpcmpgtb", + "vpcmpgtd", + "vpcmpgtq", + "vpcmpgtw", + "vpcmpestri", + "vpcmpestrm", + "vpcmpistri", + "vpcmpistrm", + "vperm2f128", + "vperm2i128", + "vpermd", + "vpermilpd", + "vpermilps", + "vpermpd", + "vpermps", + "vpermq", + "vpextrb", + "vpextrd", + "vpextrq", + "vpextrw", + "vpgatherdd", + "vpgatherdq", + "vpgatherqd", + "vpgatherqq", + "vphaddd", + "vphaddsw", + "vphaddw", + "vpmaddubsw", + "vphminposuw", + "vphsubd", + "vphsubsw", + "vphsubw", + "vpinsrb", + "vpinsrd", + "vpinsrq", + "vpinsrw", + "vpmaddwd", + "vpmaskmovd", + "vpmaskmovq", + "vpmaxsb", + "vpmaxsd", + "vpmaxsw", + "vpmaxub", + "vpmaxuw", + "vpmaxud", + "vpminsb", + "vpminsw", + "vpminsd", + "vpminub", + "vpminuw", + "vpminud", + "vpmovmskb", + "vpmovsxbd", + "vpmovsxbq", + "vpmovsxbw", + "vpmovsxdq", + "vpmovsxwd", + "vpmovsxwq", + "vpmovzxbd", + "vpmovzxbq", + "vpmovzxbw", + "vpmovzxdq", + "vpmovzxwd", + "vpmovzxwq", + "vpmuldq", + "vpmulhrsw", + "vpmulhuw", + "vpmulhw", + "vpmullq", + "vpmulld", + "vpmullw", + "vpmuludq", + "vpor", + "vpsadbw", + "vpshufb", + "vpshufd", + "vpsignb", + "vpsignd", + "vpsignw", + "vpslld", + "vpslldq", + "vpsllq", + "vpsllvd", + "vpsllvq", + "vpsllw", + "vpsrad", + "vpsravd", + "vpsraw", + "vpsrld", + "vpsrldq", + "vpsrlq", + "vpsrlvd", + "vpsrlvq", + "vpsrlw", + "vpsubb", + "vpsubd", + "vpsubq", + "vpsubsb", + "vpsubsw", + "vpsubusb", + "vpsubusw", + "vpsubw", + "vptest", + "vpunpckhbw", + "vpunpckhdq", + "vpunpckhqdq", + "vpunpckhwd", + "vpunpcklbw", + "vpunpckldq", + "vpunpcklqdq", + "vpunpcklwd", + "vpxor", + "vrcpps", + "vroundpd", + "vroundps", + "vroundsd", + "vroundss", + "vrsqrtps", + "vrsqrtss", + "vrcpss", + "vshufpd", + "vshufps", + "vsqrtpd", + "vsqrtps", + "vsqrtss", + "vsqrtsd", + "vsubpd", + "vsubps", + "vsubsd", + "vsubss", + "vtestpd", + "vtestps", + "vunpckhpd", + "vunpckhps", + "vunpcklpd", + "vunpcklps", + "vxorpd", + "vxorps", + "vzeroupper", + "vzeroall", + "vldmxcsr", + "vstmxcsr", + "pclmulqdq", + "aeskeygenassist", + "aesimc", + "aesenc", + "aesenclast", + "aesdec", + "aesdeclast", + "pcmpgtq", + "pcmpistrm", + "pcmpistri", + "pcmpestri", + "packusdw", + "pcmpestrm", + "pcmpeqq", + "ptest", + "phminposuw", + "dpps", + "dppd", + "mpsadbw", + "pmovzxdq", + "pmovsxdq", + "pmovzxbd", + "pmovsxbd", + "pmovzxwq", + "pmovsxwq", + "pmovzxbq", + "pmovsxbq", + "pmovsxwd", + "pmovzxwd", + "pextrq", + "pextrd", + "pextrw", + "pextrb", + "pmovsxbw", + "pmovzxbw", + "pinsrq", + "pinsrd", + "pinsrb", + "extractps", + "insertps", + "roundss", + "roundsd", + "roundps", + "roundpd", + "pmaxsb", + "pmaxsd", + "pmaxuw", + "pmaxud", + "pminsd", + "pminsb", + "pminud", + "pminuw", + "blendw", + "pblendvb", + "pblendw", + "blendvps", + "blendvpd", + "blendps", + "blendpd", + "pmuldq", + "movntdqa", + "pmulld", + "palignr", + "psignw", + "psignd", + "psignb", + "pshufb", + "pmulhrsw", + "pmaddubsw", + "pabsd", + "pabsw", + "pabsb", + "phsubsw", + "phsubw", + "phsubd", + "phaddd", + "phaddsw", + "phaddw", + "hsubpd", + "haddpd", + "sha1rnds4", + "sha1nexte", + "sha1msg1", + "sha1msg2", + "sha256rnds2", + "sha256msg1", + "sha256msg2", + "lzcnt", + "clgi", + "stgi", + "skinit", + "vmload", + "vmmcall", + "vmsave", + "vmrun", + "invlpga", + "invlpgb", + "tlbsync", + "movbe", + "adcx", + "adox", + "prefetchw", + "rdpid", + "cmpxchg8b", + "cmpxchg16b", + "vmptrld", + "vmptrst", + "bzhi", + "mulx", + "shlx", + "shrx", + "sarx", + "pdep", + "pext", + "rorx", + "xrstors", + "xrstors64", + "xsavec", + "xsavec64", + "xsaves", + "xsaves64", + "rdfsbase", + "rdgsbase", + "wrfsbase", + "wrgsbase", + "crc32", + "salc", + "xlat", + + "f2xm1", + "fabs", + "fadd", + "faddp", + "fbld", + "fbstp", + "fchs", + "fcmovb", + "fcmovbe", + "fcmove", + "fcmovnb", + "fcmovnbe", + "fcmovne", + "fcmovnu", + "fcmovu", + "fcom", + "fcomi", + "fcomip", + "fcomp", + "fcompp", + "fcos", + "fdecstp", + "fdisi8087_nop", + "fdiv", + "fdivp", + "fdivr", + "fdivrp", + "feni8087_nop", + "ffree", + "ffreep", + "fiadd", + "ficom", + "ficomp", + "fidiv", + "fidivr", + "fild", + "fimul", + "fincstp", + "fist", + "fistp", + "fisttp", + "fisub", + "fisubr", + "fld", + "fld1", + "fldcw", + "fldenv", + "fldl2e", + "fldl2t", + "fldlg2", + "fldln2", + "fldpi", + "fldz", + "fmul", + "fmulp", + "fnclex", + "fninit", + "fnop", + "fnsave", + "fnstcw", + "fnstenv", + "fnstor", + "fnstsw", + "fpatan", + "fprem", + "fprem1", + "fptan", + "frndint", + "frstor", + "fscale", + "fsetpm287_nop", + "fsin", + "fsincos", + "fsqrt", + "fst", + "fstp", + "fstpnce", + "fsub", + "fsubp", + "fsubr", + "fsubrp", + "ftst", + "fucom", + "fucomi", + "fucomip", + "fucomp", + "fucompp", + "fxam", + "fxch", + "fxtract", + "fyl2x", + "fyl2xp1", + "loopnz", + "loopz", + "loop", + "jcxz", + "pusha", + "popa", + "bound", + "arpl", + "aas", + "aaa", + "das", + "daa", + "aam", + "aad", + "movdir64b", + "movdiri", + "aesdec128kl", + "aesdec256kl", + "aesdecwide128kl", + "aesdecwide256kl", + "aesenc128kl", + "aesenc256kl", + "aesencwide128kl", + "aesencwide256kl", + "encodekey128", + "encodekey256", + "loadiwkey", + + // unsure + "hreset", + + // 3dnow + "femms", + "pi2fw", + "pi2fd", + "pi2iw", + "pi2id", + "pmulhrw", + "pfcmpge", + "pfmin", + "pfrcp", + "pfrsqrt", + "pfsub", + "pfadd", + "pfcmpgt", + "pfmax", + "pfrcpit1", + "pfrsqit1", + "pfsubr", + "pfacc", + "pfcmpeq", + "pfmul", + "pfmulhrw", + "pfrcpit2", + "pfnacc", + "pfpnacc", + "pswapd", + "pavgusb", + + // ENQCMD + "enqcmd", + "enqcmds", + + // INVPCID, + "invept", + "invvpid", + "invpcid", + + // PTWRITE + "ptwrite", + + // GFNI + "gf2p8affineqb", + "gf2p8affineinvqb", + "gf2p8mulb", + + // CET + "wruss", + "wrss", + "incssp", + "saveprevssp", + "setssbsy", + "clrssbsy", + "rstorssp", + + // TDX + "tdcall", + "seamret", + "seamops", + "seamcall", + + // WAITPKG + "tpause", + "umonitor", + "umwait", + + // UINTR + "uiret", + "testui", + "clui", + "stui", + "senduipi", + + // TSXLDTRK + "xsusldtrk", + "xresldtrk", + + // AVX512F + "valignd", + "valignq", + "vblendmpd", + "vblendmps", + "vcompresspd", + "vcompressps", + "vcvtpd2udq", + "vcvttpd2udq", + "vcvtps2udq", + "vcvttps2udq", + "vcvtqq2pd", + "vcvtqq2ps", + "vcvtsd2usi", + "vcvttsd2usi", + "vcvtss2usi", + "vcvttss2usi", + "vcvtudq2pd", + "vcvtudq2ps", + "vcvtusi2usd", + "vcvtusi2uss", + "vexpandpd", + "vexpandps", + "vextractf32x4", + "vextractf64x4", + "vextracti32x4", + "vextracti64x4", + "vfixupimmpd", + "vfixupimmps", + "vfixupimmsd", + "vfixupimmss", + "vgetexppd", + "vgetexpps", + "vgetexpsd", + "vgetexpss", + "vgetmantpd", + "vgetmantps", + "vgetmantsd", + "vgetmantss", + "vinsertf32x4", + "vinsertf64x4", + "vinserti64x4", + "vmovdqa32", + "vmovdqa64", + "vmovdqu32", + "vmovdqu64", + "vpblendmd", + "vpblendmq", + "vpcmpd", + "vpcmpud", + "vpcmpq", + "vpcmpuq", + "vpcompressq", + "vpcompressd", + "vpermi2d", + "vpermi2q", + "vpermi2pd", + "vpermi2ps", + "vpermt2d", + "vpermt2q", + "vpermt2pd", + "vpermt2ps", + "vpmaxsq", + "vpmaxuq", + "vpminsq", + "vpminuq", + "vpmovsqb", + "vpmovusqb", + "vpmovsqw", + "vpmovusqw", + "vpmovsqd", + "vpmovusqd", + "vpmovsdb", + "vpmovusdb", + "vpmovsdw", + "vpmovusdw", + "vprold", + "vprolq", + "vprolvd", + "vprolvq", + "vprord", + "vprorq", + "vprorrd", + "vprorrq", + "vpscatterdd", + "vpscatterdq", + "vpscatterqd", + "vpscatterqq", + "vpsraq", + "vpsravq", + "vptestnmd", + "vptestnmq", + "vpternlogd", + "vpternlogq", + "vptestmd", + "vptestmq", + "vrcp14pd", + "vrcp14ps", + "vrcp14sd", + "vrcp14ss", + "vrndscalepd", + "vrndscaleps", + "vrndscalesd", + "vrndscaless", + "vrsqrt14pd", + "vrsqrt14ps", + "vrsqrt14sd", + "vrsqrt14ss", + "vscaledpd", + "vscaledps", + "vscaledsd", + "vscaledss", + "vscatterdd", + "vscatterdq", + "vscatterqd", + "vscatterqq", + "vshuff32x4", + "vshuff64x2", + "vshufi32x4", + "vshufi64x2", + + // AVX512DQ + "vcvttpd2qq", + "vcvtpd2qq", + "vcvttpd2uqq", + "vcvtpd2uqq", + "vcvttps2qq", + "vcvtps2qq", + "vcvttps2uqq", + "vcvtps2uqq", + "vcvtuqq2pd", + "vcvtuqq2ps", + "vextractf64x2", + "vextracti64x2", + "vfpclasspd", + "vfpclassps", + "vfpclasssd", + "vfpclassss", + "vinsertf64x2", + "vinserti64x2", + "vpmovm2d", + "vpmovm2q", + "vpmovb2d", + "vpmovq2m", + "vrangepd", + "vrangeps", + "vrangesd", + "vrangess", + "vreducepd", + "vreduceps", + "vreducesd", + "vreducess", + + // AVX512BW + "vdbpsadbw", + "vmovdqu8", + "vmovdqu16", + "vpblendmb", + "vpblendmw", + "vpcmpb", + "vpcmpub", + "vpcmpw", + "vpcmpuw", + "vpermw", + "vpermi2b", + "vpermi2w", + "vpmovm2b", + "vpmovm2w", + "vpmovb2m", + "vpmovw2m", + "vpmovswb", + "vpmovuswb", + "vpsllvw", + "vpsravw", + "vpsrlvw", + "vptestnmb", + "vptestnmw", + "vptestmb", + "vptestmw", + + // AVX512CD + "vpbroadcastm", + "vpconflictd", + "vpconflictq", + "vplzcntd", + "vplzcntq", + + "kunpckbw", + "kunpckwd", + "kunpckdq", + + "kaddb", + "kandb", + "kandnb", + "kmovb", + "knotb", + "korb", + "kortestb", + "kshiftlb", + "kshiftrb", + "ktestb", + "kxnorb", + "kxorb", + "kaddw", + "kandw", + "kandnw", + "kmovw", + "knotw", + "korw", + "kortestw", + "kshiftlw", + "kshiftrw", + "ktestw", + "kxnorw", + "kxorw", + "kaddd", + "kandd", + "kandnd", + "kmovd", + "knotd", + "kord", + "kortestd", + "kshiftld", + "kshiftrd", + "ktestd", + "kxnord", + "kxord", + "kaddq", + "kandq", + "kandnq", + "kmovq", + "knotq", + "korq", + "kortestq", + "kshiftlq", + "kshiftrq", + "ktestq", + "kxnorq", + "kxorq", + + // AVX512ER + "vexp2pd", + "vexp2ps", + "vexp2sd", + "vexp2ss", + "vrcp28pd", + "vrcp28ps", + "vrcp28sd", + "vrcp28ss", + "vrsqrt28pd", + "vrsqrt28ps", + "vrsqrt28sd", + "vrsqrt28ss", + + // AVX512PF + "vgatherpf0dpd", + "vgatherpf0dps", + "vgatherpf0qpd", + "vgatherpf0qps", + "vgatherpf1dpd", + "vgatherpf1dps", + "vgatherpf1qpd", + "vgatherpf1qps", + "vscatterpf0dpd", + "vscatterpf0dps", + "vscatterpf0qpd", + "vscatterpf0qps", + "vscatterpf1dpd", + "vscatterpf1dps", + "vscatterpf1qpd", + "vscatterpf1qps", + + // MPX + "bndmk", + "bndcl", + "bndcu", + "bndcn", + "bndmov", + "bndldx", + "bndstx", + + + + "vgf2p8affineqb", + "vgf2p8affineinvqb", + "vpshrdq", + "vpshrdd", + "vpshrdw", + "vpshldq", + "vpshldd", + "vpshldw", + "vbroadcastf32x8", + "vbroadcastf64x4", + "vbroadcastf32x4", + "vbroadcastf64x2", + "vbroadcastf32x2", + "vbroadcasti32x8", + "vbroadcasti64x4", + "vbroadcasti32x4", + "vbroadcasti64x2", + "vbroadcasti32x2", + "vextracti32x8", + "vextractf32x8", + "vinserti32x8", + "vinsertf32x8", + "vinserti32x4", + "v4fnmaddss", + "v4fnmaddps", + "vcvtneps2bf16", + "v4fmaddss", + "v4fmaddps", + "vcvtne2ps2bf16", + "vp2intersectd", + "vp2intersectq", + "vp4dpwssds", + "vp4dpwssd", + "vpdpwssds", + "vpdpwssd", + "vpdpbusds", + "vdpbf16ps", + "vpbroadcastmw2d", + "vpbroadcastmb2q", + "vpmovd2m", + "vpmovqd", + "vpmovwb", + "vpmovdb", + "vpmovdw", + "vpmovqb", + "vpmovqw", + "vgf2p8mulb", + "vpmadd52huq", + "vpmadd52luq", + "vpshufbitqmb", + "vpermb", + "vpexpandd", + "vpexpandq", + "vpabsq", + "vprorvd", + "vprorvq", + "vpmultishiftqb", + "vpermt2b", + "vpermt2w", + "vpshrdvq", + "vpshrdvd", + "vpshrdvw", + "vpshldvq", + "vpshldvd", + "vpshldvw", + "vpcompressb", + "vpcompressw", + "vpexpandb", + "vpexpandw", + "vpopcntd", + "vpopcntq", + "vpopcntb", + "vpopcntw", + "vscalefss", + "vscalefsd", + "vscalefps", + "vscalefpd", + "vpdpbusd", + "vcvtusi2sd", + "vcvtusi2ss", + "vpxord", + "vpxorq", + "vpord", + "vporq", + "vpandnd", + "vpandnq", + "vpandd", + "vpandq", + "psmash", + "pvalidate", + "rmpadjust", + "rmpupdate", +]; + +impl Opcode { + fn name(&self) -> &'static str { + unsafe { + MNEMONICS.get_unchecked(*self as usize) + } + } +} + +impl Colorize for Opcode { + fn colorize(&self, colors: &Y, out: &mut T) -> fmt::Result { + match self { + Opcode::VGF2P8AFFINEQB | + Opcode::VGF2P8AFFINEINVQB | + Opcode::VPSHRDQ | + Opcode::VPSHRDD | + Opcode::VPSHRDW | + Opcode::VPSHLDQ | + Opcode::VPSHLDD | + Opcode::VPSHLDW | + Opcode::VBROADCASTF32X8 | + Opcode::VBROADCASTF64X4 | + Opcode::VBROADCASTF32X4 | + Opcode::VBROADCASTF64X2 | + Opcode::VBROADCASTF32X2 | + Opcode::VBROADCASTI32X8 | + Opcode::VBROADCASTI64X4 | + Opcode::VBROADCASTI32X4 | + Opcode::VBROADCASTI64X2 | + Opcode::VBROADCASTI32X2 | + Opcode::VEXTRACTI32X8 | + Opcode::VEXTRACTF32X8 | + Opcode::VINSERTI32X8 | + Opcode::VINSERTF32X8 | + Opcode::VINSERTI32X4 | + Opcode::V4FNMADDSS | + Opcode::V4FNMADDPS | + Opcode::VCVTNEPS2BF16 | + Opcode::V4FMADDSS | + Opcode::V4FMADDPS | + Opcode::VCVTNE2PS2BF16 | + Opcode::VP2INTERSECTD | + Opcode::VP2INTERSECTQ | + Opcode::VP4DPWSSDS | + Opcode::VP4DPWSSD | + Opcode::VPDPWSSDS | + Opcode::VPDPWSSD | + Opcode::VPDPBUSDS | + Opcode::VDPBF16PS | + Opcode::VPBROADCASTMW2D | + Opcode::VPBROADCASTMB2Q | + Opcode::VPMOVD2M | + Opcode::VPMOVQD | + Opcode::VPMOVWB | + Opcode::VPMOVDB | + Opcode::VPMOVDW | + Opcode::VPMOVQB | + Opcode::VPMOVQW | + Opcode::VGF2P8MULB | + Opcode::VPMADD52HUQ | + Opcode::VPMADD52LUQ | + Opcode::VPSHUFBITQMB | + Opcode::VPERMB | + Opcode::VPEXPANDD | + Opcode::VPEXPANDQ | + Opcode::VPABSQ | + Opcode::VPRORVD | + Opcode::VPRORVQ | + Opcode::VPMULTISHIFTQB | + Opcode::VPERMT2B | + Opcode::VPERMT2W | + Opcode::VPSHRDVQ | + Opcode::VPSHRDVD | + Opcode::VPSHRDVW | + Opcode::VPSHLDVQ | + Opcode::VPSHLDVD | + Opcode::VPSHLDVW | + Opcode::VPCOMPRESSB | + Opcode::VPCOMPRESSW | + Opcode::VPEXPANDB | + Opcode::VPEXPANDW | + Opcode::VPOPCNTD | + Opcode::VPOPCNTQ | + Opcode::VPOPCNTB | + Opcode::VPOPCNTW | + Opcode::VSCALEFSS | + Opcode::VSCALEFSD | + Opcode::VSCALEFPS | + Opcode::VSCALEFPD | + Opcode::VPDPBUSD | + Opcode::VCVTUSI2SD | + Opcode::VCVTUSI2SS | + Opcode::VPXORD | + Opcode::VPXORQ | + Opcode::VPORD | + Opcode::VPORQ | + Opcode::VPANDND | + Opcode::VPANDNQ | + Opcode::VPANDD | + Opcode::VPANDQ | + + Opcode::VHADDPS | + Opcode::VHSUBPS | + Opcode::VADDSUBPS | + Opcode::VADDPD | + Opcode::VADDPS | + Opcode::VADDSD | + Opcode::VADDSS | + Opcode::VADDSUBPD | + Opcode::VFMADD132PD | + Opcode::VFMADD132PS | + Opcode::VFMADD132SD | + Opcode::VFMADD132SS | + Opcode::VFMADD213PD | + Opcode::VFMADD213PS | + Opcode::VFMADD213SD | + Opcode::VFMADD213SS | + Opcode::VFMADD231PD | + Opcode::VFMADD231PS | + Opcode::VFMADD231SD | + Opcode::VFMADD231SS | + Opcode::VFMADDSUB132PD | + Opcode::VFMADDSUB132PS | + Opcode::VFMADDSUB213PD | + Opcode::VFMADDSUB213PS | + Opcode::VFMADDSUB231PD | + Opcode::VFMADDSUB231PS | + Opcode::VFMSUB132PD | + Opcode::VFMSUB132PS | + Opcode::VFMSUB132SD | + Opcode::VFMSUB132SS | + Opcode::VFMSUB213PD | + Opcode::VFMSUB213PS | + Opcode::VFMSUB213SD | + Opcode::VFMSUB213SS | + Opcode::VFMSUB231PD | + Opcode::VFMSUB231PS | + Opcode::VFMSUB231SD | + Opcode::VFMSUB231SS | + Opcode::VFMSUBADD132PD | + Opcode::VFMSUBADD132PS | + Opcode::VFMSUBADD213PD | + Opcode::VFMSUBADD213PS | + Opcode::VFMSUBADD231PD | + Opcode::VFMSUBADD231PS | + Opcode::VFNMADD132PD | + Opcode::VFNMADD132PS | + Opcode::VFNMADD132SD | + Opcode::VFNMADD132SS | + Opcode::VFNMADD213PD | + Opcode::VFNMADD213PS | + Opcode::VFNMADD213SD | + Opcode::VFNMADD213SS | + Opcode::VFNMADD231PD | + Opcode::VFNMADD231PS | + Opcode::VFNMADD231SD | + Opcode::VFNMADD231SS | + Opcode::VFNMSUB132PD | + Opcode::VFNMSUB132PS | + Opcode::VFNMSUB132SD | + Opcode::VFNMSUB132SS | + Opcode::VFNMSUB213PD | + Opcode::VFNMSUB213PS | + Opcode::VFNMSUB213SD | + Opcode::VFNMSUB213SS | + Opcode::VFNMSUB231PD | + Opcode::VFNMSUB231PS | + Opcode::VFNMSUB231SD | + Opcode::VFNMSUB231SS | + Opcode::VDIVPD | + Opcode::VDIVPS | + Opcode::VDIVSD | + Opcode::VDIVSS | + Opcode::VHADDPD | + Opcode::VHSUBPD | + Opcode::HADDPD | + Opcode::HSUBPD | + Opcode::VMULPD | + Opcode::VMULPS | + Opcode::VMULSD | + Opcode::VMULSS | + Opcode::VPABSB | + Opcode::VPABSD | + Opcode::VPABSW | + Opcode::PABSB | + Opcode::PABSD | + Opcode::PABSW | + Opcode::VPSIGNB | + Opcode::VPSIGND | + Opcode::VPSIGNW | + Opcode::PSIGNB | + Opcode::PSIGND | + Opcode::PSIGNW | + Opcode::VPADDB | + Opcode::VPADDD | + Opcode::VPADDQ | + Opcode::VPADDSB | + Opcode::VPADDSW | + Opcode::VPADDUSB | + Opcode::VPADDUSW | + Opcode::VPADDW | + Opcode::VPAVGB | + Opcode::VPAVGW | + Opcode::VPMULDQ | + Opcode::VPMULHRSW | + Opcode::VPMULHUW | + Opcode::VPMULHW | + Opcode::VPMULLQ | + Opcode::VPMULLD | + Opcode::VPMULLW | + Opcode::VPMULUDQ | + Opcode::PCLMULQDQ | + Opcode::PMULDQ | + Opcode::PMULHRSW | + Opcode::PMULLD | + Opcode::VPSUBB | + Opcode::VPSUBD | + Opcode::VPSUBQ | + Opcode::VPSUBSB | + Opcode::VPSUBSW | + Opcode::VPSUBUSB | + Opcode::VPSUBUSW | + Opcode::VPSUBW | + Opcode::VROUNDPD | + Opcode::VROUNDPS | + Opcode::VEXP2PD | + Opcode::VEXP2PS | + Opcode::VEXP2SD | + Opcode::VEXP2SS | + Opcode::VRCP28PD | + Opcode::VRCP28PS | + Opcode::VRCP28SD | + Opcode::VRCP28SS | + Opcode::VRCP14PD | + Opcode::VRCP14PS | + Opcode::VRCP14SD | + Opcode::VRCP14SS | + Opcode::VRNDSCALEPD | + Opcode::VRNDSCALEPS | + Opcode::VRNDSCALESD | + Opcode::VRNDSCALESS | + Opcode::VRSQRT14PD | + Opcode::VRSQRT14PS | + Opcode::VRSQRT14SD | + Opcode::VRSQRT14SS | + Opcode::VSCALEDPD | + Opcode::VSCALEDPS | + Opcode::VSCALEDSD | + Opcode::VSCALEDSS | + Opcode::VRSQRT28PD | + Opcode::VRSQRT28PS | + Opcode::VRSQRT28SD | + Opcode::VRSQRT28SS | + Opcode::VRSQRTPS | + Opcode::VSQRTPD | + Opcode::VSQRTPS | + Opcode::VSUBPD | + Opcode::VSUBPS | + Opcode::VSUBSD | + Opcode::VSUBSS | + Opcode::VRCPSS | + Opcode::VROUNDSD | + Opcode::VROUNDSS | + Opcode::ROUNDPD | + Opcode::ROUNDPS | + Opcode::ROUNDSD | + Opcode::ROUNDSS | + Opcode::VRSQRTSS | + Opcode::VSQRTSD | + Opcode::VSQRTSS | + Opcode::VPSADBW | + Opcode::VMPSADBW | + Opcode::VDBPSADBW | + Opcode::VPHADDD | + Opcode::VPHADDSW | + Opcode::VPHADDW | + Opcode::VPHSUBD | + Opcode::VPHSUBSW | + Opcode::VPHSUBW | + Opcode::VPMADDUBSW | + Opcode::VPMADDWD | + Opcode::VDPPD | + Opcode::VDPPS | + Opcode::VRCPPS | + Opcode::VORPD | + Opcode::VORPS | + Opcode::VANDPD | + Opcode::VANDPS | + Opcode::VANDNPD | + Opcode::VANDNPS | + Opcode::VPAND | + Opcode::VPANDN | + Opcode::VPOR | + Opcode::VPXOR | + Opcode::VXORPD | + Opcode::VXORPS | + Opcode::VPSLLD | + Opcode::VPSLLDQ | + Opcode::VPSLLQ | + Opcode::VPSLLVD | + Opcode::VPSLLVQ | + Opcode::VPSLLW | + Opcode::VPROLD | + Opcode::VPROLQ | + Opcode::VPROLVD | + Opcode::VPROLVQ | + Opcode::VPRORD | + Opcode::VPRORQ | + Opcode::VPRORRD | + Opcode::VPRORRQ | + Opcode::VPSLLVW | + Opcode::VPSRAQ | + Opcode::VPSRAVQ | + Opcode::VPSRAVW | + Opcode::VPSRLVW | + Opcode::VPSRAD | + Opcode::VPSRAVD | + Opcode::VPSRAW | + Opcode::VPSRLD | + Opcode::VPSRLDQ | + Opcode::VPSRLQ | + Opcode::VPSRLVD | + Opcode::VPSRLVQ | + Opcode::VPSRLW | + Opcode::PHADDD | + Opcode::PHADDSW | + Opcode::PHADDW | + Opcode::PHSUBD | + Opcode::PHSUBSW | + Opcode::PHSUBW | + Opcode::PMADDUBSW | + Opcode::ADDSUBPD | + Opcode::DPPS | + Opcode::DPPD | + Opcode::MPSADBW | + Opcode::RCPSS | + Opcode::RSQRTSS | + Opcode::SQRTSD | + Opcode::ADDSD | + Opcode::SUBSD | + Opcode::MULSD | + Opcode::DIVSD | + Opcode::SQRTSS | + Opcode::ADDSS | + Opcode::SUBSS | + Opcode::MULSS | + Opcode::DIVSS | + Opcode::HADDPS | + Opcode::HSUBPS | + Opcode::ADDSUBPS | + Opcode::PMULHRW | + Opcode::PFRCP | + Opcode::PFRSQRT | + Opcode::PFSUB | + Opcode::PFADD | + Opcode::PFRCPIT1 | + Opcode::PFRSQIT1 | + Opcode::PFSUBR | + Opcode::PFACC | + Opcode::PFMUL | + Opcode::PFMULHRW | + Opcode::PFRCPIT2 | + Opcode::PFNACC | + Opcode::PFPNACC | + Opcode::PSWAPD | + Opcode::PAVGUSB | + Opcode::XADD| + Opcode::DIV | + Opcode::IDIV | + Opcode::MUL | + Opcode::MULX | + Opcode::NEG | + Opcode::NOT | + Opcode::SAR | + Opcode::SAL | + Opcode::SHR | + Opcode::SARX | + Opcode::SHLX | + Opcode::SHRX | + Opcode::SHRD | + Opcode::SHL | + Opcode::RCR | + Opcode::RCL | + Opcode::ROR | + Opcode::RORX | + Opcode::ROL | + Opcode::INC | + Opcode::DEC | + Opcode::SBB | + Opcode::AND | + Opcode::XOR | + Opcode::OR | + Opcode::LEA | + Opcode::ADD | + Opcode::ADC | + Opcode::ADCX | + Opcode::ADOX | + Opcode::SUB | + Opcode::POPCNT | + Opcode::LZCNT | + Opcode::VPLZCNTD | + Opcode::VPLZCNTQ | + Opcode::BT | + Opcode::BTS | + Opcode::BTR | + Opcode::BTC | + Opcode::BSF | + Opcode::BSR | + Opcode::BZHI | + Opcode::PDEP | + Opcode::PEXT | + Opcode::TZCNT | + Opcode::ANDN | + Opcode::BEXTR | + Opcode::BLSI | + Opcode::BLSMSK | + Opcode::BLSR | + Opcode::ADDPS | + Opcode::ADDPD | + Opcode::ANDNPS | + Opcode::ANDNPD | + Opcode::ANDPS | + Opcode::ANDPD | + Opcode::COMISD | + Opcode::COMISS | + Opcode::DIVPS | + Opcode::DIVPD | + Opcode::MULPS | + Opcode::MULPD | + Opcode::ORPS | + Opcode::ORPD | + Opcode::PADDB | + Opcode::PADDD | + Opcode::PADDQ | + Opcode::PADDSB | + Opcode::PADDSW | + Opcode::PADDUSB | + Opcode::PADDUSW | + Opcode::PADDW | + Opcode::PAND | + Opcode::PANDN | + Opcode::PAVGB | + Opcode::PAVGW | + Opcode::PMADDWD | + Opcode::PMULHUW | + Opcode::PMULHW | + Opcode::PMULLW | + Opcode::PMULUDQ | + Opcode::POR | + Opcode::PSADBW | + Opcode::PSHUFD | + Opcode::PSHUFW | + Opcode::PSHUFB | + Opcode::PSLLD | + Opcode::PSLLDQ | + Opcode::PSLLQ | + Opcode::PSLLW | + Opcode::PSRAD | + Opcode::PSRAW | + Opcode::PSRLD | + Opcode::PSRLDQ | + Opcode::PSRLQ | + Opcode::PSRLW | + Opcode::PSUBB | + Opcode::PSUBD | + Opcode::PSUBQ | + Opcode::PSUBSB | + Opcode::PSUBSW | + Opcode::PSUBUSB | + Opcode::PSUBUSW | + Opcode::PSUBW | + Opcode::PXOR | + Opcode::RSQRTPS | + Opcode::SQRTPS | + Opcode::SQRTPD | + Opcode::SUBPS | + Opcode::SUBPD | + Opcode::XORPS | + Opcode::XORPD | + Opcode::RCPPS | + Opcode::SHLD | + Opcode::SLHD | + Opcode::UCOMISD | + Opcode::UCOMISS | + Opcode::F2XM1 | + Opcode::FABS | + Opcode::FADD | + Opcode::FADDP | + Opcode::FCHS | + Opcode::FCOS | + Opcode::FDIV | + Opcode::FDIVP | + Opcode::FDIVR | + Opcode::FDIVRP | + Opcode::FIADD | + Opcode::FIDIV | + Opcode::FIDIVR | + Opcode::FIMUL | + Opcode::FISUB | + Opcode::FISUBR | + Opcode::FMUL | + Opcode::FMULP | + Opcode::FNCLEX | + Opcode::FNINIT | + Opcode::FPATAN | + Opcode::FPREM | + Opcode::FPREM1 | + Opcode::FPTAN | + Opcode::FRNDINT | + Opcode::FSCALE | + Opcode::FSIN | + Opcode::FSINCOS | + Opcode::FSQRT | + Opcode::FSUB | + Opcode::FSUBP | + Opcode::FSUBR | + Opcode::FSUBRP | + Opcode::FXTRACT | + Opcode::FYL2X | + Opcode::FYL2XP1 | + Opcode::AAA | + Opcode::AAS | + Opcode::DAS | + Opcode::DAA | + Opcode::AAD | + Opcode::AAM | + Opcode::KADDB | + Opcode::KANDB | + Opcode::KANDNB | + Opcode::KNOTB | + Opcode::KORB | + Opcode::KSHIFTLB | + Opcode::KSHIFTRB | + Opcode::KXNORB | + Opcode::KXORB | + Opcode::KADDW | + Opcode::KANDW | + Opcode::KANDNW | + Opcode::KNOTW | + Opcode::KORW | + Opcode::KSHIFTLW | + Opcode::KSHIFTRW | + Opcode::KXNORW | + Opcode::KXORW | + Opcode::KADDD | + Opcode::KANDD | + Opcode::KANDND | + Opcode::KNOTD | + Opcode::KORD | + Opcode::KSHIFTLD | + Opcode::KSHIFTRD | + Opcode::KXNORD | + Opcode::KXORD | + Opcode::KADDQ | + Opcode::KANDQ | + Opcode::KANDNQ | + Opcode::KNOTQ | + Opcode::KORQ | + Opcode::KSHIFTLQ | + Opcode::KSHIFTRQ | + Opcode::KXNORQ | + Opcode::KXORQ | + Opcode::IMUL => { write!(out, "{}", colors.arithmetic_op(self)) } + Opcode::POPF | + Opcode::PUSHF | + Opcode::ENTER | + Opcode::LEAVE | + Opcode::PUSHA | + Opcode::POPA | + Opcode::PUSH | + Opcode::POP => { write!(out, "{}", colors.stack_op(self)) } + Opcode::WAIT | + Opcode::FNOP | + Opcode::FDISI8087_NOP | + Opcode::FENI8087_NOP | + Opcode::FSETPM287_NOP | + Opcode::PREFETCHNTA | + Opcode::PREFETCH0 | + Opcode::PREFETCH1 | + Opcode::PREFETCH2 | + Opcode::PREFETCHW | + Opcode::NOP => { write!(out, "{}", colors.nop_op(self)) } + + /* Control flow */ + Opcode::HLT | + Opcode::INT | + Opcode::INTO | + Opcode::IRET | + Opcode::IRETD | + Opcode::IRETQ | + Opcode::RETF | + Opcode::RETURN => { write!(out, "{}", colors.stop_op(self)) } + Opcode::LOOPNZ | + Opcode::LOOPZ | + Opcode::LOOP | + Opcode::JCXZ | + Opcode::CALL | + Opcode::CALLF | + Opcode::JMP | + Opcode::JMPF | + Opcode::JO | + Opcode::JNO | + Opcode::JB | + Opcode::JNB | + Opcode::JZ | + Opcode::JNZ | + Opcode::JA | + Opcode::JNA | + Opcode::JS | + Opcode::JNS | + Opcode::JP | + Opcode::JNP | + Opcode::JL | + Opcode::JGE | + Opcode::JLE | + Opcode::JG => { write!(out, "{}", colors.control_flow_op(self)) } + + /* Data transfer */ + Opcode::PI2FW | + Opcode::PI2FD | + Opcode::PF2ID | + Opcode::PF2IW | + Opcode::VCVTDQ2PD | + Opcode::VCVTDQ2PS | + Opcode::VCVTPD2DQ | + Opcode::VCVTPD2PS | + Opcode::VCVTPH2PS | + Opcode::VCVTPS2DQ | + Opcode::VCVTPS2PD | + Opcode::VCVTPS2PH | + Opcode::VCVTTPD2DQ | + Opcode::VCVTTPS2DQ | + Opcode::VCVTSD2SI | + Opcode::VCVTSD2SS | + Opcode::VCVTSI2SD | + Opcode::VCVTSI2SS | + Opcode::VCVTSS2SD | + Opcode::VCVTSS2SI | + Opcode::VCVTTSD2SI | + Opcode::VCVTTSS2SI | + Opcode::VCVTPD2UDQ | + Opcode::VCVTTPD2UDQ | + Opcode::VCVTPS2UDQ | + Opcode::VCVTTPS2UDQ | + Opcode::VCVTQQ2PD | + Opcode::VCVTQQ2PS | + Opcode::VCVTSD2USI | + Opcode::VCVTTSD2USI | + Opcode::VCVTSS2USI | + Opcode::VCVTTSS2USI | + Opcode::VCVTUDQ2PD | + Opcode::VCVTUDQ2PS | + Opcode::VCVTUSI2USD | + Opcode::VCVTUSI2USS | + Opcode::VCVTTPD2QQ | + Opcode::VCVTPD2QQ | + Opcode::VCVTTPD2UQQ | + Opcode::VCVTPD2UQQ | + Opcode::VCVTTPS2QQ | + Opcode::VCVTPS2QQ | + Opcode::VCVTTPS2UQQ | + Opcode::VCVTPS2UQQ | + Opcode::VCVTUQQ2PD | + Opcode::VCVTUQQ2PS | + Opcode::VMOVDDUP | + Opcode::VPSHUFLW | + Opcode::VPSHUFHW | + Opcode::VBLENDMPD | + Opcode::VBLENDMPS | + Opcode::VPBLENDMD | + Opcode::VPBLENDMQ | + Opcode::VBLENDPD | + Opcode::VBLENDPS | + Opcode::VBLENDVPD | + Opcode::VBLENDVPS | + Opcode::VPBLENDMB | + Opcode::VPBLENDMW | + Opcode::PBLENDVB | + Opcode::PBLENDW | + Opcode::BLENDPD | + Opcode::BLENDPS | + Opcode::BLENDVPD | + Opcode::BLENDVPS | + Opcode::BLENDW | + Opcode::VBROADCASTF128 | + Opcode::VBROADCASTI128 | + Opcode::VBROADCASTSD | + Opcode::VBROADCASTSS | + Opcode::VPBROADCASTM | + Opcode::VEXTRACTF128 | + Opcode::VEXTRACTI128 | + Opcode::VEXTRACTPS | + Opcode::EXTRACTPS | + Opcode::VGATHERDPD | + Opcode::VGATHERDPS | + Opcode::VGATHERQPD | + Opcode::VGATHERQPS | + Opcode::VGATHERPF0DPD | + Opcode::VGATHERPF0DPS | + Opcode::VGATHERPF0QPD | + Opcode::VGATHERPF0QPS | + Opcode::VGATHERPF1DPD | + Opcode::VGATHERPF1DPS | + Opcode::VGATHERPF1QPD | + Opcode::VGATHERPF1QPS | + Opcode::VSCATTERDD | + Opcode::VSCATTERDQ | + Opcode::VSCATTERQD | + Opcode::VSCATTERQQ | + Opcode::VPSCATTERDD | + Opcode::VPSCATTERDQ | + Opcode::VPSCATTERQD | + Opcode::VPSCATTERQQ | + Opcode::VSCATTERPF0DPD | + Opcode::VSCATTERPF0DPS | + Opcode::VSCATTERPF0QPD | + Opcode::VSCATTERPF0QPS | + Opcode::VSCATTERPF1DPD | + Opcode::VSCATTERPF1DPS | + Opcode::VSCATTERPF1QPD | + Opcode::VSCATTERPF1QPS | + Opcode::VINSERTF128 | + Opcode::VINSERTI128 | + Opcode::VINSERTPS | + Opcode::INSERTPS | + Opcode::VEXTRACTF32X4 | + Opcode::VEXTRACTF64X2 | + Opcode::VEXTRACTF64X4 | + Opcode::VEXTRACTI32X4 | + Opcode::VEXTRACTI64X2 | + Opcode::VEXTRACTI64X4 | + Opcode::VINSERTF32X4 | + Opcode::VINSERTF64X2 | + Opcode::VINSERTF64X4 | + Opcode::VINSERTI64X2 | + Opcode::VINSERTI64X4 | + Opcode::VSHUFF32X4 | + Opcode::VSHUFF64X2 | + Opcode::VSHUFI32X4 | + Opcode::VSHUFI64X2 | + Opcode::VMASKMOVDQU | + Opcode::VMASKMOVPD | + Opcode::VMASKMOVPS | + Opcode::VMOVAPD | + Opcode::VMOVAPS | + Opcode::VMOVD | + Opcode::VMOVDQA | + Opcode::VMOVDQU | + Opcode::VMOVHLPS | + Opcode::VMOVHPD | + Opcode::VMOVHPS | + Opcode::VMOVLHPS | + Opcode::VMOVLPD | + Opcode::VMOVLPS | + Opcode::VMOVMSKPD | + Opcode::VMOVMSKPS | + Opcode::VMOVNTDQ | + Opcode::VMOVNTDQA | + Opcode::VMOVNTPD | + Opcode::VMOVNTPS | + Opcode::MOVDIR64B | + Opcode::MOVDIRI | + Opcode::MOVNTDQA | + Opcode::VMOVQ | + Opcode::VMOVSHDUP | + Opcode::VMOVSLDUP | + Opcode::VMOVUPD | + Opcode::VMOVUPS | + Opcode::VMOVSD | + Opcode::VMOVSS | + Opcode::VMOVDQA32 | + Opcode::VMOVDQA64 | + Opcode::VMOVDQU32 | + Opcode::VMOVDQU64 | + Opcode::VPMOVM2B | + Opcode::VPMOVM2W | + Opcode::VPMOVB2M | + Opcode::VPMOVW2M | + Opcode::VPMOVSWB | + Opcode::VPMOVUSWB | + Opcode::VPMOVSQB | + Opcode::VPMOVUSQB | + Opcode::VPMOVSQW | + Opcode::VPMOVUSQW | + Opcode::VPMOVSQD | + Opcode::VPMOVUSQD | + Opcode::VPMOVSDB | + Opcode::VPMOVUSDB | + Opcode::VPMOVSDW | + Opcode::VPMOVUSDW | + Opcode::VPMOVM2D | + Opcode::VPMOVM2Q | + Opcode::VPMOVB2D | + Opcode::VPMOVQ2M | + Opcode::VMOVDQU8 | + Opcode::VMOVDQU16 | + + Opcode::VPBLENDD | + Opcode::VPBLENDVB | + Opcode::VPBLENDW | + Opcode::VPBROADCASTB | + Opcode::VPBROADCASTD | + Opcode::VPBROADCASTQ | + Opcode::VPBROADCASTW | + Opcode::VPGATHERDD | + Opcode::VPGATHERDQ | + Opcode::VPGATHERQD | + Opcode::VPGATHERQQ | + Opcode::VPCLMULQDQ | + Opcode::VPMOVMSKB | + Opcode::VPMOVSXBD | + Opcode::VPMOVSXBQ | + Opcode::VPMOVSXBW | + Opcode::VPMOVSXDQ | + Opcode::VPMOVSXWD | + Opcode::VPMOVSXWQ | + Opcode::VPMOVZXBD | + Opcode::VPMOVZXBQ | + Opcode::VPMOVZXBW | + Opcode::VPMOVZXDQ | + Opcode::VPMOVZXWD | + Opcode::VPMOVZXWQ | + Opcode::PMOVSXBD | + Opcode::PMOVSXBQ | + Opcode::PMOVSXBW | + Opcode::PMOVSXDQ | + Opcode::PMOVSXWD | + Opcode::PMOVSXWQ | + Opcode::PMOVZXBD | + Opcode::PMOVZXBQ | + Opcode::PMOVZXBW | + Opcode::PMOVZXDQ | + Opcode::PMOVZXWD | + Opcode::PMOVZXWQ | + Opcode::KUNPCKBW | + Opcode::KUNPCKWD | + Opcode::KUNPCKDQ | + Opcode::VUNPCKHPD | + Opcode::VUNPCKHPS | + Opcode::VUNPCKLPD | + Opcode::VUNPCKLPS | + Opcode::VPUNPCKHBW | + Opcode::VPUNPCKHDQ | + Opcode::VPUNPCKHQDQ | + Opcode::VPUNPCKHWD | + Opcode::VPUNPCKLBW | + Opcode::VPUNPCKLDQ | + Opcode::VPUNPCKLQDQ | + Opcode::VPUNPCKLWD | + Opcode::VSHUFPD | + Opcode::VSHUFPS | + Opcode::VPACKSSDW | + Opcode::VPACKUSDW | + Opcode::PACKUSDW | + Opcode::VPACKSSWB | + Opcode::VPACKUSWB | + Opcode::VALIGND | + Opcode::VALIGNQ | + Opcode::VPALIGNR | + Opcode::PALIGNR | + Opcode::VPERM2F128 | + Opcode::VPERM2I128 | + Opcode::VPERMD | + Opcode::VPERMILPD | + Opcode::VPERMILPS | + Opcode::VPERMPD | + Opcode::VPERMPS | + Opcode::VPERMQ | + Opcode::VPERMI2D | + Opcode::VPERMI2Q | + Opcode::VPERMI2PD | + Opcode::VPERMI2PS | + Opcode::VPERMT2D | + Opcode::VPERMT2Q | + Opcode::VPERMT2PD | + Opcode::VPERMT2PS | + Opcode::VPERMI2B | + Opcode::VPERMI2W | + Opcode::VPERMW | + Opcode::VPEXTRB | + Opcode::VPEXTRD | + Opcode::VPEXTRQ | + Opcode::VPEXTRW | + Opcode::PEXTRB | + Opcode::PEXTRD | + Opcode::PEXTRQ | + Opcode::EXTRQ | + Opcode::PINSRB | + Opcode::PINSRD | + Opcode::PINSRQ | + Opcode::INSERTQ | + Opcode::VPINSRB | + Opcode::VPINSRD | + Opcode::VPINSRQ | + Opcode::VPINSRW | + Opcode::VPMASKMOVD | + Opcode::VPMASKMOVQ | + Opcode::VCOMPRESSPD | + Opcode::VCOMPRESSPS | + Opcode::VPCOMPRESSQ | + Opcode::VPCOMPRESSD | + Opcode::VEXPANDPD | + Opcode::VEXPANDPS | + Opcode::VPSHUFB | + Opcode::VPSHUFD | + Opcode::VPHMINPOSUW | + Opcode::PHMINPOSUW | + Opcode::VZEROUPPER | + Opcode::VZEROALL | + Opcode::VFIXUPIMMPD | + Opcode::VFIXUPIMMPS | + Opcode::VFIXUPIMMSD | + Opcode::VFIXUPIMMSS | + Opcode::VREDUCEPD | + Opcode::VREDUCEPS | + Opcode::VREDUCESD | + Opcode::VREDUCESS | + Opcode::VGETEXPPD | + Opcode::VGETEXPPS | + Opcode::VGETEXPSD | + Opcode::VGETEXPSS | + Opcode::VGETMANTPD | + Opcode::VGETMANTPS | + Opcode::VGETMANTSD | + Opcode::VGETMANTSS | + Opcode::VLDDQU | + Opcode::BSWAP | + Opcode::CVTDQ2PD | + Opcode::CVTDQ2PS | + Opcode::CVTPS2DQ | + Opcode::CVTPD2DQ | + Opcode::CVTPI2PS | + Opcode::CVTPI2PD | + Opcode::CVTPS2PD | + Opcode::CVTPD2PS | + Opcode::CVTPS2PI | + Opcode::CVTPD2PI | + Opcode::CVTSD2SI | + Opcode::CVTSD2SS | + Opcode::CVTSI2SD | + Opcode::CVTSI2SS | + Opcode::CVTSS2SD | + Opcode::CVTSS2SI | + Opcode::CVTTPD2DQ | + Opcode::CVTTPS2DQ | + Opcode::CVTTPS2PI | + Opcode::CVTTPD2PI | + Opcode::CVTTSD2SI | + Opcode::CVTTSS2SI | + Opcode::MASKMOVQ | + Opcode::MASKMOVDQU | + Opcode::MOVAPS | + Opcode::MOVAPD | + Opcode::MOVD | + Opcode::MOVHPS | + Opcode::MOVHPD | + Opcode::MOVHLPS | + Opcode::MOVLPS | + Opcode::MOVLPD | + Opcode::MOVLHPS | + Opcode::MOVMSKPS | + Opcode::MOVMSKPD | + Opcode::MOVNTI | + Opcode::MOVNTPS | + Opcode::MOVNTPD | + Opcode::MOVNTSS | + Opcode::MOVNTSD | + Opcode::MOVNTQ | + Opcode::MOVNTDQ | + Opcode::MOVSD | + Opcode::MOVSS | + Opcode::MOVUPD | + Opcode::PSHUFHW | + Opcode::PSHUFLW | + Opcode::PUNPCKHBW | + Opcode::PUNPCKHDQ | + Opcode::PUNPCKHWD | + Opcode::PUNPCKLBW | + Opcode::PUNPCKLDQ | + Opcode::PUNPCKLWD | + Opcode::PUNPCKLQDQ | + Opcode::PUNPCKHQDQ | + Opcode::PACKSSDW | + Opcode::PACKSSWB | + Opcode::PACKUSWB | + Opcode::UNPCKHPS | + Opcode::UNPCKHPD | + Opcode::UNPCKLPS | + Opcode::UNPCKLPD | + Opcode::SHUFPD | + Opcode::SHUFPS | + Opcode::PMOVMSKB | + Opcode::KMOVB | + Opcode::KMOVW | + Opcode::KMOVD | + Opcode::KMOVQ | + Opcode::BNDMOV | + Opcode::LDDQU | + Opcode::CMC | + Opcode::CLC | + Opcode::CLI | + Opcode::CLD | + Opcode::STC | + Opcode::STI | + Opcode::STD | + Opcode::CBW | + Opcode::CWDE | + Opcode::CDQE | + Opcode::CWD | + Opcode::CDQ | + Opcode::CQO | + Opcode::MOVDDUP | + Opcode::MOVSLDUP | + Opcode::MOVDQ2Q | + Opcode::MOVDQU | + Opcode::MOVDQA | + Opcode::MOVQ | + Opcode::MOVQ2DQ | + Opcode::MOVSHDUP | + Opcode::MOVUPS | + Opcode::PEXTRW | + Opcode::PINSRW | + Opcode::MOV | + Opcode::MOVBE | + Opcode::LODS | + Opcode::STOS | + Opcode::LAHF | + Opcode::SAHF | + Opcode::MOVS | + Opcode::INS | + Opcode::IN | + Opcode::OUTS | + Opcode::OUT | + Opcode::MOVZX | + Opcode::MOVSX | + Opcode::MOVSXD | + Opcode::FILD | + Opcode::FBLD | + Opcode::FBSTP | + Opcode::FIST | + Opcode::FISTP | + Opcode::FISTTP | + Opcode::FLD | + Opcode::FLD1 | + Opcode::FLDCW | + Opcode::FLDENV | + Opcode::FLDL2E | + Opcode::FLDL2T | + Opcode::FLDLG2 | + Opcode::FLDLN2 | + Opcode::FLDPI | + Opcode::FLDZ | + Opcode::FST | + Opcode::FSTP | + Opcode::FSTPNCE | + Opcode::FNSAVE | + Opcode::FNSTCW | + Opcode::FNSTENV | + Opcode::FNSTOR | + Opcode::FNSTSW | + Opcode::FRSTOR | + Opcode::FXCH | + Opcode::XCHG | + Opcode::XLAT | + Opcode::CMOVA | + Opcode::CMOVB | + Opcode::CMOVG | + Opcode::CMOVGE | + Opcode::CMOVL | + Opcode::CMOVLE | + Opcode::CMOVNA | + Opcode::CMOVNB | + Opcode::CMOVNO | + Opcode::CMOVNP | + Opcode::CMOVNS | + Opcode::CMOVNZ | + Opcode::CMOVO | + Opcode::CMOVP | + Opcode::CMOVS | + Opcode::CMOVZ | + Opcode::FCMOVB | + Opcode::FCMOVBE | + Opcode::FCMOVE | + Opcode::FCMOVNB | + Opcode::FCMOVNBE | + Opcode::FCMOVNE | + Opcode::FCMOVNU | + Opcode::FCMOVU | + Opcode::SALC | + Opcode::SETO | + Opcode::SETNO | + Opcode::SETB | + Opcode::SETAE | + Opcode::SETZ | + Opcode::SETNZ | + Opcode::SETBE | + Opcode::SETA | + Opcode::SETS | + Opcode::SETNS | + Opcode::SETP | + Opcode::SETNP | + Opcode::SETL | + Opcode::SETGE | + Opcode::SETLE | + Opcode::SETG => { write!(out, "{}", colors.data_op(self)) } + + Opcode::VCOMISD | + Opcode::VCOMISS | + Opcode::VUCOMISD | + Opcode::VUCOMISS | + Opcode::KORTESTB | + Opcode::KTESTB | + Opcode::KORTESTW | + Opcode::KTESTW | + Opcode::KORTESTD | + Opcode::KTESTD | + Opcode::KORTESTQ | + Opcode::KTESTQ | + Opcode::VPTESTNMD | + Opcode::VPTESTNMQ | + Opcode::VPTERNLOGD | + Opcode::VPTERNLOGQ | + Opcode::VPTESTMD | + Opcode::VPTESTMQ | + Opcode::VPTESTNMB | + Opcode::VPTESTNMW | + Opcode::VPTESTMB | + Opcode::VPTESTMW | + Opcode::VPCMPD | + Opcode::VPCMPUD | + Opcode::VPCMPQ | + Opcode::VPCMPUQ | + Opcode::VPCMPB | + Opcode::VPCMPUB | + Opcode::VPCMPW | + Opcode::VPCMPUW | + Opcode::VCMPPD | + Opcode::VCMPPS | + Opcode::VCMPSD | + Opcode::VCMPSS | + Opcode::VMAXPD | + Opcode::VMAXPS | + Opcode::VMAXSD | + Opcode::VMAXSS | + Opcode::VPMAXSQ | + Opcode::VPMAXUQ | + Opcode::VPMINSQ | + Opcode::VPMINUQ | + Opcode::VMINPD | + Opcode::VMINPS | + Opcode::VMINSD | + Opcode::VMINSS | + Opcode::VPCMPEQB | + Opcode::VPCMPEQD | + Opcode::VPCMPEQQ | + Opcode::VPCMPEQW | + Opcode::VPCMPGTB | + Opcode::VPCMPGTD | + Opcode::VPCMPGTQ | + Opcode::VPCMPGTW | + Opcode::VPCMPESTRI | + Opcode::VPCMPESTRM | + Opcode::VPCMPISTRI | + Opcode::VPCMPISTRM | + Opcode::VPMAXSB | + Opcode::VPMAXSD | + Opcode::VPMAXSW | + Opcode::VPMAXUB | + Opcode::VPMAXUW | + Opcode::VPMAXUD | + Opcode::VPMINSB | + Opcode::VPMINSW | + Opcode::VPMINSD | + Opcode::VPMINUB | + Opcode::VPMINUW | + Opcode::VPMINUD | + Opcode::VFPCLASSPD | + Opcode::VFPCLASSPS | + Opcode::VFPCLASSSD | + Opcode::VFPCLASSSS | + Opcode::VRANGEPD | + Opcode::VRANGEPS | + Opcode::VRANGESD | + Opcode::VRANGESS | + Opcode::VPCONFLICTD | + Opcode::VPCONFLICTQ | + Opcode::VPTEST | + Opcode::VTESTPD | + Opcode::VTESTPS | + Opcode::PCMPEQB | + Opcode::PCMPEQD | + Opcode::PCMPEQQ | + Opcode::PCMPEQW | + Opcode::PCMPESTRI | + Opcode::PCMPESTRM | + Opcode::PCMPGTB | + Opcode::PCMPGTD | + Opcode::PCMPGTQ | + Opcode::PCMPGTW | + Opcode::PCMPISTRI | + Opcode::PCMPISTRM | + Opcode::PTEST | + Opcode::MAXPD | + Opcode::MAXPS | + Opcode::MAXSD | + Opcode::MAXSS | + Opcode::MINPD | + Opcode::MINPS | + Opcode::MINSD | + Opcode::MINSS | + Opcode::PMAXSB | + Opcode::PMAXSD | + Opcode::PMAXSW | + Opcode::PMAXUB | + Opcode::PMAXUD | + Opcode::PMAXUW | + Opcode::PMINSB | + Opcode::PMINSD | + Opcode::PMINSW | + Opcode::PMINUB | + Opcode::PMINUD | + Opcode::PMINUW | + Opcode::PFCMPGE | + Opcode::PFMIN | + Opcode::PFCMPGT | + Opcode::PFMAX | + Opcode::PFCMPEQ | + Opcode::CMPS | + Opcode::SCAS | + Opcode::TEST | + Opcode::FTST | + Opcode::FXAM | + Opcode::FUCOM | + Opcode::FUCOMI | + Opcode::FUCOMIP | + Opcode::FUCOMP | + Opcode::FUCOMPP | + Opcode::FCOM | + Opcode::FCOMI | + Opcode::FCOMIP | + Opcode::FCOMP | + Opcode::FCOMPP | + Opcode::FICOM | + Opcode::FICOMP | + Opcode::CMPSD | + Opcode::CMPSS | + Opcode::CMP | + Opcode::CMPPS | + Opcode::CMPPD | + Opcode::CMPXCHG8B | + Opcode::CMPXCHG16B | + Opcode::CMPXCHG => { write!(out, "{}", colors.comparison_op(self)) } + + Opcode::WRMSR | + Opcode::RDMSR | + Opcode::RDTSC | + Opcode::RDPMC | + Opcode::RDPID | + Opcode::RDFSBASE | + Opcode::RDGSBASE | + Opcode::WRFSBASE | + Opcode::WRGSBASE | + Opcode::FXSAVE | + Opcode::FXRSTOR | + Opcode::LDMXCSR | + Opcode::STMXCSR | + Opcode::VLDMXCSR | + Opcode::VSTMXCSR | + Opcode::XSAVE | + Opcode::XSAVEC | + Opcode::XSAVES | + Opcode::XSAVEC64 | + Opcode::XSAVES64 | + Opcode::XRSTOR | + Opcode::XRSTORS | + Opcode::XRSTORS64 | + Opcode::XSAVEOPT | + Opcode::LFENCE | + Opcode::MFENCE | + Opcode::SFENCE | + Opcode::CLFLUSH | + Opcode::CLFLUSHOPT | + Opcode::CLWB | + Opcode::LDS | + Opcode::LES | + Opcode::SGDT | + Opcode::SIDT | + Opcode::LGDT | + Opcode::LIDT | + Opcode::SMSW | + Opcode::LMSW | + Opcode::SWAPGS | + Opcode::RDTSCP | + Opcode::INVEPT | + Opcode::INVVPID | + Opcode::INVPCID | + Opcode::INVLPG | + Opcode::INVLPGA | + Opcode::INVLPGB | + Opcode::TLBSYNC | + Opcode::PSMASH | + Opcode::PVALIDATE | + Opcode::RMPADJUST | + Opcode::RMPUPDATE | + Opcode::CPUID | + Opcode::WBINVD | + Opcode::INVD | + Opcode::SYSRET | + Opcode::CLTS | + Opcode::SYSCALL | + Opcode::TDCALL | + Opcode::SEAMRET | + Opcode::SEAMOPS | + Opcode::SEAMCALL | + Opcode::TPAUSE | + Opcode::UMONITOR | + Opcode::UMWAIT | + Opcode::LSL | + Opcode::SLDT | + Opcode::STR | + Opcode::LLDT | + Opcode::LTR | + Opcode::VERR | + Opcode::VERW | + Opcode::JMPE | + Opcode::EMMS | + Opcode::FEMMS | + Opcode::GETSEC | + Opcode::LFS | + Opcode::LGS | + Opcode::LSS | + Opcode::RSM | + Opcode::SYSENTER | + Opcode::SYSEXIT | + Opcode::VMREAD | + Opcode::VMWRITE | + Opcode::VMCLEAR | + Opcode::VMPTRLD | + Opcode::VMPTRST | + Opcode::VMXON | + Opcode::VMCALL | + Opcode::VMLAUNCH | + Opcode::VMRESUME | + Opcode::VMLOAD | + Opcode::VMMCALL | + Opcode::VMSAVE | + Opcode::VMRUN | + Opcode::VMXOFF | + Opcode::PCONFIG | + Opcode::MONITOR | + Opcode::MWAIT | + Opcode::MONITORX | + Opcode::MWAITX | + Opcode::SKINIT | + Opcode::CLGI | + Opcode::STGI | + Opcode::CLAC | + Opcode::STAC | + Opcode::ENCLS | + Opcode::ENCLV | + Opcode::XGETBV | + Opcode::XSETBV | + Opcode::VMFUNC | + Opcode::XEND | + Opcode::XTEST | + Opcode::XABORT | + Opcode::XBEGIN | + Opcode::ENCLU | + Opcode::RDPKRU | + Opcode::WRPKRU | + Opcode::RDPRU | + Opcode::CLZERO | + Opcode::ENQCMD | + Opcode::ENQCMDS | + Opcode::PTWRITE | + Opcode::UIRET | + Opcode::TESTUI | + Opcode::CLUI | + Opcode::STUI | + Opcode::SENDUIPI | + Opcode::XSUSLDTRK | + Opcode::XRESLDTRK | + Opcode::BOUND | + Opcode::ARPL | + Opcode::BNDMK | + Opcode::BNDCL | + Opcode::BNDCU | + Opcode::BNDCN | + Opcode::BNDLDX | + Opcode::BNDSTX | + Opcode::LAR => { write!(out, "{}", colors.platform_op(self)) } + + Opcode::CRC32 | + Opcode::RDSEED | + Opcode::RDRAND | + Opcode::SHA1RNDS4 | + Opcode::SHA1NEXTE | + Opcode::SHA1MSG1 | + Opcode::SHA1MSG2 | + Opcode::SHA256RNDS2 | + Opcode::SHA256MSG1 | + Opcode::SHA256MSG2 | + Opcode::FFREE | + Opcode::FFREEP | + Opcode::FDECSTP | + Opcode::FINCSTP | + Opcode::GF2P8MULB | + Opcode::GF2P8AFFINEQB | + Opcode::GF2P8AFFINEINVQB | + Opcode::AESDEC128KL | + Opcode::AESDEC256KL | + Opcode::AESDECWIDE128KL | + Opcode::AESDECWIDE256KL | + Opcode::AESENC128KL | + Opcode::AESENC256KL | + Opcode::AESENCWIDE128KL | + Opcode::AESENCWIDE256KL | + Opcode::ENCODEKEY128 | + Opcode::ENCODEKEY256 | + Opcode::LOADIWKEY | + Opcode::HRESET | + Opcode::WRUSS | + Opcode::WRSS | + Opcode::INCSSP | + Opcode::SAVEPREVSSP | + Opcode::SETSSBSY | + Opcode::CLRSSBSY | + Opcode::RSTORSSP | + Opcode::AESDEC | + Opcode::AESDECLAST | + Opcode::AESENC | + Opcode::AESENCLAST | + Opcode::AESIMC | + Opcode::AESKEYGENASSIST | + Opcode::VAESDEC | + Opcode::VAESDECLAST | + Opcode::VAESENC | + Opcode::VAESENCLAST | + Opcode::VAESIMC | + Opcode::VAESKEYGENASSIST => { write!(out, "{}", colors.misc_op(self)) } + + Opcode::UD0 | + Opcode::UD1 | + Opcode::UD2 | + Opcode::Invalid => { write!(out, "{}", colors.invalid_op(self)) } + } + } +} + +impl fmt::Display for Instruction { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + self.display_with(DisplayStyle::Intel).colorize(&NoColors, fmt) + } +} + +impl<'instr> fmt::Display for InstructionDisplayer<'instr> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + self.colorize(&NoColors, fmt) + } +} + +/// enum controlling how `Instruction::display_with` renders instructions. `Intel` is more or less +/// intel syntax, though memory operand sizes are elided if they can be inferred from other +/// operands. +#[derive(Copy, Clone)] +pub enum DisplayStyle { + /// intel-style syntax for instructions, like + /// `add eax, [edx + ecx * 2 + 0x1234]` + Intel, + /// C-style syntax for instructions, like + /// `eax += [edx + ecx * 2 + 0x1234]` + C, + // one might imagine an ATT style here, which is mostly interesting for reversing operand + // order. + // well. + // it also complicates memory operands in an offset-only operand, and is just kind of awful, so + // it's just not implemented yet. + // ATT, +} + +pub struct InstructionDisplayer<'instr> { + pub(crate) instr: &'instr Instruction, + pub(crate) style: DisplayStyle, +} + +/* + * Can't implement this as accepting a formatter because rust + * doesn't let me build one outside println! or write! or whatever. + * + * can't write this as an intermediate struct because i refuse to copy + * all data into the struct, and having a function producing a struct with + * some lifetimes gets really hairy if it's from a trait - same GAT kind + * of nonsense as i saw with ContextRead, because someone could hold onto + * the dang intermediate struct forever. + * + * so write to some Write thing i guess. bite me. i really just want to + * stop thinking about how to support printing instructions... + */ +impl <'instr, T: fmt::Write, Y: YaxColors> Colorize for InstructionDisplayer<'instr> { + fn colorize(&self, colors: &Y, out: &mut T) -> fmt::Result { + // TODO: I DONT LIKE THIS, there is no address i can give contextualize here, + // the address operand maybe should be optional.. + self.contextualize(colors, 0, Some(&NoContext), out) + } +} + +/// No per-operand context when contextualizing an instruction! +struct NoContext; + +impl Instruction { + pub fn write_to(&self, out: &mut T) -> fmt::Result { + self.display_with(DisplayStyle::Intel).contextualize(&NoColors, 0, Some(&NoContext), out) + } +} + +fn contextualize_intel(instr: &Instruction, colors: &Y, _address: u32, _context: Option<&NoContext>, out: &mut T) -> fmt::Result { + if instr.prefixes.lock() { + write!(out, "lock ")?; + } + + if instr.prefixes.rep_any() { + if [Opcode::MOVS, Opcode::CMPS, Opcode::LODS, Opcode::STOS, Opcode::INS, Opcode::OUTS].contains(&instr.opcode) { + if instr.prefixes.rep() { + write!(out, "rep ")?; + } else if instr.prefixes.repnz() { + write!(out, "repnz ")?; + } + } + } + + out.write_str(instr.opcode.name())?; + + if instr.opcode == Opcode::XBEGIN { + return write!(out, " $+{}", colors.number(signed_i32_hex(instr.imm as i32))); + } + + if instr.operand_count > 0 { + out.write_str(" ")?; + + let x = Operand::from_spec(instr, instr.operands[0]); + if x.is_memory() { + out.write_str(MEM_SIZE_STRINGS[instr.mem_size as usize - 1])?; + out.write_str(" ")?; + } + + if let Some(prefix) = instr.segment_override_for_op(0) { + write!(out, "{}:", prefix)?; + } + x.colorize(colors, out)?; + + for i in 1..instr.operand_count { + match instr.opcode { + _ => { + match &instr.operands[i as usize] { + &OperandSpec::Nothing => { + return Ok(()); + }, + _ => { + out.write_str(", ")?; + let x = Operand::from_spec(instr, instr.operands[i as usize]); + if x.is_memory() { + out.write_str(MEM_SIZE_STRINGS[instr.mem_size as usize - 1])?; + out.write_str(" ")?; + } + if let Some(prefix) = instr.segment_override_for_op(i) { + write!(out, "{}:", prefix)?; + } + x.colorize(colors, out)?; + if let Some(evex) = instr.prefixes.evex() { + if evex.broadcast() && x.is_memory() { + let scale = if instr.opcode == Opcode::VCVTPD2PS || instr.opcode == Opcode::VCVTTPD2UDQ || instr.opcode == Opcode::VCVTPD2UDQ || instr.opcode == Opcode::VCVTUDQ2PD || instr.opcode == Opcode::VCVTPS2PD || instr.opcode == Opcode::VCVTQQ2PS || instr.opcode == Opcode::VCVTDQ2PD || instr.opcode == Opcode::VCVTTPD2DQ || instr.opcode == Opcode::VFPCLASSPS || instr.opcode == Opcode::VFPCLASSPD || instr.opcode == Opcode::VCVTNEPS2BF16 || instr.opcode == Opcode::VCVTUQQ2PS || instr.opcode == Opcode::VCVTPD2DQ || instr.opcode == Opcode::VCVTTPS2UQQ || instr.opcode == Opcode::VCVTPS2UQQ || instr.opcode == Opcode::VCVTTPS2QQ || instr.opcode == Opcode::VCVTPS2QQ { + if instr.opcode == Opcode::VFPCLASSPS || instr.opcode == Opcode::VCVTNEPS2BF16 { + if evex.vex().l() { + 8 + } else if evex.lp() { + 16 + } else { + 4 + } + } else if instr.opcode == Opcode::VFPCLASSPD { + if evex.vex().l() { + 4 + } else if evex.lp() { + 8 + } else { + 2 + } + } else { + // vcvtpd2ps is "cool": in broadcast mode, it can read a + // double-precision float (qword), resize to single-precision, + // then broadcast that to the whole destination register. this + // means we need to show `xmm, qword [addr]{1to4}` if vector + // size is 256. likewise, scale of 8 for the same truncation + // reason if vector size is 512. + // vcvtudq2pd is the same story. + // vfpclassp{s,d} is a mystery to me. + if evex.vex().l() { + 4 + } else if evex.lp() { + 8 + } else { + 2 + } + } + } else { + // this should never be `None` - that would imply two + // memory operands for a broadcasted operation. + if let Some(width) = Operand::from_spec(instr, instr.operands[i as usize - 1]).width() { + width / instr.mem_size + } else { + 0 + } + }; + write!(out, "{{1to{}}}", scale)?; + } + } + } + } + } + } + } + } + Ok(()) +} + +fn contextualize_c(instr: &Instruction, _colors: &Y, _address: u32, _context: Option<&NoContext>, out: &mut T) -> fmt::Result { + let mut brace_count = 0; + + if instr.prefixes.lock() { + out.write_str("lock { ")?; + brace_count += 1; + } + + if instr.prefixes.rep_any() { + if [Opcode::MOVS, Opcode::CMPS, Opcode::LODS, Opcode::STOS, Opcode::INS, Opcode::OUTS].contains(&instr.opcode) { + let word_str = match instr.mem_size { + 1 => "byte", + 2 => "word", + 4 => "dword", + 8 => "qword", + _ => { unreachable!("invalid word size") } + }; + + // only a few of you actually use the prefix... + if instr.prefixes.rep() { + out.write_str("rep ")?; + } else if instr.prefixes.repnz() { + out.write_str("repnz ")?; + } // TODO: other rep kinds? + + out.write_str(word_str)?; + out.write_str(" { ")?; + brace_count += 1; + } + } + + match instr.opcode { + Opcode::Invalid => { out.write_str("invalid")?; }, + Opcode::MOVS => { + out.write_str("es:[edi++] = ds:[esi++]")?; + }, + Opcode::CMPS => { + out.write_str("eflags = flags(ds:[esi++] - es:[edi++])")?; + }, + Opcode::LODS => { + // TODO: size + out.write_str("rax = ds:[esi++]")?; + }, + Opcode::STOS => { + // TODO: size + out.write_str("es:[edi++] = rax")?; + }, + Opcode::INS => { + // TODO: size + out.write_str("es:[edi++] = port(dx)")?; + }, + Opcode::OUTS => { + // TODO: size + out.write_str("port(dx) = ds:[esi++]")?; + } + Opcode::ADD => { + write!(out, "{} += {}", instr.operand(0), instr.operand(1))?; + } + Opcode::OR => { + write!(out, "{} |= {}", instr.operand(0), instr.operand(1))?; + } + Opcode::ADC => { + write!(out, "{} += {} + eflags.cf", instr.operand(0), instr.operand(1))?; + } + Opcode::ADCX => { + write!(out, "{} += {} + eflags.cf", instr.operand(0), instr.operand(1))?; + } + Opcode::ADOX => { + write!(out, "{} += {} + eflags.of", instr.operand(0), instr.operand(1))?; + } + Opcode::SBB => { + write!(out, "{} -= {} + eflags.cf", instr.operand(0), instr.operand(1))?; + } + Opcode::AND => { + write!(out, "{} &= {}", instr.operand(0), instr.operand(1))?; + } + Opcode::XOR => { + write!(out, "{} ^= {}", instr.operand(0), instr.operand(1))?; + } + Opcode::SUB => { + write!(out, "{} -= {}", instr.operand(0), instr.operand(1))?; + } + Opcode::CMP => { + write!(out, "eflags = flags({} - {})", instr.operand(0), instr.operand(1))?; + } + Opcode::TEST => { + write!(out, "eflags = flags({} & {})", instr.operand(0), instr.operand(1))?; + } + Opcode::XADD => { + write!(out, "({}, {}) = ({} + {}, {})", instr.operand(0), instr.operand(1), instr.operand(0), instr.operand(1), instr.operand(0))?; + } + Opcode::BT => { + write!(out, "bt")?; + } + Opcode::BTS => { + write!(out, "bts")?; + } + Opcode::BTC => { + write!(out, "btc")?; + } + Opcode::BSR => { + write!(out, "{} = msb({})", instr.operand(0), instr.operand(1))?; + } + Opcode::BSF => { + write!(out, "{} = lsb({}) (x86 bsf)", instr.operand(0), instr.operand(1))?; + } + Opcode::TZCNT => { + write!(out, "{} = lsb({})", instr.operand(0), instr.operand(1))?; + } + Opcode::MOV => { + write!(out, "{} = {}", instr.operand(0), instr.operand(1))?; + } + Opcode::SAR => { + write!(out, "{} = {} >>> {}", instr.operand(0), instr.operand(0), instr.operand(1))?; + } + Opcode::SAL => { + write!(out, "{} = {} <<< {}", instr.operand(0), instr.operand(0), instr.operand(1))?; + } + Opcode::SHR => { + write!(out, "{} = {} >> {}", instr.operand(0), instr.operand(0), instr.operand(1))?; + } + Opcode::SHRX => { + write!(out, "{} = {} >> {} (x86 shrx)", instr.operand(0), instr.operand(1), instr.operand(2))?; + } + Opcode::SHL => { + write!(out, "{} = {} << {}", instr.operand(0), instr.operand(0), instr.operand(1))?; + } + Opcode::SHLX => { + write!(out, "{} = {} << {} (x86 shlx)", instr.operand(0), instr.operand(1), instr.operand(2))?; + } + Opcode::ROR => { + write!(out, "{} = {} ror {}", instr.operand(0), instr.operand(0), instr.operand(1))?; + } + Opcode::RORX => { + write!(out, "{} = {} ror {} (x86 rorx)", instr.operand(0), instr.operand(1), instr.operand(2))?; + } + Opcode::ROL => { + write!(out, "{} = {} rol {}", instr.operand(0), instr.operand(0), instr.operand(1))?; + } + Opcode::RCR => { + write!(out, "{} = {} rcr {}", instr.operand(0), instr.operand(0), instr.operand(1))?; + } + Opcode::RCL => { + write!(out, "{} = {} rcl {}", instr.operand(0), instr.operand(0), instr.operand(1))?; + } + Opcode::PUSH => { + write!(out, "push({})", instr.operand(0))?; + } + Opcode::POP => { + write!(out, "{} = pop()", instr.operand(0))?; + } + Opcode::MOVD => { + write!(out, "{} = movd({})", instr.operand(0), instr.operand(1))?; + } + Opcode::MOVQ => { + write!(out, "{} = movq({})", instr.operand(0), instr.operand(1))?; + } + Opcode::MOVNTQ => { + write!(out, "{} = movntq({})", instr.operand(0), instr.operand(1))?; + } + Opcode::INC => { + if instr.operand(0).is_memory() { + match instr.mem_size { + 1 => { write!(out, "byte {}++", instr.operand(0))?; }, + 2 => { write!(out, "word {}++", instr.operand(0))?; }, + 4 => { write!(out, "dword {}++", instr.operand(0))?; }, + _ => { write!(out, "qword {}++", instr.operand(0))?; }, // sizes that are not 1, 2, or 4, *better* be 8. + } + } else { + write!(out, "{}++", instr.operand(0))?; + } + } + Opcode::DEC => { + if instr.operand(0).is_memory() { + match instr.mem_size { + 1 => { write!(out, "byte {}--", instr.operand(0))?; }, + 2 => { write!(out, "word {}--", instr.operand(0))?; }, + 4 => { write!(out, "dword {}--", instr.operand(0))?; }, + _ => { write!(out, "qword {}--", instr.operand(0))?; }, // sizes that are not 1, 2, or 4, *better* be 8. + } + } else { + write!(out, "{}--", instr.operand(0))?; + } + } + Opcode::JG => { + write!(out, "if greater(eflags) then jmp {}", instr.operand(0))?; + } + Opcode::NOP => { + write!(out, "nop")?; + } + _ => { + if instr.operand_count() == 0 { + write!(out, "{}()", instr.opcode())?; + } else { + write!(out, "{} = {}({}", instr.operand(0), instr.opcode(), instr.operand(0))?; + let mut comma = true; + for i in 1..instr.operand_count() { + if comma { + write!(out, ", ")?; + } + write!(out, "{}", instr.operand(i))?; + comma = true; + } + write!(out, ")")?; + } + } + } + + while brace_count > 0 { + out.write_str(" }")?; + brace_count -= 1; + } + + Ok(()) +} + +impl <'instr, T: fmt::Write, Y: YaxColors> ShowContextual for InstructionDisplayer<'instr> { + fn contextualize(&self, colors: &Y, address: u32, context: Option<&NoContext>, out: &mut T) -> fmt::Result { + let InstructionDisplayer { + instr, + style, + } = self; + + match style { + DisplayStyle::Intel => { + contextualize_intel(instr, colors, address, context, out) + } + DisplayStyle::C => { + contextualize_c(instr, colors, address, context, out) + } + } + } +} + +#[cfg(feature="std")] +impl ShowContextual], T, Y> for Instruction { + fn contextualize(&self, colors: &Y, _address: u64, context: Option<&[Option]>, out: &mut T) -> fmt::Result { + if self.prefixes.lock() { + write!(out, "lock ")?; + } + + if [Opcode::MOVS, Opcode::CMPS, Opcode::LODS, Opcode::STOS, Opcode::INS, Opcode::OUTS].contains(&self.opcode) { + // only a few of you actually use the prefix... + if self.prefixes.rep() { + write!(out, "rep ")?; + } else if self.prefixes.repnz() { + write!(out, "repnz ")?; + } + } + + self.opcode.colorize(colors, out)?; + + match context.and_then(|xs| xs[0].as_ref()) { + Some(s) => { write!(out, " {}", s)?; }, + None => { + match self.operands[0] { + OperandSpec::Nothing => { + return Ok(()); + }, + _ => { + write!(out, " ")?; + if let Some(prefix) = self.segment_override_for_op(0) { + write!(out, "{}:", prefix)?; + } + } + } + let x = Operand::from_spec(self, self.operands[0]); + x.colorize(colors, out)?; + } + }; + for i in 1..self.operand_count { + let i = i as usize; + match context.and_then(|xs| xs[i].as_ref()) { + Some(s) => { write!(out, ", {}", s)? } + None => { + match &self.operands[i] { + &OperandSpec::Nothing => { + return Ok(()); + }, + _ => { + write!(out, ", ")?; + if let Some(prefix) = self.segment_override_for_op(1) { + write!(out, "{}:", prefix)?; + } + let x = Operand::from_spec(self, self.operands[i]); + x.colorize(colors, out)? + } + } + } + } + } + Ok(()) + } +} diff --git a/src/real_mode/evex.rs b/src/real_mode/evex.rs new file mode 100644 index 0000000..9840b35 --- /dev/null +++ b/src/real_mode/evex.rs @@ -0,0 +1,18 @@ +// use crate::long_mode::{OperandSpec, DecodeError, RegSpec, RegisterBank, Instruction, Opcode}; +use crate::real_mode::{Arch, DecodeError, RegSpec, RegisterBank, Instruction, Opcode}; +use crate::real_mode::{read_modrm, read_E_vex, read_imm_unsigned}; +use yaxpeax_arch::Reader; + +const DEFAULT_EVEX_REGISTER_SIZE: RegisterBank = RegisterBank::D; +const DEFAULT_EVEX_REGISTER_WIDTH: u8 = 4; + +fn isa_has_qwords() -> bool { + false +} + +fn apply_disp_scale(inst: &mut Instruction) { + inst.disp *= inst.mem_size as u32; +} + +include!("../shared/generated_evex.in"); +include!("../shared/evex.in"); diff --git a/src/real_mode/mod.rs b/src/real_mode/mod.rs index de7ec27..8376230 100644 --- a/src/real_mode/mod.rs +++ b/src/real_mode/mod.rs @@ -1 +1,10676 @@ -pub struct Arch {} +mod vex; +mod evex; +#[cfg(feature = "fmt")] +mod display; +pub mod uarch; + +pub use MemoryAccessSize; + +#[cfg(feature = "fmt")] +pub use self::display::DisplayStyle; + +use core::cmp::PartialEq; +use core::hint::unreachable_unchecked; + +use yaxpeax_arch::{AddressDiff, Decoder, Reader, LengthedInstruction}; +use yaxpeax_arch::{DecodeError as ArchDecodeError}; + +use core::fmt; +impl fmt::Display for DecodeError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(self.description()) + } +} + +/// an `x86` register, including its number and type. if `fmt` is enabled, name too. +/// +/// ``` +/// use yaxpeax_x86::long_mode::{RegSpec, register_class}; +/// +/// assert_eq!(RegSpec::ecx().num(), 1); +/// assert_eq!(RegSpec::ecx().class(), register_class::D); +/// ``` +/// +/// some registers have classes of their own, and only one member: `eip` and `eflags`. +#[cfg_attr(feature="use-serde", derive(Serialize, Deserialize))] +#[derive(Copy, Clone, Debug, PartialOrd, Ord, Eq, PartialEq)] +pub struct RegSpec { + num: u8, + bank: RegisterBank +} + +use core::hash::Hash; +use core::hash::Hasher; +impl Hash for RegSpec { + fn hash(&self, state: &mut H) { + let code = ((self.bank as u16) << 8) | (self.num as u16); + code.hash(state); + } +} + +/// the condition for a conditional instruction. +/// +/// these are only obtained through [`Opcode::condition()`]: +/// ``` +/// use yaxpeax_x86::long_mode::{Opcode, ConditionCode}; +/// +/// assert_eq!(Opcode::JB.condition(), Some(ConditionCode::B)); +/// ``` +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ConditionCode { + O, + NO, + B, + AE, + Z, + NZ, + A, + BE, + S, + NS, + P, + NP, + L, + GE, + G, + LE, +} + +#[allow(non_snake_case)] +impl RegSpec { + /// the register `eip`. this register is in the class `eip`, which contains only it. + pub const EIP: RegSpec = RegSpec::eip(); + + /// the number of this register in its `RegisterClass`. + /// + /// for many registers this is a number in the name, but for registers harkening back to + /// `x86_32`, the first eight registers are `rax`, `rcx`, `rdx`, `rbx`, `rsp`, `rbp`, `rsi`, + /// and `rdi` (or `eXX` for the 32-bit forms, `XX` for 16-bit forms). + pub fn num(&self) -> u8 { + self.num + } + + /// the class of register this register is in. + /// + /// this corresponds to the register's size, but is by the register's usage in the instruction + /// set; `rax` and `mm0` are the same size, but different classes (`Q`(word) and `MM` (mmx) + /// respectively). + pub fn class(&self) -> RegisterClass { + RegisterClass { kind: self.bank } + } + + #[cfg(feature = "fmt")] + /// return a human-friendly name for this register. the returned name is the same as would be + /// used to render this register in an instruction. + pub fn name(&self) -> &'static str { + display::regspec_label(self) + } + + /// construct a `RegSpec` for x87 register `st(num)` + #[inline] + pub fn st(num: u8) -> RegSpec { + if num >= 8 { + panic!("invalid x87 reg st({})", num); + } + + RegSpec { + num, + bank: RegisterBank::ST + } + } + + /// construct a `RegSpec` for xmm reg `num` + #[inline] + pub fn xmm(num: u8) -> RegSpec { + if num >= 32 { + panic!("invalid x86 xmm reg {}", num); + } + + RegSpec { + num, + bank: RegisterBank::X + } + } + + /// construct a `RegSpec` for ymm reg `num` + #[inline] + pub fn ymm(num: u8) -> RegSpec { + if num >= 32 { + panic!("invalid x86 ymm reg {}", num); + } + + RegSpec { + num, + bank: RegisterBank::Y + } + } + + /// construct a `RegSpec` for zmm reg `num` + #[inline] + pub fn zmm(num: u8) -> RegSpec { + if num >= 32 { + panic!("invalid x86 zmm reg {}", num); + } + + RegSpec { + num, + bank: RegisterBank::Z + } + } + + /// construct a `RegSpec` for mask reg `num` + #[inline] + pub fn mask(num: u8) -> RegSpec { + if num >= 32 { + panic!("invalid x86 mask reg {}", num); + } + + RegSpec { + num, + bank: RegisterBank::K + } + } + + /// construct a `RegSpec` for dword reg `num` + #[inline] + pub fn d(num: u8) -> RegSpec { + if num >= 8 { + panic!("invalid x86 dword reg {}", num); + } + + RegSpec { + num, + bank: RegisterBank::D + } + } + + /// construct a `RegSpec` for word reg `num` + #[inline] + pub fn w(num: u8) -> RegSpec { + if num >= 8 { + panic!("invalid x86 word reg {}", num); + } + + RegSpec { + num, + bank: RegisterBank::W + } + } + + /// construct a `RegSpec` for byte reg `num` + #[inline] + pub fn b(num: u8) -> RegSpec { + if num >= 8 { + panic!("invalid x86 byte reg {}", num); + } + + RegSpec { + num, + bank: RegisterBank::B + } + } + + #[inline] + fn from_parts(num: u8, bank: RegisterBank) -> RegSpec { + RegSpec { + num: num, + bank: bank + } + } + + #[inline] + pub const fn eip() -> RegSpec { + RegSpec { + num: 0, + bank: RegisterBank::EIP + } + } + + #[inline] + pub const fn eflags() -> RegSpec { + RegSpec { + num: 0, + bank: RegisterBank::EFlags + } + } + + #[inline] + pub const fn esp() -> RegSpec { + RegSpec { bank: RegisterBank::D, num: 4 } + } + + #[inline] + pub const fn ebp() -> RegSpec { + RegSpec { bank: RegisterBank::D, num: 5 } + } + + #[inline] + pub const fn cs() -> RegSpec { + RegSpec { bank: RegisterBank::S, num: 1 } + } + + #[inline] + pub const fn ds() -> RegSpec { + RegSpec { bank: RegisterBank::S, num: 3 } + } + + #[inline] + pub const fn es() -> RegSpec { + RegSpec { bank: RegisterBank::S, num: 0 } + } + + #[inline] + pub const fn ss() -> RegSpec { + RegSpec { bank: RegisterBank::S, num: 2 } + } + + #[inline] + pub const fn fs() -> RegSpec { + RegSpec { bank: RegisterBank::S, num: 4 } + } + + #[inline] + pub const fn gs() -> RegSpec { + RegSpec { bank: RegisterBank::S, num: 5 } + } + + #[inline] + pub const fn eax() -> RegSpec { + RegSpec { bank: RegisterBank::D, num: 0 } + } + + #[inline] + pub const fn ecx() -> RegSpec { + RegSpec { bank: RegisterBank::D, num: 1 } + } + + #[inline] + pub const fn edx() -> RegSpec { + RegSpec { bank: RegisterBank::D, num: 2 } + } + + #[inline] + pub const fn ebx() -> RegSpec { + RegSpec { bank: RegisterBank::D, num: 3 } + } + + #[inline] + pub const fn esi() -> RegSpec { + RegSpec { bank: RegisterBank::D, num: 6 } + } + + #[inline] + pub const fn edi() -> RegSpec { + RegSpec { bank: RegisterBank::D, num: 7 } + } + + #[inline] + pub const fn ax() -> RegSpec { + RegSpec { bank: RegisterBank::W, num: 0 } + } + + #[inline] + pub const fn cx() -> RegSpec { + RegSpec { bank: RegisterBank::W, num: 1 } + } + + #[inline] + pub const fn dx() -> RegSpec { + RegSpec { bank: RegisterBank::W, num: 2 } + } + + #[inline] + pub const fn bx() -> RegSpec { + RegSpec { bank: RegisterBank::W, num: 3 } + } + + #[inline] + pub const fn sp() -> RegSpec { + RegSpec { bank: RegisterBank::W, num: 4 } + } + + #[inline] + pub const fn bp() -> RegSpec { + RegSpec { bank: RegisterBank::W, num: 5 } + } + + #[inline] + pub const fn si() -> RegSpec { + RegSpec { bank: RegisterBank::W, num: 6 } + } + + #[inline] + pub const fn di() -> RegSpec { + RegSpec { bank: RegisterBank::W, num: 7 } + } + + #[inline] + pub const fn al() -> RegSpec { + RegSpec { bank: RegisterBank::B, num: 0 } + } + + #[inline] + pub const fn cl() -> RegSpec { + RegSpec { bank: RegisterBank::B, num: 1 } + } + + #[inline] + pub const fn dl() -> RegSpec { + RegSpec { bank: RegisterBank::B, num: 2 } + } + + #[inline] + pub const fn ah() -> RegSpec { + RegSpec { bank: RegisterBank::B, num: 4 } + } + + #[inline] + pub const fn ch() -> RegSpec { + RegSpec { bank: RegisterBank::B, num: 5 } + } + + #[inline] + pub const fn zmm0() -> RegSpec { + RegSpec { bank: RegisterBank::Z, num: 0 } + } + + #[inline] + pub const fn ymm0() -> RegSpec { + RegSpec { bank: RegisterBank::Y, num: 0 } + } + + #[inline] + pub const fn xmm0() -> RegSpec { + RegSpec { bank: RegisterBank::X, num: 0 } + } + + #[inline] + pub const fn st0() -> RegSpec { + RegSpec { bank: RegisterBank::ST, num: 0 } + } + + #[inline] + pub const fn mm0() -> RegSpec { + RegSpec { bank: RegisterBank::MM, num: 0 } + } + + /// return the size of this register, in bytes + #[inline] + pub fn width(&self) -> u8 { + self.class().width() + } +} + +#[allow(non_camel_case_types)] +#[allow(dead_code)] +enum SizeCode { + b, + vd, +} + +/// an operand for an `x86` instruction. +/// +/// `Operand::Nothing` should be unreachable in practice; any such instructions should have an +/// operand count of 0 (or at least one fewer than the `Nothing` operand's position). +#[derive(Clone, Debug, PartialEq)] +#[non_exhaustive] +pub enum Operand { + /// a sign-extended byte + ImmediateI8(i8), + /// a zero-extended byte + ImmediateU8(u8), + /// a sign-extended word + ImmediateI16(i16), + /// a zero-extended word + ImmediateU16(u16), + /// a sign-extended dword + ImmediateI32(i32), + /// a zero-extended dword + ImmediateU32(u32), + /// a bare register operand, such as `rcx`. + Register(RegSpec), + /// an `avx512` register operand with optional mask register and merge mode, such as + /// `zmm3{k4}{z}`. + /// + /// if the mask register is `k0`, there is no masking applied, and the default x86 operation is + /// `MergeMode::Merge`. + RegisterMaskMerge(RegSpec, RegSpec, MergeMode), + /// an `avx512` register operand with optional mask register, merge mode, and suppressed + /// exceptions, such as `zmm3{k4}{z}{rd-sae}`. + /// + /// if the mask register is `k0`, there is no masking applied, and the default x86 operation is + /// `MergeMode::Merge`. + RegisterMaskMergeSae(RegSpec, RegSpec, MergeMode, SaeMode), + /// an `avx512` register operand with optional mask register, merge mode, and suppressed + /// exceptions, with no overridden rounding mode, such as `zmm3{k4}{z}{sae}`. + /// + /// if the mask register is `k0`, there is no masking applied, and the default x86 operation is + /// `MergeMode::Merge`. + RegisterMaskMergeSaeNoround(RegSpec, RegSpec, MergeMode), + /// a memory access to a literal word address. it's extremely rare that a well-formed x86 + /// instruction uses this mode. as an example, `[0x1133]` + DisplacementU16(u16), + /// a memory access to a literal qword address. it's relatively rare that a well-formed x86 + /// instruction uses this mode, but plausibe. for example, `fs:[0x14]`. segment overrides, + /// however, are maintained on the instruction itself. + DisplacementU32(u32), + /// a simple dereference of the address held in some register. for example: `[esi]`. + RegDeref(RegSpec), + /// a dereference of the address held in some register with offset. for example: `[esi + 0x14]`. + RegDisp(RegSpec, i32), + /// a dereference of the address held in some register scaled by 1, 2, 4, or 8. this is almost always used with the `lea` instruction. for example: `[edx * 4]`. + RegScale(RegSpec, u8), + /// a dereference of the address from summing two registers. for example: `[ebp + rax]` + RegIndexBase(RegSpec, RegSpec), + /// a dereference of the address from summing two registers with offset. for example: `[edi + ecx + 0x40]` + RegIndexBaseDisp(RegSpec, RegSpec, i32), + /// a dereference of the address held in some register scaled by 1, 2, 4, or 8 with offset. this is almost always used with the `lea` instruction. for example: `[eax * 4 + 0x30]`. + RegScaleDisp(RegSpec, u8, i32), + /// a dereference of the address from summing a register and index register scaled by 1, 2, 4, + /// or 8. for + /// example: `[esi + ecx * 4]` + RegIndexBaseScale(RegSpec, RegSpec, u8), + /// a dereference of the address from summing a register and index register scaled by 1, 2, 4, + /// or 8, with offset. for + /// example: `[esi + ecx * 4 + 0x1234]` + RegIndexBaseScaleDisp(RegSpec, RegSpec, u8, i32), + /// an `avx512` dereference of register with optional masking. for example: `[edx]{k3}` + RegDerefMasked(RegSpec, RegSpec), + /// an `avx512` dereference of register plus offset, with optional masking. for example: `[esp + 0x40]{k3}` + RegDispMasked(RegSpec, i32, RegSpec), + /// an `avx512` dereference of a register scaled by 1, 2, 4, or 8, with optional masking. this + /// seems extraordinarily unlikely to occur in practice. for example: `[esi * 4]{k2}` + RegScaleMasked(RegSpec, u8, RegSpec), + /// an `avx512` dereference of a register plus index scaled by 1, 2, 4, or 8, with optional masking. + /// for example: `[esi + eax * 4]{k6}` + RegIndexBaseMasked(RegSpec, RegSpec, RegSpec), + /// an `avx512` dereference of a register plus offset, with optional masking. for example: + /// `[esi + eax + 0x1313]{k6}` + RegIndexBaseDispMasked(RegSpec, RegSpec, i32, RegSpec), + /// an `avx512` dereference of a register scaled by 1, 2, 4, or 8 plus offset, with optional + /// masking. this seems extraordinarily unlikely to occur in practice. for example: `[esi * + /// 4 + 0x1357]{k2}` + RegScaleDispMasked(RegSpec, u8, i32, RegSpec), + /// an `avx512` dereference of a register plus index scaled by 1, 2, 4, or 8, with optional + /// masking. for example: `[esi + eax * 4]{k6}` + RegIndexBaseScaleMasked(RegSpec, RegSpec, u8, RegSpec), + /// an `avx512` dereference of a register plus index scaled by 1, 2, 4, or 8 and offset, with + /// optional masking. for example: `[esi + eax * 4 + 0x1313]{k6}` + RegIndexBaseScaleDispMasked(RegSpec, RegSpec, u8, i32, RegSpec), + /// no operand. it is a bug for `yaxpeax-x86` to construct an `Operand` of this kind for public + /// use; the instruction's `operand_count` should be reduced so as to make this invisible to + /// library clients. + Nothing, +} + +impl OperandSpec { + fn masked(self) -> Self { + match self { + OperandSpec::RegRRR => OperandSpec::RegRRR_maskmerge, + OperandSpec::RegMMM => OperandSpec::RegMMM_maskmerge, + OperandSpec::RegVex => OperandSpec::RegVex_maskmerge, + OperandSpec::Deref => OperandSpec::Deref_mask, + OperandSpec::RegDisp => OperandSpec::RegDisp_mask, + OperandSpec::RegScale => OperandSpec::RegScale_mask, + OperandSpec::RegScaleDisp => OperandSpec::RegScaleDisp_mask, + OperandSpec::RegIndexBase => OperandSpec::RegIndexBase_mask, + OperandSpec::RegIndexBaseDisp => OperandSpec::RegIndexBaseDisp_mask, + OperandSpec::RegIndexBaseScale => OperandSpec::RegIndexBaseScale_mask, + OperandSpec::RegIndexBaseScaleDisp => OperandSpec::RegIndexBaseScaleDisp_mask, + o => o, + } + } + fn is_memory(&self) -> bool { + match self { + OperandSpec::DispU16 | + OperandSpec::DispU32 | + OperandSpec::Deref | + OperandSpec::Deref_si | + OperandSpec::Deref_di | + OperandSpec::Deref_esi | + OperandSpec::Deref_edi | + OperandSpec::RegDisp | + OperandSpec::RegScale | + OperandSpec::RegIndexBase | + OperandSpec::RegIndexBaseDisp | + OperandSpec::RegScaleDisp | + OperandSpec::RegIndexBaseScale | + OperandSpec::RegIndexBaseScaleDisp | + OperandSpec::Deref_mask | + OperandSpec::RegDisp_mask | + OperandSpec::RegScale_mask | + OperandSpec::RegScaleDisp_mask | + OperandSpec::RegIndexBase_mask | + OperandSpec::RegIndexBaseDisp_mask | + OperandSpec::RegIndexBaseScale_mask | + OperandSpec::RegIndexBaseScaleDisp_mask => { + true + }, + OperandSpec::ImmI8 | + OperandSpec::ImmI16 | + OperandSpec::ImmI32 | + OperandSpec::ImmU8 | + OperandSpec::ImmU16 | + OperandSpec::RegRRR | + OperandSpec::RegRRR_maskmerge | + OperandSpec::RegRRR_maskmerge_sae | + OperandSpec::RegRRR_maskmerge_sae_noround | + OperandSpec::RegMMM | + OperandSpec::RegMMM_maskmerge | + OperandSpec::RegMMM_maskmerge_sae_noround | + OperandSpec::RegVex | + OperandSpec::RegVex_maskmerge | + OperandSpec::Reg4 | + OperandSpec::ImmInDispField | + OperandSpec::Nothing => { + false + } + } + } +} +/// an `avx512` merging mode. +/// +/// the behavior for non-`avx512` instructions is equivalent to `merge`. `zero` is only useful in +/// conjunction with a mask register, where bits specified in the mask register correspond to +/// unmodified items in the instruction's desination. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum MergeMode { + Merge, + Zero, +} +impl From for MergeMode { + fn from(b: bool) -> Self { + if b { + MergeMode::Zero + } else { + MergeMode::Merge + } + } +} +/// an `avx512` custom rounding mode. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum SaeMode { + RoundNearest, + RoundDown, + RoundUp, + RoundZero, +} +const SAE_MODES: [SaeMode; 4] = [ + SaeMode::RoundNearest, + SaeMode::RoundDown, + SaeMode::RoundUp, + SaeMode::RoundZero, +]; +impl SaeMode { + /// a human-friendly label for this `SaeMode`: + /// + /// ``` + /// use yaxpeax_x86::long_mode::SaeMode; + /// + /// assert_eq!(SaeMode::RoundNearest.label(), "{rne-sae}"); + /// assert_eq!(SaeMode::RoundDown.label(), "{rd-sae}"); + /// assert_eq!(SaeMode::RoundUp.label(), "{ru-sae}"); + /// assert_eq!(SaeMode::RoundZero.label(), "{rz-sae}"); + /// ``` + pub fn label(&self) -> &'static str { + match self { + SaeMode::RoundNearest => "{rne-sae}", + SaeMode::RoundDown => "{rd-sae}", + SaeMode::RoundUp => "{ru-sae}", + SaeMode::RoundZero => "{rz-sae}", + } + } + + fn from(l: bool, lp: bool) -> Self { + let mut idx = 0; + if l { + idx |= 1; + } + if lp { + idx |= 2; + } + SAE_MODES[idx] + } +} +impl Operand { + fn from_spec(inst: &Instruction, spec: OperandSpec) -> Operand { + match spec { + OperandSpec::Nothing => { + Operand::Nothing + } + // the register in modrm_rrr + OperandSpec::RegRRR => { + Operand::Register(inst.regs[0]) + } + OperandSpec::RegRRR_maskmerge => { + Operand::RegisterMaskMerge( + inst.regs[0], + RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg()), + MergeMode::from(inst.prefixes.evex_unchecked().merge()), + ) + } + OperandSpec::RegRRR_maskmerge_sae => { + Operand::RegisterMaskMergeSae( + inst.regs[0], + RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg()), + MergeMode::from(inst.prefixes.evex_unchecked().merge()), + SaeMode::from(inst.prefixes.evex_unchecked().vex().l(), inst.prefixes.evex_unchecked().lp()), + ) + } + OperandSpec::RegRRR_maskmerge_sae_noround => { + Operand::RegisterMaskMergeSaeNoround( + inst.regs[0], + RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg()), + MergeMode::from(inst.prefixes.evex_unchecked().merge()), + ) + } + // the register in modrm_mmm (eg modrm mod bits were 11) + OperandSpec::RegMMM => { + Operand::Register(inst.regs[1]) + } + OperandSpec::RegMMM_maskmerge => { + Operand::RegisterMaskMerge( + inst.regs[1], + RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg()), + MergeMode::from(inst.prefixes.evex_unchecked().merge()), + ) + } + OperandSpec::RegMMM_maskmerge_sae_noround => { + Operand::RegisterMaskMergeSaeNoround( + inst.regs[1], + RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg()), + MergeMode::from(inst.prefixes.evex_unchecked().merge()), + ) + } + OperandSpec::RegVex => { + Operand::Register(inst.regs[3]) + } + OperandSpec::RegVex_maskmerge => { + Operand::RegisterMaskMerge( + inst.regs[3], + RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg()), + MergeMode::from(inst.prefixes.evex_unchecked().merge()), + ) + } + OperandSpec::Reg4 => { + Operand::Register(RegSpec { num: inst.imm as u8, bank: inst.regs[3].bank }) + } + OperandSpec::ImmI8 => Operand::ImmediateI8(inst.imm as i8), + OperandSpec::ImmU8 => Operand::ImmediateU8(inst.imm as u8), + OperandSpec::ImmI16 => Operand::ImmediateI16(inst.imm as i16), + OperandSpec::ImmU16 => Operand::ImmediateU16(inst.imm as u16), + OperandSpec::ImmI32 => Operand::ImmediateI32(inst.imm as i32), + OperandSpec::ImmInDispField => Operand::ImmediateU16(inst.disp as u16), + OperandSpec::DispU16 => Operand::DisplacementU16(inst.disp as u16), + OperandSpec::DispU32 => Operand::DisplacementU32(inst.disp), + OperandSpec::Deref => { + Operand::RegDeref(inst.regs[1]) + } + OperandSpec::Deref_si => { + Operand::RegDeref(RegSpec::si()) + } + OperandSpec::Deref_di => { + Operand::RegDeref(RegSpec::di()) + } + OperandSpec::Deref_esi => { + Operand::RegDeref(RegSpec::esi()) + } + OperandSpec::Deref_edi => { + Operand::RegDeref(RegSpec::edi()) + } + OperandSpec::RegDisp => { + Operand::RegDisp(inst.regs[1], inst.disp as i32) + } + OperandSpec::RegScale => { + Operand::RegScale(inst.regs[2], inst.scale) + } + OperandSpec::RegIndexBase => { + Operand::RegIndexBase(inst.regs[1], inst.regs[2]) + } + OperandSpec::RegIndexBaseDisp => { + Operand::RegIndexBaseDisp(inst.regs[1], inst.regs[2], inst.disp as i32) + } + OperandSpec::RegScaleDisp => { + Operand::RegScaleDisp(inst.regs[2], inst.scale, inst.disp as i32) + } + OperandSpec::RegIndexBaseScale => { + Operand::RegIndexBaseScale(inst.regs[1], inst.regs[2], inst.scale) + } + OperandSpec::RegIndexBaseScaleDisp => { + Operand::RegIndexBaseScaleDisp(inst.regs[1], inst.regs[2], inst.scale, inst.disp as i32) + } + OperandSpec::Deref_mask => { + if inst.prefixes.evex_unchecked().mask_reg() != 0 { + Operand::RegDerefMasked(inst.regs[1], RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) + } else { + Operand::RegDeref(inst.regs[1]) + } + } + OperandSpec::RegDisp_mask => { + if inst.prefixes.evex_unchecked().mask_reg() != 0 { + Operand::RegDispMasked(inst.regs[1], inst.disp as i32, RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) + } else { + Operand::RegDisp(inst.regs[1], inst.disp as i32) + } + } + OperandSpec::RegScale_mask => { + if inst.prefixes.evex_unchecked().mask_reg() != 0 { + Operand::RegScaleMasked(inst.regs[2], inst.scale, RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) + } else { + Operand::RegScale(inst.regs[2], inst.scale) + } + } + OperandSpec::RegScaleDisp_mask => { + if inst.prefixes.evex_unchecked().mask_reg() != 0 { + Operand::RegScaleDispMasked(inst.regs[2], inst.scale, inst.disp as i32, RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) + } else { + Operand::RegScaleDisp(inst.regs[2], inst.scale, inst.disp as i32) + } + } + OperandSpec::RegIndexBase_mask => { + if inst.prefixes.evex_unchecked().mask_reg() != 0 { + Operand::RegIndexBaseMasked(inst.regs[1], inst.regs[2], RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) + } else { + Operand::RegIndexBase(inst.regs[1], inst.regs[2]) + } + } + OperandSpec::RegIndexBaseDisp_mask => { + if inst.prefixes.evex_unchecked().mask_reg() != 0 { + Operand::RegIndexBaseDispMasked(inst.regs[1], inst.regs[2], inst.disp as i32, RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) + } else { + Operand::RegIndexBaseDisp(inst.regs[1], inst.regs[2], inst.disp as i32) + } + } + OperandSpec::RegIndexBaseScale_mask => { + if inst.prefixes.evex_unchecked().mask_reg() != 0 { + Operand::RegIndexBaseScaleMasked(inst.regs[1], inst.regs[2], inst.scale, RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) + } else { + Operand::RegIndexBaseScale(inst.regs[1], inst.regs[2], inst.scale) + } + } + OperandSpec::RegIndexBaseScaleDisp_mask => { + if inst.prefixes.evex_unchecked().mask_reg() != 0 { + Operand::RegIndexBaseScaleDispMasked(inst.regs[1], inst.regs[2], inst.scale, inst.disp as i32, RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) + } else { + Operand::RegIndexBaseScaleDisp(inst.regs[1], inst.regs[2], inst.scale, inst.disp as i32) + } + } + } + } + /// returns `true` if this operand implies a memory access, `false` otherwise. + /// + /// notably, the `lea` instruction uses a memory operand without actually ever accessing + /// memory. + pub fn is_memory(&self) -> bool { + match self { + Operand::DisplacementU16(_) | + Operand::DisplacementU32(_) | + Operand::RegDeref(_) | + Operand::RegDisp(_, _) | + Operand::RegScale(_, _) | + Operand::RegIndexBase(_, _) | + Operand::RegIndexBaseDisp(_, _, _) | + Operand::RegScaleDisp(_, _, _) | + Operand::RegIndexBaseScale(_, _, _) | + Operand::RegIndexBaseScaleDisp(_, _, _, _) | + Operand::RegDerefMasked(_, _) | + Operand::RegDispMasked(_, _, _) | + Operand::RegScaleMasked(_, _, _) | + Operand::RegIndexBaseMasked(_, _, _) | + Operand::RegIndexBaseDispMasked(_, _, _, _) | + Operand::RegScaleDispMasked(_, _, _, _) | + Operand::RegIndexBaseScaleMasked(_, _, _, _) | + Operand::RegIndexBaseScaleDispMasked(_, _, _, _, _) => { + true + }, + Operand::ImmediateI8(_) | + Operand::ImmediateU8(_) | + Operand::ImmediateI16(_) | + Operand::ImmediateU16(_) | + Operand::ImmediateU32(_) | + Operand::ImmediateI32(_) | + Operand::Register(_) | + Operand::RegisterMaskMerge(_, _, _) | + Operand::RegisterMaskMergeSae(_, _, _, _) | + Operand::RegisterMaskMergeSaeNoround(_, _, _) | + Operand::Nothing => { + false + } + } + } + + /// return the width of this operand, in bytes. register widths are determined by the + /// register's class. the widths of memory operands are recorded on the instruction this + /// `Operand` came from; `None` here means the authoritative width is `instr.mem_size()`. + pub fn width(&self) -> Option { + match self { + Operand::Register(reg) => { + Some(reg.width()) + } + Operand::RegisterMaskMerge(reg, _, _) => { + Some(reg.width()) + } + Operand::ImmediateI8(_) | + Operand::ImmediateU8(_) => { + Some(1) + } + Operand::ImmediateI16(_) | + Operand::ImmediateU16(_) => { + Some(2) + } + Operand::ImmediateI32(_) | + Operand::ImmediateU32(_) => { + Some(4) + } + // memory operands or `Nothing` + _ => { + None + } + } + } +} + +#[test] +fn operand_size() { + assert_eq!(core::mem::size_of::(), 1); + assert_eq!(core::mem::size_of::(), 2); + // assert_eq!(core::mem::size_of::(), 4); + // assert_eq!(core::mem::size_of::(), 40); +} + +/// an `x86` register class - `qword`, `dword`, `xmmword`, `segment`, and so on. +/// +/// this is mostly useful for comparing a `RegSpec`'s [`RegSpec::class()`] with a constant out of +/// [`register_class`]. +#[cfg_attr(feature="use-serde", derive(Serialize, Deserialize))] +#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +pub struct RegisterClass { + kind: RegisterBank, +} + +const REGISTER_CLASS_NAMES: &[&'static str] = &[ + "dword", + "word", + "byte", + "cr", + "dr", + "segment", + "xmm", + "BUG. PLEASE REPORT.", + "BUG. PLEASE REPORT.", + "BUG. PLEASE REPORT.", + "ymm", + "BUG. PLEASE REPORT.", + "BUG. PLEASE REPORT.", + "BUG. PLEASE REPORT.", + "zmm", + "BUG. PLEASE REPORT.", + "BUG. PLEASE REPORT.", + "BUG. PLEASE REPORT.", + "x87-stack", + "mmx", + "k", + "eip", + "eflags", +]; + +/// high-level register classes in an x86 machine, such as "2-byte general purpose", "xmm", "x87", +/// and so on. constants in this module are useful for inspecting the register class of a decoded +/// instruction. as an example: +/// ``` +/// extern crate yaxpeax_arch; +/// use yaxpeax_x86::real_mode::{self as amd64}; +/// use yaxpeax_x86::real_mode::{Opcode, Operand, RegisterClass}; +/// use yaxpeax_arch::{Decoder, U8Reader}; +/// +/// let movsx_ax_cl = &[0x0f, 0xbe, 0xc1]; +/// let decoder = amd64::InstDecoder::default(); +/// let instruction = decoder +/// .decode(&mut U8Reader::new(movsx_ax_cl)) +/// .expect("can decode"); +/// +/// assert_eq!(instruction.opcode(), Opcode::MOVSX); +/// +/// fn show_register_class_info(regclass: RegisterClass) { +/// match regclass { +/// amd64::register_class::W => { +/// println!(" and is a word register"); +/// } +/// amd64::register_class::B => { +/// println!(" and is a byte register"); +/// } +/// other => { +/// panic!("unexpected and invalid register class {:?}", other); +/// } +/// } +/// } +/// +/// if let Operand::Register(regspec) = instruction.operand(0) { +/// println!("first operand is {}", regspec); +/// show_register_class_info(regspec.class()); +/// } +/// +/// if let Operand::Register(regspec) = instruction.operand(1) { +/// println!("first operand is {}", regspec); +/// show_register_class_info(regspec.class()); +/// } +/// ``` +/// +/// this is preferable to alternatives like checking register names against a known list: a +/// register class is one byte and "is qword general-purpose" can then be a simple one-byte +/// compare, instead of 16 string compares. +/// +/// `yaxpeax-x86` does not attempt to further distinguish between, for example, register +/// suitability as operands. as an example, `cl` is only a byte register, with no additional +/// register class to describe its use as an implicit shift operand. +pub mod register_class { + use super::{RegisterBank, RegisterClass}; + /// doubleword registers: eax through edi. + pub const D: RegisterClass = RegisterClass { kind: RegisterBank::D }; + /// word registers: ax through di. + pub const W: RegisterClass = RegisterClass { kind: RegisterBank::W }; + /// byte registers: al, cl, dl, bl, ah, ch, dh, bh. + pub const B: RegisterClass = RegisterClass { kind: RegisterBank::B }; + /// control registers cr0 through cr7. + pub const CR: RegisterClass = RegisterClass { kind: RegisterBank::CR}; + /// debug registers dr0 through dr7. + pub const DR: RegisterClass = RegisterClass { kind: RegisterBank::DR }; + /// segment registers es, cs, ss, ds, fs, gs. + pub const S: RegisterClass = RegisterClass { kind: RegisterBank::S }; + /// xmm registers xmm0 through xmm31. + pub const X: RegisterClass = RegisterClass { kind: RegisterBank::X }; + /// ymm registers ymm0 through ymm31. + pub const Y: RegisterClass = RegisterClass { kind: RegisterBank::Y }; + /// zmm registers zmm0 through zmm31. + pub const Z: RegisterClass = RegisterClass { kind: RegisterBank::Z }; + /// x87 floating point stack entries st(0) through st(7). + pub const ST: RegisterClass = RegisterClass { kind: RegisterBank::ST }; + /// mmx registers mm0 through mm7. + pub const MM: RegisterClass = RegisterClass { kind: RegisterBank::MM }; + /// `AVX512` mask registers k0 through k7. + pub const K: RegisterClass = RegisterClass { kind: RegisterBank::K }; + /// the full instruction pointer register. + pub const EIP: RegisterClass = RegisterClass { kind: RegisterBank::EIP }; + /// the full cpu flags register. + pub const EFLAGS: RegisterClass = RegisterClass { kind: RegisterBank::EFlags }; +} + +impl RegisterClass { + /// return a human-friendly name for this register class + pub fn name(&self) -> &'static str { + REGISTER_CLASS_NAMES[self.kind as usize] + } + + /// return the size of this register class, in bytes + pub fn width(&self) -> u8 { + match self.kind { + RegisterBank::D => 4, + RegisterBank::W => 2, + RegisterBank::B => 1, + RegisterBank::CR | + RegisterBank::DR => { + 4 + }, + RegisterBank::S => { + 2 + }, + RegisterBank::EIP => { + 4 + } + RegisterBank::EFlags => { + 4 + } + RegisterBank::X => { + 16 + } + RegisterBank::Y => { + 32 + } + RegisterBank::Z => { + 64 + } + RegisterBank::ST => { + 10 + } + RegisterBank::MM => { + 8 + } + RegisterBank::K => { + 8 + } + } + } +} + +#[allow(non_camel_case_types)] +#[cfg_attr(feature="use-serde", derive(Serialize, Deserialize))] +#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] +enum RegisterBank { + D = 0, W = 1, B = 2, // Dword, Word, Byte + CR = 3, DR = 4, S = 5, EIP = 21, EFlags = 22, // Control reg, Debug reg, Selector, ... + X = 6, Y = 10, Z = 14, // XMM, YMM, ZMM + ST = 18, MM = 19, // ST, MM regs (x87, mmx) + K = 20, // AVX512 mask registers +} + +/// the segment register used by the corresponding instruction. +/// +/// typically this will be `ds` but can be overridden. some instructions have specific segment +/// registers used regardless of segment prefixes, and in these cases `yaxpeax-x86` will report the +/// actual segment register a physical processor would use. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum Segment { + DS = 0, CS, ES, FS, GS, SS +} + +const BMI1: [Opcode; 6] = [ + Opcode::ANDN, + Opcode::BEXTR, + Opcode::BLSI, + Opcode::BLSMSK, + Opcode::BLSR, + Opcode::TZCNT, +]; + +const BMI2: [Opcode; 8] = [ + Opcode::BZHI, + Opcode::MULX, + Opcode::PDEP, + Opcode::PEXT, + Opcode::RORX, + Opcode::SARX, + Opcode::SHRX, + Opcode::SHLX, +]; + +#[allow(dead_code)] +const XSAVE: [Opcode; 10] = [ + Opcode::XGETBV, + Opcode::XRSTOR, + Opcode::XRSTORS, + Opcode::XSAVE, + Opcode::XSAVEC, + Opcode::XSAVEC64, + Opcode::XSAVEOPT, + Opcode::XSAVES, + Opcode::XSAVES64, + Opcode::XSETBV, +]; + +#[allow(non_camel_case_types)] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[non_exhaustive] +pub enum Opcode { + Invalid, + ADD, + OR, + ADC, + SBB, + AND, + XOR, + SUB, + CMP, + XADD, + BT, + BTS, + BTC, + BTR, + BSF, + BSR, + TZCNT, + MOVSS, + ADDSS, + SUBSS, + MULSS, + DIVSS, + MINSS, + MAXSS, + SQRTSS, + MOVSD, + SQRTSD, + ADDSD, + SUBSD, + MULSD, + DIVSD, + MINSD, + MAXSD, + MOVSLDUP, + MOVSHDUP, + MOVDDUP, + HADDPS, + HSUBPS, + ADDSUBPD, + ADDSUBPS, + CVTSI2SS, + CVTSI2SD, + CVTTSD2SI, + CVTTPS2DQ, + CVTPD2DQ, + CVTPD2PS, + CVTPS2DQ, + CVTSD2SI, + CVTSD2SS, + CVTTSS2SI, + CVTSS2SI, + CVTSS2SD, + CVTDQ2PD, + LDDQU, + MOVZX, + MOVSX, + MOVSXD, + SAR, + SAL, + SHR, + SHRD, + SHL, + RCR, + RCL, + ROR, + ROL, + INC, + DEC, + HLT, + CALL, + CALLF, + JMP, + JMPF, + PUSH, + POP, + LEA, + NOP, + PREFETCHNTA, + PREFETCH0, + PREFETCH1, + PREFETCH2, + XCHG, + POPF, + INT, + INTO, + IRET, + IRETD, + IRETQ, + RETF, + ENTER, + LEAVE, + MOV, + RETURN, + PUSHF, + WAIT, + CBW, + CWDE, + CDQE, + CWD, + CDQ, + CQO, + LODS, + STOS, + LAHF, + SAHF, + CMPS, + SCAS, + MOVS, + TEST, + INS, + IN, + OUTS, + OUT, + IMUL, + JO, + JNO, + JB, + JNB, + JZ, + JNZ, + JA, + JNA, + JS, + JNS, + JP, + JNP, + JL, + JGE, + JLE, + JG, + CMOVA, + CMOVB, + CMOVG, + CMOVGE, + CMOVL, + CMOVLE, + CMOVNA, + CMOVNB, + CMOVNO, + CMOVNP, + CMOVNS, + CMOVNZ, + CMOVO, + CMOVP, + CMOVS, + CMOVZ, + DIV, + IDIV, + MUL, + NEG, + NOT, + CMPXCHG, + SETO, + SETNO, + SETB, + SETAE, + SETZ, + SETNZ, + SETBE, + SETA, + SETS, + SETNS, + SETP, + SETNP, + SETL, + SETGE, + SETLE, + SETG, + CPUID, + UD0, + UD1, + UD2, + WBINVD, + INVD, + SYSRET, + CLTS, + SYSCALL, + LSL, + LAR, + LES, + LDS, + SGDT, + SIDT, + LGDT, + LIDT, + SMSW, + LMSW, + SWAPGS, + RDTSCP, + INVLPG, + FXSAVE, + FXRSTOR, + LDMXCSR, + STMXCSR, + XSAVE, + XRSTOR, + XSAVEOPT, + LFENCE, + MFENCE, + SFENCE, + CLFLUSH, + CLFLUSHOPT, + CLWB, + WRMSR, + RDTSC, + RDMSR, + RDPMC, + SLDT, + STR, + LLDT, + LTR, + VERR, + VERW, + CMC, + CLC, + STC, + CLI, + STI, + CLD, + STD, + JMPE, + POPCNT, + MOVDQU, + MOVDQA, + MOVQ, + CMPSS, + CMPSD, + UNPCKLPS, + UNPCKLPD, + UNPCKHPS, + UNPCKHPD, + PSHUFHW, + PSHUFLW, + MOVUPS, + MOVQ2DQ, + MOVDQ2Q, + RSQRTSS, + RCPSS, + + ANDN, + BEXTR, + BLSI, + BLSMSK, + BLSR, + VMCLEAR, + VMXON, + VMCALL, + VMLAUNCH, + VMRESUME, + VMXOFF, + PCONFIG, + MONITOR, + MWAIT, + MONITORX, + MWAITX, + CLAC, + STAC, + ENCLS, + ENCLV, + XGETBV, + XSETBV, + VMFUNC, + XABORT, + XBEGIN, + XEND, + XTEST, + ENCLU, + RDPKRU, + WRPKRU, + + RDPRU, + CLZERO, + + RDSEED, + RDRAND, + + ADDPS, + ADDPD, + ANDNPS, + ANDNPD, + ANDPS, + ANDPD, + BSWAP, + CMPPD, + CMPPS, + COMISD, + COMISS, + CVTDQ2PS, + CVTPI2PS, + CVTPI2PD, + CVTPS2PD, + CVTPS2PI, + CVTPD2PI, + CVTTPS2PI, + CVTTPD2PI, + CVTTPD2DQ, + DIVPS, + DIVPD, + EMMS, + GETSEC, + LFS, + LGS, + LSS, + MASKMOVQ, + MASKMOVDQU, + MAXPS, + MAXPD, + MINPS, + MINPD, + MOVAPS, + MOVAPD, + MOVD, + MOVLPS, + MOVLPD, + MOVHPS, + MOVHPD, + MOVLHPS, + MOVHLPS, + MOVUPD, + MOVMSKPS, + MOVMSKPD, + MOVNTI, + MOVNTPS, + MOVNTPD, + EXTRQ, + INSERTQ, + MOVNTSS, + MOVNTSD, + MOVNTQ, + MOVNTDQ, + MULPS, + MULPD, + ORPS, + ORPD, + PACKSSDW, + PACKSSWB, + PACKUSWB, + PADDB, + PADDD, + PADDQ, + PADDSB, + PADDSW, + PADDUSB, + PADDUSW, + PADDW, + PAND, + PANDN, + PAVGB, + PAVGW, + PCMPEQB, + PCMPEQD, + PCMPEQW, + PCMPGTB, + PCMPGTD, + PCMPGTW, + PINSRW, + PMADDWD, + PMAXSW, + PMAXUB, + PMINSW, + PMINUB, + PMOVMSKB, + PMULHUW, + PMULHW, + PMULLW, + PMULUDQ, + POR, + PSADBW, + PSHUFW, + PSHUFD, + PSLLD, + PSLLDQ, + PSLLQ, + PSLLW, + PSRAD, + PSRAW, + PSRLD, + PSRLDQ, + PSRLQ, + PSRLW, + PSUBB, + PSUBD, + PSUBQ, + PSUBSB, + PSUBSW, + PSUBUSB, + PSUBUSW, + PSUBW, + PUNPCKHBW, + PUNPCKHDQ, + PUNPCKHWD, + PUNPCKLBW, + PUNPCKLDQ, + PUNPCKLWD, + PUNPCKLQDQ, + PUNPCKHQDQ, + PXOR, + RCPPS, + RSM, + RSQRTPS, + SHLD, + SHUFPD, + SHUFPS, + SLHD, + SQRTPS, + SQRTPD, + SUBPS, + SUBPD, + SYSENTER, + SYSEXIT, + UCOMISD, + UCOMISS, + VMREAD, + VMWRITE, + XORPS, + XORPD, + + VMOVDDUP, + VPSHUFLW, + VPSHUFHW, + VHADDPS, + VHSUBPS, + VADDSUBPS, + VCVTPD2DQ, + VLDDQU, + + VCOMISD, + VCOMISS, + VUCOMISD, + VUCOMISS, + VADDPD, + VADDPS, + VADDSD, + VADDSS, + VADDSUBPD, + VAESDEC, + VAESDECLAST, + VAESENC, + VAESENCLAST, + VAESIMC, + VAESKEYGENASSIST, + VBLENDPD, + VBLENDPS, + VBLENDVPD, + VBLENDVPS, + VBROADCASTF128, + VBROADCASTI128, + VBROADCASTSD, + VBROADCASTSS, + VCMPSD, + VCMPSS, + VCMPPD, + VCMPPS, + VCVTDQ2PD, + VCVTDQ2PS, + VCVTPD2PS, + VCVTPH2PS, + VCVTPS2DQ, + VCVTPS2PD, + VCVTSS2SD, + VCVTSI2SS, + VCVTSI2SD, + VCVTSD2SI, + VCVTSD2SS, + VCVTPS2PH, + VCVTSS2SI, + VCVTTPD2DQ, + VCVTTPS2DQ, + VCVTTSS2SI, + VCVTTSD2SI, + VDIVPD, + VDIVPS, + VDIVSD, + VDIVSS, + VDPPD, + VDPPS, + VEXTRACTF128, + VEXTRACTI128, + VEXTRACTPS, + VFMADD132PD, + VFMADD132PS, + VFMADD132SD, + VFMADD132SS, + VFMADD213PD, + VFMADD213PS, + VFMADD213SD, + VFMADD213SS, + VFMADD231PD, + VFMADD231PS, + VFMADD231SD, + VFMADD231SS, + VFMADDSUB132PD, + VFMADDSUB132PS, + VFMADDSUB213PD, + VFMADDSUB213PS, + VFMADDSUB231PD, + VFMADDSUB231PS, + VFMSUB132PD, + VFMSUB132PS, + VFMSUB132SD, + VFMSUB132SS, + VFMSUB213PD, + VFMSUB213PS, + VFMSUB213SD, + VFMSUB213SS, + VFMSUB231PD, + VFMSUB231PS, + VFMSUB231SD, + VFMSUB231SS, + VFMSUBADD132PD, + VFMSUBADD132PS, + VFMSUBADD213PD, + VFMSUBADD213PS, + VFMSUBADD231PD, + VFMSUBADD231PS, + VFNMADD132PD, + VFNMADD132PS, + VFNMADD132SD, + VFNMADD132SS, + VFNMADD213PD, + VFNMADD213PS, + VFNMADD213SD, + VFNMADD213SS, + VFNMADD231PD, + VFNMADD231PS, + VFNMADD231SD, + VFNMADD231SS, + VFNMSUB132PD, + VFNMSUB132PS, + VFNMSUB132SD, + VFNMSUB132SS, + VFNMSUB213PD, + VFNMSUB213PS, + VFNMSUB213SD, + VFNMSUB213SS, + VFNMSUB231PD, + VFNMSUB231PS, + VFNMSUB231SD, + VFNMSUB231SS, + VGATHERDPD, + VGATHERDPS, + VGATHERQPD, + VGATHERQPS, + VHADDPD, + VHSUBPD, + VINSERTF128, + VINSERTI128, + VINSERTPS, + VMASKMOVDQU, + VMASKMOVPD, + VMASKMOVPS, + VMAXPD, + VMAXPS, + VMAXSD, + VMAXSS, + VMINPD, + VMINPS, + VMINSD, + VMINSS, + VMOVAPD, + VMOVAPS, + VMOVD, + VMOVDQA, + VMOVDQU, + VMOVHLPS, + VMOVHPD, + VMOVHPS, + VMOVLHPS, + VMOVLPD, + VMOVLPS, + VMOVMSKPD, + VMOVMSKPS, + VMOVNTDQ, + VMOVNTDQA, + VMOVNTPD, + VMOVNTPS, + VMOVQ, + VMOVSS, + VMOVSD, + VMOVSHDUP, + VMOVSLDUP, + VMOVUPD, + VMOVUPS, + VMPSADBW, + VMULPD, + VMULPS, + VMULSD, + VMULSS, + VPABSB, + VPABSD, + VPABSW, + VPACKSSDW, + VPACKUSDW, + VPACKSSWB, + VPACKUSWB, + VPADDB, + VPADDD, + VPADDQ, + VPADDSB, + VPADDSW, + VPADDUSB, + VPADDUSW, + VPADDW, + VPALIGNR, + VANDPD, + VANDPS, + VORPD, + VORPS, + VANDNPD, + VANDNPS, + VPAND, + VPANDN, + VPAVGB, + VPAVGW, + VPBLENDD, + VPBLENDVB, + VPBLENDW, + VPBROADCASTB, + VPBROADCASTD, + VPBROADCASTQ, + VPBROADCASTW, + VPCLMULQDQ, + VPCMPEQB, + VPCMPEQD, + VPCMPEQQ, + VPCMPEQW, + VPCMPGTB, + VPCMPGTD, + VPCMPGTQ, + VPCMPGTW, + VPCMPESTRI, + VPCMPESTRM, + VPCMPISTRI, + VPCMPISTRM, + VPERM2F128, + VPERM2I128, + VPERMD, + VPERMILPD, + VPERMILPS, + VPERMPD, + VPERMPS, + VPERMQ, + VPEXTRB, + VPEXTRD, + VPEXTRQ, + VPEXTRW, + VPGATHERDD, + VPGATHERDQ, + VPGATHERQD, + VPGATHERQQ, + VPHADDD, + VPHADDSW, + VPHADDW, + VPMADDUBSW, + VPHMINPOSUW, + VPHSUBD, + VPHSUBSW, + VPHSUBW, + VPINSRB, + VPINSRD, + VPINSRQ, + VPINSRW, + VPMADDWD, + VPMASKMOVD, + VPMASKMOVQ, + VPMAXSB, + VPMAXSD, + VPMAXSW, + VPMAXUB, + VPMAXUW, + VPMAXUD, + VPMINSB, + VPMINSW, + VPMINSD, + VPMINUB, + VPMINUW, + VPMINUD, + VPMOVMSKB, + VPMOVSXBD, + VPMOVSXBQ, + VPMOVSXBW, + VPMOVSXDQ, + VPMOVSXWD, + VPMOVSXWQ, + VPMOVZXBD, + VPMOVZXBQ, + VPMOVZXBW, + VPMOVZXDQ, + VPMOVZXWD, + VPMOVZXWQ, + VPMULDQ, + VPMULHRSW, + VPMULHUW, + VPMULHW, + VPMULLQ, + VPMULLD, + VPMULLW, + VPMULUDQ, + VPOR, + VPSADBW, + VPSHUFB, + VPSHUFD, + VPSIGNB, + VPSIGND, + VPSIGNW, + VPSLLD, + VPSLLDQ, + VPSLLQ, + VPSLLVD, + VPSLLVQ, + VPSLLW, + VPSRAD, + VPSRAVD, + VPSRAW, + VPSRLD, + VPSRLDQ, + VPSRLQ, + VPSRLVD, + VPSRLVQ, + VPSRLW, + VPSUBB, + VPSUBD, + VPSUBQ, + VPSUBSB, + VPSUBSW, + VPSUBUSB, + VPSUBUSW, + VPSUBW, + VPTEST, + VPUNPCKHBW, + VPUNPCKHDQ, + VPUNPCKHQDQ, + VPUNPCKHWD, + VPUNPCKLBW, + VPUNPCKLDQ, + VPUNPCKLQDQ, + VPUNPCKLWD, + VPXOR, + VRCPPS, + VROUNDPD, + VROUNDPS, + VROUNDSD, + VROUNDSS, + VRSQRTPS, + VRSQRTSS, + VRCPSS, + VSHUFPD, + VSHUFPS, + VSQRTPD, + VSQRTPS, + VSQRTSS, + VSQRTSD, + VSUBPD, + VSUBPS, + VSUBSD, + VSUBSS, + VTESTPD, + VTESTPS, + VUNPCKHPD, + VUNPCKHPS, + VUNPCKLPD, + VUNPCKLPS, + VXORPD, + VXORPS, + VZEROUPPER, + VZEROALL, + VLDMXCSR, + VSTMXCSR, + + PCLMULQDQ, + AESKEYGENASSIST, + AESIMC, + AESENC, + AESENCLAST, + AESDEC, + AESDECLAST, + PCMPGTQ, + PCMPISTRM, + PCMPISTRI, + PCMPESTRI, + PACKUSDW, + PCMPESTRM, + PCMPEQQ, + PTEST, + PHMINPOSUW, + DPPS, + DPPD, + MPSADBW, + PMOVZXDQ, + PMOVSXDQ, + PMOVZXBD, + PMOVSXBD, + PMOVZXWQ, + PMOVSXWQ, + PMOVZXBQ, + PMOVSXBQ, + PMOVSXWD, + PMOVZXWD, + PEXTRQ, + PEXTRD, + PEXTRW, + PEXTRB, + PMOVSXBW, + PMOVZXBW, + PINSRQ, + PINSRD, + PINSRB, + EXTRACTPS, + INSERTPS, + ROUNDSS, + ROUNDSD, + ROUNDPS, + ROUNDPD, + PMAXSB, + PMAXSD, + PMAXUW, + PMAXUD, + PMINSD, + PMINSB, + PMINUD, + PMINUW, + BLENDW, + PBLENDVB, + PBLENDW, + BLENDVPS, + BLENDVPD, + BLENDPS, + BLENDPD, + PMULDQ, + MOVNTDQA, + PMULLD, + PALIGNR, + PSIGNW, + PSIGND, + PSIGNB, + PSHUFB, + PMULHRSW, + PMADDUBSW, + PABSD, + PABSW, + PABSB, + PHSUBSW, + PHSUBW, + PHSUBD, + PHADDD, + PHADDSW, + PHADDW, + HSUBPD, + HADDPD, + + SHA1RNDS4, + SHA1NEXTE, + SHA1MSG1, + SHA1MSG2, + SHA256RNDS2, + SHA256MSG1, + SHA256MSG2, + + LZCNT, + CLGI, + STGI, + SKINIT, + VMLOAD, + VMMCALL, + VMSAVE, + VMRUN, + INVLPGA, + INVLPGB, + TLBSYNC, + + MOVBE, + + ADCX, + ADOX, + + PREFETCHW, + + RDPID, + CMPXCHG8B, + CMPXCHG16B, + VMPTRLD, + VMPTRST, + + BZHI, + MULX, + SHLX, + SHRX, + SARX, + PDEP, + PEXT, + RORX, + XRSTORS, + XRSTORS64, + XSAVEC, + XSAVEC64, + XSAVES, + XSAVES64, + + RDFSBASE, + RDGSBASE, + WRFSBASE, + WRGSBASE, + + CRC32, + SALC, + XLAT, + + F2XM1, + FABS, + FADD, + FADDP, + FBLD, + FBSTP, + FCHS, + FCMOVB, + FCMOVBE, + FCMOVE, + FCMOVNB, + FCMOVNBE, + FCMOVNE, + FCMOVNU, + FCMOVU, + FCOM, + FCOMI, + FCOMIP, + FCOMP, + FCOMPP, + FCOS, + FDECSTP, + FDISI8087_NOP, + FDIV, + FDIVP, + FDIVR, + FDIVRP, + FENI8087_NOP, + FFREE, + FFREEP, + FIADD, + FICOM, + FICOMP, + FIDIV, + FIDIVR, + FILD, + FIMUL, + FINCSTP, + FIST, + FISTP, + FISTTP, + FISUB, + FISUBR, + FLD, + FLD1, + FLDCW, + FLDENV, + FLDL2E, + FLDL2T, + FLDLG2, + FLDLN2, + FLDPI, + FLDZ, + FMUL, + FMULP, + FNCLEX, + FNINIT, + FNOP, + FNSAVE, + FNSTCW, + FNSTENV, + FNSTOR, + FNSTSW, + FPATAN, + FPREM, + FPREM1, + FPTAN, + FRNDINT, + FRSTOR, + FSCALE, + FSETPM287_NOP, + FSIN, + FSINCOS, + FSQRT, + FST, + FSTP, + FSTPNCE, + FSUB, + FSUBP, + FSUBR, + FSUBRP, + FTST, + FUCOM, + FUCOMI, + FUCOMIP, + FUCOMP, + FUCOMPP, + FXAM, + FXCH, + FXTRACT, + FYL2X, + FYL2XP1, + + LOOPNZ, + LOOPZ, + LOOP, + JCXZ, + + PUSHA, + POPA, + BOUND, + ARPL, + AAS, + AAA, + DAS, + DAA, + AAM, + AAD, + + // started shipping in Tremont, 2020 sept 23 + MOVDIR64B, + MOVDIRI, + + // started shipping in Tiger Lake, 2020 sept 2 + AESDEC128KL, + AESDEC256KL, + AESDECWIDE128KL, + AESDECWIDE256KL, + AESENC128KL, + AESENC256KL, + AESENCWIDE128KL, + AESENCWIDE256KL, + ENCODEKEY128, + ENCODEKEY256, + LOADIWKEY, + + // unsure + HRESET, + + // 3dnow + FEMMS, + PI2FW, + PI2FD, + PF2IW, + PF2ID, + PMULHRW, + PFCMPGE, + PFMIN, + PFRCP, + PFRSQRT, + PFSUB, + PFADD, + PFCMPGT, + PFMAX, + PFRCPIT1, + PFRSQIT1, + PFSUBR, + PFACC, + PFCMPEQ, + PFMUL, + PFMULHRW, + PFRCPIT2, + PFNACC, + PFPNACC, + PSWAPD, + PAVGUSB, + + // ENQCMD + ENQCMD, + ENQCMDS, + + // INVPCID + INVEPT, + INVVPID, + INVPCID, + + // PTWRITE + PTWRITE, + + // GFNI + GF2P8AFFINEQB, + GF2P8AFFINEINVQB, + GF2P8MULB, + + // CET + WRUSS, + WRSS, + INCSSP, + SAVEPREVSSP, + SETSSBSY, + CLRSSBSY, + RSTORSSP, + + // TDX + TDCALL, + SEAMRET, + SEAMOPS, + SEAMCALL, + + // WAITPKG + TPAUSE, + UMONITOR, + UMWAIT, + + // UINTR + UIRET, + TESTUI, + CLUI, + STUI, + SENDUIPI, + + // TSXLDTRK + XSUSLDTRK, + XRESLDTRK, + + // AVX512F + VALIGND, + VALIGNQ, + VBLENDMPD, + VBLENDMPS, + VCOMPRESSPD, + VCOMPRESSPS, + VCVTPD2UDQ, + VCVTTPD2UDQ, + VCVTPS2UDQ, + VCVTTPS2UDQ, + VCVTQQ2PD, + VCVTQQ2PS, + VCVTSD2USI, + VCVTTSD2USI, + VCVTSS2USI, + VCVTTSS2USI, + VCVTUDQ2PD, + VCVTUDQ2PS, + VCVTUSI2USD, + VCVTUSI2USS, + VEXPANDPD, + VEXPANDPS, + VEXTRACTF32X4, + VEXTRACTF64X4, + VEXTRACTI32X4, + VEXTRACTI64X4, + VFIXUPIMMPD, + VFIXUPIMMPS, + VFIXUPIMMSD, + VFIXUPIMMSS, + VGETEXPPD, + VGETEXPPS, + VGETEXPSD, + VGETEXPSS, + VGETMANTPD, + VGETMANTPS, + VGETMANTSD, + VGETMANTSS, + VINSERTF32X4, + VINSERTF64X4, + VINSERTI64X4, + VMOVDQA32, + VMOVDQA64, + VMOVDQU32, + VMOVDQU64, + VPBLENDMD, + VPBLENDMQ, + VPCMPD, + VPCMPUD, + VPCMPQ, + VPCMPUQ, + VPCOMPRESSQ, + VPCOMPRESSD, + VPERMI2D, + VPERMI2Q, + VPERMI2PD, + VPERMI2PS, + VPERMT2D, + VPERMT2Q, + VPERMT2PD, + VPERMT2PS, + VPMAXSQ, + VPMAXUQ, + VPMINSQ, + VPMINUQ, + VPMOVSQB, + VPMOVUSQB, + VPMOVSQW, + VPMOVUSQW, + VPMOVSQD, + VPMOVUSQD, + VPMOVSDB, + VPMOVUSDB, + VPMOVSDW, + VPMOVUSDW, + VPROLD, + VPROLQ, + VPROLVD, + VPROLVQ, + VPRORD, + VPRORQ, + VPRORRD, + VPRORRQ, + VPSCATTERDD, + VPSCATTERDQ, + VPSCATTERQD, + VPSCATTERQQ, + VPSRAQ, + VPSRAVQ, + VPTESTNMD, + VPTESTNMQ, + VPTERNLOGD, + VPTERNLOGQ, + VPTESTMD, + VPTESTMQ, + VRCP14PD, + VRCP14PS, + VRCP14SD, + VRCP14SS, + VRNDSCALEPD, + VRNDSCALEPS, + VRNDSCALESD, + VRNDSCALESS, + VRSQRT14PD, + VRSQRT14PS, + VRSQRT14SD, + VRSQRT14SS, + VSCALEDPD, + VSCALEDPS, + VSCALEDSD, + VSCALEDSS, + VSCATTERDD, + VSCATTERDQ, + VSCATTERQD, + VSCATTERQQ, + VSHUFF32X4, + VSHUFF64X2, + VSHUFI32X4, + VSHUFI64X2, + + // AVX512DQ + VCVTTPD2QQ, + VCVTPD2QQ, + VCVTTPD2UQQ, + VCVTPD2UQQ, + VCVTTPS2QQ, + VCVTPS2QQ, + VCVTTPS2UQQ, + VCVTPS2UQQ, + VCVTUQQ2PD, + VCVTUQQ2PS, + VEXTRACTF64X2, + VEXTRACTI64X2, + VFPCLASSPD, + VFPCLASSPS, + VFPCLASSSD, + VFPCLASSSS, + VINSERTF64X2, + VINSERTI64X2, + VPMOVM2D, + VPMOVM2Q, + VPMOVB2D, + VPMOVQ2M, + VRANGEPD, + VRANGEPS, + VRANGESD, + VRANGESS, + VREDUCEPD, + VREDUCEPS, + VREDUCESD, + VREDUCESS, + + // AVX512BW + VDBPSADBW, + VMOVDQU8, + VMOVDQU16, + VPBLENDMB, + VPBLENDMW, + VPCMPB, + VPCMPUB, + VPCMPW, + VPCMPUW, + VPERMW, + VPERMI2B, + VPERMI2W, + VPMOVM2B, + VPMOVM2W, + VPMOVB2M, + VPMOVW2M, + VPMOVSWB, + VPMOVUSWB, + VPSLLVW, + VPSRAVW, + VPSRLVW, + VPTESTNMB, + VPTESTNMW, + VPTESTMB, + VPTESTMW, + + // AVX512CD + VPBROADCASTM, + VPCONFLICTD, + VPCONFLICTQ, + VPLZCNTD, + VPLZCNTQ, + + KUNPCKBW, + KUNPCKWD, + KUNPCKDQ, + + KADDB, + KANDB, + KANDNB, + KMOVB, + KNOTB, + KORB, + KORTESTB, + KSHIFTLB, + KSHIFTRB, + KTESTB, + KXNORB, + KXORB, + KADDW, + KANDW, + KANDNW, + KMOVW, + KNOTW, + KORW, + KORTESTW, + KSHIFTLW, + KSHIFTRW, + KTESTW, + KXNORW, + KXORW, + KADDD, + KANDD, + KANDND, + KMOVD, + KNOTD, + KORD, + KORTESTD, + KSHIFTLD, + KSHIFTRD, + KTESTD, + KXNORD, + KXORD, + KADDQ, + KANDQ, + KANDNQ, + KMOVQ, + KNOTQ, + KORQ, + KORTESTQ, + KSHIFTLQ, + KSHIFTRQ, + KTESTQ, + KXNORQ, + KXORQ, + + // AVX512ER + VEXP2PD, + VEXP2PS, + VEXP2SD, + VEXP2SS, + VRCP28PD, + VRCP28PS, + VRCP28SD, + VRCP28SS, + VRSQRT28PD, + VRSQRT28PS, + VRSQRT28SD, + VRSQRT28SS, + + // AVX512PF + VGATHERPF0DPD, + VGATHERPF0DPS, + VGATHERPF0QPD, + VGATHERPF0QPS, + VGATHERPF1DPD, + VGATHERPF1DPS, + VGATHERPF1QPD, + VGATHERPF1QPS, + VSCATTERPF0DPD, + VSCATTERPF0DPS, + VSCATTERPF0QPD, + VSCATTERPF0QPS, + VSCATTERPF1DPD, + VSCATTERPF1DPS, + VSCATTERPF1QPD, + VSCATTERPF1QPS, + + // MPX + BNDMK, + BNDCL, + BNDCU, + BNDCN, + BNDMOV, + BNDLDX, + BNDSTX, + + VGF2P8AFFINEQB, + VGF2P8AFFINEINVQB, + VPSHRDQ, + VPSHRDD, + VPSHRDW, + VPSHLDQ, + VPSHLDD, + VPSHLDW, + VBROADCASTF32X8, + VBROADCASTF64X4, + VBROADCASTF32X4, + VBROADCASTF64X2, + VBROADCASTF32X2, + VBROADCASTI32X8, + VBROADCASTI64X4, + VBROADCASTI32X4, + VBROADCASTI64X2, + VBROADCASTI32X2, + VEXTRACTI32X8, + VEXTRACTF32X8, + VINSERTI32X8, + VINSERTF32X8, + VINSERTI32X4, + V4FNMADDSS, + V4FNMADDPS, + VCVTNEPS2BF16, + V4FMADDSS, + V4FMADDPS, + VCVTNE2PS2BF16, + VP2INTERSECTD, + VP2INTERSECTQ, + VP4DPWSSDS, + VP4DPWSSD, + VPDPWSSDS, + VPDPWSSD, + VPDPBUSDS, + VDPBF16PS, + VPBROADCASTMW2D, + VPBROADCASTMB2Q, + VPMOVD2M, + VPMOVQD, + VPMOVWB, + VPMOVDB, + VPMOVDW, + VPMOVQB, + VPMOVQW, + VGF2P8MULB, + VPMADD52HUQ, + VPMADD52LUQ, + VPSHUFBITQMB, + VPERMB, + VPEXPANDD, + VPEXPANDQ, + VPABSQ, + VPRORVD, + VPRORVQ, + VPMULTISHIFTQB, + VPERMT2B, + VPERMT2W, + VPSHRDVQ, + VPSHRDVD, + VPSHRDVW, + VPSHLDVQ, + VPSHLDVD, + VPSHLDVW, + VPCOMPRESSB, + VPCOMPRESSW, + VPEXPANDB, + VPEXPANDW, + VPOPCNTD, + VPOPCNTQ, + VPOPCNTB, + VPOPCNTW, + VSCALEFSS, + VSCALEFSD, + VSCALEFPS, + VSCALEFPD, + VPDPBUSD, + VCVTUSI2SD, + VCVTUSI2SS, + VPXORD, + VPXORQ, + VPORD, + VPORQ, + VPANDND, + VPANDNQ, + VPANDD, + VPANDQ, + + PSMASH, + PVALIDATE, + RMPADJUST, + RMPUPDATE, +} + +impl PartialEq for Instruction { + fn eq(&self, other: &Self) -> bool { + if self.prefixes != other.prefixes { + return false; + } + + if self.opcode != other.opcode { + return false; + } + + if self.operand_count != other.operand_count { + return false; + } + + if self.mem_size != other.mem_size { + return false; + } + + for i in 0..self.operand_count { + if self.operands[i as usize] != other.operands[i as usize] { + return false; + } + + if self.operand(i) != other.operand(i) { + return false; + } + } + + true + } +} + +/// an `x86` instruction. +/// +/// typically an opcode will be inspected by [`Instruction::opcode()`], and an instruction has +/// [`Instruction::operand_count()`] many operands. operands are provided by +/// [`Instruction::operand()`]. +#[derive(Debug, Clone, Copy, Eq)] +pub struct Instruction { + pub prefixes: Prefixes, + /* + modrm_rrr: RegSpec, + modrm_mmm: RegSpec, // doubles as sib_base + sib_index: RegSpec, + vex_reg: RegSpec, + */ + regs: [RegSpec; 4], + scale: u8, + length: u8, + operand_count: u8, + operands: [OperandSpec; 4], + imm: u32, + disp: u32, + opcode: Opcode, + mem_size: u8, +} + +impl yaxpeax_arch::Instruction for Instruction { + fn well_defined(&self) -> bool { + // TODO: this is incorrect! + true + } +} + +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +#[non_exhaustive] +pub enum DecodeError { + ExhaustedInput, + InvalidOpcode, + InvalidOperand, + InvalidPrefixes, + TooLong, + IncompleteDecoder, +} + +impl yaxpeax_arch::DecodeError for DecodeError { + fn data_exhausted(&self) -> bool { self == &DecodeError::ExhaustedInput } + fn bad_opcode(&self) -> bool { self == &DecodeError::InvalidOpcode } + fn bad_operand(&self) -> bool { self == &DecodeError::InvalidOperand } + fn description(&self) -> &'static str { + match self { + DecodeError::ExhaustedInput => { "exhausted input" }, + DecodeError::InvalidOpcode => { "invalid opcode" }, + DecodeError::InvalidOperand => { "invalid operand" }, + DecodeError::InvalidPrefixes => { "invalid prefixes" }, + DecodeError::TooLong => { "too long" }, + DecodeError::IncompleteDecoder => { "the decoder is incomplete" }, + } + } +} + +#[allow(non_camel_case_types)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +enum OperandSpec { + Nothing, + // the register in modrm_rrr + RegRRR, + // the register in modrm_rrr and is EVEX-encoded (may have a mask register, is merged or + // zeroed) + RegRRR_maskmerge, + // the register in modrm_rrr and is EVEX-encoded (may have a mask register, is merged or + // zeroed). additionally, this instruction has exceptions suppressed with a potentially + // custom rounding mode. + RegRRR_maskmerge_sae, + // the register in modrm_rrr and is EVEX-encoded (may have a mask register, is merged or + // zeroed). additionally, this instruction has exceptions suppressed. + RegRRR_maskmerge_sae_noround, + // the register in modrm_mmm (eg modrm mod bits were 11) + RegMMM, + // same as `RegRRR`: the register is modrm's `mmm` bits, and may be masekd. + RegMMM_maskmerge, + RegMMM_maskmerge_sae_noround, + // the register selected by vex-vvvv bits + RegVex, + RegVex_maskmerge, + // the register selected by a handful of avx2 vex-coded instructions, + // stuffed in imm4. + Reg4, + ImmI8, + ImmI16, + ImmI32, + ImmU8, + ImmU16, + // ENTER is a two-immediate instruction, where the first immediate is stored in the disp field. + // for this case, a second immediate-style operand is needed. + // turns out `insertq` and `extrq` are also two-immediate instructions, so this is generalized + // to cover them too. + ImmInDispField, + DispU16, + DispU32, + Deref, + Deref_si, + Deref_di, + Deref_esi, + Deref_edi, + RegDisp, + RegScale, + RegIndexBase, + RegIndexBaseDisp, + RegScaleDisp, + RegIndexBaseScale, + RegIndexBaseScaleDisp, + Deref_mask, + RegDisp_mask, + RegScale_mask, + RegScaleDisp_mask, + RegIndexBase_mask, + RegIndexBaseDisp_mask, + RegIndexBaseScale_mask, + RegIndexBaseScaleDisp_mask, +} + +// the Hash, Eq, and PartialEq impls here are possibly misleading. +// They exist because downstream some structs are spelled like +// Foo for T == x86. This is only to access associated types +// which themselves are bounded, but their #[derive] require T to +// implement these traits. +/// a trivial struct for `yaxpeax_arch::Arch` to be implemented on. it's only interesting for the +/// associated type parameters. +#[cfg_attr(feature="use-serde", derive(Serialize, Deserialize))] +#[derive(Hash, Eq, PartialEq, Debug, Copy, Clone)] +#[allow(non_camel_case_types)] +pub struct Arch; + +impl yaxpeax_arch::Arch for Arch { + type Address = u32; + type Word = u8; + type Instruction = Instruction; + type DecodeError = DecodeError; + type Decoder = InstDecoder; + type Operand = Operand; +} + +impl LengthedInstruction for Instruction { + type Unit = AddressDiff; + #[inline] + fn len(&self) -> Self::Unit { + AddressDiff::from_const(self.length.into()) + } + #[inline] + fn min_size() -> Self::Unit { + AddressDiff::from_const(1) + } +} + +/// an `x86` instruction decoder. +/// +/// fundamentally this is one or two primitives with no additional state kept during decoding. it +/// can be copied cheaply, hashed cheaply, compared cheaply. if you really want to share an +/// `InstDecoder` between threads, you could - but you might want to clone it instead. +/// +/// unless you're using an `Arc>`, which is _fine_ but i'd be very curious about +/// the design requiring that. +#[derive(PartialEq, Copy, Clone, Eq, Hash, PartialOrd, Ord)] +pub struct InstDecoder { + // extensions tracked here: + // 0. SSE3 + // 1. SSSE3 + // 2. monitor (intel-only?) + // 3. vmx (some atom chips still lack it) + // 4. fma3 (intel haswell/broadwell+, amd piledriver+) + // 5. cmpxchg16b (some amd are missing this one) + // 6. sse4.1 + // 7. sse4.2 + // 8. movbe + // 9. popcnt (independent of BMI) + // 10. aesni + // 11. xsave (xsave, xrestor, xsetbv, xgetbv) + // 12. rdrand (intel ivybridge+, amd ..??) + // 13. sgx (eadd, eblock, ecreate, edbgrd, edbgwr, einit, eldb, eldu, epa, eremove, etrace, + // ewb, eenter, eexit, egetkey, ereport, eresume) + // 14. bmi1 (intel haswell+, amd jaguar+) + // 15. avx2 (intel haswell+, amd excavator+) + // 16. bmi2 (intel ?, amd ?) + // 17. invpcid + // 18. mpx + // 19. avx512_f + // 20. avx512_dq + // 21. rdseed + // 22. adx + // 23. avx512_fma + // 24. pcommit + // 25. clflushopt + // 26. clwb + // 27. avx512_pf + // 28. avx512_er + // 29. avx512_cd + // 30. sha + // 31. avx512_bw + // 32. avx512_vl + // 33. prefetchwt1 + // 34. avx512_vbmi + // 35. avx512_vbmi2 + // 36. gfni (galois field instructions) + // 37. vaes + // 38. pclmulqdq + // 39. avx_vnni + // 40. avx512_bitalg + // 41. avx512_vpopcntdq + // 42. avx512_4vnniw + // 43. avx512_4fmaps + // 44. cx8 // cmpxchg8 - is this actually optional in x86? + // 45. syscall // syscall/sysret - actually optional in x86? + // 46. rdtscp // actually optional in x86? + // 47. abm (lzcnt, popcnt) + // 48. sse4a + // 49. 3dnowprefetch // actually optional? + // 50. xop + // 51. skinit + // 52. tbm + // 53. intel quirks + // 54. amd quirks + // 55. avx (intel ?, amd ?) + // 56. amd-v/svm + // 57. lahfsahf + // 58. cmov + // 59. f16c + // 60. fma4 + // 61. prefetchw + // 62. tsx + // 63. lzcnt + flags: u64, +} + +impl InstDecoder { + /// instantiates an x86 decoder that decodes the bare minimum of real-mode x86. + /// + /// pedantic and only decodes what the spec says is well-defined, rejecting undefined sequences + /// and any instructions defined by extensions. + pub fn minimal() -> Self { + InstDecoder { + flags: 0, + } + } + + /// helper to decode an instruction directly from a byte slice. + /// + /// this lets callers avoid the work of setting up a [`yaxpeax_arch::U8Reader`] for the slice + /// to decode. + pub fn decode_slice(&self, data: &[u8]) -> Result { + let mut reader = yaxpeax_arch::U8Reader::new(data); + self.decode(&mut reader) + } + + pub fn sse3(&self) -> bool { + self.flags & (1 << 0) != 0 + } + + pub fn with_sse3(mut self) -> Self { + self.flags |= 1 << 0; + self + } + + pub fn ssse3(&self) -> bool { + self.flags & (1 << 1) != 0 + } + + pub fn with_ssse3(mut self) -> Self { + self.flags |= 1 << 1; + self + } + + pub fn monitor(&self) -> bool { + self.flags & (1 << 2) != 0 + } + + pub fn with_monitor(mut self) -> Self { + self.flags |= 1 << 2; + self + } + + pub fn vmx(&self) -> bool { + self.flags & (1 << 3) != 0 + } + + pub fn with_vmx(mut self) -> Self { + self.flags |= 1 << 3; + self + } + + pub fn fma3(&self) -> bool { + self.flags & (1 << 4) != 0 + } + + pub fn with_fma3(mut self) -> Self { + self.flags |= 1 << 4; + self + } + + pub fn cmpxchg16b(&self) -> bool { + self.flags & (1 << 5) != 0 + } + + pub fn with_cmpxchg16b(mut self) -> Self { + self.flags |= 1 << 5; + self + } + + pub fn sse4_1(&self) -> bool { + self.flags & (1 << 6) != 0 + } + + pub fn with_sse4_1(mut self) -> Self { + self.flags |= 1 << 6; + self + } + + pub fn sse4_2(&self) -> bool { + self.flags & (1 << 7) != 0 + } + + pub fn with_sse4_2(mut self) -> Self { + self.flags |= 1 << 7; + self + } + + pub fn with_sse4(self) -> Self { + self + .with_sse4_1() + .with_sse4_2() + } + + pub fn movbe(&self) -> bool { + self.flags & (1 << 8) != 0 + } + + pub fn with_movbe(mut self) -> Self { + self.flags |= 1 << 8; + self + } + + pub fn popcnt(&self) -> bool { + self.flags & (1 << 9) != 0 + } + + pub fn with_popcnt(mut self) -> Self { + self.flags |= 1 << 9; + self + } + + pub fn aesni(&self) -> bool { + self.flags & (1 << 10) != 0 + } + + pub fn with_aesni(mut self) -> Self { + self.flags |= 1 << 10; + self + } + + pub fn xsave(&self) -> bool { + self.flags & (1 << 11) != 0 + } + + pub fn with_xsave(mut self) -> Self { + self.flags |= 1 << 11; + self + } + + pub fn rdrand(&self) -> bool { + self.flags & (1 << 12) != 0 + } + + pub fn with_rdrand(mut self) -> Self { + self.flags |= 1 << 12; + self + } + + pub fn sgx(&self) -> bool { + self.flags & (1 << 13) != 0 + } + + pub fn with_sgx(mut self) -> Self { + self.flags |= 1 << 13; + self + } + + pub fn bmi1(&self) -> bool { + self.flags & (1 << 14) != 0 + } + + pub fn with_bmi1(mut self) -> Self { + self.flags |= 1 << 14; + self + } + + pub fn avx2(&self) -> bool { + self.flags & (1 << 15) != 0 + } + + pub fn with_avx2(mut self) -> Self { + self.flags |= 1 << 15; + self + } + + /// `bmi2` indicates support for the `BZHI`, `MULX`, `PDEP`, `PEXT`, `RORX`, `SARX`, `SHRX`, + /// and `SHLX` instructions. `bmi2` is implemented in all x86 chips that implement `bmi`, + /// except the amd `piledriver` and `steamroller` microarchitectures. + pub fn bmi2(&self) -> bool { + self.flags & (1 << 16) != 0 + } + + pub fn with_bmi2(mut self) -> Self { + self.flags |= 1 << 16; + self + } + + pub fn invpcid(&self) -> bool { + self.flags & (1 << 17) != 0 + } + + pub fn with_invpcid(mut self) -> Self { + self.flags |= 1 << 17; + self + } + + pub fn mpx(&self) -> bool { + self.flags & (1 << 18) != 0 + } + + pub fn with_mpx(mut self) -> Self { + self.flags |= 1 << 18; + self + } + + pub fn avx512_f(&self) -> bool { + self.flags & (1 << 19) != 0 + } + + pub fn with_avx512_f(mut self) -> Self { + self.flags |= 1 << 19; + self + } + + pub fn avx512_dq(&self) -> bool { + self.flags & (1 << 20) != 0 + } + + pub fn with_avx512_dq(mut self) -> Self { + self.flags |= 1 << 20; + self + } + + pub fn rdseed(&self) -> bool { + self.flags & (1 << 21) != 0 + } + + pub fn with_rdseed(mut self) -> Self { + self.flags |= 1 << 21; + self + } + + pub fn adx(&self) -> bool { + self.flags & (1 << 22) != 0 + } + + pub fn with_adx(mut self) -> Self { + self.flags |= 1 << 22; + self + } + + pub fn avx512_fma(&self) -> bool { + self.flags & (1 << 23) != 0 + } + + pub fn with_avx512_fma(mut self) -> Self { + self.flags |= 1 << 23; + self + } + + pub fn pcommit(&self) -> bool { + self.flags & (1 << 24) != 0 + } + + pub fn with_pcommit(mut self) -> Self { + self.flags |= 1 << 24; + self + } + + pub fn clflushopt(&self) -> bool { + self.flags & (1 << 25) != 0 + } + + pub fn with_clflushopt(mut self) -> Self { + self.flags |= 1 << 25; + self + } + + pub fn clwb(&self) -> bool { + self.flags & (1 << 26) != 0 + } + + pub fn with_clwb(mut self) -> Self { + self.flags |= 1 << 26; + self + } + + pub fn avx512_pf(&self) -> bool { + self.flags & (1 << 27) != 0 + } + + pub fn with_avx512_pf(mut self) -> Self { + self.flags |= 1 << 27; + self + } + + pub fn avx512_er(&self) -> bool { + self.flags & (1 << 28) != 0 + } + + pub fn with_avx512_er(mut self) -> Self { + self.flags |= 1 << 28; + self + } + + pub fn avx512_cd(&self) -> bool { + self.flags & (1 << 29) != 0 + } + + pub fn with_avx512_cd(mut self) -> Self { + self.flags |= 1 << 29; + self + } + + pub fn sha(&self) -> bool { + self.flags & (1 << 30) != 0 + } + + pub fn with_sha(mut self) -> Self { + self.flags |= 1 << 30; + self + } + + pub fn avx512_bw(&self) -> bool { + self.flags & (1 << 31) != 0 + } + + pub fn with_avx512_bw(mut self) -> Self { + self.flags |= 1 << 31; + self + } + + pub fn avx512_vl(&self) -> bool { + self.flags & (1 << 32) != 0 + } + + pub fn with_avx512_vl(mut self) -> Self { + self.flags |= 1 << 32; + self + } + + pub fn prefetchwt1(&self) -> bool { + self.flags & (1 << 33) != 0 + } + + pub fn with_prefetchwt1(mut self) -> Self { + self.flags |= 1 << 33; + self + } + + pub fn avx512_vbmi(&self) -> bool { + self.flags & (1 << 34) != 0 + } + + pub fn with_avx512_vbmi(mut self) -> Self { + self.flags |= 1 << 34; + self + } + + pub fn avx512_vbmi2(&self) -> bool { + self.flags & (1 << 35) != 0 + } + + pub fn with_avx512_vbmi2(mut self) -> Self { + self.flags |= 1 << 35; + self + } + + pub fn gfni(&self) -> bool { + self.flags & (1 << 36) != 0 + } + + pub fn with_gfni(mut self) -> Self { + self.flags |= 1 << 36; + self + } + + pub fn vaes(&self) -> bool { + self.flags & (1 << 37) != 0 + } + + pub fn with_vaes(mut self) -> Self { + self.flags |= 1 << 37; + self + } + + pub fn pclmulqdq(&self) -> bool { + self.flags & (1 << 38) != 0 + } + + pub fn with_pclmulqdq(mut self) -> Self { + self.flags |= 1 << 38; + self + } + + pub fn avx_vnni(&self) -> bool { + self.flags & (1 << 39) != 0 + } + + pub fn with_avx_vnni(mut self) -> Self { + self.flags |= 1 << 39; + self + } + + pub fn avx512_bitalg(&self) -> bool { + self.flags & (1 << 40) != 0 + } + + pub fn with_avx512_bitalg(mut self) -> Self { + self.flags |= 1 << 40; + self + } + + pub fn avx512_vpopcntdq(&self) -> bool { + self.flags & (1 << 41) != 0 + } + + pub fn with_avx512_vpopcntdq(mut self) -> Self { + self.flags |= 1 << 41; + self + } + + pub fn avx512_4vnniw(&self) -> bool { + self.flags & (1 << 42) != 0 + } + + pub fn with_avx512_4vnniw(mut self) -> Self { + self.flags |= 1 << 42; + self + } + + pub fn avx512_4fmaps(&self) -> bool { + self.flags & (1 << 43) != 0 + } + + pub fn with_avx512_4fmaps(mut self) -> Self { + self.flags |= 1 << 43; + self + } + + /// returns `true` if this `InstDecoder` has **all** `avx512` features enabled. + pub fn avx512(&self) -> bool { + let avx512_mask = + (1 << 19) | + (1 << 20) | + (1 << 23) | + (1 << 27) | + (1 << 28) | + (1 << 29) | + (1 << 31) | + (1 << 32) | + (1 << 34) | + (1 << 35) | + (1 << 40) | + (1 << 41) | + (1 << 42) | + (1 << 43); + + (self.flags & avx512_mask) == avx512_mask + } + + /// enable all `avx512` features on this `InstDecoder`. no real CPU, at time of writing, + /// actually has such a feature comination, but this is a useful overestimate for `avx512` + /// generally. + pub fn with_avx512(mut self) -> Self { + let avx512_mask = + (1 << 19) | + (1 << 20) | + (1 << 23) | + (1 << 27) | + (1 << 28) | + (1 << 29) | + (1 << 31) | + (1 << 32) | + (1 << 34) | + (1 << 35) | + (1 << 40) | + (1 << 41) | + (1 << 42) | + (1 << 43); + + self.flags |= avx512_mask; + self + } + + pub fn cx8(&self) -> bool { + self.flags & (1 << 44) != 0 + } + + pub fn with_cx8(mut self) -> Self { + self.flags |= 1 << 44; + self + } + + pub fn syscall(&self) -> bool { + self.flags & (1 << 45) != 0 + } + + pub fn with_syscall(mut self) -> Self { + self.flags |= 1 << 45; + self + } + + pub fn rdtscp(&self) -> bool { + self.flags & (1 << 46) != 0 + } + + pub fn with_rdtscp(mut self) -> Self { + self.flags |= 1 << 46; + self + } + + pub fn abm(&self) -> bool { + self.flags & (1 << 47) != 0 + } + + pub fn with_abm(mut self) -> Self { + self.flags |= 1 << 47; + self + } + + pub fn sse4a(&self) -> bool { + self.flags & (1 << 48) != 0 + } + + pub fn with_sse4a(mut self) -> Self { + self.flags |= 1 << 48; + self + } + + pub fn _3dnowprefetch(&self) -> bool { + self.flags & (1 << 49) != 0 + } + + pub fn with_3dnowprefetch(mut self) -> Self { + self.flags |= 1 << 49; + self + } + + pub fn xop(&self) -> bool { + self.flags & (1 << 50) != 0 + } + + pub fn with_xop(mut self) -> Self { + self.flags |= 1 << 50; + self + } + + pub fn skinit(&self) -> bool { + self.flags & (1 << 51) != 0 + } + + pub fn with_skinit(mut self) -> Self { + self.flags |= 1 << 51; + self + } + + pub fn tbm(&self) -> bool { + self.flags & (1 << 52) != 0 + } + + pub fn with_tbm(mut self) -> Self { + self.flags |= 1 << 52; + self + } + + pub fn intel_quirks(&self) -> bool { + self.flags & (1 << 53) != 0 + } + + pub fn with_intel_quirks(mut self) -> Self { + self.flags |= 1 << 53; + self + } + + pub fn amd_quirks(&self) -> bool { + self.flags & (1 << 54) != 0 + } + + pub fn with_amd_quirks(mut self) -> Self { + self.flags |= 1 << 54; + self + } + + pub fn avx(&self) -> bool { + self.flags & (1 << 55) != 0 + } + + pub fn with_avx(mut self) -> Self { + self.flags |= 1 << 55; + self + } + + pub fn svm(&self) -> bool { + self.flags & (1 << 56) != 0 + } + + pub fn with_svm(mut self) -> Self { + self.flags |= 1 << 56; + self + } + + /// `lahfsahf` is only unset for early revisions of 64-bit amd and intel chips. unfortunately + /// the clearest documentation on when these instructions were reintroduced into 64-bit + /// architectures seems to be + /// [wikipedia](https://en.wikipedia.org/wiki/X86-64#Older_implementations): + /// ```text + /// Early AMD64 and Intel 64 CPUs lacked LAHF and SAHF instructions in 64-bit mode. AMD + /// introduced these instructions (also in 64-bit mode) with their Athlon 64, Opteron and + /// Turion 64 revision D processors in March 2005[48][49][50] while Intel introduced the + /// instructions with the Pentium 4 G1 stepping in December 2005. The 64-bit version of Windows + /// 8.1 requires this feature.[47] + /// ``` + /// + /// this puts reintroduction of these instructions somewhere in the middle of prescott and k8 + /// lifecycles, for intel and amd respectively. because there is no specific uarch where these + /// features become enabled, prescott and k8 default to not supporting these instructions, + /// where later uarches support these instructions. + pub fn lahfsahf(&self) -> bool { + self.flags & (1 << 57) != 0 + } + + pub fn with_lahfsahf(mut self) -> Self { + self.flags |= 1 << 57; + self + } + + pub fn cmov(&self) -> bool { + self.flags & (1 << 58) != 0 + } + + pub fn with_cmov(mut self) -> Self { + self.flags |= 1 << 58; + self + } + + pub fn f16c(&self) -> bool { + self.flags & (1 << 59) != 0 + } + + pub fn with_f16c(mut self) -> Self { + self.flags |= 1 << 59; + self + } + + pub fn fma4(&self) -> bool { + self.flags & (1 << 60) != 0 + } + + pub fn with_fma4(mut self) -> Self { + self.flags |= 1 << 60; + self + } + + pub fn prefetchw(&self) -> bool { + self.flags & (1 << 61) != 0 + } + + pub fn with_prefetchw(mut self) -> Self { + self.flags |= 1 << 61; + self + } + + pub fn tsx(&self) -> bool { + self.flags & (1 << 62) != 0 + } + + pub fn with_tsx(mut self) -> Self { + self.flags |= 1 << 62; + self + } + + pub fn lzcnt(&self) -> bool { + self.flags & (1 << 63) != 0 + } + + pub fn with_lzcnt(mut self) -> Self { + self.flags |= 1 << 63; + self + } + + /// Optionally reject or reinterpret instruction according to the decoder's + /// declared extensions. + fn revise_instruction(&self, inst: &mut Instruction) -> Result<(), DecodeError> { + if inst.prefixes.evex().is_some() { + if !self.avx512() { + return Err(DecodeError::InvalidOpcode); + } else { + return Ok(()); + } + } + match inst.opcode { + Opcode::TZCNT => { + if !self.bmi1() { + // tzcnt is only supported if bmi1 is enabled. without bmi1, this decodes as + // bsf. + inst.opcode = Opcode::BSF; + } + } + Opcode::LDDQU | + Opcode::ADDSUBPS | + Opcode::ADDSUBPD | + Opcode::HADDPS | + Opcode::HSUBPS | + Opcode::HADDPD | + Opcode::HSUBPD | + Opcode::MOVSHDUP | + Opcode::MOVSLDUP | + Opcode::MOVDDUP | + Opcode::MONITOR | + Opcode::MWAIT => { + // via Intel section 5.7, SSE3 Instructions + if !self.sse3() { + return Err(DecodeError::InvalidOpcode); + } + } + Opcode::PHADDW | + Opcode::PHADDSW | + Opcode::PHADDD | + Opcode::PHSUBW | + Opcode::PHSUBSW | + Opcode::PHSUBD | + Opcode::PABSB | + Opcode::PABSW | + Opcode::PABSD | + Opcode::PMADDUBSW | + Opcode::PMULHRSW | + Opcode::PSHUFB | + Opcode::PSIGNB | + Opcode::PSIGNW | + Opcode::PSIGND | + Opcode::PALIGNR => { + // via Intel section 5.8, SSSE3 Instructions + if !self.ssse3() { + return Err(DecodeError::InvalidOpcode); + } + } + Opcode::PMULLD | + Opcode::PMULDQ | + Opcode::MOVNTDQA | + Opcode::BLENDPD | + Opcode::BLENDPS | + Opcode::BLENDVPD | + Opcode::BLENDVPS | + Opcode::PBLENDVB | + Opcode::BLENDW | + Opcode::PMINUW | + Opcode::PMINUD | + Opcode::PMINSB | + Opcode::PMINSD | + Opcode::PMAXUW | + Opcode::PMAXUD | + Opcode::PMAXSB | + Opcode::PMAXSD | + Opcode::ROUNDPS | + Opcode::ROUNDPD | + Opcode::ROUNDSS | + Opcode::ROUNDSD | + Opcode::PBLENDW | + Opcode::EXTRACTPS | + Opcode::INSERTPS | + Opcode::PINSRB | + Opcode::PINSRD | + Opcode::PINSRQ | + Opcode::PMOVSXBW | + Opcode::PMOVZXBW | + Opcode::PMOVSXBD | + Opcode::PMOVZXBD | + Opcode::PMOVSXWD | + Opcode::PMOVZXWD | + Opcode::PMOVSXBQ | + Opcode::PMOVZXBQ | + Opcode::PMOVSXWQ | + Opcode::PMOVZXWQ | + Opcode::PMOVSXDQ | + Opcode::PMOVZXDQ | + Opcode::DPPS | + Opcode::DPPD | + Opcode::MPSADBW | + Opcode::PHMINPOSUW | + Opcode::PTEST | + Opcode::PCMPEQQ | + Opcode::PEXTRB | + Opcode::PEXTRW | + Opcode::PEXTRD | + Opcode::PEXTRQ | + Opcode::PACKUSDW => { + // via Intel section 5.10, SSE4.1 Instructions + if !self.sse4_1() { + return Err(DecodeError::InvalidOpcode); + } + } + Opcode::EXTRQ | + Opcode::INSERTQ | + Opcode::MOVNTSS | + Opcode::MOVNTSD => { + if !self.sse4a() { + return Err(DecodeError::InvalidOpcode); + } + } + Opcode::CRC32 | + Opcode::PCMPESTRI | + Opcode::PCMPESTRM | + Opcode::PCMPISTRI | + Opcode::PCMPISTRM | + Opcode::PCMPGTQ => { + // via Intel section 5.11, SSE4.2 Instructions + if !self.sse4_2() { + return Err(DecodeError::InvalidOpcode); + } + } + Opcode::AESDEC | + Opcode::AESDECLAST | + Opcode::AESENC | + Opcode::AESENCLAST | + Opcode::AESIMC | + Opcode::AESKEYGENASSIST => { + // via Intel section 5.12. AESNI AND PCLMULQDQ + if !self.aesni() { + return Err(DecodeError::InvalidOpcode); + } + } + Opcode::PCLMULQDQ => { + // via Intel section 5.12. AESNI AND PCLMULQDQ + if !self.pclmulqdq() { + return Err(DecodeError::InvalidOpcode); + } + } + Opcode::XABORT | + Opcode::XBEGIN | + Opcode::XEND | + Opcode::XTEST => { + if !self.tsx() { + return Err(DecodeError::InvalidOpcode); + } + } + Opcode::SHA1MSG1 | + Opcode::SHA1MSG2 | + Opcode::SHA1NEXTE | + Opcode::SHA1RNDS4 | + Opcode::SHA256MSG1 | + Opcode::SHA256MSG2 | + Opcode::SHA256RNDS2 => { + if !self.sha() { + return Err(DecodeError::InvalidOpcode); + } + } + Opcode::ENCLV | + Opcode::ENCLS | + Opcode::ENCLU => { + if !self.sgx() { + return Err(DecodeError::InvalidOpcode); + } + } + // AVX... + Opcode::VMOVDDUP | + Opcode::VPSHUFLW | + Opcode::VPSHUFHW | + Opcode::VHADDPS | + Opcode::VHSUBPS | + Opcode::VADDSUBPS | + Opcode::VCVTPD2DQ | + Opcode::VLDDQU | + Opcode::VCOMISD | + Opcode::VCOMISS | + Opcode::VUCOMISD | + Opcode::VUCOMISS | + Opcode::VADDPD | + Opcode::VADDPS | + Opcode::VADDSD | + Opcode::VADDSS | + Opcode::VADDSUBPD | + Opcode::VBLENDPD | + Opcode::VBLENDPS | + Opcode::VBLENDVPD | + Opcode::VBLENDVPS | + Opcode::VBROADCASTF128 | + Opcode::VBROADCASTI128 | + Opcode::VBROADCASTSD | + Opcode::VBROADCASTSS | + Opcode::VCMPSD | + Opcode::VCMPSS | + Opcode::VCMPPD | + Opcode::VCMPPS | + Opcode::VCVTDQ2PD | + Opcode::VCVTDQ2PS | + Opcode::VCVTPD2PS | + Opcode::VCVTPS2DQ | + Opcode::VCVTPS2PD | + Opcode::VCVTSS2SD | + Opcode::VCVTSI2SS | + Opcode::VCVTSI2SD | + Opcode::VCVTSD2SI | + Opcode::VCVTSD2SS | + Opcode::VCVTSS2SI | + Opcode::VCVTTPD2DQ | + Opcode::VCVTTPS2DQ | + Opcode::VCVTTSS2SI | + Opcode::VCVTTSD2SI | + Opcode::VDIVPD | + Opcode::VDIVPS | + Opcode::VDIVSD | + Opcode::VDIVSS | + Opcode::VDPPD | + Opcode::VDPPS | + Opcode::VEXTRACTF128 | + Opcode::VEXTRACTI128 | + Opcode::VEXTRACTPS | + Opcode::VFMADD132PD | + Opcode::VFMADD132PS | + Opcode::VFMADD132SD | + Opcode::VFMADD132SS | + Opcode::VFMADD213PD | + Opcode::VFMADD213PS | + Opcode::VFMADD213SD | + Opcode::VFMADD213SS | + Opcode::VFMADD231PD | + Opcode::VFMADD231PS | + Opcode::VFMADD231SD | + Opcode::VFMADD231SS | + Opcode::VFMADDSUB132PD | + Opcode::VFMADDSUB132PS | + Opcode::VFMADDSUB213PD | + Opcode::VFMADDSUB213PS | + Opcode::VFMADDSUB231PD | + Opcode::VFMADDSUB231PS | + Opcode::VFMSUB132PD | + Opcode::VFMSUB132PS | + Opcode::VFMSUB132SD | + Opcode::VFMSUB132SS | + Opcode::VFMSUB213PD | + Opcode::VFMSUB213PS | + Opcode::VFMSUB213SD | + Opcode::VFMSUB213SS | + Opcode::VFMSUB231PD | + Opcode::VFMSUB231PS | + Opcode::VFMSUB231SD | + Opcode::VFMSUB231SS | + Opcode::VFMSUBADD132PD | + Opcode::VFMSUBADD132PS | + Opcode::VFMSUBADD213PD | + Opcode::VFMSUBADD213PS | + Opcode::VFMSUBADD231PD | + Opcode::VFMSUBADD231PS | + Opcode::VFNMADD132PD | + Opcode::VFNMADD132PS | + Opcode::VFNMADD132SD | + Opcode::VFNMADD132SS | + Opcode::VFNMADD213PD | + Opcode::VFNMADD213PS | + Opcode::VFNMADD213SD | + Opcode::VFNMADD213SS | + Opcode::VFNMADD231PD | + Opcode::VFNMADD231PS | + Opcode::VFNMADD231SD | + Opcode::VFNMADD231SS | + Opcode::VFNMSUB132PD | + Opcode::VFNMSUB132PS | + Opcode::VFNMSUB132SD | + Opcode::VFNMSUB132SS | + Opcode::VFNMSUB213PD | + Opcode::VFNMSUB213PS | + Opcode::VFNMSUB213SD | + Opcode::VFNMSUB213SS | + Opcode::VFNMSUB231PD | + Opcode::VFNMSUB231PS | + Opcode::VFNMSUB231SD | + Opcode::VFNMSUB231SS | + Opcode::VGATHERDPD | + Opcode::VGATHERDPS | + Opcode::VGATHERQPD | + Opcode::VGATHERQPS | + Opcode::VHADDPD | + Opcode::VHSUBPD | + Opcode::VINSERTF128 | + Opcode::VINSERTI128 | + Opcode::VINSERTPS | + Opcode::VMASKMOVDQU | + Opcode::VMASKMOVPD | + Opcode::VMASKMOVPS | + Opcode::VMAXPD | + Opcode::VMAXPS | + Opcode::VMAXSD | + Opcode::VMAXSS | + Opcode::VMINPD | + Opcode::VMINPS | + Opcode::VMINSD | + Opcode::VMINSS | + Opcode::VMOVAPD | + Opcode::VMOVAPS | + Opcode::VMOVD | + Opcode::VMOVDQA | + Opcode::VMOVDQU | + Opcode::VMOVHLPS | + Opcode::VMOVHPD | + Opcode::VMOVHPS | + Opcode::VMOVLHPS | + Opcode::VMOVLPD | + Opcode::VMOVLPS | + Opcode::VMOVMSKPD | + Opcode::VMOVMSKPS | + Opcode::VMOVNTDQ | + Opcode::VMOVNTDQA | + Opcode::VMOVNTPD | + Opcode::VMOVNTPS | + Opcode::VMOVQ | + Opcode::VMOVSS | + Opcode::VMOVSD | + Opcode::VMOVSHDUP | + Opcode::VMOVSLDUP | + Opcode::VMOVUPD | + Opcode::VMOVUPS | + Opcode::VMPSADBW | + Opcode::VMULPD | + Opcode::VMULPS | + Opcode::VMULSD | + Opcode::VMULSS | + Opcode::VPABSB | + Opcode::VPABSD | + Opcode::VPABSW | + Opcode::VPACKSSDW | + Opcode::VPACKUSDW | + Opcode::VPACKSSWB | + Opcode::VPACKUSWB | + Opcode::VPADDB | + Opcode::VPADDD | + Opcode::VPADDQ | + Opcode::VPADDSB | + Opcode::VPADDSW | + Opcode::VPADDUSB | + Opcode::VPADDUSW | + Opcode::VPADDW | + Opcode::VPALIGNR | + Opcode::VPAND | + Opcode::VANDPD | + Opcode::VANDPS | + Opcode::VANDNPD | + Opcode::VANDNPS | + Opcode::VORPD | + Opcode::VORPS | + Opcode::VPANDN | + Opcode::VPAVGB | + Opcode::VPAVGW | + Opcode::VPBLENDD | + Opcode::VPBLENDVB | + Opcode::VPBLENDW | + Opcode::VPBROADCASTB | + Opcode::VPBROADCASTD | + Opcode::VPBROADCASTQ | + Opcode::VPBROADCASTW | + Opcode::VPCLMULQDQ | + Opcode::VPCMPEQB | + Opcode::VPCMPEQD | + Opcode::VPCMPEQQ | + Opcode::VPCMPEQW | + Opcode::VPCMPGTB | + Opcode::VPCMPGTD | + Opcode::VPCMPGTQ | + Opcode::VPCMPGTW | + Opcode::VPCMPESTRI | + Opcode::VPCMPESTRM | + Opcode::VPCMPISTRI | + Opcode::VPCMPISTRM | + Opcode::VPERM2F128 | + Opcode::VPERM2I128 | + Opcode::VPERMD | + Opcode::VPERMILPD | + Opcode::VPERMILPS | + Opcode::VPERMPD | + Opcode::VPERMPS | + Opcode::VPERMQ | + Opcode::VPEXTRB | + Opcode::VPEXTRD | + Opcode::VPEXTRQ | + Opcode::VPEXTRW | + Opcode::VPGATHERDD | + Opcode::VPGATHERDQ | + Opcode::VPGATHERQD | + Opcode::VPGATHERQQ | + Opcode::VPHADDD | + Opcode::VPHADDSW | + Opcode::VPHADDW | + Opcode::VPMADDUBSW | + Opcode::VPHMINPOSUW | + Opcode::VPHSUBD | + Opcode::VPHSUBSW | + Opcode::VPHSUBW | + Opcode::VPINSRB | + Opcode::VPINSRD | + Opcode::VPINSRQ | + Opcode::VPINSRW | + Opcode::VPMADDWD | + Opcode::VPMASKMOVD | + Opcode::VPMASKMOVQ | + Opcode::VPMAXSB | + Opcode::VPMAXSD | + Opcode::VPMAXSW | + Opcode::VPMAXUB | + Opcode::VPMAXUW | + Opcode::VPMAXUD | + Opcode::VPMINSB | + Opcode::VPMINSW | + Opcode::VPMINSD | + Opcode::VPMINUB | + Opcode::VPMINUW | + Opcode::VPMINUD | + Opcode::VPMOVMSKB | + Opcode::VPMOVSXBD | + Opcode::VPMOVSXBQ | + Opcode::VPMOVSXBW | + Opcode::VPMOVSXDQ | + Opcode::VPMOVSXWD | + Opcode::VPMOVSXWQ | + Opcode::VPMOVZXBD | + Opcode::VPMOVZXBQ | + Opcode::VPMOVZXBW | + Opcode::VPMOVZXDQ | + Opcode::VPMOVZXWD | + Opcode::VPMOVZXWQ | + Opcode::VPMULDQ | + Opcode::VPMULHRSW | + Opcode::VPMULHUW | + Opcode::VPMULHW | + Opcode::VPMULLQ | + Opcode::VPMULLD | + Opcode::VPMULLW | + Opcode::VPMULUDQ | + Opcode::VPOR | + Opcode::VPSADBW | + Opcode::VPSHUFB | + Opcode::VPSHUFD | + Opcode::VPSIGNB | + Opcode::VPSIGND | + Opcode::VPSIGNW | + Opcode::VPSLLD | + Opcode::VPSLLDQ | + Opcode::VPSLLQ | + Opcode::VPSLLVD | + Opcode::VPSLLVQ | + Opcode::VPSLLW | + Opcode::VPSRAD | + Opcode::VPSRAVD | + Opcode::VPSRAW | + Opcode::VPSRLD | + Opcode::VPSRLDQ | + Opcode::VPSRLQ | + Opcode::VPSRLVD | + Opcode::VPSRLVQ | + Opcode::VPSRLW | + Opcode::VPSUBB | + Opcode::VPSUBD | + Opcode::VPSUBQ | + Opcode::VPSUBSB | + Opcode::VPSUBSW | + Opcode::VPSUBUSB | + Opcode::VPSUBUSW | + Opcode::VPSUBW | + Opcode::VPTEST | + Opcode::VPUNPCKHBW | + Opcode::VPUNPCKHDQ | + Opcode::VPUNPCKHQDQ | + Opcode::VPUNPCKHWD | + Opcode::VPUNPCKLBW | + Opcode::VPUNPCKLDQ | + Opcode::VPUNPCKLQDQ | + Opcode::VPUNPCKLWD | + Opcode::VPXOR | + Opcode::VRCPPS | + Opcode::VROUNDPD | + Opcode::VROUNDPS | + Opcode::VROUNDSD | + Opcode::VROUNDSS | + Opcode::VRSQRTPS | + Opcode::VRSQRTSS | + Opcode::VRCPSS | + Opcode::VSHUFPD | + Opcode::VSHUFPS | + Opcode::VSQRTPD | + Opcode::VSQRTPS | + Opcode::VSQRTSS | + Opcode::VSQRTSD | + Opcode::VSUBPD | + Opcode::VSUBPS | + Opcode::VSUBSD | + Opcode::VSUBSS | + Opcode::VTESTPD | + Opcode::VTESTPS | + Opcode::VUNPCKHPD | + Opcode::VUNPCKHPS | + Opcode::VUNPCKLPD | + Opcode::VUNPCKLPS | + Opcode::VXORPD | + Opcode::VXORPS | + Opcode::VZEROUPPER | + Opcode::VZEROALL | + Opcode::VLDMXCSR | + Opcode::VSTMXCSR => { + // TODO: check a table for these + if !self.avx() { + return Err(DecodeError::InvalidOpcode); + } + } + Opcode::VAESDEC | + Opcode::VAESDECLAST | + Opcode::VAESENC | + Opcode::VAESENCLAST | + Opcode::VAESIMC | + Opcode::VAESKEYGENASSIST => { + // TODO: check a table for these + if !self.avx() || !self.aesni() { + return Err(DecodeError::InvalidOpcode); + } + } + Opcode::MOVBE => { + if !self.movbe() { + return Err(DecodeError::InvalidOpcode); + } + } + Opcode::POPCNT => { + /* + * from the intel SDM: + * ``` + * Before an application attempts to use the POPCNT instruction, it must check that + * the processor supports SSE4.2 (if CPUID.01H:ECX.SSE4_2[bit 20] = 1) and POPCNT + * (if CPUID.01H:ECX.POPCNT[bit 23] = 1). + * ``` + */ + if self.intel_quirks() && (self.sse4_2() || self.popcnt()) { + return Ok(()); + } else if !self.popcnt() { + /* + * elsewhere from the amd APM: + * `Instruction Subsets and CPUID Feature Flags` on page 507 indicates that + * popcnt is present when the popcnt bit is reported by cpuid. this seems to be + * the less quirky default, so `intel_quirks` is considered the outlier, and + * before this default. + * */ + return Err(DecodeError::InvalidOpcode); + } + } + Opcode::LZCNT => { + /* + * amd APM, `LZCNT` page 212: + * LZCNT is an Advanced Bit Manipulation (ABM) instruction. Support for the LZCNT + * instruction is indicated by CPUID Fn8000_0001_ECX[ABM] = 1. + * + * meanwhile the intel SDM simply states: + * ``` + * CPUID.EAX=80000001H:ECX.LZCNT[bit 5]: if 1 indicates the processor supports the + * LZCNT instruction. + * ``` + * + * so that's considered the less-quirky (default) case here. + * */ + if self.amd_quirks() && !self.abm() { + return Err(DecodeError::InvalidOpcode); + } else if !self.lzcnt() { + return Err(DecodeError::InvalidOpcode); + } + } + Opcode::ADCX | + Opcode::ADOX => { + if !self.adx() { + return Err(DecodeError::InvalidOpcode); + } + } + Opcode::VMRUN | + Opcode::VMLOAD | + Opcode::VMSAVE | + Opcode::CLGI | + Opcode::VMMCALL | + Opcode::INVLPGA => { + if !self.svm() { + return Err(DecodeError::InvalidOpcode); + } + } + Opcode::STGI | + Opcode::SKINIT => { + if !self.svm() || !self.skinit() { + return Err(DecodeError::InvalidOpcode); + } + } + Opcode::LAHF | + Opcode::SAHF => { + if !self.lahfsahf() { + return Err(DecodeError::InvalidOpcode); + } + } + Opcode::VCVTPS2PH | + Opcode::VCVTPH2PS => { + /* + * from intel SDM: + * ``` + * 14.4.1 Detection of F16C Instructions Application using float 16 instruction + * must follow a detection sequence similar to AVX to ensure: • The OS has + * enabled YMM state management support, • The processor support AVX as + * indicated by the CPUID feature flag, i.e. CPUID.01H:ECX.AVX[bit 28] = 1. • + * The processor support 16-bit floating-point conversion instructions via a + * CPUID feature flag (CPUID.01H:ECX.F16C[bit 29] = 1). + * ``` + * + * TODO: only the VEX-coded variant of this instruction should be gated on `f16c`. + * the EVEX-coded variant should be gated on `avx512f` or `avx512vl` if not + * EVEX.512-coded. + */ + if !self.avx() || !self.f16c() { + return Err(DecodeError::InvalidOpcode); + } + } + Opcode::RDRAND => { + if !self.rdrand() { + return Err(DecodeError::InvalidOpcode); + } + } + Opcode::RDSEED => { + if !self.rdseed() { + return Err(DecodeError::InvalidOpcode); + } + } + Opcode::MONITORX | Opcode::MWAITX | // these are gated on the `monitorx` and `mwaitx` cpuid bits, but are AMD-only. + Opcode::CLZERO | Opcode::RDPRU => { // again, gated on specific cpuid bits, but AMD-only. + if !self.amd_quirks() { + return Err(DecodeError::InvalidOpcode); + } + } + other => { + if !self.bmi1() { + if BMI1.contains(&other) { + return Err(DecodeError::InvalidOpcode); + } + } + if !self.bmi2() { + if BMI2.contains(&other) { + return Err(DecodeError::InvalidOpcode); + } + } + } + } + Ok(()) + } +} + +impl Default for InstDecoder { + /// Instantiates an x86 decoder that probably decodes what you want. + /// + /// Attempts to match real processors in interpretation of undefined sequences, and decodes any + /// instruction defined in any extension. + fn default() -> Self { + Self { + flags: 0xffffffff_ffffffff, + } + } +} + +impl Decoder for InstDecoder { + fn decode::Address, ::Word>>(&self, words: &mut T) -> Result::DecodeError> { + let mut instr = Instruction::invalid(); + read_instr(self, words, &mut instr)?; + + instr.length = words.offset() as u8; + if words.offset() > 15 { + return Err(DecodeError::TooLong); + } + + if self != &InstDecoder::default() { + self.revise_instruction(&mut instr)?; + } + + Ok(instr) + } + fn decode_into::Address, ::Word>>(&self, instr: &mut Instruction, words: &mut T) -> Result<(), ::DecodeError> { + read_instr(self, words, instr)?; + + instr.length = words.offset() as u8; + if words.offset() > 15 { + return Err(DecodeError::TooLong); + } + + if self != &InstDecoder::default() { + self.revise_instruction(instr)?; + } + + Ok(()) + } +} + +impl Opcode { + /// get the [`ConditionCode`] for this instruction, if it is in fact conditional. x86's + /// conditional instructions are `Jcc`, `CMOVcc`, andd `SETcc`. + pub fn condition(&self) -> Option { + match self { + Opcode::JO | + Opcode::CMOVO | + Opcode::SETO => { Some(ConditionCode::O) }, + Opcode::JNO | + Opcode::CMOVNO | + Opcode::SETNO => { Some(ConditionCode::NO) }, + Opcode::JB | + Opcode::CMOVB | + Opcode::SETB => { Some(ConditionCode::B) }, + Opcode::JNB | + Opcode::CMOVNB | + Opcode::SETAE => { Some(ConditionCode::AE) }, + Opcode::JZ | + Opcode::CMOVZ | + Opcode::SETZ => { Some(ConditionCode::Z) }, + Opcode::JNZ | + Opcode::CMOVNZ | + Opcode::SETNZ => { Some(ConditionCode::NZ) }, + Opcode::JA | + Opcode::CMOVA | + Opcode::SETA => { Some(ConditionCode::A) }, + Opcode::JNA | + Opcode::CMOVNA | + Opcode::SETBE => { Some(ConditionCode::BE) }, + Opcode::JS | + Opcode::CMOVS | + Opcode::SETS => { Some(ConditionCode::S) }, + Opcode::JNS | + Opcode::CMOVNS | + Opcode::SETNS => { Some(ConditionCode::NS) }, + Opcode::JP | + Opcode::CMOVP | + Opcode::SETP => { Some(ConditionCode::P) }, + Opcode::JNP | + Opcode::CMOVNP | + Opcode::SETNP => { Some(ConditionCode::NP) }, + Opcode::JL | + Opcode::CMOVL | + Opcode::SETL => { Some(ConditionCode::L) }, + Opcode::JGE | + Opcode::CMOVGE | + Opcode::SETGE => { Some(ConditionCode::GE) }, + Opcode::JG | + Opcode::CMOVG | + Opcode::SETG => { Some(ConditionCode::G) }, + Opcode::JLE | + Opcode::CMOVLE | + Opcode::SETLE => { Some(ConditionCode::LE) }, + _ => None, + } + } +} + +impl Default for Instruction { + fn default() -> Self { + Instruction::invalid() + } +} + +impl Instruction { + /// get the `Opcode` of this instruction. + pub fn opcode(&self) -> Opcode { + self.opcode + } + + /// get the `Operand` at the provided index. + /// + /// panics if the index is `>= 4`. + pub fn operand(&self, i: u8) -> Operand { + assert!(i < 4); + Operand::from_spec(self, self.operands[i as usize]) + } + + /// get the number of operands in this instruction. useful in iterating an instruction's + /// operands generically. + pub fn operand_count(&self) -> u8 { + self.operand_count + } + + /// check if operand `i` is an actual operand or not. will be `false` for `i >= + /// inst.operand_count()`. + pub fn operand_present(&self, i: u8) -> bool { + assert!(i < 4); + if i >= self.operand_count { + return false; + } + + if let OperandSpec::Nothing = self.operands[i as usize] { + false + } else { + true + } + } + + /// get the memory access information for this instruction, if it accesses memory. + /// + /// the corresponding `MemoryAccessSize` may report that the size of accessed memory is + /// indeterminate; this is the case for `xsave/xrestor`-style instructions whose operation size + /// varies based on physical processor. + pub fn mem_size(&self) -> Option { + if self.mem_size != 0 { + Some(MemoryAccessSize { size: self.mem_size }) + } else { + None + } + } + + /// build a new instruction representing nothing in particular. this is primarily useful as a + /// default to pass to `decode_into`. + pub fn invalid() -> Instruction { + Instruction { + prefixes: Prefixes::new(0), + opcode: Opcode::NOP, + mem_size: 0, + regs: [RegSpec::eax(); 4], + scale: 0, + length: 0, + disp: 0, + imm: 0, + operand_count: 0, + operands: [OperandSpec::Nothing; 4], + } + } + + /// get the `Segment` that will *actually* be used for accessing the operand at index `i`. + /// + /// `stos`, `lods`, `movs`, and `cmps` specifically name some segments for use regardless of + /// prefixes. + pub fn segment_override_for_op(&self, op: u8) -> Option { + match self.opcode { + Opcode::STOS => { + if op == 0 { + Some(Segment::ES) + } else { + None + } + } + Opcode::LODS => { + if op == 1 { + Some(self.prefixes.segment) + } else { + None + } + } + Opcode::MOVS => { + if op == 0 { + Some(Segment::ES) + } else if op == 1 { + Some(self.prefixes.segment) + } else { + None + } + } + Opcode::CMPS => { + if op == 0 { + Some(self.prefixes.segment) + } else if op == 1 { + Some(Segment::ES) + } else { + None + } + }, + _ => { + // most operands are pretty simple: + if self.operands[op as usize].is_memory() && + self.prefixes.segment != Segment::DS { + Some(self.prefixes.segment) + } else { + None + } + } + } + } + + #[cfg(feature = "fmt")] + /// wrap a reference to this instruction with a `DisplayStyle` to format the instruction with + /// later. see the documentation on [`display::DisplayStyle`] for more. + /// + /// ``` + /// use yaxpeax_x86::long_mode::{InstDecoder, DisplayStyle}; + /// + /// let decoder = InstDecoder::default(); + /// let inst = decoder.decode_slice(&[0x33, 0xc1]).unwrap(); + /// + /// assert_eq!("eax ^= ecx", inst.display_with(DisplayStyle::C).to_string()); + /// assert_eq!("xor eax, ecx", inst.display_with(DisplayStyle::Intel).to_string()); + /// ``` + pub fn display_with<'a>(&'a self, style: display::DisplayStyle) -> display::InstructionDisplayer<'a> { + display::InstructionDisplayer { + style, + instr: self, + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +struct EvexData { + // data: present, z, b, Lp, Rp. aaa + bits: u8, +} + +/// the prefixes on an instruction. +/// +/// `rep`, `repnz`, `lock`, and segment override prefixes are directly accessible here. `vex` and +/// `evex` prefixes are available through their associated helpers. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct Prefixes { + bits: u8, + vex: PrefixVex, + segment: Segment, + evex_data: EvexData, +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct PrefixEvex { + vex: PrefixVex, + evex_data: EvexData, +} + +impl PrefixEvex { + fn present(&self) -> bool { + self.evex_data.present() + } + /// the `evex` prefix's parts that overlap with `vex` definitions - `L`, `W`, `R`, `X`, and `B` + /// bits. + pub fn vex(&self) -> &PrefixVex { + &self.vex + } + /// the `avx512` mask register in use. `0` indicates "no mask register". + pub fn mask_reg(&self) -> u8 { + self.evex_data.aaa() + } + pub fn broadcast(&self) -> bool { + self.evex_data.b() + } + pub fn merge(&self) -> bool { + self.evex_data.z() + } + /// the `evex` `L'` bit. + pub fn lp(&self) -> bool { + self.evex_data.lp() + } + /// the `evex` `R'` bit. + pub fn rp(&self) -> bool { + self.evex_data.rp() + } +} + +/// bits specified in an avx/avx2 [`vex`](https://en.wikipedia.org/wiki/VEX_prefix) prefix, `L`, `W`, `R`, `X`, and `B`. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct PrefixVex { + bits: u8, +} + +#[allow(dead_code)] +impl PrefixVex { + #[inline] + pub fn b(&self) -> bool { (self.bits & 0x01) == 0x01 } + #[inline] + pub fn x(&self) -> bool { (self.bits & 0x02) == 0x02 } + #[inline] + pub fn r(&self) -> bool { (self.bits & 0x04) == 0x04 } + #[inline] + pub fn w(&self) -> bool { (self.bits & 0x08) == 0x08 } + #[inline] + pub fn l(&self) -> bool { (self.bits & 0x10) == 0x10 } + #[inline] + fn present(&self) -> bool { (self.bits & 0x80) == 0x80 } + #[inline] + fn compressed_disp(&self) -> bool { (self.bits & 0x20) == 0x20 } +} + +#[allow(dead_code)] +impl Prefixes { + fn new(bits: u8) -> Prefixes { + Prefixes { + bits: bits, + vex: PrefixVex { bits: 0 }, + segment: Segment::DS, + evex_data: EvexData { bits: 0 }, + } + } + fn vex_from(&mut self, bits: u8) { + self.vex = PrefixVex { + bits + }; + } + #[inline] + pub fn rep(&self) -> bool { self.bits & 0x30 == 0x10 } + #[inline] + fn set_rep(&mut self) { self.bits = (self.bits & 0xcf) | 0x10 } + #[inline] + pub fn repnz(&self) -> bool { self.bits & 0x30 == 0x30 } + #[inline] + fn set_repnz(&mut self) { self.bits = (self.bits & 0xcf) | 0x30 } + #[inline] + pub fn rep_any(&self) -> bool { self.bits & 0x30 != 0x00 } + #[inline] + fn operand_size(&self) -> bool { self.bits & 0x1 == 1 } + #[inline] + fn set_operand_size(&mut self) { self.bits = self.bits | 0x1 } + #[inline] + fn unset_operand_size(&mut self) { self.bits = self.bits & !0x1 } + #[inline] + fn address_size(&self) -> bool { self.bits & 0x2 == 2 } + #[inline] + fn set_address_size(&mut self) { self.bits = self.bits | 0x2 } + #[inline] + fn set_lock(&mut self) { self.bits |= 0x4 } + #[inline] + pub fn lock(&self) -> bool { self.bits & 0x4 == 4 } + #[inline] + pub fn cs(&mut self) { self.segment = Segment::CS } + #[inline] + fn set_cs(&mut self) { self.segment = Segment::CS } + #[inline] + pub fn ds(&self) -> bool { self.segment == Segment::DS } + #[inline] + fn set_ds(&mut self) { self.segment = Segment::DS } + #[inline] + pub fn es(&self) -> bool { self.segment == Segment::ES } + #[inline] + fn set_es(&mut self) { self.segment = Segment::ES } + #[inline] + pub fn fs(&self) -> bool { self.segment == Segment::FS } + #[inline] + fn set_fs(&mut self) { self.segment = Segment::FS } + #[inline] + pub fn gs(&self) -> bool { self.segment == Segment::GS } + #[inline] + fn set_gs(&mut self) { self.segment = Segment::GS } + #[inline] + pub fn ss(&self) -> bool { self.segment == Segment::SS } + #[inline] + fn set_ss(&mut self) { self.segment = Segment::SS } + #[inline] + fn vex_unchecked(&self) -> PrefixVex { PrefixVex { bits: self.vex.bits } } + #[inline] + pub fn vex(&self) -> Option { + let vex = self.vex_unchecked(); + if vex.present() { + Some(vex) + } else { + None + } + } + #[inline] + fn evex_unchecked(&self) -> PrefixEvex { PrefixEvex { vex: PrefixVex { bits: self.vex.bits }, evex_data: self.evex_data } } + #[inline] + pub fn evex(&self) -> Option { + let evex = self.evex_unchecked(); + if evex.present() { + Some(evex) + } else { + None + } + } + + #[inline] + fn apply_compressed_disp(&mut self, state: bool) { + if state { + self.vex.bits |= 0x20; + } else { + self.vex.bits &= 0xdf; + } + } + + #[inline] + fn vex_from_c5(&mut self, bits: u8) { + // collect rex bits + let r = bits & 0x80; + let wrxb = (r >> 5) ^ 0x04; + let l = (bits & 0x04) << 2; + let synthetic_rex = wrxb | l | 0x80; + self.vex = PrefixVex { bits: synthetic_rex }; + } + + #[inline] + fn vex_from_c4(&mut self, high: u8, low: u8) { + let w = low & 0x80; + let rxb = (high >> 5) ^ 0x07; + let wrxb = rxb | w >> 4; + let l = (low & 0x04) << 2; + let synthetic_vex = wrxb | l | 0x80; + self.vex = PrefixVex { bits: synthetic_vex }; + } + + #[inline] + fn evex_from(&mut self, b1: u8, b2: u8, b3: u8) { + let w = b2 & 0x80; + let rxb = ((b1 >> 5) & 0b111) ^ 0b111; // `rxb` is provided in inverted form + let wrxb = rxb | (w >> 4); + let l = (b3 & 0x20) >> 1; + let synthetic_vex = wrxb | l | 0x80; + self.vex_from(synthetic_vex); + + // R' is provided in inverted form + let rp = ((b1 & 0x10) >> 4) ^ 1; + let lp = (b3 & 0x40) >> 6; + let aaa = b3 & 0b111; + let z = (b3 & 0x80) >> 7; + let b = (b3 & 0x10) >> 4; + self.evex_data.from(rp, lp, z, b, aaa); + } +} + +impl EvexData { + fn from(&mut self, rp: u8, lp: u8, z: u8, b: u8, aaa: u8) { + let mut bits = 0; + bits |= aaa; + bits |= b << 3; + bits |= z << 4; + bits |= lp << 5; + bits |= rp << 6; + bits |= 0x80; + self.bits = bits; + } +} + +impl EvexData { + pub(crate) fn present(&self) -> bool { + self.bits & 0b1000_0000 != 0 + } + + pub(crate) fn aaa(&self) -> u8 { + self.bits & 0b111 + } + + pub(crate) fn b(&self) -> bool { + (self.bits & 0b0000_1000) != 0 + } + + pub(crate) fn z(&self) -> bool { + (self.bits & 0b0001_0000) != 0 + } + + pub(crate) fn lp(&self) -> bool { + (self.bits & 0b0010_0000) != 0 + } + + pub(crate) fn rp(&self) -> bool { + (self.bits & 0b0100_0000) != 0 + } +} + +#[derive(Debug)] +struct OperandCodeBuilder { + bits: u16 +} + +#[allow(non_camel_case_types)] +enum ZOperandCategory { + Zv_R = 0, + Zv_AX = 1, + Zb_Ib_R = 2, + Zv_Iv_R = 3, +} + +struct ZOperandInstructions { + bits: u16 +} + +impl ZOperandInstructions { + fn category(&self) -> u8 { + (self.bits >> 4) as u8 & 0b11 + } + fn reg(&self) -> u8 { + (self.bits & 0b111) as u8 + } +} + +struct EmbeddedOperandInstructions { + bits: u16 +} + +impl EmbeddedOperandInstructions { + #[allow(unused)] + fn bits(&self) -> u16 { + self.bits + } +} + +#[allow(non_snake_case)] +impl OperandCodeBuilder { + const fn new() -> Self { + OperandCodeBuilder { bits: 0 } + } + + const fn bits(&self) -> u16 { + self.bits + } + + const fn from_bits(bits: u16) -> Self { + Self { bits } + } + + const fn read_modrm(mut self) -> Self { + self.bits |= 0x8000; + self + } + + const fn op0_is_rrr_and_embedded_instructions(mut self) -> Self { + self = self.set_embedded_instructions(); + self.bits |= 0x2000; + self + } + + const fn set_embedded_instructions(mut self) -> Self { + self.bits |= 0x4000; + self + } + + #[allow(unused)] + const fn op0_is_rrr(&self) -> bool { + self.bits & 0x2000 != 0 + } + + fn has_embedded_instructions(&self) -> bool { + self.bits & 0x4000 != 0 + } + + fn get_embedded_instructions(&self) -> Result { + // 0x4000 indicates embedded instructions + // 0x3fff > 0x0080 indicates the embedded instructions are a Z-style operand + if self.bits & 0x7f80 <= 0x407f { + Ok(ZOperandInstructions { bits: self.bits }) + } else { + Err(EmbeddedOperandInstructions { bits: self.bits }) + } + } + + #[allow(unused)] + fn special_case_handler_index(&self) -> u16 { + self.bits & 0xff + } + + const fn special_case(mut self, case: u16) -> Self { + // leave 0x4000 unset + self.bits |= case & 0xff; + self + } + + const fn operand_case(mut self, case: u16) -> Self { + // leave 0x4000 unset + self.bits |= case & 0xff; + self + } + + const fn op0_is_rrr_and_Z_operand(mut self, category: ZOperandCategory, reg_num: u8) -> Self { + self = self.set_embedded_instructions(); + // if op0 is rrr, 0x2000 unset indicates the operand category written in bits 11:10 + // further, reg number is bits 0:2 + // + // when 0x2000 is unset: + // 0x1cf8 are all unused bits, so far + // + // if you're counting, that's 8 bits remaining. + // it also means one of those (0x0400?) can be used to pick some other interpretation + // scheme. + self.bits |= (category as u8 as u16) << 4; + self.bits |= reg_num as u16 & 0b111; + self + } + + const fn read_E(mut self) -> Self { + self.bits |= 0x1000; + self + } + + const fn has_read_E(&self) -> bool { + self.bits & 0x1000 != 0 + } + + const fn byte_operands(mut self) -> Self { + self.bits |= 0x0800; + self + } + + const fn mem_reg(mut self) -> Self { + self.bits |= 0x0400; + self + } + + const fn reg_mem(self) -> Self { + // 0x0400 unset + self + } + + const fn has_byte_operands(&self) -> bool { + (self.bits & 0x0800) != 0 + } + + #[allow(unused)] + const fn has_mem_reg(&self) -> bool { + (self.bits & 0x0400) != 0 + } + + const fn has_reg_mem(&self) -> bool { + (self.bits & 0x0400) == 0 + } + + const fn only_modrm_operands(mut self) -> Self { + self.bits |= 0x0200; + self + } + + const fn is_only_modrm_operands(&self) -> bool { + self.bits & 0x0200 != 0 + } + + // WHEN AN IMMEDIATE IS PRESENT, THERE ARE ONLY 0x3F ALLOWED SPECIAL CASES. + // WHEN NO IMMEDIATE IS PRESENT, THERE ARE 0xFF ALLOWED SPECIAL CASES. + // SIZE IS DECIDED BY THE FOLLOWING TABLE: + // 0: 1 BYTE + // 1: 4 BYTES + const fn with_imm(mut self, only_imm: bool, size: u8) -> Self { + self.bits |= 0x100; + self.bits |= (size as u16) << 6; + self.bits |= (only_imm as u16) << 7; + self + } + + fn has_imm(&self) -> Option<(bool, u8)> { + if self.bits & 0x100 != 0 { + Some(((self.bits & 0x80) != 0, (self.bits as u8 >> 6) & 1)) + } else { + None + } + } +} + +#[allow(non_camel_case_types)] +// might be able to pack these into a u8, but with `Operand` being u16 as well now there's little +// point. table entries will have a padding byte per record already. +// +// many of the one-off per-opcode variants could be written as 'decide based on opcode' but trying +// to pack this more tightly only makes sense if opcode were smaller, to get some space savings. +// +// bit 15 is "read modrm?" +// 0bMxxx_xxxx_xxxx_xxxx +// | +// | +// | +// | +// | +// | +// ---------------------------> read modr/m? +#[repr(u16)] +#[derive(Copy, Clone, Debug, PartialEq)] +enum OperandCode { + Ivs = OperandCodeBuilder::new().special_case(25).bits(), + I_3 = OperandCodeBuilder::new().special_case(27).bits(), + Nothing = OperandCodeBuilder::new().special_case(28).bits(), + Ib = OperandCodeBuilder::new().with_imm(false, 0).special_case(32).bits(), + Ibs = OperandCodeBuilder::new().with_imm(true, 0).special_case(33).bits(), + Jvds = OperandCodeBuilder::new().with_imm(true, 1).special_case(32).bits(), + Yv_Xv = OperandCodeBuilder::new().special_case(50).bits(), + + x87_d8 = OperandCodeBuilder::new().special_case(32).bits(), + x87_d9 = OperandCodeBuilder::new().special_case(33).bits(), + x87_da = OperandCodeBuilder::new().special_case(34).bits(), + x87_db = OperandCodeBuilder::new().special_case(35).bits(), + x87_dc = OperandCodeBuilder::new().special_case(36).bits(), + x87_dd = OperandCodeBuilder::new().special_case(37).bits(), + x87_de = OperandCodeBuilder::new().special_case(38).bits(), + x87_df = OperandCodeBuilder::new().special_case(39).bits(), + + Eb_R0 = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .byte_operands() + .operand_case(0) + .bits(), + AL_Ib = OperandCodeBuilder::new().special_case(33).with_imm(false, 0).bits(), + AX_Ib = OperandCodeBuilder::new().special_case(34).with_imm(false, 0).bits(), + Ib_AL = OperandCodeBuilder::new().special_case(35).with_imm(false, 0).bits(), + Ib_AX = OperandCodeBuilder::new().special_case(36).with_imm(false, 0).bits(), + AX_DX = OperandCodeBuilder::new().special_case(44).bits(), + AL_DX = OperandCodeBuilder::new().special_case(45).bits(), + DX_AX = OperandCodeBuilder::new().special_case(46).bits(), + DX_AL = OperandCodeBuilder::new().special_case(47).bits(), + MOVQ_f30f = OperandCodeBuilder::new().special_case(48).bits(), + +// Unsupported = OperandCodeBuilder::new().special_case(49).bits(), + + ModRM_0x0f00 = OperandCodeBuilder::new().read_modrm().special_case(40).bits(), + ModRM_0x0f01 = OperandCodeBuilder::new().read_modrm().special_case(41).bits(), + ModRM_0x0f0d = OperandCodeBuilder::new().read_modrm().special_case(42).bits(), + ModRM_0x0f0f = OperandCodeBuilder::new().read_modrm().special_case(65).bits(), // 3dnow + ModRM_0x0fae = OperandCodeBuilder::new().read_modrm().special_case(43).bits(), + ModRM_0x0fba = OperandCodeBuilder::new().read_modrm().special_case(44).bits(), +// ModRM_0xf30fae = OperandCodeBuilder::new().read_modrm().special_case(46).bits(), +// ModRM_0x660fae = OperandCodeBuilder::new().read_modrm().special_case(47).bits(), +// ModRM_0xf30fc7 = OperandCodeBuilder::new().read_modrm().special_case(48).bits(), +// ModRM_0x660f38 = OperandCodeBuilder::new().read_modrm().special_case(49).bits(), +// ModRM_0xf20f38 = OperandCodeBuilder::new().read_modrm().special_case(50).bits(), +// ModRM_0xf30f38 = OperandCodeBuilder::new().read_modrm().special_case(51).bits(), + ModRM_0xf30f38d8 = OperandCodeBuilder::new().read_modrm().special_case(45).bits(), + ModRM_0xf30f38dc = OperandCodeBuilder::new().read_modrm().special_case(46).bits(), + ModRM_0xf30f38dd = OperandCodeBuilder::new().read_modrm().special_case(47).bits(), + ModRM_0xf30f38de = OperandCodeBuilder::new().read_modrm().special_case(48).bits(), + ModRM_0xf30f38df = OperandCodeBuilder::new().read_modrm().special_case(49).bits(), + ModRM_0xf30f38fa = OperandCodeBuilder::new().read_modrm().special_case(50).bits(), + ModRM_0xf30f38fb = OperandCodeBuilder::new().read_modrm().special_case(51).bits(), + ModRM_0xf30f3af0 = OperandCodeBuilder::new().read_modrm().special_case(52).bits(), +// ModRM_0x660f3a = OperandCodeBuilder::new().read_modrm().special_case(52).bits(), +// ModRM_0x0f38 = OperandCodeBuilder::new().read_modrm().special_case(53).bits(), +// ModRM_0x0f3a = OperandCodeBuilder::new().read_modrm().special_case(54).bits(), + ModRM_0x0f71 = OperandCodeBuilder::new().read_modrm().special_case(55).bits(), + ModRM_0x0f72 = OperandCodeBuilder::new().read_modrm().special_case(56).bits(), + ModRM_0x0f73 = OperandCodeBuilder::new().read_modrm().special_case(57).bits(), + ModRM_0xf20f78 = OperandCodeBuilder::new().read_modrm().special_case(58).bits(), + ModRM_0x660f78 = OperandCodeBuilder::new().read_modrm().special_case(59).bits(), +// ModRM_0x660f12 = OperandCodeBuilder::new().read_modrm().special_case(58).bits(), +// ModRM_0x660f16 = OperandCodeBuilder::new().read_modrm().special_case(59).bits(), +// ModRM_0x660f71 = OperandCodeBuilder::new().read_modrm().special_case(60).bits(), +// ModRM_0x660f72 = OperandCodeBuilder::new().read_modrm().special_case(61).bits(), +// ModRM_0x660f73 = OperandCodeBuilder::new().read_modrm().special_case(62).bits(), +// ModRM_0x660fc7 = OperandCodeBuilder::new().read_modrm().special_case(63).bits(), + ModRM_0x0fc7 = OperandCodeBuilder::new().read_modrm().special_case(64).bits(), + ModRM_0xc4 = OperandCodeBuilder::new().read_modrm().special_case(66).bits(), + ModRM_0xc5 = OperandCodeBuilder::new().read_modrm().special_case(67).bits(), + // xmmword? + ModRM_0x0f12 = OperandCodeBuilder::new() + .read_modrm() + .op0_is_rrr_and_embedded_instructions() + .read_E() + .reg_mem() + .operand_case(65) + .bits(), + // xmmword? + ModRM_0x0f16 = OperandCodeBuilder::new() + .read_modrm() + .op0_is_rrr_and_embedded_instructions() + .read_E() + .reg_mem() + .operand_case(66) + .bits(), + // encode immediates? + ModRM_0xc0_Eb_Ib = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .byte_operands() + .operand_case(5) + .bits(), + ModRM_0xc1_Ev_Ib = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(6) + .bits(), + ModRM_0xd0_Eb_1 = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .byte_operands() + .operand_case(7) + .bits(), + ModRM_0xd1_Ev_1 = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(8) + .bits(), + ModRM_0xd2_Eb_CL = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .byte_operands() + .operand_case(9) + .bits(), + ModRM_0xd3_Ev_CL = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(10) + .bits(), + ModRM_0x80_Eb_Ib = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .with_imm(false, 0) + .byte_operands() + .operand_case(1) + .bits(), + ModRM_0x83_Ev_Ibs = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .with_imm(false, 0) + .operand_case(26) + .bits(), + // this would be Eb_Ivs, 0x8e + ModRM_0x81_Ev_Ivs = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(2) + .bits(), + ModRM_0xc6_Eb_Ib = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .byte_operands() + .operand_case(3) + .bits(), + ModRM_0xc7_Ev_Iv = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(4) + .bits(), + ModRM_0xfe_Eb = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .byte_operands() + .operand_case(13) + .bits(), + ModRM_0x8f_Ev = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(30) + .bits(), + // gap, 0x94 + ModRM_0xff_Ev = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(14) + .bits(), + ModRM_0x0f18 = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(58) + .bits(), + ModRM_0xf6 = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .byte_operands() + .operand_case(11) + .bits(), + ModRM_0xf7 = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(12) + .bits(), + Ev = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(18) + .bits(), + Zv_R0 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 0).bits(), + Zv_R1 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 1).bits(), + Zv_R2 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 2).bits(), + Zv_R3 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 3).bits(), + Zv_R4 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 4).bits(), + Zv_R5 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 5).bits(), + Zv_R6 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 6).bits(), + Zv_R7 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 7).bits(), + // Zv_AX_R0 = 0x48, + Zv_AX_R1 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 1).bits(), + Zv_AX_R2 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 2).bits(), + Zv_AX_R3 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 3).bits(), + Zv_AX_R4 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 4).bits(), + Zv_AX_R5 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 5).bits(), + Zv_AX_R6 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 6).bits(), + Zv_AX_R7 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 7).bits(), + Zb_Ib_R0 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zb_Ib_R, 0).bits(), + Zb_Ib_R1 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zb_Ib_R, 1).bits(), + Zb_Ib_R2 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zb_Ib_R, 2).bits(), + Zb_Ib_R3 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zb_Ib_R, 3).bits(), + Zb_Ib_R4 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zb_Ib_R, 4).bits(), + Zb_Ib_R5 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zb_Ib_R, 5).bits(), + Zb_Ib_R6 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zb_Ib_R, 6).bits(), + Zb_Ib_R7 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zb_Ib_R, 7).bits(), + Zv_Iv_R0 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Iv_R, 0).bits(), + Zv_Iv_R1 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Iv_R, 1).bits(), + Zv_Iv_R2 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Iv_R, 2).bits(), + Zv_Iv_R3 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Iv_R, 3).bits(), + Zv_Iv_R4 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Iv_R, 4).bits(), + Zv_Iv_R5 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Iv_R, 5).bits(), + Zv_Iv_R6 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Iv_R, 6).bits(), + Zv_Iv_R7 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Iv_R, 7).bits(), + Gv_Eb = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(15).bits(), + Gv_Ew = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(16).bits(), + Gv_Ew_LSL = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(37).bits(), +// Gdq_Ed = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(17).bits(), + Gd_Ed = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().operand_case(51).bits(), + Md_Gd = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().operand_case(52).bits(), +// Gdq_Ed = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(17).bits(), + Gd_Ev = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(40).bits(), +// Md_Gd = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(51).bits(), + G_E_xmm_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(22).bits(), + G_E_xmm_Ub = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(60).bits(), + G_U_xmm_Ub = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(61).bits(), + AL_Ob = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(50).bits(), + AL_Xb = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(52).bits(), + AX_Ov = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(53).bits(), + AL_Ibs = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().with_imm(false, 0).byte_operands().operand_case(23).bits(), + AX_Ivd = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(24).bits(), + + Eb_Gb = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().byte_operands().only_modrm_operands().mem_reg().bits(), + Ev_Gv = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().only_modrm_operands().mem_reg().bits(), + Gb_Eb = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().byte_operands().only_modrm_operands().reg_mem().bits(), + Gv_Ev = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().only_modrm_operands().reg_mem().bits(), + Gv_M = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().only_modrm_operands().reg_mem().operand_case(25).bits(), + MOVDIR64B = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(108).bits(), + M_Gv = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(109).bits(), + Gv_Ev_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().with_imm(false, 0).reg_mem().operand_case(40).bits(), + + Gv_Ev_Iv = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(41).bits(), + Rv_Gmm_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_modrm().read_E().reg_mem().operand_case(55).bits(), + // gap, 0x9a + G_xmm_E_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(53).bits(), + G_xmm_U_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(54).bits(), + U_mm_G_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(55).bits(), + G_xmm_Ed = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(57).bits(), + G_mm_E_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(58).bits(), + Gd_U_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(59).bits(), + Gv_E_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(60).bits(), + //= 0x816f, // mirror G_xmm_Ed, but also read an immediate + G_xmm_Ew_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(61).bits(), + G_U_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(62).bits(), + G_M_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(20).bits(), + G_E_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(21).bits(), + E_G_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(19).bits(), + G_Ed_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(31).bits(), + Ed_G_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(29).bits(), + M_G_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(63).bits(), + G_E_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(64).bits(), + G_U_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(65).bits(), + E_G_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(66).bits(), + Ed_G_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(67).bits(), + // Ed_G_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(68).bits(), + G_mm_Ed = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(69).bits(), + G_mm_E = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(70).bits(), + Ev_Gv_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(71).bits(), + Ev_Gv_CL = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(72).bits(), + G_mm_U_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(73).bits(), + G_Mq_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(74).bits(), + G_mm_Ew_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(75).bits(), + G_E_q = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(76).bits(), + E_G_q = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(77).bits(), + CVT_AA = OperandCodeBuilder::new().special_case(77).bits(), + CVT_DA = OperandCodeBuilder::new().special_case(78).bits(), + Rq_Cq_0 = OperandCodeBuilder::new().special_case(79).bits(), + Rq_Dq_0 = OperandCodeBuilder::new().special_case(80).bits(), + Cq_Rq_0 = OperandCodeBuilder::new().special_case(81).bits(), + Dq_Rq_0 = OperandCodeBuilder::new().special_case(82).bits(), + FS = OperandCodeBuilder::new().special_case(83).bits(), + GS = OperandCodeBuilder::new().special_case(84).bits(), + Yb_DX = OperandCodeBuilder::new().special_case(85).bits(), + Yv_DX = OperandCodeBuilder::new().special_case(86).bits(), + DX_Xb = OperandCodeBuilder::new().special_case(87).bits(), + DX_Xv = OperandCodeBuilder::new().special_case(88).bits(), + AH = OperandCodeBuilder::new().special_case(89).bits(), + AX_Xv = OperandCodeBuilder::new().special_case(90).bits(), + Ew_Sw = OperandCodeBuilder::new().special_case(91).bits(), + Fw = OperandCodeBuilder::new().special_case(92).bits(), + I_1 = OperandCodeBuilder::new().special_case(93).bits(), + Iw = OperandCodeBuilder::new().special_case(94).bits(), + Iw_Ib = OperandCodeBuilder::new().special_case(95).bits(), + Ob_AL = OperandCodeBuilder::new().special_case(96).bits(), + Ov_AX = OperandCodeBuilder::new().special_case(97).bits(), + Sw_Ew = OperandCodeBuilder::new().special_case(98).bits(), + Yb_AL = OperandCodeBuilder::new().special_case(99).bits(), + Yb_Xb = OperandCodeBuilder::new().special_case(100).bits(), + Yv_AX = OperandCodeBuilder::new().special_case(101).bits(), + Ew_Gw = OperandCodeBuilder::new().special_case(102).bits(), + ES = OperandCodeBuilder::new().special_case(103).bits(), + CS = OperandCodeBuilder::new().special_case(104).bits(), + SS = OperandCodeBuilder::new().special_case(105).bits(), + DS = OperandCodeBuilder::new().special_case(106).bits(), + ModRM_0x62 = OperandCodeBuilder::new().special_case(107).bits(), + INV_Gv_M = OperandCodeBuilder::new().special_case(108).bits(), + PMOVX_G_E_xmm = OperandCodeBuilder::new().operand_case(109).bits(), + PMOVX_E_G_xmm = OperandCodeBuilder::new().operand_case(110).bits(), + G_Ev_xmm_Ib = OperandCodeBuilder::new().operand_case(111).bits(), + G_E_mm_Ib = OperandCodeBuilder::new().operand_case(112).bits(), +} + +const LOCKABLE_INSTRUCTIONS: &[Opcode] = &[ + Opcode::ADD, + Opcode::ADC, + Opcode::AND, + Opcode::BTC, + Opcode::BTR, + Opcode::BTS, + Opcode::CMPXCHG, + Opcode::CMPXCHG8B, + Opcode::DEC, + Opcode::INC, + Opcode::NEG, + Opcode::NOT, + Opcode::OR, + Opcode::SBB, + Opcode::SUB, + Opcode::XOR, + Opcode::XADD, + Opcode::XCHG, +]; + +fn base_opcode_map(v: u8) -> Opcode { + match v { + 0 => Opcode::ADD, + 1 => Opcode::OR, + 2 => Opcode::ADC, + 3 => Opcode::SBB, + 4 => Opcode::AND, + 5 => Opcode::SUB, + 6 => Opcode::XOR, + 7 => Opcode::CMP, + _ => { unsafe { unreachable_unchecked() } } + } +} + +const BITWISE_OPCODE_MAP: [Opcode; 8] = [ + Opcode::ROL, + Opcode::ROR, + Opcode::RCL, + Opcode::RCR, + Opcode::SHL, + Opcode::SHR, + Opcode::SAL, + Opcode::SAR +]; + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum Interpretation { + Instruction(Opcode), + Prefix, +} + +#[derive(Copy, Clone, Debug, PartialEq)] +// this should be a 32-byte struct.. +struct OpcodeRecord(Interpretation, OperandCode); + +#[test] +fn opcode_record_size() { + // there are more than 256 opcodes... + assert_eq!(core::mem::size_of::(), 4); +} + +const OPCODES: [OpcodeRecord; 256] = [ + OpcodeRecord(Interpretation::Instruction(Opcode::ADD), OperandCode::Eb_Gb), + OpcodeRecord(Interpretation::Instruction(Opcode::ADD), OperandCode::Ev_Gv), + OpcodeRecord(Interpretation::Instruction(Opcode::ADD), OperandCode::Gb_Eb), + OpcodeRecord(Interpretation::Instruction(Opcode::ADD), OperandCode::Gv_Ev), + OpcodeRecord(Interpretation::Instruction(Opcode::ADD), OperandCode::AL_Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::ADD), OperandCode::AX_Ivd), + OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::ES), + OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::ES), + OpcodeRecord(Interpretation::Instruction(Opcode::OR), OperandCode::Eb_Gb), + OpcodeRecord(Interpretation::Instruction(Opcode::OR), OperandCode::Ev_Gv), + OpcodeRecord(Interpretation::Instruction(Opcode::OR), OperandCode::Gb_Eb), + OpcodeRecord(Interpretation::Instruction(Opcode::OR), OperandCode::Gv_Ev), + OpcodeRecord(Interpretation::Instruction(Opcode::OR), OperandCode::AL_Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::OR), OperandCode::AX_Ivd), + OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::CS), + OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::ADC), OperandCode::Eb_Gb), + OpcodeRecord(Interpretation::Instruction(Opcode::ADC), OperandCode::Ev_Gv), + OpcodeRecord(Interpretation::Instruction(Opcode::ADC), OperandCode::Gb_Eb), + OpcodeRecord(Interpretation::Instruction(Opcode::ADC), OperandCode::Gv_Ev), + OpcodeRecord(Interpretation::Instruction(Opcode::ADC), OperandCode::AL_Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::ADC), OperandCode::AX_Ivd), + OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::SS), + OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::SS), + OpcodeRecord(Interpretation::Instruction(Opcode::SBB), OperandCode::Eb_Gb), + OpcodeRecord(Interpretation::Instruction(Opcode::SBB), OperandCode::Ev_Gv), + OpcodeRecord(Interpretation::Instruction(Opcode::SBB), OperandCode::Gb_Eb), + OpcodeRecord(Interpretation::Instruction(Opcode::SBB), OperandCode::Gv_Ev), + OpcodeRecord(Interpretation::Instruction(Opcode::SBB), OperandCode::AL_Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::SBB), OperandCode::AX_Ivd), + OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::DS), + OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::DS), + OpcodeRecord(Interpretation::Instruction(Opcode::AND), OperandCode::Eb_Gb), + OpcodeRecord(Interpretation::Instruction(Opcode::AND), OperandCode::Ev_Gv), + OpcodeRecord(Interpretation::Instruction(Opcode::AND), OperandCode::Gb_Eb), + OpcodeRecord(Interpretation::Instruction(Opcode::AND), OperandCode::Gv_Ev), + OpcodeRecord(Interpretation::Instruction(Opcode::AND), OperandCode::AL_Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::AND), OperandCode::AX_Ivd), + OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::DAA), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::SUB), OperandCode::Eb_Gb), + OpcodeRecord(Interpretation::Instruction(Opcode::SUB), OperandCode::Ev_Gv), + OpcodeRecord(Interpretation::Instruction(Opcode::SUB), OperandCode::Gb_Eb), + OpcodeRecord(Interpretation::Instruction(Opcode::SUB), OperandCode::Gv_Ev), + OpcodeRecord(Interpretation::Instruction(Opcode::SUB), OperandCode::AL_Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::SUB), OperandCode::AX_Ivd), + OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::DAS), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::XOR), OperandCode::Eb_Gb), + OpcodeRecord(Interpretation::Instruction(Opcode::XOR), OperandCode::Ev_Gv), + OpcodeRecord(Interpretation::Instruction(Opcode::XOR), OperandCode::Gb_Eb), + OpcodeRecord(Interpretation::Instruction(Opcode::XOR), OperandCode::Gv_Ev), + OpcodeRecord(Interpretation::Instruction(Opcode::XOR), OperandCode::AL_Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::XOR), OperandCode::AX_Ivd), + OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::AAA), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::CMP), OperandCode::Eb_Gb), + OpcodeRecord(Interpretation::Instruction(Opcode::CMP), OperandCode::Ev_Gv), + OpcodeRecord(Interpretation::Instruction(Opcode::CMP), OperandCode::Gb_Eb), + OpcodeRecord(Interpretation::Instruction(Opcode::CMP), OperandCode::Gv_Ev), + OpcodeRecord(Interpretation::Instruction(Opcode::CMP), OperandCode::AL_Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::CMP), OperandCode::AX_Ivd), + OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::AAS), OperandCode::Nothing), +// 0x40: + OpcodeRecord(Interpretation::Instruction(Opcode::INC), OperandCode::Zv_R0), + OpcodeRecord(Interpretation::Instruction(Opcode::INC), OperandCode::Zv_R1), + OpcodeRecord(Interpretation::Instruction(Opcode::INC), OperandCode::Zv_R2), + OpcodeRecord(Interpretation::Instruction(Opcode::INC), OperandCode::Zv_R3), + OpcodeRecord(Interpretation::Instruction(Opcode::INC), OperandCode::Zv_R4), + OpcodeRecord(Interpretation::Instruction(Opcode::INC), OperandCode::Zv_R5), + OpcodeRecord(Interpretation::Instruction(Opcode::INC), OperandCode::Zv_R6), + OpcodeRecord(Interpretation::Instruction(Opcode::INC), OperandCode::Zv_R7), + OpcodeRecord(Interpretation::Instruction(Opcode::DEC), OperandCode::Zv_R0), + OpcodeRecord(Interpretation::Instruction(Opcode::DEC), OperandCode::Zv_R1), + OpcodeRecord(Interpretation::Instruction(Opcode::DEC), OperandCode::Zv_R2), + OpcodeRecord(Interpretation::Instruction(Opcode::DEC), OperandCode::Zv_R3), + OpcodeRecord(Interpretation::Instruction(Opcode::DEC), OperandCode::Zv_R4), + OpcodeRecord(Interpretation::Instruction(Opcode::DEC), OperandCode::Zv_R5), + OpcodeRecord(Interpretation::Instruction(Opcode::DEC), OperandCode::Zv_R6), + OpcodeRecord(Interpretation::Instruction(Opcode::DEC), OperandCode::Zv_R7), +// 0x50: + OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Zv_R0), + OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Zv_R1), + OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Zv_R2), + OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Zv_R3), + OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Zv_R4), + OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Zv_R5), + OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Zv_R6), + OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Zv_R7), + OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::Zv_R0), + OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::Zv_R1), + OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::Zv_R2), + OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::Zv_R3), + OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::Zv_R4), + OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::Zv_R5), + OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::Zv_R6), + OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::Zv_R7), +// 0x60 + OpcodeRecord(Interpretation::Instruction(Opcode::PUSHA), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::POPA), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::BOUND), OperandCode::ModRM_0x62), + OpcodeRecord(Interpretation::Instruction(Opcode::ARPL), OperandCode::Ew_Gw), + OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), + OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), + OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), + OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Ivs), + OpcodeRecord(Interpretation::Instruction(Opcode::IMUL), OperandCode::Gv_Ev_Iv), + OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::IMUL), OperandCode::Gv_Ev_Ib), + OpcodeRecord(Interpretation::Instruction(Opcode::INS), OperandCode::Yb_DX), + OpcodeRecord(Interpretation::Instruction(Opcode::INS), OperandCode::Yv_DX), + OpcodeRecord(Interpretation::Instruction(Opcode::OUTS), OperandCode::DX_Xb), + OpcodeRecord(Interpretation::Instruction(Opcode::OUTS), OperandCode::DX_Xv), +// 0x70 + OpcodeRecord(Interpretation::Instruction(Opcode::JO), OperandCode::Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::JNO), OperandCode::Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::JB), OperandCode::Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::JNB), OperandCode::Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::JZ), OperandCode::Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::JNZ), OperandCode::Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::JNA), OperandCode::Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::JA), OperandCode::Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::JS), OperandCode::Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::JNS), OperandCode::Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::JP), OperandCode::Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::JNP), OperandCode::Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::JL), OperandCode::Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::JGE), OperandCode::Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::JLE), OperandCode::Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::JG), OperandCode::Ibs), +// 0x80 + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x80_Eb_Ib), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x81_Ev_Ivs), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x83_Ev_Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::TEST), OperandCode::Eb_Gb), + OpcodeRecord(Interpretation::Instruction(Opcode::TEST), OperandCode::Ev_Gv), + OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Eb_Gb), + OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Ev_Gv), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Eb_Gb), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Ev_Gv), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Gb_Eb), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Gv_Ev), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Ew_Sw), + OpcodeRecord(Interpretation::Instruction(Opcode::LEA), OperandCode::Gv_M), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Sw_Ew), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x8f_Ev), + OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R1), + OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R2), + OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R3), + OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R4), + OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R5), + OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R6), + OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R7), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::CVT_AA), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::CVT_DA), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::WAIT), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::PUSHF), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::POPF), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::SAHF), OperandCode::AH), + OpcodeRecord(Interpretation::Instruction(Opcode::LAHF), OperandCode::AH), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::AL_Ob), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::AX_Ov), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Ob_AL), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Ov_AX), + OpcodeRecord(Interpretation::Instruction(Opcode::MOVS), OperandCode::Yb_Xb), + OpcodeRecord(Interpretation::Instruction(Opcode::MOVS), OperandCode::Yv_Xv), + OpcodeRecord(Interpretation::Instruction(Opcode::CMPS), OperandCode::Yb_Xb), + OpcodeRecord(Interpretation::Instruction(Opcode::CMPS), OperandCode::Yv_Xv), + OpcodeRecord(Interpretation::Instruction(Opcode::TEST), OperandCode::AL_Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::TEST), OperandCode::AX_Ivd), + OpcodeRecord(Interpretation::Instruction(Opcode::STOS), OperandCode::Yb_AL), + OpcodeRecord(Interpretation::Instruction(Opcode::STOS), OperandCode::Yv_AX), + OpcodeRecord(Interpretation::Instruction(Opcode::LODS), OperandCode::AL_Xb), + OpcodeRecord(Interpretation::Instruction(Opcode::LODS), OperandCode::AX_Xv), + OpcodeRecord(Interpretation::Instruction(Opcode::SCAS), OperandCode::Yb_AL), + OpcodeRecord(Interpretation::Instruction(Opcode::SCAS), OperandCode::Yv_AX), +// 0xb0 + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zb_Ib_R0), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zb_Ib_R1), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zb_Ib_R2), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zb_Ib_R3), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zb_Ib_R4), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zb_Ib_R5), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zb_Ib_R6), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zb_Ib_R7), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zv_Iv_R0), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zv_Iv_R1), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zv_Iv_R2), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zv_Iv_R3), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zv_Iv_R4), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zv_Iv_R5), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zv_Iv_R6), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zv_Iv_R7), +// 0xc0 + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xc0_Eb_Ib), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xc1_Ev_Ib), + OpcodeRecord(Interpretation::Instruction(Opcode::RETURN), OperandCode::Iw), + OpcodeRecord(Interpretation::Instruction(Opcode::RETURN), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::LES), OperandCode::ModRM_0xc4), + OpcodeRecord(Interpretation::Instruction(Opcode::LDS), OperandCode::ModRM_0xc5), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::ModRM_0xc6_Eb_Ib), + OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::ModRM_0xc7_Ev_Iv), + OpcodeRecord(Interpretation::Instruction(Opcode::ENTER), OperandCode::Iw_Ib), + OpcodeRecord(Interpretation::Instruction(Opcode::LEAVE), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::RETF), OperandCode::Iw), + OpcodeRecord(Interpretation::Instruction(Opcode::RETF), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::INT), OperandCode::I_3), + OpcodeRecord(Interpretation::Instruction(Opcode::INT), OperandCode::Ib), + OpcodeRecord(Interpretation::Instruction(Opcode::INTO), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::IRET), OperandCode::Fw), +// 0xd0 + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xd0_Eb_1), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xd1_Ev_1), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xd2_Eb_CL), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xd3_Ev_CL), + OpcodeRecord(Interpretation::Instruction(Opcode::AAM), OperandCode::Ib), + OpcodeRecord(Interpretation::Instruction(Opcode::AAD), OperandCode::Ib), + OpcodeRecord(Interpretation::Instruction(Opcode::SALC), OperandCode::Nothing), + // XLAT + OpcodeRecord(Interpretation::Instruction(Opcode::XLAT), OperandCode::Nothing), + // x86 d8 + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_d8), + // x86 d9 + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_d9), + // x86 da + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_da), + // x86 db + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_db), + // x86 dc + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_dc), + // x86 dd + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_dd), + // x86 de + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_de), + // x86 df + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_df), +// 0xe0 + OpcodeRecord(Interpretation::Instruction(Opcode::LOOPNZ), OperandCode::Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::LOOPZ), OperandCode::Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::LOOP), OperandCode::Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::JCXZ), OperandCode::Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::IN), OperandCode::AL_Ib), + OpcodeRecord(Interpretation::Instruction(Opcode::IN), OperandCode::AX_Ib), + OpcodeRecord(Interpretation::Instruction(Opcode::OUT), OperandCode::Ib_AL), + OpcodeRecord(Interpretation::Instruction(Opcode::OUT), OperandCode::Ib_AX), +// 0xe8 + OpcodeRecord(Interpretation::Instruction(Opcode::CALL), OperandCode::Jvds), + OpcodeRecord(Interpretation::Instruction(Opcode::JMP), OperandCode::Jvds), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::JMP), OperandCode::Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::IN), OperandCode::AL_DX), + OpcodeRecord(Interpretation::Instruction(Opcode::IN), OperandCode::AX_DX), + OpcodeRecord(Interpretation::Instruction(Opcode::OUT), OperandCode::DX_AL), + OpcodeRecord(Interpretation::Instruction(Opcode::OUT), OperandCode::DX_AX), +// 0xf0 + OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), + // ICEBP? + OpcodeRecord(Interpretation::Instruction(Opcode::INT), OperandCode::I_1), + OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), + OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), +// 0xf4 + OpcodeRecord(Interpretation::Instruction(Opcode::HLT), OperandCode::Nothing), + // CMC + OpcodeRecord(Interpretation::Instruction(Opcode::CMC), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf6), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf7), + OpcodeRecord(Interpretation::Instruction(Opcode::CLC), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::STC), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::CLI), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::STI), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::CLD), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::STD), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xfe_Eb), + // TODO: test 0xff /3 + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xff_Ev), +]; + +#[allow(non_snake_case)] +pub(self) fn read_E::Address, ::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8, width: u8) -> Result { + let bank = width_to_gp_reg_bank(width); + if modrm >= 0b11000000 { + read_modrm_reg(instr, modrm, bank) + } else { + read_M(words, instr, modrm) + } +} +#[allow(non_snake_case)] +pub(self) fn read_E_mm::Address, ::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8) -> Result { + if modrm >= 0b11000000 { + read_modrm_reg(instr, modrm, RegisterBank::MM) + } else { + read_M(words, instr, modrm) + } +} +#[allow(non_snake_case)] +pub(self) fn read_E_st::Address, ::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8) -> Result { + if modrm >= 0b11000000 { + read_modrm_reg(instr, modrm, RegisterBank::ST) + } else { + read_M(words, instr, modrm) + } +} +#[allow(non_snake_case)] +pub(self) fn read_E_xmm::Address, ::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8) -> Result { + if modrm >= 0b11000000 { + read_modrm_reg(instr, modrm, RegisterBank::X) + } else { + read_M(words, instr, modrm) + } +} +#[allow(non_snake_case)] +pub(self) fn read_E_ymm::Address, ::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8) -> Result { + if modrm >= 0b11000000 { + read_modrm_reg(instr, modrm, RegisterBank::Y) + } else { + read_M(words, instr, modrm) + } +} +#[allow(non_snake_case)] +pub(self) fn read_E_vex::Address, ::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8, bank: RegisterBank) -> Result { + if modrm >= 0b11000000 { + read_modrm_reg(instr, modrm, bank) + } else { + let res = read_M(words, instr, modrm)?; + if (modrm & 0b01_000_000) == 0b01_000_000 { + instr.prefixes.apply_compressed_disp(true); + } + Ok(res) + } +} + +#[allow(non_snake_case)] +fn read_modrm_reg(instr: &mut Instruction, modrm: u8, reg_bank: RegisterBank) -> Result { + instr.regs[1] = RegSpec::from_parts(modrm & 7, reg_bank); + Ok(OperandSpec::RegMMM) +} + +#[allow(non_snake_case)] +fn read_sib::Address, ::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8) -> Result { + let modbits = modrm >> 6; + let sibbyte = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; + instr.regs[1].num |= sibbyte & 7; + instr.regs[2].num |= (sibbyte >> 3) & 7; + + let disp = if modbits == 0b00 { + if (sibbyte & 7) == 0b101 { + read_num(words, 4)? as i32 + } else { + 0 + } + } else if modbits == 0b01 { + read_num(words, 1)? as i8 as i32 + } else { + read_num(words, 4)? as i32 + }; + instr.disp = disp as u32; + + let scale = 1u8 << (sibbyte >> 6); + instr.scale = scale; + + let op_spec = if (sibbyte & 7) == 0b101 { + if ((sibbyte >> 3) & 7) == 0b100 { + if modbits == 0b00 { + OperandSpec::DispU32 + } else { + instr.regs[1].num |= 0b101; + + if disp == 0 { + OperandSpec::Deref + } else { + OperandSpec::RegDisp + } + } + } else { + instr.regs[1].num |= 0b101; + instr.regs[2].num |= (sibbyte >> 3) & 7; + + let scale = 1u8 << (sibbyte >> 6); + instr.scale = scale; + + if disp == 0 { + if modbits == 0 { + OperandSpec::RegScale + } else { + OperandSpec::RegIndexBaseScale + } + } else { + if modbits == 0 { + OperandSpec::RegScaleDisp + } else { + OperandSpec::RegIndexBaseScaleDisp + } + } + } + } else { + instr.regs[1].num |= sibbyte & 7; + + if ((sibbyte >> 3) & 7) == 0b100 { + if disp == 0 { + OperandSpec::Deref + } else { + OperandSpec::RegDisp + } + } else { + instr.regs[2].num |= (sibbyte >> 3) & 7; + + let scale = 1u8 << (sibbyte >> 6); + instr.scale = scale; + if disp == 0 { + OperandSpec::RegIndexBaseScale + } else { + OperandSpec::RegIndexBaseScaleDisp + } + } + }; + Ok(op_spec) +} + +#[allow(non_snake_case)] +fn read_M_16bit::Address, ::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8) -> Result { + let modbits = modrm >> 6; + let mmm = modrm & 7; + if modbits == 0b00 && mmm == 0b110 { + return Ok(OperandSpec::DispU16); + } + match mmm { + 0b000 => { + instr.regs[1] = RegSpec::bx(); + instr.regs[2] = RegSpec::si(); + }, + 0b001 => { + instr.regs[1] = RegSpec::bx(); + instr.regs[2] = RegSpec::di(); + }, + 0b010 => { + instr.regs[1] = RegSpec::bp(); + instr.regs[2] = RegSpec::si(); + }, + 0b011 => { + instr.regs[1] = RegSpec::bp(); + instr.regs[2] = RegSpec::di(); + }, + 0b100 => { + instr.regs[1] = RegSpec::si(); + }, + 0b101 => { + instr.regs[1] = RegSpec::di(); + }, + 0b110 => { + instr.regs[1] = RegSpec::bp(); + }, + 0b111 => { + instr.regs[1] = RegSpec::bx(); + }, + _ => { unreachable!("impossible bit pattern"); } + } + match modbits { + 0b00 => { + if mmm > 3 { + Ok(OperandSpec::Deref) + } else { + Ok(OperandSpec::RegIndexBase) + } + }, + 0b01 => { + instr.disp = read_num(words, 1)? as i8 as i32 as u32; + if mmm > 3 { + if instr.disp != 0 { + Ok(OperandSpec::RegDisp) + } else { + Ok(OperandSpec::Deref) + } + } else { + if instr.disp != 0 { + Ok(OperandSpec::RegIndexBaseDisp) + } else { + Ok(OperandSpec::RegIndexBase) + } + } + }, + 0b10 => { + instr.disp = read_num(words, 2)? as i16 as i32 as u32; + if mmm > 3 { + if instr.disp != 0 { + Ok(OperandSpec::RegDisp) + } else { + Ok(OperandSpec::Deref) + } + } else { + if instr.disp != 0 { + Ok(OperandSpec::RegIndexBaseDisp) + } else { + Ok(OperandSpec::RegIndexBase) + } + } + }, + _ => { + unreachable!("read_M_16but but mod bits were not a memory operand"); + } + } +} + +#[allow(non_snake_case)] +fn read_M::Address, ::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8) -> Result { + // by default read M as a 16-bit size address + if !instr.prefixes.address_size() { + return read_M_16bit(words, instr, modrm); + } + instr.regs[1].bank = RegisterBank::D; + let modbits = modrm >> 6; + let mmm = modrm & 7; + let op_spec = if mmm == 4 { + return read_sib(words, instr, modrm); + } else if mmm == 5 && modbits == 0b00 { + instr.disp = read_num(words, 4)?; + OperandSpec::DispU32 + } else { + instr.regs[1].num |= mmm; + + if modbits == 0b00 { + OperandSpec::Deref + } else { + let disp = if modbits == 0b01 { + read_num(words, 1)? as i8 as i32 + } else { + read_num(words, 4)? as i32 + }; + if disp == 0 { + OperandSpec::Deref + } else { + instr.disp = disp as i32 as u32; + OperandSpec::RegDisp + } + } + }; + Ok(op_spec) +} + +#[inline] +fn width_to_gp_reg_bank(width: u8) -> RegisterBank { + match width { + 1 => return RegisterBank::B, + 2 => return RegisterBank::W, + 4 => return RegisterBank::D, + _ => unsafe { unreachable_unchecked(); } + } +} + +fn read_0f_opcode(opcode: u8, prefixes: &mut Prefixes) -> OpcodeRecord { + // seems like f2 takes priority, then f3, then 66, then "no prefix". for SOME instructions an + // invalid prefix is in fact an invalid instruction. so just duplicate for the four kinds of + // opcode lists. + if prefixes.repnz() { + match opcode { + 0x00 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f00), + 0x01 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f01), + 0x02 => OpcodeRecord(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew), + 0x03 => OpcodeRecord(Interpretation::Instruction(Opcode::LSL), OperandCode::Gv_Ew_LSL), + 0x04 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x05 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSCALL), OperandCode::Nothing), + 0x06 => OpcodeRecord(Interpretation::Instruction(Opcode::CLTS), OperandCode::Nothing), + 0x07 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSRET), OperandCode::Nothing), + 0x08 => OpcodeRecord(Interpretation::Instruction(Opcode::INVD), OperandCode::Nothing), + 0x09 => OpcodeRecord(Interpretation::Instruction(Opcode::WBINVD), OperandCode::Nothing), + 0x0a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x0b => OpcodeRecord(Interpretation::Instruction(Opcode::UD2), OperandCode::Nothing), + 0x0c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x0d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f0d), + 0x0e => OpcodeRecord(Interpretation::Instruction(Opcode::FEMMS), OperandCode::Nothing), + 0x0f => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f0f), + + 0x10 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSD), OperandCode::PMOVX_G_E_xmm), + 0x11 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSD), OperandCode::PMOVX_E_G_xmm), + 0x12 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVDDUP), OperandCode::PMOVX_G_E_xmm), + 0x13 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x14 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x15 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x16 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x17 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x18 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f18), + 0x19 => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + 0x1a => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + 0x1b => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + 0x1c => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + 0x1d => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + 0x1e => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + 0x1f => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), +// 0x20 + 0x20 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Rq_Cq_0), + 0x21 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Rq_Dq_0), + 0x22 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Cq_Rq_0), + 0x23 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Dq_Rq_0), + 0x24 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x25 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x26 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x27 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x28 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x29 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x2a => OpcodeRecord(Interpretation::Instruction(Opcode::CVTSI2SD), OperandCode::G_xmm_Ed), + 0x2b => OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTSD), OperandCode::M_G_xmm), + 0x2c => OpcodeRecord(Interpretation::Instruction(Opcode::CVTTSD2SI), OperandCode::PMOVX_G_E_xmm), + 0x2d => OpcodeRecord(Interpretation::Instruction(Opcode::CVTSD2SI), OperandCode::PMOVX_G_E_xmm), + 0x2e => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x2f => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + + 0x30 => OpcodeRecord(Interpretation::Instruction(Opcode::WRMSR), OperandCode::Nothing), + 0x31 => OpcodeRecord(Interpretation::Instruction(Opcode::RDTSC), OperandCode::Nothing), + 0x32 => OpcodeRecord(Interpretation::Instruction(Opcode::RDMSR), OperandCode::Nothing), + 0x33 => OpcodeRecord(Interpretation::Instruction(Opcode::RDPMC), OperandCode::Nothing), + 0x34 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSENTER), OperandCode::Nothing), + 0x35 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSEXIT), OperandCode::Nothing), + 0x36 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x37 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x38 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // handled before getting to `read_0f_opcode` + 0x39 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x3a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // handled before getting to `read_0f_opcode` + 0x3b => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x3c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x3d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x3e => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x3f => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + + 0x40 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVO), OperandCode::Gv_Ev), + 0x41 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNO), OperandCode::Gv_Ev), + 0x42 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVB), OperandCode::Gv_Ev), + 0x43 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNB), OperandCode::Gv_Ev), + 0x44 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVZ), OperandCode::Gv_Ev), + 0x45 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNZ), OperandCode::Gv_Ev), + 0x46 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNA), OperandCode::Gv_Ev), + 0x47 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVA), OperandCode::Gv_Ev), + 0x48 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVS), OperandCode::Gv_Ev), + 0x49 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNS), OperandCode::Gv_Ev), + 0x4a => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVP), OperandCode::Gv_Ev), + 0x4b => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNP), OperandCode::Gv_Ev), + 0x4c => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVL), OperandCode::Gv_Ev), + 0x4d => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVGE), OperandCode::Gv_Ev), + 0x4e => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVLE), OperandCode::Gv_Ev), + 0x4f => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVG), OperandCode::Gv_Ev), + + 0x50 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x51 => OpcodeRecord(Interpretation::Instruction(Opcode::SQRTSD), OperandCode::PMOVX_G_E_xmm), + 0x52 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x53 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x54 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x55 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x56 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x57 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x58 => OpcodeRecord(Interpretation::Instruction(Opcode::ADDSD), OperandCode::PMOVX_G_E_xmm), + 0x59 => OpcodeRecord(Interpretation::Instruction(Opcode::MULSD), OperandCode::PMOVX_G_E_xmm), + 0x5a => OpcodeRecord(Interpretation::Instruction(Opcode::CVTSD2SS), OperandCode::PMOVX_G_E_xmm), + 0x5b => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x5c => OpcodeRecord(Interpretation::Instruction(Opcode::SUBSD), OperandCode::PMOVX_G_E_xmm), + 0x5d => OpcodeRecord(Interpretation::Instruction(Opcode::MINSD), OperandCode::PMOVX_G_E_xmm), + 0x5e => OpcodeRecord(Interpretation::Instruction(Opcode::DIVSD), OperandCode::PMOVX_G_E_xmm), + 0x5f => OpcodeRecord(Interpretation::Instruction(Opcode::MAXSD), OperandCode::PMOVX_G_E_xmm), + + 0x60 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x61 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x62 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x63 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x64 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x65 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x66 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x67 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x68 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x69 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x6a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x6b => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x6c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x6d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x6e => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x6f => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + + 0x70 => OpcodeRecord(Interpretation::Instruction(Opcode::PSHUFLW), OperandCode::G_E_xmm_Ib), + 0x71 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // no f2-0f71 instructions, so we can stop early + 0x72 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // no f2-0f72 instructions, so we can stop early + 0x73 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // no f2-0f73 instructions, so we can stop early + 0x74 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x75 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x76 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x77 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x78 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf20f78), + 0x79 => OpcodeRecord(Interpretation::Instruction(Opcode::INSERTQ), OperandCode::G_U_xmm), + 0x7a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x7b => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x7c => OpcodeRecord(Interpretation::Instruction(Opcode::HADDPS), OperandCode::G_E_xmm), + 0x7d => OpcodeRecord(Interpretation::Instruction(Opcode::HSUBPS), OperandCode::G_E_xmm), + 0x7e => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x7f => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), +// 0x80 + 0x80 => OpcodeRecord(Interpretation::Instruction(Opcode::JO), OperandCode::Jvds), + 0x81 => OpcodeRecord(Interpretation::Instruction(Opcode::JNO), OperandCode::Jvds), + 0x82 => OpcodeRecord(Interpretation::Instruction(Opcode::JB), OperandCode::Jvds), + 0x83 => OpcodeRecord(Interpretation::Instruction(Opcode::JNB), OperandCode::Jvds), + 0x84 => OpcodeRecord(Interpretation::Instruction(Opcode::JZ), OperandCode::Jvds), + 0x85 => OpcodeRecord(Interpretation::Instruction(Opcode::JNZ), OperandCode::Jvds), + 0x86 => OpcodeRecord(Interpretation::Instruction(Opcode::JNA), OperandCode::Jvds), + 0x87 => OpcodeRecord(Interpretation::Instruction(Opcode::JA), OperandCode::Jvds), + 0x88 => OpcodeRecord(Interpretation::Instruction(Opcode::JS), OperandCode::Jvds), + 0x89 => OpcodeRecord(Interpretation::Instruction(Opcode::JNS), OperandCode::Jvds), + 0x8a => OpcodeRecord(Interpretation::Instruction(Opcode::JP), OperandCode::Jvds), + 0x8b => OpcodeRecord(Interpretation::Instruction(Opcode::JNP), OperandCode::Jvds), + 0x8c => OpcodeRecord(Interpretation::Instruction(Opcode::JL), OperandCode::Jvds), + 0x8d => OpcodeRecord(Interpretation::Instruction(Opcode::JGE), OperandCode::Jvds), + 0x8e => OpcodeRecord(Interpretation::Instruction(Opcode::JLE), OperandCode::Jvds), + 0x8f => OpcodeRecord(Interpretation::Instruction(Opcode::JG), OperandCode::Jvds), + +// 0x90 + 0x90 => OpcodeRecord(Interpretation::Instruction(Opcode::SETO), OperandCode::Eb_R0), + 0x91 => OpcodeRecord(Interpretation::Instruction(Opcode::SETNO), OperandCode::Eb_R0), + 0x92 => OpcodeRecord(Interpretation::Instruction(Opcode::SETB), OperandCode::Eb_R0), + 0x93 => OpcodeRecord(Interpretation::Instruction(Opcode::SETAE), OperandCode::Eb_R0), + 0x94 => OpcodeRecord(Interpretation::Instruction(Opcode::SETZ), OperandCode::Eb_R0), + 0x95 => OpcodeRecord(Interpretation::Instruction(Opcode::SETNZ), OperandCode::Eb_R0), + 0x96 => OpcodeRecord(Interpretation::Instruction(Opcode::SETBE), OperandCode::Eb_R0), + 0x97 => OpcodeRecord(Interpretation::Instruction(Opcode::SETA), OperandCode::Eb_R0), + 0x98 => OpcodeRecord(Interpretation::Instruction(Opcode::SETS), OperandCode::Eb_R0), + 0x99 => OpcodeRecord(Interpretation::Instruction(Opcode::SETNS), OperandCode::Eb_R0), + 0x9a => OpcodeRecord(Interpretation::Instruction(Opcode::SETP), OperandCode::Eb_R0), + 0x9b => OpcodeRecord(Interpretation::Instruction(Opcode::SETNP), OperandCode::Eb_R0), + 0x9c => OpcodeRecord(Interpretation::Instruction(Opcode::SETL), OperandCode::Eb_R0), + 0x9d => OpcodeRecord(Interpretation::Instruction(Opcode::SETGE), OperandCode::Eb_R0), + 0x9e => OpcodeRecord(Interpretation::Instruction(Opcode::SETLE), OperandCode::Eb_R0), + 0x9f => OpcodeRecord(Interpretation::Instruction(Opcode::SETG), OperandCode::Eb_R0), + +// 0xa0 + 0xa0 => OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::FS), + 0xa1 => OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::FS), + 0xa2 => OpcodeRecord(Interpretation::Instruction(Opcode::CPUID), OperandCode::Nothing), + 0xa3 => OpcodeRecord(Interpretation::Instruction(Opcode::BT), OperandCode::Ev_Gv), + 0xa4 => OpcodeRecord(Interpretation::Instruction(Opcode::SHLD), OperandCode::Ev_Gv_Ib), + 0xa5 => OpcodeRecord(Interpretation::Instruction(Opcode::SHLD), OperandCode::Ev_Gv_CL), + 0xa6 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xa7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xa8 => OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::GS), + 0xa9 => OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::GS), + 0xaa => OpcodeRecord(Interpretation::Instruction(Opcode::RSM), OperandCode::Nothing), + 0xab => OpcodeRecord(Interpretation::Instruction(Opcode::BTS), OperandCode::Ev_Gv), + 0xac => OpcodeRecord(Interpretation::Instruction(Opcode::SHRD), OperandCode::Ev_Gv_Ib), + 0xad => OpcodeRecord(Interpretation::Instruction(Opcode::SHRD), OperandCode::Ev_Gv_CL), + 0xae => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fae), + 0xaf => OpcodeRecord(Interpretation::Instruction(Opcode::IMUL), OperandCode::Gv_Ev), + +// 0xb0 + 0xb0 => OpcodeRecord(Interpretation::Instruction(Opcode::CMPXCHG), OperandCode::Eb_Gb), + 0xb1 => OpcodeRecord(Interpretation::Instruction(Opcode::CMPXCHG), OperandCode::Ev_Gv), + 0xb2 => OpcodeRecord(Interpretation::Instruction(Opcode::LSS), OperandCode::INV_Gv_M), + 0xb3 => OpcodeRecord(Interpretation::Instruction(Opcode::BTR), OperandCode::Ev_Gv), + 0xb4 => OpcodeRecord(Interpretation::Instruction(Opcode::LFS), OperandCode::INV_Gv_M), + 0xb5 => OpcodeRecord(Interpretation::Instruction(Opcode::LGS), OperandCode::INV_Gv_M), + 0xb6 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVZX), OperandCode::Gv_Eb), + 0xb7 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVZX), OperandCode::Gv_Ew), + 0xb8 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xb9 => OpcodeRecord(Interpretation::Instruction(Opcode::UD1), OperandCode::Gv_Ev), + 0xba => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fba), + 0xbb => OpcodeRecord(Interpretation::Instruction(Opcode::BTC), OperandCode::Ev_Gv), + 0xbc => OpcodeRecord(Interpretation::Instruction(Opcode::BSF), OperandCode::Gv_Ev), + 0xbd => OpcodeRecord(Interpretation::Instruction(Opcode::BSR), OperandCode::Gv_Ev), + 0xbe => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSX), OperandCode::Gv_Eb), + 0xbf => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSX), OperandCode::Gv_Ew), +// 0xc0 + 0xc0 => OpcodeRecord(Interpretation::Instruction(Opcode::XADD), OperandCode::Eb_Gb), + 0xc1 => OpcodeRecord(Interpretation::Instruction(Opcode::XADD), OperandCode::Ev_Gv), + 0xc2 => OpcodeRecord(Interpretation::Instruction(Opcode::CMPSD), OperandCode::G_E_xmm_Ib), + 0xc3 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xc4 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xc5 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xc6 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xc7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fc7), // cmpxchg permits an f2 prefix, which is the only reason this entry is not `Nothing` + 0xc8 => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R0), + 0xc9 => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R1), + 0xca => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R2), + 0xcb => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R3), + 0xcc => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R4), + 0xcd => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R5), + 0xce => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R6), + 0xcf => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R7), + + 0xd0 => OpcodeRecord(Interpretation::Instruction(Opcode::ADDSUBPS), OperandCode::G_E_xmm), + 0xd1 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xd2 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xd3 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xd4 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xd5 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xd6 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVDQ2Q), OperandCode::U_mm_G_xmm), + 0xd7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xd8 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xd9 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xda => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xdb => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xdc => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xdd => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xde => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xdf => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), +// 0xe0 + 0xe0 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xe1 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xe2 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xe3 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xe4 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xe5 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xe6 => OpcodeRecord(Interpretation::Instruction(Opcode::CVTPD2DQ), OperandCode::G_E_xmm), + 0xe7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xe8 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xe9 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xea => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xeb => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xec => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xed => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xee => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xef => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + + 0xf0 => OpcodeRecord(Interpretation::Instruction(Opcode::LDDQU), OperandCode::G_M_xmm), + 0xf1 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xf2 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xf3 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xf4 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xf5 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xf6 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xf7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xf8 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xf9 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xfa => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xfb => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xfc => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xfd => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xfe => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xff => OpcodeRecord(Interpretation::Instruction(Opcode::UD0), OperandCode::Gd_Ed), + } + } else if prefixes.rep() { + match opcode { + 0x00 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f00), + 0x01 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f01), + 0x02 => OpcodeRecord(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew), + 0x03 => OpcodeRecord(Interpretation::Instruction(Opcode::LSL), OperandCode::Gv_Ew_LSL), + 0x04 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x05 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSCALL), OperandCode::Nothing), + 0x06 => OpcodeRecord(Interpretation::Instruction(Opcode::CLTS), OperandCode::Nothing), + 0x07 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSRET), OperandCode::Nothing), + 0x08 => OpcodeRecord(Interpretation::Instruction(Opcode::INVD), OperandCode::Nothing), + 0x09 => OpcodeRecord(Interpretation::Instruction(Opcode::WBINVD), OperandCode::Nothing), + 0x0a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x0b => OpcodeRecord(Interpretation::Instruction(Opcode::UD2), OperandCode::Nothing), + 0x0c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x0d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f0d), + 0x0e => OpcodeRecord(Interpretation::Instruction(Opcode::FEMMS), OperandCode::Nothing), + 0x0f => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f0f), + + 0x10 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSS), OperandCode::G_Ed_xmm), + 0x11 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSS), OperandCode::Ed_G_xmm), + 0x12 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSLDUP), OperandCode::G_E_xmm), + 0x13 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x14 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x15 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x16 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSHDUP), OperandCode::G_E_xmm), + 0x17 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x18 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f18), + 0x19 => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + 0x1a => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + 0x1b => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + 0x1c => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + 0x1d => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + 0x1e => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + 0x1f => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + + 0x20 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Rq_Cq_0), + 0x21 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Rq_Dq_0), + 0x22 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Cq_Rq_0), + 0x23 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Dq_Rq_0), + 0x24 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x25 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x26 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x27 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x28 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x29 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x2a => OpcodeRecord(Interpretation::Instruction(Opcode::CVTSI2SS), OperandCode::G_xmm_Ed), + 0x2b => OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTSS), OperandCode::M_G_xmm), + 0x2c => OpcodeRecord(Interpretation::Instruction(Opcode::CVTTSS2SI), OperandCode::Gv_E_xmm), + 0x2d => OpcodeRecord(Interpretation::Instruction(Opcode::CVTSS2SI), OperandCode::Gv_E_xmm), + 0x2e => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x2f => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + + 0x30 => OpcodeRecord(Interpretation::Instruction(Opcode::WRMSR), OperandCode::Nothing), + 0x31 => OpcodeRecord(Interpretation::Instruction(Opcode::RDTSC), OperandCode::Nothing), + 0x32 => OpcodeRecord(Interpretation::Instruction(Opcode::RDMSR), OperandCode::Nothing), + 0x33 => OpcodeRecord(Interpretation::Instruction(Opcode::RDPMC), OperandCode::Nothing), + 0x34 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSENTER), OperandCode::Nothing), + 0x35 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSEXIT), OperandCode::Nothing), + 0x36 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x37 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x38 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // handled before getting to `read_0f_opcode` + 0x39 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x3a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // handled before getting to `read_0f_opcode` + 0x3b => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x3c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x3d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x3e => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x3f => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + + 0x40 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVO), OperandCode::Gv_Ev), + 0x41 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNO), OperandCode::Gv_Ev), + 0x42 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVB), OperandCode::Gv_Ev), + 0x43 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNB), OperandCode::Gv_Ev), + 0x44 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVZ), OperandCode::Gv_Ev), + 0x45 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNZ), OperandCode::Gv_Ev), + 0x46 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNA), OperandCode::Gv_Ev), + 0x47 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVA), OperandCode::Gv_Ev), + 0x48 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVS), OperandCode::Gv_Ev), + 0x49 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNS), OperandCode::Gv_Ev), + 0x4a => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVP), OperandCode::Gv_Ev), + 0x4b => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNP), OperandCode::Gv_Ev), + 0x4c => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVL), OperandCode::Gv_Ev), + 0x4d => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVGE), OperandCode::Gv_Ev), + 0x4e => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVLE), OperandCode::Gv_Ev), + 0x4f => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVG), OperandCode::Gv_Ev), +// 0x50 + 0x50 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x51 => OpcodeRecord(Interpretation::Instruction(Opcode::SQRTSS), OperandCode::G_Ed_xmm), + 0x52 => OpcodeRecord(Interpretation::Instruction(Opcode::RSQRTSS), OperandCode::G_Ed_xmm), + 0x53 => OpcodeRecord(Interpretation::Instruction(Opcode::RCPSS), OperandCode::G_Ed_xmm), + 0x54 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x55 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x56 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x57 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x58 => OpcodeRecord(Interpretation::Instruction(Opcode::ADDSS), OperandCode::G_Ed_xmm), + 0x59 => OpcodeRecord(Interpretation::Instruction(Opcode::MULSS), OperandCode::G_Ed_xmm), + 0x5a => OpcodeRecord(Interpretation::Instruction(Opcode::CVTSS2SD), OperandCode::PMOVX_G_E_xmm), + 0x5b => OpcodeRecord(Interpretation::Instruction(Opcode::CVTTPS2DQ), OperandCode::G_E_xmm), + 0x5c => OpcodeRecord(Interpretation::Instruction(Opcode::SUBSS), OperandCode::G_Ed_xmm), + 0x5d => OpcodeRecord(Interpretation::Instruction(Opcode::MINSS), OperandCode::G_Ed_xmm), + 0x5e => OpcodeRecord(Interpretation::Instruction(Opcode::DIVSS), OperandCode::G_Ed_xmm), + 0x5f => OpcodeRecord(Interpretation::Instruction(Opcode::MAXSS), OperandCode::G_Ed_xmm), +// 0x60 + 0x60 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x61 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x62 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x63 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x64 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x65 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x66 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x67 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x68 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x69 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x6a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x6b => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x6c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x6d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x6e => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x6f => OpcodeRecord(Interpretation::Instruction(Opcode::MOVDQU), OperandCode::G_E_xmm), +// 0x70 + 0x70 => OpcodeRecord(Interpretation::Instruction(Opcode::PSHUFHW), OperandCode::G_E_xmm_Ib), + 0x71 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // no f3-0f71 instructions, so we can stop early + 0x72 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // no f3-0f72 instructions, so we can stop early + 0x73 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // no f3-0f73 instructions, so we can stop early + 0x74 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x75 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x76 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x77 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x78 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x79 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x7a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x7b => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x7c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x7d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x7e => OpcodeRecord(Interpretation::Instruction(Opcode::MOVQ), OperandCode::MOVQ_f30f), + 0x7f => OpcodeRecord(Interpretation::Instruction(Opcode::MOVDQU), OperandCode::E_G_xmm), +// 0x80 + 0x80 => OpcodeRecord(Interpretation::Instruction(Opcode::JO), OperandCode::Jvds), + 0x81 => OpcodeRecord(Interpretation::Instruction(Opcode::JNO), OperandCode::Jvds), + 0x82 => OpcodeRecord(Interpretation::Instruction(Opcode::JB), OperandCode::Jvds), + 0x83 => OpcodeRecord(Interpretation::Instruction(Opcode::JNB), OperandCode::Jvds), + 0x84 => OpcodeRecord(Interpretation::Instruction(Opcode::JZ), OperandCode::Jvds), + 0x85 => OpcodeRecord(Interpretation::Instruction(Opcode::JNZ), OperandCode::Jvds), + 0x86 => OpcodeRecord(Interpretation::Instruction(Opcode::JNA), OperandCode::Jvds), + 0x87 => OpcodeRecord(Interpretation::Instruction(Opcode::JA), OperandCode::Jvds), + 0x88 => OpcodeRecord(Interpretation::Instruction(Opcode::JS), OperandCode::Jvds), + 0x89 => OpcodeRecord(Interpretation::Instruction(Opcode::JNS), OperandCode::Jvds), + 0x8a => OpcodeRecord(Interpretation::Instruction(Opcode::JP), OperandCode::Jvds), + 0x8b => OpcodeRecord(Interpretation::Instruction(Opcode::JNP), OperandCode::Jvds), + 0x8c => OpcodeRecord(Interpretation::Instruction(Opcode::JL), OperandCode::Jvds), + 0x8d => OpcodeRecord(Interpretation::Instruction(Opcode::JGE), OperandCode::Jvds), + 0x8e => OpcodeRecord(Interpretation::Instruction(Opcode::JLE), OperandCode::Jvds), + 0x8f => OpcodeRecord(Interpretation::Instruction(Opcode::JG), OperandCode::Jvds), + +// 0x90 + 0x90 => OpcodeRecord(Interpretation::Instruction(Opcode::SETO), OperandCode::Eb_R0), + 0x91 => OpcodeRecord(Interpretation::Instruction(Opcode::SETNO), OperandCode::Eb_R0), + 0x92 => OpcodeRecord(Interpretation::Instruction(Opcode::SETB), OperandCode::Eb_R0), + 0x93 => OpcodeRecord(Interpretation::Instruction(Opcode::SETAE), OperandCode::Eb_R0), + 0x94 => OpcodeRecord(Interpretation::Instruction(Opcode::SETZ), OperandCode::Eb_R0), + 0x95 => OpcodeRecord(Interpretation::Instruction(Opcode::SETNZ), OperandCode::Eb_R0), + 0x96 => OpcodeRecord(Interpretation::Instruction(Opcode::SETBE), OperandCode::Eb_R0), + 0x97 => OpcodeRecord(Interpretation::Instruction(Opcode::SETA), OperandCode::Eb_R0), + 0x98 => OpcodeRecord(Interpretation::Instruction(Opcode::SETS), OperandCode::Eb_R0), + 0x99 => OpcodeRecord(Interpretation::Instruction(Opcode::SETNS), OperandCode::Eb_R0), + 0x9a => OpcodeRecord(Interpretation::Instruction(Opcode::SETP), OperandCode::Eb_R0), + 0x9b => OpcodeRecord(Interpretation::Instruction(Opcode::SETNP), OperandCode::Eb_R0), + 0x9c => OpcodeRecord(Interpretation::Instruction(Opcode::SETL), OperandCode::Eb_R0), + 0x9d => OpcodeRecord(Interpretation::Instruction(Opcode::SETGE), OperandCode::Eb_R0), + 0x9e => OpcodeRecord(Interpretation::Instruction(Opcode::SETLE), OperandCode::Eb_R0), + 0x9f => OpcodeRecord(Interpretation::Instruction(Opcode::SETG), OperandCode::Eb_R0), + +// 0xa0 + 0xa0 => OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::FS), + 0xa1 => OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::FS), + 0xa2 => OpcodeRecord(Interpretation::Instruction(Opcode::CPUID), OperandCode::Nothing), + 0xa3 => OpcodeRecord(Interpretation::Instruction(Opcode::BT), OperandCode::Ev_Gv), + 0xa4 => OpcodeRecord(Interpretation::Instruction(Opcode::SHLD), OperandCode::Ev_Gv_Ib), + 0xa5 => OpcodeRecord(Interpretation::Instruction(Opcode::SHLD), OperandCode::Ev_Gv_CL), + 0xa6 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xa7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xa8 => OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::GS), + 0xa9 => OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::GS), + 0xaa => OpcodeRecord(Interpretation::Instruction(Opcode::RSM), OperandCode::Nothing), + 0xab => OpcodeRecord(Interpretation::Instruction(Opcode::BTS), OperandCode::Ev_Gv), + 0xac => OpcodeRecord(Interpretation::Instruction(Opcode::SHRD), OperandCode::Ev_Gv_Ib), + 0xad => OpcodeRecord(Interpretation::Instruction(Opcode::SHRD), OperandCode::Ev_Gv_CL), + 0xae => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fae), + 0xaf => OpcodeRecord(Interpretation::Instruction(Opcode::IMUL), OperandCode::Gv_Ev), + +// 0xb0 + 0xb0 => OpcodeRecord(Interpretation::Instruction(Opcode::CMPXCHG), OperandCode::Eb_Gb), + 0xb1 => OpcodeRecord(Interpretation::Instruction(Opcode::CMPXCHG), OperandCode::Ev_Gv), + 0xb2 => OpcodeRecord(Interpretation::Instruction(Opcode::LSS), OperandCode::INV_Gv_M), + 0xb3 => OpcodeRecord(Interpretation::Instruction(Opcode::BTR), OperandCode::Ev_Gv), + 0xb4 => OpcodeRecord(Interpretation::Instruction(Opcode::LFS), OperandCode::INV_Gv_M), + 0xb5 => OpcodeRecord(Interpretation::Instruction(Opcode::LGS), OperandCode::INV_Gv_M), + 0xb6 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVZX), OperandCode::Gv_Eb), + 0xb7 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVZX), OperandCode::Gv_Ew), + 0xb8 => OpcodeRecord(Interpretation::Instruction(Opcode::POPCNT), OperandCode::Gv_Ev), + 0xb9 => OpcodeRecord(Interpretation::Instruction(Opcode::UD1), OperandCode::Gv_Ev), + 0xba => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fba), + 0xbb => OpcodeRecord(Interpretation::Instruction(Opcode::BTC), OperandCode::Ev_Gv), + 0xbc => OpcodeRecord(Interpretation::Instruction(Opcode::TZCNT), OperandCode::Gv_Ev), + 0xbd => OpcodeRecord(Interpretation::Instruction(Opcode::LZCNT), OperandCode::Gv_Ev), + 0xbe => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSX), OperandCode::Gv_Eb), + 0xbf => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSX), OperandCode::Gv_Ew), +// 0xc0 + 0xc0 => OpcodeRecord(Interpretation::Instruction(Opcode::XADD), OperandCode::Eb_Gb), + 0xc1 => OpcodeRecord(Interpretation::Instruction(Opcode::XADD), OperandCode::Ev_Gv), + 0xc2 => OpcodeRecord(Interpretation::Instruction(Opcode::CMPSS), OperandCode::G_E_xmm_Ib), + 0xc3 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xc4 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xc5 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xc6 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xc7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fc7), + 0xc8 => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R0), + 0xc9 => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R1), + 0xca => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R2), + 0xcb => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R3), + 0xcc => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R4), + 0xcd => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R5), + 0xce => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R6), + 0xcf => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R7), + + 0xd0 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xd1 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xd2 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xd3 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xd4 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xd5 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xd6 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVQ2DQ), OperandCode::G_xmm_U_mm), + 0xd7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xd8 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xd9 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xda => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xdb => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xdc => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xdd => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xde => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xdf => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), +// 0xe0 + 0xe0 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xe1 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xe2 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xe3 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xe4 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xe5 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xe6 => OpcodeRecord(Interpretation::Instruction(Opcode::CVTDQ2PD), OperandCode::G_E_xmm), + 0xe7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xe8 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xe9 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xea => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xeb => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xec => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xed => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xee => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xef => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), +// 0xf0 + 0xf0 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xf1 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xf2 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xf3 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xf4 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xf5 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xf6 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xf7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xf8 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xf9 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xfa => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xfb => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xfc => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xfd => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xfe => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xff => OpcodeRecord(Interpretation::Instruction(Opcode::UD0), OperandCode::Gd_Ed), + } + } else if prefixes.operand_size() { + match opcode { + 0x00 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f00), + 0x01 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f01), + 0x02 => OpcodeRecord(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew), + 0x03 => OpcodeRecord(Interpretation::Instruction(Opcode::LSL), OperandCode::Gv_Ew_LSL), + 0x04 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x05 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSCALL), OperandCode::Nothing), + 0x06 => OpcodeRecord(Interpretation::Instruction(Opcode::CLTS), OperandCode::Nothing), + 0x07 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSRET), OperandCode::Nothing), + 0x08 => OpcodeRecord(Interpretation::Instruction(Opcode::INVD), OperandCode::Nothing), + 0x09 => OpcodeRecord(Interpretation::Instruction(Opcode::WBINVD), OperandCode::Nothing), + 0x0a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x0b => OpcodeRecord(Interpretation::Instruction(Opcode::UD2), OperandCode::Nothing), + 0x0c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x0d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f0d), + 0x0e => OpcodeRecord(Interpretation::Instruction(Opcode::FEMMS), OperandCode::Nothing), + 0x0f => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f0f), + + 0x10 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVUPD), OperandCode::G_E_xmm), + 0x11 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVUPD), OperandCode::E_G_xmm), + 0x12 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVLPD), OperandCode::PMOVX_G_E_xmm), + 0x13 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVLPD), OperandCode::PMOVX_E_G_xmm), + 0x14 => OpcodeRecord(Interpretation::Instruction(Opcode::UNPCKLPD), OperandCode::G_E_xmm), + 0x15 => OpcodeRecord(Interpretation::Instruction(Opcode::UNPCKHPD), OperandCode::G_E_xmm), + 0x16 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVHPD), OperandCode::PMOVX_G_E_xmm), + 0x17 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVHPD), OperandCode::PMOVX_E_G_xmm), + 0x18 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f18), + 0x19 => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + 0x1a => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + 0x1b => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + 0x1c => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + 0x1d => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + 0x1e => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + 0x1f => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + + 0x20 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Rq_Cq_0), + 0x21 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Rq_Dq_0), + 0x22 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Cq_Rq_0), + 0x23 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Dq_Rq_0), + 0x24 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x25 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x26 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x27 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x28 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVAPD), OperandCode::G_E_xmm), + 0x29 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVAPD), OperandCode::E_G_xmm), + 0x2a => OpcodeRecord(Interpretation::Instruction(Opcode::CVTPI2PD), OperandCode::G_xmm_E_mm), + 0x2b => OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTPD), OperandCode::M_G_xmm), + 0x2c => OpcodeRecord(Interpretation::Instruction(Opcode::CVTTPD2PI), OperandCode::G_mm_E_xmm), + 0x2d => OpcodeRecord(Interpretation::Instruction(Opcode::CVTPD2PI), OperandCode::G_mm_E_xmm), + 0x2e => OpcodeRecord(Interpretation::Instruction(Opcode::UCOMISD), OperandCode::PMOVX_G_E_xmm), + 0x2f => OpcodeRecord(Interpretation::Instruction(Opcode::COMISD), OperandCode::PMOVX_G_E_xmm), + + 0x30 => OpcodeRecord(Interpretation::Instruction(Opcode::WRMSR), OperandCode::Nothing), + 0x31 => OpcodeRecord(Interpretation::Instruction(Opcode::RDTSC), OperandCode::Nothing), + 0x32 => OpcodeRecord(Interpretation::Instruction(Opcode::RDMSR), OperandCode::Nothing), + 0x33 => OpcodeRecord(Interpretation::Instruction(Opcode::RDPMC), OperandCode::Nothing), + 0x34 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSENTER), OperandCode::Nothing), + 0x35 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSEXIT), OperandCode::Nothing), + 0x36 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x37 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x38 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // handled before getting to `read_0f_opcode` + 0x39 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x3a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // handled before getting to `read_0f_opcode` + 0x3b => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x3c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x3d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x3e => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x3f => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + + 0x40 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVO), OperandCode::Gv_Ev), + 0x41 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNO), OperandCode::Gv_Ev), + 0x42 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVB), OperandCode::Gv_Ev), + 0x43 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNB), OperandCode::Gv_Ev), + 0x44 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVZ), OperandCode::Gv_Ev), + 0x45 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNZ), OperandCode::Gv_Ev), + 0x46 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNA), OperandCode::Gv_Ev), + 0x47 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVA), OperandCode::Gv_Ev), + 0x48 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVS), OperandCode::Gv_Ev), + 0x49 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNS), OperandCode::Gv_Ev), + 0x4a => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVP), OperandCode::Gv_Ev), + 0x4b => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNP), OperandCode::Gv_Ev), + 0x4c => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVL), OperandCode::Gv_Ev), + 0x4d => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVGE), OperandCode::Gv_Ev), + 0x4e => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVLE), OperandCode::Gv_Ev), + 0x4f => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVG), OperandCode::Gv_Ev), + 0x50 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVMSKPD), OperandCode::Gd_U_xmm), + 0x51 => OpcodeRecord(Interpretation::Instruction(Opcode::SQRTPD), OperandCode::G_E_xmm), + 0x52 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x53 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x54 => OpcodeRecord(Interpretation::Instruction(Opcode::ANDPD), OperandCode::G_E_xmm), + 0x55 => OpcodeRecord(Interpretation::Instruction(Opcode::ANDNPD), OperandCode::G_E_xmm), + 0x56 => OpcodeRecord(Interpretation::Instruction(Opcode::ORPD), OperandCode::G_E_xmm), + 0x57 => OpcodeRecord(Interpretation::Instruction(Opcode::XORPD), OperandCode::G_E_xmm), + 0x58 => OpcodeRecord(Interpretation::Instruction(Opcode::ADDPD), OperandCode::G_E_xmm), + 0x59 => OpcodeRecord(Interpretation::Instruction(Opcode::MULPD), OperandCode::G_E_xmm), + 0x5a => OpcodeRecord(Interpretation::Instruction(Opcode::CVTPD2PS), OperandCode::G_E_xmm), + 0x5b => OpcodeRecord(Interpretation::Instruction(Opcode::CVTPS2DQ), OperandCode::G_E_xmm), + 0x5c => OpcodeRecord(Interpretation::Instruction(Opcode::SUBPD), OperandCode::G_E_xmm), + 0x5d => OpcodeRecord(Interpretation::Instruction(Opcode::MINPD), OperandCode::G_E_xmm), + 0x5e => OpcodeRecord(Interpretation::Instruction(Opcode::DIVPD), OperandCode::G_E_xmm), + 0x5f => OpcodeRecord(Interpretation::Instruction(Opcode::MAXPD), OperandCode::G_E_xmm), + 0x60 => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKLBW), OperandCode::G_E_xmm), + 0x61 => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKLWD), OperandCode::G_E_xmm), + 0x62 => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKLDQ), OperandCode::G_E_xmm), + 0x63 => OpcodeRecord(Interpretation::Instruction(Opcode::PACKSSWB), OperandCode::G_E_xmm), + 0x64 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPGTB), OperandCode::G_E_xmm), + 0x65 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPGTW), OperandCode::G_E_xmm), + 0x66 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPGTD), OperandCode::G_E_xmm), + 0x67 => OpcodeRecord(Interpretation::Instruction(Opcode::PACKUSWB), OperandCode::G_E_xmm), + 0x68 => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKHBW), OperandCode::G_E_xmm), + 0x69 => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKHWD), OperandCode::G_E_xmm), + 0x6a => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKHDQ), OperandCode::G_E_xmm), + 0x6b => OpcodeRecord(Interpretation::Instruction(Opcode::PACKSSDW), OperandCode::G_E_xmm), + 0x6c => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKLQDQ), OperandCode::G_E_xmm), + 0x6d => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKHQDQ), OperandCode::G_E_xmm), + 0x6e => OpcodeRecord(Interpretation::Instruction(Opcode::MOVD), OperandCode::G_xmm_Ed), + 0x6f => OpcodeRecord(Interpretation::Instruction(Opcode::MOVDQA), OperandCode::G_E_xmm), + 0x70 => OpcodeRecord(Interpretation::Instruction(Opcode::PSHUFD), OperandCode::G_E_xmm_Ib), + 0x71 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f71), + 0x72 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f72), + 0x73 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f73), + 0x74 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPEQB), OperandCode::G_E_xmm), + 0x75 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPEQW), OperandCode::G_E_xmm), + 0x76 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPEQD), OperandCode::G_E_xmm), + 0x77 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x78 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x660f78), + 0x79 => OpcodeRecord(Interpretation::Instruction(Opcode::EXTRQ), OperandCode::G_U_xmm), + 0x7a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x7b => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x7c => OpcodeRecord(Interpretation::Instruction(Opcode::HADDPD), OperandCode::G_E_xmm), + 0x7d => OpcodeRecord(Interpretation::Instruction(Opcode::HSUBPD), OperandCode::G_E_xmm), + 0x7e => OpcodeRecord(Interpretation::Instruction(Opcode::MOVD), OperandCode::Ed_G_xmm), + 0x7f => OpcodeRecord(Interpretation::Instruction(Opcode::MOVDQA), OperandCode::E_G_xmm), +// 0x80 + 0x80 => OpcodeRecord(Interpretation::Instruction(Opcode::JO), OperandCode::Jvds), + 0x81 => OpcodeRecord(Interpretation::Instruction(Opcode::JNO), OperandCode::Jvds), + 0x82 => OpcodeRecord(Interpretation::Instruction(Opcode::JB), OperandCode::Jvds), + 0x83 => OpcodeRecord(Interpretation::Instruction(Opcode::JNB), OperandCode::Jvds), + 0x84 => OpcodeRecord(Interpretation::Instruction(Opcode::JZ), OperandCode::Jvds), + 0x85 => OpcodeRecord(Interpretation::Instruction(Opcode::JNZ), OperandCode::Jvds), + 0x86 => OpcodeRecord(Interpretation::Instruction(Opcode::JNA), OperandCode::Jvds), + 0x87 => OpcodeRecord(Interpretation::Instruction(Opcode::JA), OperandCode::Jvds), + 0x88 => OpcodeRecord(Interpretation::Instruction(Opcode::JS), OperandCode::Jvds), + 0x89 => OpcodeRecord(Interpretation::Instruction(Opcode::JNS), OperandCode::Jvds), + 0x8a => OpcodeRecord(Interpretation::Instruction(Opcode::JP), OperandCode::Jvds), + 0x8b => OpcodeRecord(Interpretation::Instruction(Opcode::JNP), OperandCode::Jvds), + 0x8c => OpcodeRecord(Interpretation::Instruction(Opcode::JL), OperandCode::Jvds), + 0x8d => OpcodeRecord(Interpretation::Instruction(Opcode::JGE), OperandCode::Jvds), + 0x8e => OpcodeRecord(Interpretation::Instruction(Opcode::JLE), OperandCode::Jvds), + 0x8f => OpcodeRecord(Interpretation::Instruction(Opcode::JG), OperandCode::Jvds), + +// 0x90 + 0x90 => OpcodeRecord(Interpretation::Instruction(Opcode::SETO), OperandCode::Eb_R0), + 0x91 => OpcodeRecord(Interpretation::Instruction(Opcode::SETNO), OperandCode::Eb_R0), + 0x92 => OpcodeRecord(Interpretation::Instruction(Opcode::SETB), OperandCode::Eb_R0), + 0x93 => OpcodeRecord(Interpretation::Instruction(Opcode::SETAE), OperandCode::Eb_R0), + 0x94 => OpcodeRecord(Interpretation::Instruction(Opcode::SETZ), OperandCode::Eb_R0), + 0x95 => OpcodeRecord(Interpretation::Instruction(Opcode::SETNZ), OperandCode::Eb_R0), + 0x96 => OpcodeRecord(Interpretation::Instruction(Opcode::SETBE), OperandCode::Eb_R0), + 0x97 => OpcodeRecord(Interpretation::Instruction(Opcode::SETA), OperandCode::Eb_R0), + 0x98 => OpcodeRecord(Interpretation::Instruction(Opcode::SETS), OperandCode::Eb_R0), + 0x99 => OpcodeRecord(Interpretation::Instruction(Opcode::SETNS), OperandCode::Eb_R0), + 0x9a => OpcodeRecord(Interpretation::Instruction(Opcode::SETP), OperandCode::Eb_R0), + 0x9b => OpcodeRecord(Interpretation::Instruction(Opcode::SETNP), OperandCode::Eb_R0), + 0x9c => OpcodeRecord(Interpretation::Instruction(Opcode::SETL), OperandCode::Eb_R0), + 0x9d => OpcodeRecord(Interpretation::Instruction(Opcode::SETGE), OperandCode::Eb_R0), + 0x9e => OpcodeRecord(Interpretation::Instruction(Opcode::SETLE), OperandCode::Eb_R0), + 0x9f => OpcodeRecord(Interpretation::Instruction(Opcode::SETG), OperandCode::Eb_R0), + +// 0xa0 + 0xa0 => OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::FS), + 0xa1 => OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::FS), + 0xa2 => OpcodeRecord(Interpretation::Instruction(Opcode::CPUID), OperandCode::Nothing), + 0xa3 => OpcodeRecord(Interpretation::Instruction(Opcode::BT), OperandCode::Ev_Gv), + 0xa4 => OpcodeRecord(Interpretation::Instruction(Opcode::SHLD), OperandCode::Ev_Gv_Ib), + 0xa5 => OpcodeRecord(Interpretation::Instruction(Opcode::SHLD), OperandCode::Ev_Gv_CL), + 0xa6 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xa7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xa8 => OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::GS), + 0xa9 => OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::GS), + 0xaa => OpcodeRecord(Interpretation::Instruction(Opcode::RSM), OperandCode::Nothing), + 0xab => OpcodeRecord(Interpretation::Instruction(Opcode::BTS), OperandCode::Ev_Gv), + 0xac => OpcodeRecord(Interpretation::Instruction(Opcode::SHRD), OperandCode::Ev_Gv_Ib), + 0xad => OpcodeRecord(Interpretation::Instruction(Opcode::SHRD), OperandCode::Ev_Gv_CL), + 0xae => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fae), + 0xaf => OpcodeRecord(Interpretation::Instruction(Opcode::IMUL), OperandCode::Gv_Ev), + +// 0xb0 + 0xb0 => OpcodeRecord(Interpretation::Instruction(Opcode::CMPXCHG), OperandCode::Eb_Gb), + 0xb1 => OpcodeRecord(Interpretation::Instruction(Opcode::CMPXCHG), OperandCode::Ev_Gv), + 0xb2 => OpcodeRecord(Interpretation::Instruction(Opcode::LSS), OperandCode::Gv_M), + 0xb3 => OpcodeRecord(Interpretation::Instruction(Opcode::BTR), OperandCode::Ev_Gv), + 0xb4 => OpcodeRecord(Interpretation::Instruction(Opcode::LFS), OperandCode::Gv_M), + 0xb5 => OpcodeRecord(Interpretation::Instruction(Opcode::LGS), OperandCode::Gv_M), + 0xb6 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVZX), OperandCode::Gv_Eb), + 0xb7 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVZX), OperandCode::Gv_Ew), + 0xb8 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xb9 => OpcodeRecord(Interpretation::Instruction(Opcode::UD1), OperandCode::Gv_Ev), + 0xba => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fba), + 0xbb => OpcodeRecord(Interpretation::Instruction(Opcode::BTC), OperandCode::Ev_Gv), + 0xbc => OpcodeRecord(Interpretation::Instruction(Opcode::BSF), OperandCode::Gv_Ev), + 0xbd => OpcodeRecord(Interpretation::Instruction(Opcode::BSR), OperandCode::Gv_Ev), + 0xbe => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSX), OperandCode::Gv_Eb), + 0xbf => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSX), OperandCode::Gv_Ew), +// 0xc0 + 0xc0 => OpcodeRecord(Interpretation::Instruction(Opcode::XADD), OperandCode::Eb_Gb), + 0xc1 => OpcodeRecord(Interpretation::Instruction(Opcode::XADD), OperandCode::Ev_Gv), + 0xc2 => OpcodeRecord(Interpretation::Instruction(Opcode::CMPPD), OperandCode::G_E_xmm_Ib), + 0xc3 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xc4 => OpcodeRecord(Interpretation::Instruction(Opcode::PINSRW), OperandCode::G_xmm_Ew_Ib), + 0xc5 => OpcodeRecord(Interpretation::Instruction(Opcode::PEXTRW), OperandCode::G_U_xmm_Ub), + 0xc6 => OpcodeRecord(Interpretation::Instruction(Opcode::SHUFPD), OperandCode::G_E_xmm_Ib), + 0xc7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fc7), + 0xc8 => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R0), + 0xc9 => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R1), + 0xca => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R2), + 0xcb => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R3), + 0xcc => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R4), + 0xcd => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R5), + 0xce => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R6), + 0xcf => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R7), +// 0xd0 + 0xd0 => OpcodeRecord(Interpretation::Instruction(Opcode::ADDSUBPD), OperandCode::G_E_xmm), + 0xd1 => OpcodeRecord(Interpretation::Instruction(Opcode::PSRLW), OperandCode::G_E_xmm), + 0xd2 => OpcodeRecord(Interpretation::Instruction(Opcode::PSRLD), OperandCode::G_E_xmm), + 0xd3 => OpcodeRecord(Interpretation::Instruction(Opcode::PSRLQ), OperandCode::G_E_xmm), + 0xd4 => OpcodeRecord(Interpretation::Instruction(Opcode::PADDQ), OperandCode::G_E_xmm), + 0xd5 => OpcodeRecord(Interpretation::Instruction(Opcode::PMULLW), OperandCode::G_E_xmm), + 0xd6 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVQ), OperandCode::PMOVX_E_G_xmm), + 0xd7 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVMSKB), OperandCode::Gd_U_xmm), + 0xd8 => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBUSB), OperandCode::G_E_xmm), + 0xd9 => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBUSW), OperandCode::G_E_xmm), + 0xda => OpcodeRecord(Interpretation::Instruction(Opcode::PMINUB), OperandCode::G_E_xmm), + 0xdb => OpcodeRecord(Interpretation::Instruction(Opcode::PAND), OperandCode::G_E_xmm), + 0xdc => OpcodeRecord(Interpretation::Instruction(Opcode::PADDUSB), OperandCode::G_E_xmm), + 0xdd => OpcodeRecord(Interpretation::Instruction(Opcode::PADDUSW), OperandCode::G_E_xmm), + 0xde => OpcodeRecord(Interpretation::Instruction(Opcode::PMAXUB), OperandCode::G_E_xmm), + 0xdf => OpcodeRecord(Interpretation::Instruction(Opcode::PANDN), OperandCode::G_E_xmm), +// 0xe0 + 0xe0 => OpcodeRecord(Interpretation::Instruction(Opcode::PAVGB), OperandCode::G_E_xmm), + 0xe1 => OpcodeRecord(Interpretation::Instruction(Opcode::PSRAW), OperandCode::G_E_xmm), + 0xe2 => OpcodeRecord(Interpretation::Instruction(Opcode::PSRAD), OperandCode::G_E_xmm), + 0xe3 => OpcodeRecord(Interpretation::Instruction(Opcode::PAVGW), OperandCode::G_E_xmm), + 0xe4 => OpcodeRecord(Interpretation::Instruction(Opcode::PMULHUW), OperandCode::G_E_xmm), + 0xe5 => OpcodeRecord(Interpretation::Instruction(Opcode::PMULHW), OperandCode::G_E_xmm), + 0xe6 => OpcodeRecord(Interpretation::Instruction(Opcode::CVTTPD2DQ), OperandCode::G_E_xmm), + 0xe7 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTDQ), OperandCode::M_G_xmm), + 0xe8 => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBSB), OperandCode::G_E_xmm), + 0xe9 => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBSW), OperandCode::G_E_xmm), + 0xea => OpcodeRecord(Interpretation::Instruction(Opcode::PMINSW), OperandCode::G_E_xmm), + 0xeb => OpcodeRecord(Interpretation::Instruction(Opcode::POR), OperandCode::G_E_xmm), + 0xec => OpcodeRecord(Interpretation::Instruction(Opcode::PADDSB), OperandCode::G_E_xmm), + 0xed => OpcodeRecord(Interpretation::Instruction(Opcode::PADDSW), OperandCode::G_E_xmm), + 0xee => OpcodeRecord(Interpretation::Instruction(Opcode::PMAXSW), OperandCode::G_E_xmm), + 0xef => OpcodeRecord(Interpretation::Instruction(Opcode::PXOR), OperandCode::G_E_xmm), +// 0xf0 + 0xf0 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xf1 => OpcodeRecord(Interpretation::Instruction(Opcode::PSLLW), OperandCode::G_E_xmm), + 0xf2 => OpcodeRecord(Interpretation::Instruction(Opcode::PSLLD), OperandCode::G_E_xmm), + 0xf3 => OpcodeRecord(Interpretation::Instruction(Opcode::PSLLQ), OperandCode::G_E_xmm), + 0xf4 => OpcodeRecord(Interpretation::Instruction(Opcode::PMULUDQ), OperandCode::G_E_xmm), + 0xf5 => OpcodeRecord(Interpretation::Instruction(Opcode::PMADDWD), OperandCode::G_E_xmm), + 0xf6 => OpcodeRecord(Interpretation::Instruction(Opcode::PSADBW), OperandCode::G_E_xmm), + 0xf7 => OpcodeRecord(Interpretation::Instruction(Opcode::MASKMOVDQU), OperandCode::G_U_xmm), + 0xf8 => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBB), OperandCode::G_E_xmm), + 0xf9 => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBW), OperandCode::G_E_xmm), + 0xfa => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBD), OperandCode::G_E_xmm), + 0xfb => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBQ), OperandCode::G_E_xmm), + 0xfc => OpcodeRecord(Interpretation::Instruction(Opcode::PADDB), OperandCode::G_E_xmm), + 0xfd => OpcodeRecord(Interpretation::Instruction(Opcode::PADDW), OperandCode::G_E_xmm), + 0xfe => OpcodeRecord(Interpretation::Instruction(Opcode::PADDD), OperandCode::G_E_xmm), + 0xff => OpcodeRecord(Interpretation::Instruction(Opcode::UD0), OperandCode::Gd_Ed), + } + } else { + match opcode { + 0x00 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f00), + 0x01 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f01), + 0x02 => OpcodeRecord(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew), + 0x03 => OpcodeRecord(Interpretation::Instruction(Opcode::LSL), OperandCode::Gv_Ew_LSL), + 0x04 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x05 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSCALL), OperandCode::Nothing), + 0x06 => OpcodeRecord(Interpretation::Instruction(Opcode::CLTS), OperandCode::Nothing), + 0x07 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSRET), OperandCode::Nothing), + 0x08 => OpcodeRecord(Interpretation::Instruction(Opcode::INVD), OperandCode::Nothing), + 0x09 => OpcodeRecord(Interpretation::Instruction(Opcode::WBINVD), OperandCode::Nothing), + 0x0a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x0b => OpcodeRecord(Interpretation::Instruction(Opcode::UD2), OperandCode::Nothing), + 0x0c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x0d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f0d), + 0x0e => OpcodeRecord(Interpretation::Instruction(Opcode::FEMMS), OperandCode::Nothing), + 0x0f => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f0f), + + 0x10 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVUPS), OperandCode::G_E_xmm), + 0x11 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVUPS), OperandCode::E_G_xmm), + 0x12 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f12), + 0x13 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVLPS), OperandCode::M_G_xmm), + 0x14 => OpcodeRecord(Interpretation::Instruction(Opcode::UNPCKLPS), OperandCode::G_E_xmm), + 0x15 => OpcodeRecord(Interpretation::Instruction(Opcode::UNPCKHPS), OperandCode::G_E_xmm), + 0x16 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f16), + 0x17 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVHPS), OperandCode::PMOVX_E_G_xmm), + 0x18 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f18), + 0x19 => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + 0x1a => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + 0x1b => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + 0x1c => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + 0x1d => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + 0x1e => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + 0x1f => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), + + 0x20 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Rq_Cq_0), + 0x21 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Rq_Dq_0), + 0x22 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Cq_Rq_0), + 0x23 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Dq_Rq_0), + 0x24 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x25 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x26 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x27 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x28 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVAPS), OperandCode::G_E_xmm), + 0x29 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVAPS), OperandCode::E_G_xmm), + 0x2a => OpcodeRecord(Interpretation::Instruction(Opcode::CVTPI2PS), OperandCode::G_xmm_E_mm), + 0x2b => OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTPS), OperandCode::M_G_xmm), + 0x2c => OpcodeRecord(Interpretation::Instruction(Opcode::CVTTPS2PI), OperandCode::G_mm_E_xmm), + 0x2d => OpcodeRecord(Interpretation::Instruction(Opcode::CVTPS2PI), OperandCode::G_mm_E_xmm), + 0x2e => OpcodeRecord(Interpretation::Instruction(Opcode::UCOMISS), OperandCode::PMOVX_G_E_xmm), + 0x2f => OpcodeRecord(Interpretation::Instruction(Opcode::COMISS), OperandCode::PMOVX_G_E_xmm), +// 0x30 + 0x30 => OpcodeRecord(Interpretation::Instruction(Opcode::WRMSR), OperandCode::Nothing), + 0x31 => OpcodeRecord(Interpretation::Instruction(Opcode::RDTSC), OperandCode::Nothing), + 0x32 => OpcodeRecord(Interpretation::Instruction(Opcode::RDMSR), OperandCode::Nothing), + 0x33 => OpcodeRecord(Interpretation::Instruction(Opcode::RDPMC), OperandCode::Nothing), + 0x34 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSENTER), OperandCode::Nothing), + 0x35 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSEXIT), OperandCode::Nothing), + 0x36 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x37 => OpcodeRecord(Interpretation::Instruction(Opcode::GETSEC), OperandCode::Nothing), + 0x38 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // handled before getting to `read_0f_opcode` + 0x39 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x3a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // handled before getting to `read_0f_opcode` + 0x3b => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x3c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x3d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x3e => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x3f => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + +// 0x40 + 0x40 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVO), OperandCode::Gv_Ev), + 0x41 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNO), OperandCode::Gv_Ev), + 0x42 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVB), OperandCode::Gv_Ev), + 0x43 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNB), OperandCode::Gv_Ev), + 0x44 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVZ), OperandCode::Gv_Ev), + 0x45 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNZ), OperandCode::Gv_Ev), + 0x46 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNA), OperandCode::Gv_Ev), + 0x47 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVA), OperandCode::Gv_Ev), + 0x48 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVS), OperandCode::Gv_Ev), + 0x49 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNS), OperandCode::Gv_Ev), + 0x4a => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVP), OperandCode::Gv_Ev), + 0x4b => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNP), OperandCode::Gv_Ev), + 0x4c => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVL), OperandCode::Gv_Ev), + 0x4d => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVGE), OperandCode::Gv_Ev), + 0x4e => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVLE), OperandCode::Gv_Ev), + 0x4f => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVG), OperandCode::Gv_Ev), + +// 0x50 + 0x50 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVMSKPS), OperandCode::Gd_U_xmm), + 0x51 => OpcodeRecord(Interpretation::Instruction(Opcode::SQRTPS), OperandCode::G_E_xmm), + 0x52 => OpcodeRecord(Interpretation::Instruction(Opcode::RSQRTPS), OperandCode::G_E_xmm), + 0x53 => OpcodeRecord(Interpretation::Instruction(Opcode::RCPPS), OperandCode::G_E_xmm), + 0x54 => OpcodeRecord(Interpretation::Instruction(Opcode::ANDPS), OperandCode::G_E_xmm), + 0x55 => OpcodeRecord(Interpretation::Instruction(Opcode::ANDNPS), OperandCode::G_E_xmm), + 0x56 => OpcodeRecord(Interpretation::Instruction(Opcode::ORPS), OperandCode::G_E_xmm), + 0x57 => OpcodeRecord(Interpretation::Instruction(Opcode::XORPS), OperandCode::G_E_xmm), + 0x58 => OpcodeRecord(Interpretation::Instruction(Opcode::ADDPS), OperandCode::G_E_xmm), + 0x59 => OpcodeRecord(Interpretation::Instruction(Opcode::MULPS), OperandCode::G_E_xmm), + 0x5a => OpcodeRecord(Interpretation::Instruction(Opcode::CVTPS2PD), OperandCode::PMOVX_G_E_xmm), + 0x5b => OpcodeRecord(Interpretation::Instruction(Opcode::CVTDQ2PS), OperandCode::G_E_xmm), + 0x5c => OpcodeRecord(Interpretation::Instruction(Opcode::SUBPS), OperandCode::G_E_xmm), + 0x5d => OpcodeRecord(Interpretation::Instruction(Opcode::MINPS), OperandCode::G_E_xmm), + 0x5e => OpcodeRecord(Interpretation::Instruction(Opcode::DIVPS), OperandCode::G_E_xmm), + 0x5f => OpcodeRecord(Interpretation::Instruction(Opcode::MAXPS), OperandCode::G_E_xmm), + +// 0x60 + 0x60 => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKLBW), OperandCode::G_E_mm), + 0x61 => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKLWD), OperandCode::G_E_mm), + 0x62 => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKLDQ), OperandCode::G_E_mm), + 0x63 => OpcodeRecord(Interpretation::Instruction(Opcode::PACKSSWB), OperandCode::G_E_mm), + 0x64 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPGTB), OperandCode::G_E_mm), + 0x65 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPGTW), OperandCode::G_E_mm), + 0x66 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPGTD), OperandCode::G_E_mm), + 0x67 => OpcodeRecord(Interpretation::Instruction(Opcode::PACKUSWB), OperandCode::G_E_mm), + 0x68 => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKHBW), OperandCode::G_E_mm), + 0x69 => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKHWD), OperandCode::G_E_mm), + 0x6a => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKHDQ), OperandCode::G_E_mm), + 0x6b => OpcodeRecord(Interpretation::Instruction(Opcode::PACKSSDW), OperandCode::G_E_mm), + 0x6c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x6d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x6e => OpcodeRecord(Interpretation::Instruction(Opcode::MOVD), OperandCode::G_mm_Ed), + 0x6f => OpcodeRecord(Interpretation::Instruction(Opcode::MOVQ), OperandCode::G_mm_E), + +// 0x70 + 0x70 => OpcodeRecord(Interpretation::Instruction(Opcode::PSHUFW), OperandCode::G_E_mm_Ib), + 0x71 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f71), + 0x72 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f72), + 0x73 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f73), + 0x74 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPEQB), OperandCode::G_E_mm), + 0x75 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPEQW), OperandCode::G_E_mm), + 0x76 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPEQD), OperandCode::G_E_mm), + 0x77 => OpcodeRecord(Interpretation::Instruction(Opcode::EMMS), OperandCode::Nothing), + 0x78 => OpcodeRecord(Interpretation::Instruction(Opcode::VMREAD), OperandCode::E_G_q), + 0x79 => OpcodeRecord(Interpretation::Instruction(Opcode::VMWRITE), OperandCode::G_E_q), + 0x7a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x7b => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x7c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x7d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0x7e => OpcodeRecord(Interpretation::Instruction(Opcode::MOVD), OperandCode::Ed_G_mm), + 0x7f => OpcodeRecord(Interpretation::Instruction(Opcode::MOVQ), OperandCode::E_G_mm), + +// 0x80 + 0x80 => OpcodeRecord(Interpretation::Instruction(Opcode::JO), OperandCode::Jvds), + 0x81 => OpcodeRecord(Interpretation::Instruction(Opcode::JNO), OperandCode::Jvds), + 0x82 => OpcodeRecord(Interpretation::Instruction(Opcode::JB), OperandCode::Jvds), + 0x83 => OpcodeRecord(Interpretation::Instruction(Opcode::JNB), OperandCode::Jvds), + 0x84 => OpcodeRecord(Interpretation::Instruction(Opcode::JZ), OperandCode::Jvds), + 0x85 => OpcodeRecord(Interpretation::Instruction(Opcode::JNZ), OperandCode::Jvds), + 0x86 => OpcodeRecord(Interpretation::Instruction(Opcode::JNA), OperandCode::Jvds), + 0x87 => OpcodeRecord(Interpretation::Instruction(Opcode::JA), OperandCode::Jvds), + 0x88 => OpcodeRecord(Interpretation::Instruction(Opcode::JS), OperandCode::Jvds), + 0x89 => OpcodeRecord(Interpretation::Instruction(Opcode::JNS), OperandCode::Jvds), + 0x8a => OpcodeRecord(Interpretation::Instruction(Opcode::JP), OperandCode::Jvds), + 0x8b => OpcodeRecord(Interpretation::Instruction(Opcode::JNP), OperandCode::Jvds), + 0x8c => OpcodeRecord(Interpretation::Instruction(Opcode::JL), OperandCode::Jvds), + 0x8d => OpcodeRecord(Interpretation::Instruction(Opcode::JGE), OperandCode::Jvds), + 0x8e => OpcodeRecord(Interpretation::Instruction(Opcode::JLE), OperandCode::Jvds), + 0x8f => OpcodeRecord(Interpretation::Instruction(Opcode::JG), OperandCode::Jvds), + +// 0x90 + 0x90 => OpcodeRecord(Interpretation::Instruction(Opcode::SETO), OperandCode::Eb_R0), + 0x91 => OpcodeRecord(Interpretation::Instruction(Opcode::SETNO), OperandCode::Eb_R0), + 0x92 => OpcodeRecord(Interpretation::Instruction(Opcode::SETB), OperandCode::Eb_R0), + 0x93 => OpcodeRecord(Interpretation::Instruction(Opcode::SETAE), OperandCode::Eb_R0), + 0x94 => OpcodeRecord(Interpretation::Instruction(Opcode::SETZ), OperandCode::Eb_R0), + 0x95 => OpcodeRecord(Interpretation::Instruction(Opcode::SETNZ), OperandCode::Eb_R0), + 0x96 => OpcodeRecord(Interpretation::Instruction(Opcode::SETBE), OperandCode::Eb_R0), + 0x97 => OpcodeRecord(Interpretation::Instruction(Opcode::SETA), OperandCode::Eb_R0), + 0x98 => OpcodeRecord(Interpretation::Instruction(Opcode::SETS), OperandCode::Eb_R0), + 0x99 => OpcodeRecord(Interpretation::Instruction(Opcode::SETNS), OperandCode::Eb_R0), + 0x9a => OpcodeRecord(Interpretation::Instruction(Opcode::SETP), OperandCode::Eb_R0), + 0x9b => OpcodeRecord(Interpretation::Instruction(Opcode::SETNP), OperandCode::Eb_R0), + 0x9c => OpcodeRecord(Interpretation::Instruction(Opcode::SETL), OperandCode::Eb_R0), + 0x9d => OpcodeRecord(Interpretation::Instruction(Opcode::SETGE), OperandCode::Eb_R0), + 0x9e => OpcodeRecord(Interpretation::Instruction(Opcode::SETLE), OperandCode::Eb_R0), + 0x9f => OpcodeRecord(Interpretation::Instruction(Opcode::SETG), OperandCode::Eb_R0), + +// 0xa0 + 0xa0 => OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::FS), + 0xa1 => OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::FS), + 0xa2 => OpcodeRecord(Interpretation::Instruction(Opcode::CPUID), OperandCode::Nothing), + 0xa3 => OpcodeRecord(Interpretation::Instruction(Opcode::BT), OperandCode::Ev_Gv), + 0xa4 => OpcodeRecord(Interpretation::Instruction(Opcode::SHLD), OperandCode::Ev_Gv_Ib), + 0xa5 => OpcodeRecord(Interpretation::Instruction(Opcode::SHLD), OperandCode::Ev_Gv_CL), + 0xa6 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xa7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xa8 => OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::GS), + 0xa9 => OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::GS), + 0xaa => OpcodeRecord(Interpretation::Instruction(Opcode::RSM), OperandCode::Nothing), + 0xab => OpcodeRecord(Interpretation::Instruction(Opcode::BTS), OperandCode::Ev_Gv), + 0xac => OpcodeRecord(Interpretation::Instruction(Opcode::SHRD), OperandCode::Ev_Gv_Ib), + 0xad => OpcodeRecord(Interpretation::Instruction(Opcode::SHRD), OperandCode::Ev_Gv_CL), + 0xae => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fae), + 0xaf => OpcodeRecord(Interpretation::Instruction(Opcode::IMUL), OperandCode::Gv_Ev), + +// 0xb0 + 0xb0 => OpcodeRecord(Interpretation::Instruction(Opcode::CMPXCHG), OperandCode::Eb_Gb), + 0xb1 => OpcodeRecord(Interpretation::Instruction(Opcode::CMPXCHG), OperandCode::Ev_Gv), + 0xb2 => OpcodeRecord(Interpretation::Instruction(Opcode::LSS), OperandCode::INV_Gv_M), + 0xb3 => OpcodeRecord(Interpretation::Instruction(Opcode::BTR), OperandCode::Ev_Gv), + 0xb4 => OpcodeRecord(Interpretation::Instruction(Opcode::LFS), OperandCode::INV_Gv_M), + 0xb5 => OpcodeRecord(Interpretation::Instruction(Opcode::LGS), OperandCode::INV_Gv_M), + 0xb6 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVZX), OperandCode::Gv_Eb), + 0xb7 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVZX), OperandCode::Gv_Ew), + 0xb8 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // JMPE, ITANIUM + 0xb9 => OpcodeRecord(Interpretation::Instruction(Opcode::UD1), OperandCode::Gv_Ev), + 0xba => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fba), + 0xbb => OpcodeRecord(Interpretation::Instruction(Opcode::BTC), OperandCode::Ev_Gv), + 0xbc => OpcodeRecord(Interpretation::Instruction(Opcode::BSF), OperandCode::Gv_Ev), + 0xbd => OpcodeRecord(Interpretation::Instruction(Opcode::BSR), OperandCode::Gv_Ev), + 0xbe => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSX), OperandCode::Gv_Eb), + 0xbf => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSX), OperandCode::Gv_Ew), + +// 0xc0 + 0xc0 => OpcodeRecord(Interpretation::Instruction(Opcode::XADD), OperandCode::Eb_Gb), + 0xc1 => OpcodeRecord(Interpretation::Instruction(Opcode::XADD), OperandCode::Ev_Gv), + 0xc2 => OpcodeRecord(Interpretation::Instruction(Opcode::CMPPS), OperandCode::G_E_xmm_Ib), + 0xc3 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTI), OperandCode::Md_Gd), + 0xc4 => OpcodeRecord(Interpretation::Instruction(Opcode::PINSRW), OperandCode::G_mm_Ew_Ib), + 0xc5 => OpcodeRecord(Interpretation::Instruction(Opcode::PEXTRW), OperandCode::Rv_Gmm_Ib), + 0xc6 => OpcodeRecord(Interpretation::Instruction(Opcode::SHUFPS), OperandCode::G_E_xmm_Ib), + 0xc7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fc7), + 0xc8 => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R0), + 0xc9 => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R1), + 0xca => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R2), + 0xcb => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R3), + 0xcc => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R4), + 0xcd => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R5), + 0xce => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R6), + 0xcf => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R7), + +// 0xd0 + 0xd0 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xd1 => OpcodeRecord(Interpretation::Instruction(Opcode::PSRLW), OperandCode::G_E_mm), + 0xd2 => OpcodeRecord(Interpretation::Instruction(Opcode::PSRLD), OperandCode::G_E_mm), + 0xd3 => OpcodeRecord(Interpretation::Instruction(Opcode::PSRLQ), OperandCode::G_E_mm), + 0xd4 => OpcodeRecord(Interpretation::Instruction(Opcode::PADDQ), OperandCode::G_E_mm), + 0xd5 => OpcodeRecord(Interpretation::Instruction(Opcode::PMULLW), OperandCode::G_E_mm), + 0xd6 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xd7 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVMSKB), OperandCode::G_U_mm), + 0xd8 => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBUSB), OperandCode::G_E_mm), + 0xd9 => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBUSW), OperandCode::G_E_mm), + 0xda => OpcodeRecord(Interpretation::Instruction(Opcode::PMINUB), OperandCode::G_E_mm), + 0xdb => OpcodeRecord(Interpretation::Instruction(Opcode::PAND), OperandCode::G_E_mm), + 0xdc => OpcodeRecord(Interpretation::Instruction(Opcode::PADDUSB), OperandCode::G_E_mm), + 0xdd => OpcodeRecord(Interpretation::Instruction(Opcode::PADDUSW), OperandCode::G_E_mm), + 0xde => OpcodeRecord(Interpretation::Instruction(Opcode::PMAXUB), OperandCode::G_E_mm), + 0xdf => OpcodeRecord(Interpretation::Instruction(Opcode::PANDN), OperandCode::G_E_mm), + +// 0xe0 + 0xe0 => OpcodeRecord(Interpretation::Instruction(Opcode::PAVGB), OperandCode::G_E_mm), + 0xe1 => OpcodeRecord(Interpretation::Instruction(Opcode::PSRAW), OperandCode::G_E_mm), + 0xe2 => OpcodeRecord(Interpretation::Instruction(Opcode::PSRAD), OperandCode::G_E_mm), + 0xe3 => OpcodeRecord(Interpretation::Instruction(Opcode::PAVGW), OperandCode::G_E_mm), + 0xe4 => OpcodeRecord(Interpretation::Instruction(Opcode::PMULHUW), OperandCode::G_E_mm), + 0xe5 => OpcodeRecord(Interpretation::Instruction(Opcode::PMULHW), OperandCode::G_E_mm), + 0xe6 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xe7 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTQ), OperandCode::G_Mq_mm), + 0xe8 => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBSB), OperandCode::G_E_mm), + 0xe9 => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBSW), OperandCode::G_E_mm), + 0xea => OpcodeRecord(Interpretation::Instruction(Opcode::PMINSW), OperandCode::G_E_mm), + 0xeb => OpcodeRecord(Interpretation::Instruction(Opcode::POR), OperandCode::G_E_mm), + 0xec => OpcodeRecord(Interpretation::Instruction(Opcode::PADDSB), OperandCode::G_E_mm), + 0xed => OpcodeRecord(Interpretation::Instruction(Opcode::PADDSW), OperandCode::G_E_mm), + 0xee => OpcodeRecord(Interpretation::Instruction(Opcode::PMAXSW), OperandCode::G_E_mm), + 0xef => OpcodeRecord(Interpretation::Instruction(Opcode::PXOR), OperandCode::G_E_mm), +// 0xf0 + 0xf0 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + 0xf1 => OpcodeRecord(Interpretation::Instruction(Opcode::PSLLW), OperandCode::G_E_mm), + 0xf2 => OpcodeRecord(Interpretation::Instruction(Opcode::PSLLD), OperandCode::G_E_mm), + 0xf3 => OpcodeRecord(Interpretation::Instruction(Opcode::PSLLQ), OperandCode::G_E_mm), + 0xf4 => OpcodeRecord(Interpretation::Instruction(Opcode::PMULUDQ), OperandCode::G_E_mm), + 0xf5 => OpcodeRecord(Interpretation::Instruction(Opcode::PMADDWD), OperandCode::G_E_mm), + 0xf6 => OpcodeRecord(Interpretation::Instruction(Opcode::PSADBW), OperandCode::G_E_mm), + 0xf7 => OpcodeRecord(Interpretation::Instruction(Opcode::MASKMOVQ), OperandCode::G_mm_U_mm), + 0xf8 => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBB), OperandCode::G_E_mm), + 0xf9 => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBW), OperandCode::G_E_mm), + 0xfa => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBD), OperandCode::G_E_mm), + 0xfb => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBQ), OperandCode::G_E_mm), + 0xfc => OpcodeRecord(Interpretation::Instruction(Opcode::PADDB), OperandCode::G_E_mm), + 0xfd => OpcodeRecord(Interpretation::Instruction(Opcode::PADDW), OperandCode::G_E_mm), + 0xfe => OpcodeRecord(Interpretation::Instruction(Opcode::PADDD), OperandCode::G_E_mm), + 0xff => OpcodeRecord(Interpretation::Instruction(Opcode::UD0), OperandCode::Gd_Ed), + } + } +} + +fn read_0f38_opcode(opcode: u8, prefixes: &mut Prefixes) -> OpcodeRecord { + if prefixes.rep() { + return match opcode { + 0xd8 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf30f38d8), + 0xdc => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf30f38dc), + 0xdd => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf30f38dd), + 0xde => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf30f38de), + 0xdf => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf30f38df), + 0xf6 => OpcodeRecord(Interpretation::Instruction(Opcode::ADOX), OperandCode::Gv_Ev), + 0xf8 => { + prefixes.unset_operand_size(); + OpcodeRecord(Interpretation::Instruction(Opcode::ENQCMDS), OperandCode::INV_Gv_M) + }, + 0xfa => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf30f38fa), + 0xfb => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf30f38fb), + _ => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + }; + } + + if prefixes.repnz() { + return match opcode { + 0xf0 => OpcodeRecord(Interpretation::Instruction(Opcode::CRC32), OperandCode::Gv_Eb), + 0xf1 => OpcodeRecord(Interpretation::Instruction(Opcode::CRC32), OperandCode::Gd_Ev), + 0xf8 => { + prefixes.unset_operand_size(); + OpcodeRecord(Interpretation::Instruction(Opcode::ENQCMD), OperandCode::INV_Gv_M) + }, + _ => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + }; + } + + if prefixes.operand_size() { + // leave operand size present for `movbe` + if opcode != 0xf0 && opcode != 0xf1 { + prefixes.unset_operand_size(); + } + + return match opcode { + 0x00 => OpcodeRecord(Interpretation::Instruction(Opcode::PSHUFB), OperandCode::G_E_xmm), + 0x01 => OpcodeRecord(Interpretation::Instruction(Opcode::PHADDW), OperandCode::G_E_xmm), + 0x02 => OpcodeRecord(Interpretation::Instruction(Opcode::PHADDD), OperandCode::G_E_xmm), + 0x03 => OpcodeRecord(Interpretation::Instruction(Opcode::PHADDSW), OperandCode::G_E_xmm), + 0x04 => OpcodeRecord(Interpretation::Instruction(Opcode::PMADDUBSW), OperandCode::G_E_xmm), + 0x05 => OpcodeRecord(Interpretation::Instruction(Opcode::PHSUBW), OperandCode::G_E_xmm), + 0x06 => OpcodeRecord(Interpretation::Instruction(Opcode::PHSUBD), OperandCode::G_E_xmm), + 0x07 => OpcodeRecord(Interpretation::Instruction(Opcode::PHSUBSW), OperandCode::G_E_xmm), + 0x08 => OpcodeRecord(Interpretation::Instruction(Opcode::PSIGNB), OperandCode::G_E_xmm), + 0x09 => OpcodeRecord(Interpretation::Instruction(Opcode::PSIGNW), OperandCode::G_E_xmm), + 0x0a => OpcodeRecord(Interpretation::Instruction(Opcode::PSIGND), OperandCode::G_E_xmm), + 0x0b => OpcodeRecord(Interpretation::Instruction(Opcode::PMULHRSW), OperandCode::G_E_xmm), + 0x10 => OpcodeRecord(Interpretation::Instruction(Opcode::PBLENDVB), OperandCode::G_E_xmm), + 0x14 => OpcodeRecord(Interpretation::Instruction(Opcode::BLENDVPS), OperandCode::G_E_xmm), + 0x15 => OpcodeRecord(Interpretation::Instruction(Opcode::BLENDVPD), OperandCode::G_E_xmm), + 0x17 => OpcodeRecord(Interpretation::Instruction(Opcode::PTEST), OperandCode::G_E_xmm), + 0x1c => OpcodeRecord(Interpretation::Instruction(Opcode::PABSB), OperandCode::G_E_xmm), + 0x1d => OpcodeRecord(Interpretation::Instruction(Opcode::PABSW), OperandCode::G_E_xmm), + 0x1e => OpcodeRecord(Interpretation::Instruction(Opcode::PABSD), OperandCode::G_E_xmm), + 0x20 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVSXBW), OperandCode::PMOVX_G_E_xmm), + 0x21 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVSXBD), OperandCode::PMOVX_G_E_xmm), + 0x22 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVSXBQ), OperandCode::PMOVX_G_E_xmm), + 0x23 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVSXWD), OperandCode::PMOVX_G_E_xmm), + 0x24 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVSXWQ), OperandCode::PMOVX_G_E_xmm), + 0x25 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVSXDQ), OperandCode::PMOVX_G_E_xmm), + 0x28 => OpcodeRecord(Interpretation::Instruction(Opcode::PMULDQ), OperandCode::G_E_xmm), + 0x29 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPEQQ), OperandCode::G_E_xmm), + 0x2a => OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTDQA), OperandCode::G_M_xmm), + 0x2b => OpcodeRecord(Interpretation::Instruction(Opcode::PACKUSDW), OperandCode::G_E_xmm), + 0x30 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVZXBW), OperandCode::PMOVX_G_E_xmm), + 0x31 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVZXBD), OperandCode::PMOVX_G_E_xmm), + 0x32 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVZXBQ), OperandCode::PMOVX_G_E_xmm), + 0x33 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVZXWD), OperandCode::PMOVX_G_E_xmm), + 0x34 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVZXWQ), OperandCode::PMOVX_G_E_xmm), + 0x35 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVZXDQ), OperandCode::PMOVX_G_E_xmm), + 0x37 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPGTQ), OperandCode::G_E_xmm), + 0x38 => OpcodeRecord(Interpretation::Instruction(Opcode::PMINSB), OperandCode::G_E_xmm), + 0x39 => OpcodeRecord(Interpretation::Instruction(Opcode::PMINSD), OperandCode::G_E_xmm), + 0x3a => OpcodeRecord(Interpretation::Instruction(Opcode::PMINUW), OperandCode::G_E_xmm), + 0x3b => OpcodeRecord(Interpretation::Instruction(Opcode::PMINUD), OperandCode::G_E_xmm), + 0x3c => OpcodeRecord(Interpretation::Instruction(Opcode::PMAXSB), OperandCode::G_E_xmm), + 0x3d => OpcodeRecord(Interpretation::Instruction(Opcode::PMAXSD), OperandCode::G_E_xmm), + 0x3e => OpcodeRecord(Interpretation::Instruction(Opcode::PMAXUW), OperandCode::G_E_xmm), + 0x3f => OpcodeRecord(Interpretation::Instruction(Opcode::PMAXUD), OperandCode::G_E_xmm), + 0x40 => OpcodeRecord(Interpretation::Instruction(Opcode::PMULLD), OperandCode::G_E_xmm), + 0x41 => OpcodeRecord(Interpretation::Instruction(Opcode::PHMINPOSUW), OperandCode::G_E_xmm), + 0x80 => OpcodeRecord(Interpretation::Instruction(Opcode::INVEPT), OperandCode::INV_Gv_M), + 0x81 => OpcodeRecord(Interpretation::Instruction(Opcode::INVVPID), OperandCode::INV_Gv_M), + 0x82 => OpcodeRecord(Interpretation::Instruction(Opcode::INVPCID), OperandCode::INV_Gv_M), + 0xcf => OpcodeRecord(Interpretation::Instruction(Opcode::GF2P8MULB), OperandCode::G_E_xmm), + 0xdb => OpcodeRecord(Interpretation::Instruction(Opcode::AESIMC), OperandCode::G_E_xmm), + 0xdc => OpcodeRecord(Interpretation::Instruction(Opcode::AESENC), OperandCode::G_E_xmm), + 0xdd => OpcodeRecord(Interpretation::Instruction(Opcode::AESENCLAST), OperandCode::G_E_xmm), + 0xde => OpcodeRecord(Interpretation::Instruction(Opcode::AESDEC), OperandCode::G_E_xmm), + 0xdf => OpcodeRecord(Interpretation::Instruction(Opcode::AESDECLAST), OperandCode::G_E_xmm), + 0xf0 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVBE), OperandCode::Gv_M), + 0xf1 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVBE), OperandCode::M_Gv), + 0xf5 => OpcodeRecord(Interpretation::Instruction(Opcode::WRUSS), OperandCode::Md_Gd), + 0xf6 => OpcodeRecord(Interpretation::Instruction(Opcode::ADCX), OperandCode::Gv_Ev), + 0xf8 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVDIR64B), OperandCode::MOVDIR64B), + _ => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + }; + } else { + return match opcode { + 0x00 => OpcodeRecord(Interpretation::Instruction(Opcode::PSHUFB), OperandCode::G_E_mm), + 0x01 => OpcodeRecord(Interpretation::Instruction(Opcode::PHADDW), OperandCode::G_E_mm), + 0x02 => OpcodeRecord(Interpretation::Instruction(Opcode::PHADDD), OperandCode::G_E_mm), + 0x03 => OpcodeRecord(Interpretation::Instruction(Opcode::PHADDSW), OperandCode::G_E_mm), + 0x04 => OpcodeRecord(Interpretation::Instruction(Opcode::PMADDUBSW), OperandCode::G_E_mm), + 0x05 => OpcodeRecord(Interpretation::Instruction(Opcode::PHSUBW), OperandCode::G_E_mm), + 0x06 => OpcodeRecord(Interpretation::Instruction(Opcode::PHSUBD), OperandCode::G_E_mm), + 0x07 => OpcodeRecord(Interpretation::Instruction(Opcode::PHSUBSW), OperandCode::G_E_mm), + 0x08 => OpcodeRecord(Interpretation::Instruction(Opcode::PSIGNB), OperandCode::G_E_mm), + 0x09 => OpcodeRecord(Interpretation::Instruction(Opcode::PSIGNW), OperandCode::G_E_mm), + 0x0a => OpcodeRecord(Interpretation::Instruction(Opcode::PSIGND), OperandCode::G_E_mm), + 0x0b => OpcodeRecord(Interpretation::Instruction(Opcode::PMULHRSW), OperandCode::G_E_mm), + 0x1c => OpcodeRecord(Interpretation::Instruction(Opcode::PABSB), OperandCode::G_E_mm), + 0x1d => OpcodeRecord(Interpretation::Instruction(Opcode::PABSW), OperandCode::G_E_mm), + 0x1e => OpcodeRecord(Interpretation::Instruction(Opcode::PABSD), OperandCode::G_E_mm), + 0xc8 => OpcodeRecord(Interpretation::Instruction(Opcode::SHA1NEXTE), OperandCode::G_E_xmm), + 0xc9 => OpcodeRecord(Interpretation::Instruction(Opcode::SHA1MSG1), OperandCode::G_E_xmm), + 0xca => OpcodeRecord(Interpretation::Instruction(Opcode::SHA1MSG2), OperandCode::G_E_xmm), + 0xcb => OpcodeRecord(Interpretation::Instruction(Opcode::SHA256RNDS2), OperandCode::G_E_xmm), + 0xcc => OpcodeRecord(Interpretation::Instruction(Opcode::SHA256MSG1), OperandCode::G_E_xmm), + 0xcd => OpcodeRecord(Interpretation::Instruction(Opcode::SHA256MSG2), OperandCode::G_E_xmm), + 0xf0 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVBE), OperandCode::Gv_M), + 0xf1 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVBE), OperandCode::M_Gv), + 0xf6 => OpcodeRecord(Interpretation::Instruction(Opcode::WRSS), OperandCode::Md_Gd), + 0xf9 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVDIRI), OperandCode::Md_Gd), + _ => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + }; + } +} + +fn read_0f3a_opcode(opcode: u8, prefixes: &mut Prefixes) -> OpcodeRecord { + if prefixes.rep() { + if prefixes != &Prefixes::new(0x10) { + return OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing); + } + return match opcode { + 0xf0 => OpcodeRecord(Interpretation::Instruction(Opcode::HRESET), OperandCode::ModRM_0xf30f3af0), + _ => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + }; + } + + if prefixes.repnz() { + return OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing); + } + + if prefixes.operand_size() { + return match opcode { + 0x08 => OpcodeRecord(Interpretation::Instruction(Opcode::ROUNDPS), OperandCode::G_E_xmm_Ib), + 0x09 => OpcodeRecord(Interpretation::Instruction(Opcode::ROUNDPD), OperandCode::G_E_xmm_Ib), + 0x0a => OpcodeRecord(Interpretation::Instruction(Opcode::ROUNDSS), OperandCode::G_E_xmm_Ib), + 0x0b => OpcodeRecord(Interpretation::Instruction(Opcode::ROUNDSD), OperandCode::G_E_xmm_Ib), + 0x0c => OpcodeRecord(Interpretation::Instruction(Opcode::BLENDPS), OperandCode::G_E_xmm_Ib), + 0x0d => OpcodeRecord(Interpretation::Instruction(Opcode::BLENDPD), OperandCode::G_E_xmm_Ib), + 0x0e => OpcodeRecord(Interpretation::Instruction(Opcode::PBLENDW), OperandCode::G_E_xmm_Ib), + 0x0f => OpcodeRecord(Interpretation::Instruction(Opcode::PALIGNR), OperandCode::G_E_xmm_Ib), + 0x14 => OpcodeRecord(Interpretation::Instruction(Opcode::PEXTRB), OperandCode::G_Ev_xmm_Ib), + 0x15 => OpcodeRecord(Interpretation::Instruction(Opcode::PEXTRW), OperandCode::G_Ev_xmm_Ib), + 0x16 => OpcodeRecord(Interpretation::Instruction(Opcode::PEXTRD), OperandCode::G_Ev_xmm_Ib), + 0x17 => OpcodeRecord(Interpretation::Instruction(Opcode::EXTRACTPS), OperandCode::G_Ev_xmm_Ib), + 0x20 => OpcodeRecord(Interpretation::Instruction(Opcode::PINSRB), OperandCode::G_Ev_xmm_Ib), + 0x21 => OpcodeRecord(Interpretation::Instruction(Opcode::INSERTPS), OperandCode::G_Ev_xmm_Ib), + 0x22 => OpcodeRecord(Interpretation::Instruction(Opcode::PINSRD), OperandCode::G_Ev_xmm_Ib), + 0x40 => OpcodeRecord(Interpretation::Instruction(Opcode::DPPS), OperandCode::G_E_xmm_Ib), + 0x41 => OpcodeRecord(Interpretation::Instruction(Opcode::DPPD), OperandCode::G_E_xmm_Ib), + 0x42 => OpcodeRecord(Interpretation::Instruction(Opcode::MPSADBW), OperandCode::G_E_xmm_Ib), + 0x44 => OpcodeRecord(Interpretation::Instruction(Opcode::PCLMULQDQ), OperandCode::G_E_xmm_Ib), + 0x60 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPESTRM), OperandCode::G_E_xmm_Ib), + 0x61 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPESTRI), OperandCode::G_E_xmm_Ib), + 0x62 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPISTRM), OperandCode::G_E_xmm_Ib), + 0x63 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPISTRI), OperandCode::G_E_xmm_Ib), + 0xcc => OpcodeRecord(Interpretation::Instruction(Opcode::SHA1RNDS4), OperandCode::G_E_xmm_Ib), + 0xce => OpcodeRecord(Interpretation::Instruction(Opcode::GF2P8AFFINEQB), OperandCode::G_E_xmm_Ub), + 0xcf => OpcodeRecord(Interpretation::Instruction(Opcode::GF2P8AFFINEINVQB), OperandCode::G_E_xmm_Ub), + 0xdf => OpcodeRecord(Interpretation::Instruction(Opcode::AESKEYGENASSIST), OperandCode::G_E_xmm_Ub), + _ => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + }; + } + + return match opcode { + 0xcc => OpcodeRecord(Interpretation::Instruction(Opcode::SHA1RNDS4), OperandCode::G_E_xmm_Ub), + 0x0f => OpcodeRecord(Interpretation::Instruction(Opcode::PALIGNR), OperandCode::G_E_mm_Ib), + _ => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + }; +} + +fn read_instr::Address, ::Word>>(decoder: &InstDecoder, words: &mut T, instruction: &mut Instruction) -> Result<(), DecodeError> { + words.mark(); + let mut nextb = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; + let mut next_rec = OPCODES[nextb as usize]; + let mut prefixes = Prefixes::new(0); + + // default registers to `[eax; 4]` + instruction.regs = unsafe { core::mem::transmute(0u64) }; + instruction.mem_size = 0; + // default operands to [RegRRR, Nothing, Nothing, Nothing] + instruction.operands = unsafe { core::mem::transmute(0x00_00_00_01) }; + instruction.operand_count = 2; + + + let record: OpcodeRecord = loop { + let record = next_rec; + if let Interpretation::Instruction(_) = record.0 { + break record; + } else { + let b = nextb; + if words.offset() >= 15 { + return Err(DecodeError::TooLong); + } + if b == 0x0f { + let b = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; + if b == 0x38 { + let b = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; + break read_0f38_opcode(b, &mut prefixes); + } else if b == 0x3a { + let b = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; + break read_0f3a_opcode(b, &mut prefixes); + } else { + break read_0f_opcode(b, &mut prefixes); + } + } + + nextb = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; + next_rec = unsafe { + core::ptr::read_volatile(&OPCODES[nextb as usize]) + }; + match b { + 0x26 => { + prefixes.set_es(); + }, + 0x2e => { + prefixes.set_cs(); + }, + 0x36 => { + prefixes.set_ss(); + }, + 0x3e => { + prefixes.set_ds(); + }, + 0x64 => { + prefixes.set_fs(); + }, + 0x65 => { + prefixes.set_gs(); + }, + 0x66 => { + prefixes.set_operand_size(); + }, + 0x67 => { + prefixes.set_address_size(); + }, + 0xf0 => { + prefixes.set_lock(); + }, + 0xf2 => { + prefixes.set_repnz(); + }, + 0xf3 => { + prefixes.set_rep(); + }, + _ => { unsafe { unreachable_unchecked(); } } + } + } + }; + if record == OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing) { + return Err(DecodeError::InvalidOpcode); + } + if let Interpretation::Instruction(opcode) = record.0 { + instruction.opcode = opcode; + } else { + unsafe { unreachable_unchecked(); } + } + instruction.prefixes = prefixes; + read_operands(decoder, words, instruction, record.1)?; + instruction.length = words.offset() as u8; + if instruction.length > 15 { + return Err(DecodeError::TooLong); + } + + if instruction.prefixes.lock() { + if !LOCKABLE_INSTRUCTIONS.contains(&instruction.opcode) || !instruction.operands[0].is_memory() { + return Err(DecodeError::InvalidPrefixes); + } + } + + if decoder != &InstDecoder::default() { + // we might have to fix up or reject this instruction under whatever cpu features we need to + // pretend to have. + decoder.revise_instruction(instruction)?; + } + Ok(()) +} +/* likely cases + OperandCode::Eb_R0 => 0 + _op @ OperandCode::ModRM_0x80_Eb_Ib => 1 + _op @ OperandCode::ModRM_0x81_Ev_Ivs => 2 + op @ OperandCode::ModRM_0xc6_Eb_Ib => 3 + op @ OperandCode::ModRM_0xc7_Ev_Iv => 4 + op @ OperandCode::ModRM_0xc0_Eb_Ib => 5 + op @ OperandCode::ModRM_0xc1_Ev_Ib => 6 + op @ OperandCode::ModRM_0xd0_Eb_1 => 7 + op @ OperandCode::ModRM_0xd1_Ev_1 => 8 + op @ OperandCode::ModRM_0xd2_Eb_CL => 9 + op @ OperandCode::ModRM_0xd3_Ev_CL => 10 + _op @ OperandCode::ModRM_0xf6 => 11 + _op @ OperandCode::ModRM_0xf7 => 12 + OperandCode::ModRM_0xfe_Eb => 13 + OperandCode::ModRM_0xff_Ev => 14 + OperandCode::Gv_Eb => 15 + OperandCode::Gv_Ew => 16 + OperandCode::Ev => 18 + OperandCode::E_G_xmm => 19 + op @ OperandCode::G_M_xmm => 20 + op @ OperandCode::G_E_xmm => 21 + OperandCode::G_E_xmm_Ib => 22 + OperandCode::AL_Ibs => 23 + OperandCode::AX_Ivd => 24 + OperandCode::Ivs => 25 + OperandCode::ModRM_0x83_Ev_Ibs => 26 + OperandCode::I_3 => 27 + OperandCode::Nothing => 28 + OperandCode::G_E_mm_Ib => 29 + OperandCode::ModRM_0x8f_Ev => 30 + + */ +fn read_operands::Address, ::Word>>(decoder: &InstDecoder, words: &mut T, instruction: &mut Instruction, operand_code: OperandCode) -> Result<(), DecodeError> { + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operand_count = 2; + let operand_code = OperandCodeBuilder::from_bits(operand_code as u16); + if operand_code.has_embedded_instructions() { + match operand_code.get_embedded_instructions() { + Ok(z_operand_code) => { + let reg = z_operand_code.reg(); + match z_operand_code.category() { + 0 => { + // these are Zv_R + let bank = if instruction.prefixes.operand_size() { + RegisterBank::D + } else { + RegisterBank::W + }; + instruction.regs[0] = + RegSpec::from_parts(reg, bank); + instruction.operand_count = 1; + } + 1 => { + // Zv_AX + let bank = if instruction.prefixes.operand_size() { + RegisterBank::D + } else { + RegisterBank::W + }; + instruction.regs[0] = + RegSpec::from_parts(0, bank); + instruction.operands[1] = OperandSpec::RegMMM; + instruction.regs[1] = + RegSpec::from_parts(reg, bank); + instruction.operand_count = 2; + } + 2 => { + // these are Zb_Ib_R + instruction.regs[0] = + RegSpec::from_parts(reg, RegisterBank::B); + instruction.imm = + read_imm_unsigned(words, 1)?; + instruction.operands[1] = OperandSpec::ImmU8; + } + 3 => { + // category == 3, Zv_Iv_R + if instruction.prefixes.operand_size() { + instruction.regs[0] = + RegSpec::from_parts(reg, RegisterBank::D); + instruction.imm = + read_imm_unsigned(words, 4)?; + instruction.operands[1] = OperandSpec::ImmI32; + } else { + instruction.regs[0] = + RegSpec::from_parts(reg, RegisterBank::W); + instruction.imm = + read_imm_unsigned(words, 2)?; + instruction.operands[1] = OperandSpec::ImmI16; + } + } + _ => { + unreachable!("bad category"); + } + } + return Ok(()); + }, + // EmbeddedOperandInstructions but those are entirely handled in the fall-through + // below. one day this may grow to be an `Err(the_operand_instructions)` though, so for + // a simpler diff the above is pre-`match`/`Ok`'d. + _ => {} + } + } + + let mut modrm = 0; + let bank: RegisterBank; + let mut mem_oper = OperandSpec::Nothing; + if operand_code.has_read_E() { + // cool! we can precompute opwidth and know we need to read_E. + if !operand_code.has_byte_operands() { + // further, this is an vd E, but adcx is always 32-bit operands + if instruction.prefixes.operand_size() || instruction.opcode == Opcode::ADCX || instruction.opcode == Opcode::ADOX { + instruction.mem_size = 4; + bank = RegisterBank::D; + } else { + instruction.mem_size = 2; + bank = RegisterBank::W; + } + } else { + instruction.mem_size = 1; + bank = RegisterBank::B; + }; + modrm = read_modrm(words)?; + instruction.regs[0].bank = bank; + instruction.regs[0].num = (modrm >> 3) & 7; + + mem_oper = if modrm >= 0b11000000 { + if operand_code.bits() == (OperandCode::Gv_M as u16) { + return Err(DecodeError::InvalidOperand); + } + read_modrm_reg(instruction, modrm, bank)? + } else { + read_M(words, instruction, modrm)? + }; + instruction.operands[1] = mem_oper; + } + + if let Some((only_imm, immsz)) = operand_code.has_imm() { + instruction.imm = + read_imm_signed(words, 1 << (immsz * 1))? as u32; + if only_imm { + if immsz == 0 { + instruction.operands[0] = OperandSpec::ImmI8; + } else { + instruction.operands[0] = OperandSpec::ImmI32; + } + instruction.operand_count = 1; + return Ok(()); + } + } + + if operand_code.is_only_modrm_operands() { + if !operand_code.has_reg_mem() { + instruction.operands[0] = mem_oper; + instruction.operands[1] = OperandSpec::RegRRR; + }; + } else { +// match operand_code { + match operand_code.special_case_handler_index() { + 0 => { + instruction.operands[0] = mem_oper; + instruction.operand_count = 1; + }, + 1 => { + instruction.opcode = base_opcode_map((modrm >> 3) & 7); + instruction.operands[0] = mem_oper; + instruction.operands[1] = OperandSpec::ImmI8; + instruction.operand_count = 2; + } + 2 => { + instruction.operands[0] = mem_oper; + let numwidth = if instruction.prefixes.operand_size() { + 4 + } else { + 2 + }; + instruction.imm = read_imm_signed(words, numwidth)? as u32; + instruction.opcode = base_opcode_map((modrm >> 3) & 7); + instruction.operands[1] = match numwidth { + 2 => OperandSpec::ImmI16, + 4 => OperandSpec::ImmI32, + _ => unsafe { unreachable_unchecked() } + }; + instruction.operand_count = 2; + }, + 3 => { // ModRM_0xc6_Eb_Ib + if modrm == 0xf8 { + instruction.opcode = Opcode::XABORT; + instruction.imm = read_imm_signed(words, 1)? as u32; + instruction.operands[0] = OperandSpec::ImmI8; + instruction.operand_count = 1; + return Ok(()); + } + if (modrm & 0b00111000) != 0 { + return Err(DecodeError::InvalidOperand); // Err("Invalid modr/m for opcode 0xc7".to_string()); + } + + instruction.operands[0] = mem_oper; + instruction.opcode = Opcode::MOV; + instruction.imm = read_imm_signed(words, 1)? as u32; + instruction.operands[1] = OperandSpec::ImmI8; + instruction.operand_count = 2; + } + 4 => { // ModRM_0xc7_Ev_Iv + if modrm == 0xf8 { + instruction.opcode = Opcode::XBEGIN; + instruction.imm = if instruction.prefixes.operand_size() { + read_imm_signed(words, 5)? as i32 as u32 + } else { + read_imm_signed(words, 2)? as i16 as i32 as u32 + }; + instruction.operands[0] = OperandSpec::ImmI32; + instruction.operand_count = 1; + return Ok(()); + } + if (modrm & 0b00111000) != 0 { + return Err(DecodeError::InvalidOperand); // Err("Invalid modr/m for opcode 0xc7".to_string()); + } + + instruction.operands[0] = mem_oper; + instruction.opcode = Opcode::MOV; + if !instruction.prefixes.operand_size() { + instruction.imm = read_imm_signed(words, 2)? as u32; + instruction.operands[1] = OperandSpec::ImmI16; + } else { + instruction.imm = read_imm_signed(words, 4)? as u32; + instruction.operands[1] = OperandSpec::ImmI32; + } + }, + op @ 5 | + op @ 6 | + op @ 7 | + op @ 8 | + op @ 9 | + op @ 10 => { + instruction.operands[0] = mem_oper; + instruction.opcode = BITWISE_OPCODE_MAP[((modrm >> 3) & 7) as usize].clone(); + if op == 10 { + instruction.regs[0] = RegSpec::cl(); + instruction.operands[1] = OperandSpec::RegRRR; + } else if op == 9 { + instruction.regs[0] = RegSpec::cl(); + instruction.operands[1] = OperandSpec::RegRRR; + } else { + let num = match op { + 5 | + 6 => { + read_num(words, 1)? + } + _ => { + // these are the _1 variants, everything else is unreachable + 1 + } + }; + instruction.imm = num; + instruction.operands[1] = OperandSpec::ImmI8; + } + instruction.operand_count = 2; + }, + op @ 11 | + op @ 12 => { + let opwidth = if op == 11 { + 1 + } else { + if instruction.prefixes.operand_size() { + 4 + } else { + 2 + } + }; + instruction.operands[0] = mem_oper; + const TABLE: [Opcode; 8] = [ + Opcode::TEST, Opcode::TEST, Opcode::NOT, Opcode::NEG, + Opcode::MUL, Opcode::IMUL, Opcode::DIV, Opcode::IDIV, + ]; + let rrr = (modrm >> 3) & 7; + instruction.opcode = TABLE[rrr as usize]; + if rrr < 2 { + instruction.opcode = Opcode::TEST; + let numwidth = if opwidth == 8 { 4 } else { opwidth }; + instruction.imm = read_imm_signed(words, numwidth)? as u32; + instruction.operands[1] = match opwidth { + 1 => OperandSpec::ImmI8, + 2 => OperandSpec::ImmI16, + 4 => OperandSpec::ImmI32, + _ => unsafe { unreachable_unchecked() } + }; + } else { + instruction.operand_count = 1; + } + }, + 13 => { + instruction.operands[0] = mem_oper; + let r = (modrm >> 3) & 7; + if r >= 2 { + return Err(DecodeError::InvalidOpcode); + } + instruction.opcode = [ + Opcode::INC, + Opcode::DEC, + ][r as usize]; + instruction.operand_count = 1; + } + 14 => { + instruction.operands[0] = mem_oper; + let r = (modrm >> 3) & 7; + if r == 7 { + return Err(DecodeError::InvalidOpcode); + } + let opcode = [ + Opcode::INC, + Opcode::DEC, + Opcode::CALL, + Opcode::CALLF, + Opcode::JMP, + Opcode::JMPF, + Opcode::PUSH, + ][r as usize]; + if instruction.operands[0] == OperandSpec::RegMMM { + // in real mode, `xed` reports that operand-size does in fact override from word to + // dword. unlikely larger modes, operand-size can't shrink the call operand down. + if opcode == Opcode::CALLF || opcode == Opcode::JMPF { + return Err(DecodeError::InvalidOperand); + } + } else { + if opcode == Opcode::CALL || opcode == Opcode::JMP || opcode == Opcode::PUSH || opcode == Opcode::POP { + if instruction.prefixes.operand_size() { + instruction.mem_size = 4; + } else { + instruction.mem_size = 2; + } + } else if opcode == Opcode::CALLF || opcode == Opcode::JMPF { + instruction.mem_size = 4; + } + } + instruction.opcode = opcode; + instruction.operand_count = 1; + } + 15 => { + let modrm = read_modrm(words)?; + + instruction.operands[1] = read_E(words, instruction, modrm, 1)?; + instruction.regs[0] = if instruction.prefixes.operand_size() || instruction.opcode == Opcode::CRC32 { + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D) + } else { + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::W) + }; + if instruction.operands[1] != OperandSpec::RegMMM { + instruction.mem_size = 1; + } + instruction.operand_count = 2; + }, + 16 => { + let modrm = read_modrm(words)?; + + instruction.operands[1] = read_E(words, instruction, modrm, 2)?; + instruction.regs[0] = if instruction.prefixes.operand_size() { + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D) + } else { + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::W) + }; + if instruction.operands[1] != OperandSpec::RegMMM { + instruction.mem_size = 2; + } + instruction.operand_count = 2; + }, + 18 => { + instruction.operands[0] = mem_oper; + instruction.operand_count = 1; + }, + 19 => { + instruction.regs[0].bank = RegisterBank::X; + instruction.operands[0] = mem_oper; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.operand_count = 2; + if instruction.operands[0] == OperandSpec::RegMMM { + // fix the register to XMM + instruction.regs[1].bank = RegisterBank::X; + } else { + instruction.mem_size = 16; + } + }, + op @ 20 | + op @ 21 => { + instruction.regs[0].bank = RegisterBank::X; + instruction.operand_count = 2; + if instruction.operands[1] == OperandSpec::RegMMM { + if op == 20 { + return Err(DecodeError::InvalidOperand); + } else { + // fix the register to XMM + instruction.regs[1].bank = RegisterBank::X; + } + } else { + if instruction.opcode == Opcode::MOVDDUP { + instruction.mem_size = 8; + } else { + instruction.mem_size = 16; + } + } + }, + 22 => { + let modrm = read_modrm(words)?; + + instruction.operands[1] = read_E_xmm(words, instruction, modrm)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + instruction.imm = + read_num(words, 1)? as u8 as u32; + if instruction.operands[1] != OperandSpec::RegMMM { + if instruction.opcode == Opcode::CMPSS { + instruction.mem_size = 4; + } else if instruction.opcode == Opcode::CMPSD { + instruction.mem_size = 8; + } else { + instruction.mem_size = 16; + } + } + instruction.operands[2] = OperandSpec::ImmI8; + instruction.operand_count = 3; + }, + 23 => { + instruction.regs[0] = + RegSpec::al(); + instruction.operands[1] = OperandSpec::ImmI8; + instruction.operand_count = 2; + } + 24 => { + let opwidth = if instruction.prefixes.operand_size() { + instruction.regs[0] = + RegSpec::from_parts(0, RegisterBank::D); + 4 + } else { + instruction.regs[0] = + RegSpec::from_parts(0, RegisterBank::W); + 2 + }; + instruction.imm = + read_imm_signed(words, opwidth)? as u32; + instruction.operands[1] = match opwidth { + 2 => OperandSpec::ImmI16, + 4 => OperandSpec::ImmI32, + _ => unsafe { unreachable_unchecked() } + }; + instruction.operand_count = 2; + } + 25 => { + let opwidth = if instruction.prefixes.operand_size() { + 4 + } else { + 2 + }; + instruction.imm = + read_imm_unsigned(words, opwidth)?; + instruction.operands[0] = match opwidth { + 2 => OperandSpec::ImmI16, + 4 => OperandSpec::ImmI32, + _ => unsafe { unreachable_unchecked() } + }; + instruction.operand_count = 1; + }, + 26 => { + instruction.operands[0] = mem_oper; + instruction.opcode = base_opcode_map((modrm >> 3) & 7); + instruction.operands[1] = OperandSpec::ImmI8; + instruction.operand_count = 2; + }, + 27 => { + instruction.imm = 3; + instruction.operands[0] = OperandSpec::ImmU8; + instruction.operand_count = 1; + } + 28 => { + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + return Ok(()); + }, + 29 => { + instruction.regs[0].bank = RegisterBank::X; + instruction.operands[0] = mem_oper; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.operand_count = 2; + if instruction.operands[0] == OperandSpec::RegMMM { + // fix the register to XMM + if instruction.opcode == Opcode::MOVD { + instruction.regs[1].bank = RegisterBank::D; + } else { + instruction.regs[1].bank = RegisterBank::X; + } + } else { + instruction.mem_size = 4; + } + }, + 30 => { + instruction.operands[0] = mem_oper; + let r = (modrm >> 3) & 7; + if r >= 1 { + // TODO: this is where XOP decoding would occur + return Err(DecodeError::IncompleteDecoder); + } + instruction.opcode = [ + Opcode::POP, + ][r as usize]; + instruction.operand_count = 1; + } + 31 => { + instruction.regs[0].bank = RegisterBank::X; + instruction.operand_count = 2; + if instruction.operands[1] == OperandSpec::RegMMM { + // fix the register to XMM + instruction.regs[1].bank = RegisterBank::X; + } else { + instruction.mem_size = 4; + } + }, + _ => { + let operand_code: OperandCode = unsafe { core::mem::transmute(operand_code.bits()) }; + unlikely_operands(decoder, words, instruction, operand_code, mem_oper)?; + } + }; + } + + Ok(()) +} +fn unlikely_operands::Address, ::Word>>(decoder: &InstDecoder, words: &mut T, instruction: &mut Instruction, operand_code: OperandCode, mem_oper: OperandSpec) -> Result<(), DecodeError> { + match operand_code { + OperandCode::G_E_mm_Ib => { + let modrm = read_modrm(words)?; + + instruction.operands[1] = read_E_mm(words, instruction, modrm)?; + instruction.regs[0] = RegSpec { bank: RegisterBank::MM, num: (modrm >> 3) & 7 }; + if instruction.operands[1] == OperandSpec::RegMMM { + instruction.regs[1].bank = RegisterBank::MM; + } else { + instruction.mem_size = 8; + } + instruction.imm = read_num(words, 1)? as u8 as u32; + instruction.operands[2] = OperandSpec::ImmI8; + instruction.operand_count = 3; + } + OperandCode::G_Ev_xmm_Ib => { + let modrm = read_modrm(words)?; + + instruction.operands[1] = read_E_xmm(words, instruction, modrm)?; + instruction.regs[0] = RegSpec { bank: RegisterBank::X, num: (modrm >> 3) & 7 }; + instruction.imm = read_num(words, 1)? as u8 as u32; + if instruction.operands[1] != OperandSpec::RegMMM { + instruction.mem_size = match instruction.opcode { + Opcode::PEXTRB => 1, + Opcode::PEXTRW => 2, + Opcode::PEXTRD => 4, + Opcode::EXTRACTPS => 4, + Opcode::INSERTPS => 4, + Opcode::PINSRB => 1, + Opcode::PINSRW => 2, + Opcode::PINSRD => 4, + _ => 8, + }; + } + instruction.operands[2] = OperandSpec::ImmI8; + instruction.operand_count = 3; + } + OperandCode::PMOVX_E_G_xmm => { + let modrm = read_modrm(words)?; + + instruction.regs[0] = RegSpec { bank: RegisterBank::X, num: (modrm >> 3) & 7 }; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.operands[0] = read_E_xmm(words, instruction, modrm)?; + if instruction.operands[0] != OperandSpec::RegMMM { + if [].contains(&instruction.opcode) { + instruction.mem_size = 2; + } else { + instruction.mem_size = 8; + } + } else { + if instruction.opcode == Opcode::MOVLPD || instruction.opcode == Opcode::MOVHPD || instruction.opcode == Opcode::MOVHPS { + return Err(DecodeError::InvalidOperand); + } + } + } + OperandCode::PMOVX_G_E_xmm => { + let modrm = read_modrm(words)?; + + instruction.regs[0] = RegSpec { bank: RegisterBank::X, num: (modrm >> 3) & 7 }; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = read_E_xmm(words, instruction, modrm)?; + if instruction.opcode == Opcode::CVTTSD2SI || instruction.opcode == Opcode::CVTSD2SI { + instruction.regs[0].bank = RegisterBank::D; + } + if instruction.operands[1] != OperandSpec::RegMMM { + if [Opcode::PMOVSXBQ, Opcode::PMOVZXBQ].contains(&instruction.opcode) { + instruction.mem_size = 2; + } else if [Opcode::PMOVZXBD, Opcode::UCOMISS, Opcode::COMISS, Opcode::CVTSS2SD].contains(&instruction.opcode) { + instruction.mem_size = 4; + } else { + instruction.mem_size = 8; + } + } else { + if instruction.opcode == Opcode::MOVLPD || instruction.opcode == Opcode::MOVHPD { + return Err(DecodeError::InvalidOperand); + } + } + } + OperandCode::INV_Gv_M => { + let modrm = read_modrm(words)?; + if modrm >= 0xc0 { + return Err(DecodeError::InvalidOperand); + } + + instruction.regs[0] = RegSpec { bank: RegisterBank::D, num: (modrm >> 3) & 7 }; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = read_M(words, instruction, modrm)?; + if [Opcode::LFS, Opcode::LGS, Opcode::LSS].contains(&instruction.opcode) { + if instruction.prefixes.operand_size() { + instruction.mem_size = 4; + } else { + instruction.mem_size = 6; + } + } else if [Opcode::ENQCMD, Opcode::ENQCMDS].contains(&instruction.opcode) { + instruction.regs[0].bank = RegisterBank::W; + instruction.mem_size = 64; + } else { + instruction.mem_size = 16; + } + } + OperandCode::ModRM_0xc4 => { + let modrm = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; + if modrm & 0b11000000 == 0b11000000 { + // interpret the c4 as a vex prefix + if instruction.prefixes.lock() || instruction.prefixes.operand_size() || instruction.prefixes.rep() || instruction.prefixes.repnz() { + // prefixes and then vex is invalid! reject it. + return Err(DecodeError::InvalidPrefixes); + } else { + vex::three_byte_vex(words, modrm, instruction)?; + + if decoder != &InstDecoder::default() { + decoder.revise_instruction(instruction)?; + } + return Ok(()); + } + } else { + // LES + instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, if instruction.prefixes.operand_size() { RegisterBank::D } else { RegisterBank::W }); + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = read_M(words, instruction, modrm)?; + if instruction.prefixes.operand_size() { + instruction.mem_size = 6; + } else { + instruction.mem_size = 4; + } + } + }, + OperandCode::ModRM_0xc5 => { + let modrm = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; + if (modrm & 0b1100_0000) == 0b1100_0000 { + // interpret the c5 as a vex prefix + if instruction.prefixes.lock() || instruction.prefixes.operand_size() || instruction.prefixes.rep() || instruction.prefixes.repnz() { + // prefixes and then vex is invalid! reject it. + return Err(DecodeError::InvalidPrefixes); + } else { + vex::two_byte_vex(words, modrm, instruction)?; + + if decoder != &InstDecoder::default() { + decoder.revise_instruction(instruction)?; + } + return Ok(()); + } + } else { + // LDS + instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, if instruction.prefixes.operand_size() { RegisterBank::D } else { RegisterBank::W }); + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = read_M(words, instruction, modrm)?; + if instruction.prefixes.operand_size() { + instruction.mem_size = 6; + } else { + instruction.mem_size = 4; + } + } + }, + OperandCode::G_U_xmm_Ub => { + let modrm = read_modrm(words)?; + + instruction.operands[1] = read_E_xmm(words, instruction, modrm)?; + if instruction.operands[1] != OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D); + instruction.imm = + read_num(words, 1)? as u8 as u32; + instruction.operands[2] = OperandSpec::ImmU8; + instruction.operand_count = 3; + } + OperandCode::ModRM_0xf20f78 => { + instruction.opcode = Opcode::INSERTQ; + + let modrm = read_modrm(words)?; + + if modrm < 0b11_000_000 { + return Err(DecodeError::InvalidOperand); + } + + instruction.operands[0] = OperandSpec::RegRRR; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + instruction.operands[1] = OperandSpec::RegMMM; + instruction.regs[1] = + RegSpec::from_parts(modrm & 7, RegisterBank::X); + instruction.imm = + read_num(words, 1)? as u8 as u32; + instruction.disp = + read_num(words, 1)? as u8 as u32; + instruction.operands[2] = OperandSpec::ImmU8; + instruction.operands[3] = OperandSpec::ImmInDispField; + instruction.operand_count = 4; + } + OperandCode::ModRM_0x660f78 => { + instruction.opcode = Opcode::EXTRQ; + + let modrm = read_modrm(words)?; + + if modrm < 0b11_000_000 { + return Err(DecodeError::InvalidOperand); + } + + if modrm >= 0b11_001_000 { + return Err(DecodeError::InvalidOperand); + } + + instruction.operands[0] = OperandSpec::RegMMM; + instruction.regs[1] = + RegSpec::from_parts(modrm & 7, RegisterBank::X); + instruction.imm = + read_num(words, 1)? as u8 as u32; + instruction.disp = + read_num(words, 1)? as u8 as u32; + instruction.operands[1] = OperandSpec::ImmU8; + instruction.operands[2] = OperandSpec::ImmInDispField; + instruction.operand_count = 3; + + } + OperandCode::G_E_xmm_Ub => { + let modrm = read_modrm(words)?; + + instruction.operands[1] = read_E_xmm(words, instruction, modrm)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + instruction.imm = + read_num(words, 1)? as u8 as u32; + if instruction.operands[1] != OperandSpec::RegMMM { + instruction.mem_size = 16; + } + instruction.operands[2] = OperandSpec::ImmU8; + instruction.operand_count = 3; + } + OperandCode::Gd_Ed => { + instruction.regs[0].bank = RegisterBank::D; + if mem_oper == OperandSpec::RegMMM { + instruction.regs[1].bank = RegisterBank::D; + } else { + instruction.mem_size = 4; + } + instruction.operands[1] = mem_oper; + instruction.operand_count = 2; + } + OperandCode::Md_Gd => { + instruction.regs[0].bank = RegisterBank::D; + if mem_oper == OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.mem_size = 4; + instruction.operands[1] = instruction.operands[0]; + instruction.operands[0] = mem_oper; + instruction.operand_count = 2; + } + OperandCode::G_U_xmm => { + instruction.regs[0].bank = RegisterBank::X; + if mem_oper != OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.regs[1].bank = RegisterBank::X; + instruction.operand_count = 2; + }, + OperandCode::Gv_Ev_Ib => { + instruction.operands[2] = OperandSpec::ImmI8; + instruction.operand_count = 3; + } + OperandCode::Gv_Ev_Iv => { + let opwidth = if instruction.prefixes.operand_size() { + 4 + } else { + 2 + }; + instruction.imm = + read_imm_signed(words, opwidth)? as u32; + instruction.operands[2] = match opwidth { + 2 => OperandSpec::ImmI16, + 4 => OperandSpec::ImmI32, + _ => unsafe { unreachable_unchecked() } + }; + instruction.operand_count = 3; + } + OperandCode::Ev_Gv_Ib => { + instruction.operands[0] = mem_oper; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.imm = + read_imm_signed(words, 1)? as u32; + instruction.operands[2] = OperandSpec::ImmI8; + instruction.operand_count = 3; + } + OperandCode::Ev_Gv_CL => { + instruction.operands[0] = mem_oper; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.operands[2] = OperandSpec::RegVex; + instruction.regs[3] = RegSpec::cl(); + instruction.operand_count = 3; + } + OperandCode::G_mm_Ew_Ib => { + let modrm = read_modrm(words)?; + + instruction.operands[1] = read_E(words, instruction, modrm, 4)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::MM); + if instruction.operands[1] == OperandSpec::RegMMM { + instruction.regs[1].bank = RegisterBank::D; + } else { + instruction.mem_size = 2; + } + instruction.imm = + read_num(words, 1)? as u8 as u32; + instruction.operands[2] = OperandSpec::ImmI8; + instruction.operand_count = 3; + } + OperandCode::G_E_mm => { + instruction.regs[0].bank = RegisterBank::MM; + instruction.regs[0].num &= 0b111; + if mem_oper == OperandSpec::RegMMM { + instruction.regs[1].bank = RegisterBank::MM; + instruction.regs[1].num &= 0b111; + } else { + if [Opcode::PUNPCKLBW, Opcode::PUNPCKLWD, Opcode::PUNPCKLDQ].contains(&instruction.opcode) { + instruction.mem_size = 4; + } else { + instruction.mem_size = 8; + } + } + instruction.operand_count = 2; + }, + OperandCode::G_U_mm => { + instruction.regs[0].bank = RegisterBank::D; + if mem_oper != OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.regs[1].bank = RegisterBank::MM; + instruction.regs[1].num &= 0b111; + instruction.operand_count = 2; + }, + OperandCode::Gv_Ew_LSL => { + let modrm = read_modrm(words)?; + if !instruction.prefixes.operand_size() { + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::W); + } else { + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::W); + }; + + instruction.operands[1] = read_E(words, instruction, modrm, 2)?; + // lsl is weird. the full register width is written, but only the low 16 bits are used. + if instruction.operands[1] == OperandSpec::RegMMM { + instruction.regs[1].bank = RegisterBank::W; + } else { + instruction.mem_size = 2; + } + instruction.operand_count = 2; + }, + OperandCode::Gd_Ev => { + let modrm = read_modrm(words)?; + + let opwidth = if instruction.prefixes.operand_size() { + 4 + } else { + 2 + }; + instruction.operands[1] = read_E(words, instruction, modrm, opwidth)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D); + instruction.operand_count = 2; + if instruction.operands[1] != OperandSpec::RegMMM { + instruction.mem_size = opwidth; + } + }, + op @ OperandCode::AL_Ob | + op @ OperandCode::AX_Ov => { + instruction.regs[0] = match op { + OperandCode::AL_Ob => { + instruction.mem_size = 1; + RegSpec::al() + }, + OperandCode::AX_Ov => { + if !instruction.prefixes.operand_size() { + instruction.mem_size = 2; + RegSpec::ax() + } else { + instruction.mem_size = 4; + RegSpec::eax() + } + } + _ => { + unsafe { unreachable_unchecked() } + } + }; + let addr_width = if instruction.prefixes.address_size() { 4 } else { 2 }; + let imm = read_num(words, addr_width)?; + instruction.disp = imm; + if instruction.prefixes.address_size() { + instruction.operands[1] = OperandSpec::DispU16; + } else { + instruction.operands[1] = OperandSpec::DispU32; + }; + instruction.operand_count = 2; + } + op @ OperandCode::Ob_AL | + op @ OperandCode::Ov_AX => { + instruction.regs[0] = match op { + OperandCode::Ob_AL => { + instruction.mem_size = 1; + RegSpec::al() + }, + OperandCode::Ov_AX => { + if !instruction.prefixes.operand_size() { + instruction.mem_size = 2; + RegSpec::ax() + } else { + instruction.mem_size = 4; + RegSpec::eax() + } + } + _ => { + unsafe { unreachable_unchecked() } + } + }; + let addr_width = if instruction.prefixes.address_size() { 4 } else { 2 }; + let imm = read_num(words, addr_width)?; + instruction.disp = imm; + instruction.operands[0] = if instruction.prefixes.address_size() { + OperandSpec::DispU16 + } else { + OperandSpec::DispU32 + }; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.operand_count = 2; + } + OperandCode::I_1 => { + instruction.imm = 1; + instruction.operands[0] = OperandSpec::ImmU8; + instruction.operand_count = 1; + } + /* + OperandCode::Unsupported => { + return Err(DecodeError::IncompleteDecoder); + } + */ + OperandCode::Iw_Ib => { + instruction.disp = read_num(words, 2)?; + instruction.imm = read_num(words, 1)?; + instruction.operands[0] = OperandSpec::ImmInDispField; + instruction.operands[1] = OperandSpec::ImmU8; + instruction.operand_count = 2; + } + OperandCode::Fw => { + if !instruction.prefixes.operand_size() { + instruction.opcode = Opcode::IRET; + } else { + instruction.opcode = Opcode::IRETD; + } + instruction.operand_count = 0; + } + OperandCode::G_mm_U_mm => { + instruction.regs[0].bank = RegisterBank::MM; + if mem_oper != OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.regs[1].bank = RegisterBank::MM; + instruction.regs[1].num &= 0b111; + instruction.regs[0].num &= 0b111; + instruction.operand_count = 2; + }, + OperandCode::E_G_q => { + if instruction.prefixes.operand_size() { + return Err(DecodeError::InvalidOpcode); + } + + let modrm = read_modrm(words)?; + + instruction.operands[0] = read_E(words, instruction, modrm, 4)?; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D); + instruction.operand_count = 2; + if instruction.operands[0] != OperandSpec::RegMMM { + instruction.mem_size = 4; + } + } + OperandCode::G_E_q => { + if instruction.prefixes.operand_size() { + return Err(DecodeError::InvalidOpcode); + } + + let modrm = read_modrm(words)?; + + instruction.operands[0] = OperandSpec::RegRRR; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D); + instruction.operands[1] = read_E(words, instruction, modrm, 4)?; + if instruction.operands[0] != OperandSpec::RegMMM { + instruction.mem_size = 4; + } + instruction.operand_count = 2; + } + OperandCode::G_Mq_mm => { + instruction.operands[1] = instruction.operands[0]; + instruction.operands[0] = mem_oper; + instruction.regs[0].bank = RegisterBank::MM; + if mem_oper == OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } else { + instruction.mem_size = 8; + } + instruction.regs[0].num &= 0b111; + instruction.operand_count = 2; + }, + OperandCode::MOVQ_f30f => { + instruction.operand_count = 2; + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + instruction.operands[1] = read_E_xmm(words, instruction, modrm)?; + if instruction.operands[1] != OperandSpec::RegMMM { + instruction.mem_size = 8; + } + } + OperandCode::ModRM_0x0f0d => { + let modrm = read_modrm(words)?; + let r = (modrm >> 3) & 0b111; + + let opwidth = if instruction.prefixes.operand_size() { + 4 + } else { + 2 + }; + + match r { + 1 => { + instruction.opcode = Opcode::PREFETCHW; + } + _ => { + instruction.opcode = Opcode::NOP; + } + } + instruction.operands[0] = read_E(words, instruction, modrm, opwidth)?; + if instruction.operands[0] != OperandSpec::RegMMM { + instruction.mem_size = 64; + } + instruction.operand_count = 1; + } + OperandCode::ModRM_0x0f0f => { + // 3dnow instructions are WILD, the opcode is encoded as an imm8 trailing the + // instruction. + + let modrm = read_modrm(words)?; + instruction.operands[1] = read_E_mm(words, instruction, modrm)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.regs[0] = RegSpec { bank: RegisterBank::MM, num: (modrm >> 3) & 7 }; + if instruction.operands[1] != OperandSpec::RegMMM { + instruction.mem_size = 8; + } + + let opcode = read_modrm(words)?; + match opcode { + 0x0c => { + instruction.opcode = Opcode::PI2FW; + } + 0x0d => { + instruction.opcode = Opcode::PI2FD; + } + 0x1c => { + instruction.opcode = Opcode::PF2IW; + } + 0x1d => { + instruction.opcode = Opcode::PF2ID; + } + 0x8a => { + instruction.opcode = Opcode::PFNACC; + } + 0x8e => { + instruction.opcode = Opcode::PFPNACC; + } + 0x90 => { + instruction.opcode = Opcode::PFCMPGE; + } + 0x94 => { + instruction.opcode = Opcode::PFMIN; + } + 0x96 => { + instruction.opcode = Opcode::PFRCP; + } + 0x97 => { + instruction.opcode = Opcode::PFRSQRT; + } + 0x9a => { + instruction.opcode = Opcode::PFSUB; + } + 0x9e => { + instruction.opcode = Opcode::PFADD; + } + 0xa0 => { + instruction.opcode = Opcode::PFCMPGT; + } + 0xa4 => { + instruction.opcode = Opcode::PFMAX; + } + 0xa6 => { + instruction.opcode = Opcode::PFRCPIT1; + } + 0xa7 => { + instruction.opcode = Opcode::PFRSQIT1; + } + 0xaa => { + instruction.opcode = Opcode::PFSUBR; + } + 0xae => { + instruction.opcode = Opcode::PFACC; + } + 0xb0 => { + instruction.opcode = Opcode::PFCMPEQ; + } + 0xb4 => { + instruction.opcode = Opcode::PFMUL; + } + 0xb6 => { + instruction.opcode = Opcode::PFRCPIT2; + } + 0xb7 => { + instruction.opcode = Opcode::PMULHRW; + } + 0xbb => { + instruction.opcode = Opcode::PSWAPD; + } + 0xbf => { + instruction.opcode = Opcode::PAVGUSB; + } + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + } + OperandCode::ModRM_0x0fc7 => { + if instruction.prefixes.repnz() { + let modrm = read_modrm(words)?; + let is_reg = (modrm & 0xc0) == 0xc0; + + let r = (modrm >> 3) & 7; + match r { + 1 => { + if is_reg { + return Err(DecodeError::InvalidOperand); + } else { + instruction.opcode = Opcode::CMPXCHG8B; + instruction.mem_size = 8; + instruction.operand_count = 1; + instruction.operands[0] = read_E(words, instruction, modrm, 4)?; + } + return Ok(()); + } + _ => { + return Err(DecodeError::InvalidOperand); + } + } + } + if instruction.prefixes.operand_size() { + let opwidth = if instruction.prefixes.operand_size() { + 4 + } else { + 2 + }; + let modrm = read_modrm(words)?; + let is_reg = (modrm & 0xc0) == 0xc0; + + let r = (modrm >> 3) & 7; + match r { + 1 => { + if is_reg { + return Err(DecodeError::InvalidOperand); + } else { + instruction.opcode = Opcode::CMPXCHG8B; + instruction.mem_size = 8; + instruction.operand_count = 1; + instruction.operands[0] = read_E(words, instruction, modrm, 4)?; + } + return Ok(()); + } + 6 => { + instruction.opcode = Opcode::VMCLEAR; + instruction.operands[0] = read_E(words, instruction, modrm, opwidth)?; + if instruction.operands[0] == OperandSpec::RegMMM { + // this would be invalid as `vmclear`, so fall back to the parse as + // 66-prefixed rdrand. this is a register operand, so just demote it to the + // dword-form operand: + instruction.regs[1] = RegSpec { bank: RegisterBank::D, num: instruction.regs[1].num }; + instruction.opcode = Opcode::RDRAND; + } else { + instruction.mem_size = 8; + } + instruction.operand_count = 1; + return Ok(()); + } + 7 => { + instruction.operands[0] = read_E(words, instruction, modrm, opwidth)?; + if instruction.operands[0] == OperandSpec::RegMMM { + // this would be invalid as `vmclear`, so fall back to the parse as + // 66-prefixed rdrand. this is a register operand, so just demote it to the + // dword-form operand: + instruction.regs[1] = RegSpec { bank: RegisterBank::D, num: instruction.regs[1].num }; + instruction.opcode = Opcode::RDSEED; + } else { + return Err(DecodeError::InvalidOpcode); + } + instruction.operand_count = 1; + return Ok(()); + } + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + } + + if instruction.prefixes.rep() { + let opwidth = if instruction.prefixes.operand_size() { + 4 + } else { + 2 + }; + let modrm = read_modrm(words)?; + let is_reg = (modrm & 0xc0) == 0xc0; + + let r = (modrm >> 3) & 7; + match r { + 1 => { + if is_reg { + return Err(DecodeError::InvalidOperand); + } else { + instruction.opcode = Opcode::CMPXCHG8B; + instruction.mem_size = 8; + instruction.operand_count = 1; + instruction.operands[0] = read_E(words, instruction, modrm, 4)?; + } + } + 6 => { + instruction.opcode = Opcode::VMXON; + instruction.operands[0] = read_E(words, instruction, modrm, opwidth)?; + if instruction.operands[0] == OperandSpec::RegMMM { + // invalid as `vmxon`, reg-form is `senduipi` + instruction.opcode = Opcode::SENDUIPI; + // and the operand is always a dword register + instruction.regs[1].bank = RegisterBank::D; + } else { + instruction.mem_size = 8; + } + instruction.operand_count = 1; + } + 7 => { + instruction.opcode = Opcode::RDPID; + instruction.operands[0] = read_E(words, instruction, modrm, 4)?; + if instruction.operands[0] != OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.operand_count = 1; + } + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + return Ok(()); + } + + let modrm = read_modrm(words)?; + let is_reg = (modrm & 0xc0) == 0xc0; + + let r = (modrm >> 3) & 0b111; + + let opcode = match r { + 0b001 => { + if is_reg { + return Err(DecodeError::InvalidOperand); + } else { + instruction.mem_size = 8; + Opcode::CMPXCHG8B + } + } + 0b011 => { + if is_reg { + return Err(DecodeError::InvalidOperand); + } else { + instruction.mem_size = 63; + Opcode::XRSTORS + } + } + 0b100 => { + if is_reg { + return Err(DecodeError::InvalidOperand); + } else { + instruction.mem_size = 63; + Opcode::XSAVEC + } + } + 0b101 => { + if is_reg { + return Err(DecodeError::InvalidOperand); + } else { + instruction.mem_size = 63; + Opcode::XSAVES + } + } + 0b110 => { + if is_reg { + Opcode::RDRAND + } else { + instruction.mem_size = 8; + Opcode::VMPTRLD + } + } + 0b111 => { + if is_reg { + Opcode::RDSEED + } else { + instruction.mem_size = 8; + Opcode::VMPTRST + } + } + _ => { + return Err(DecodeError::InvalidOperand); + } + }; + + instruction.opcode = opcode; + instruction.operand_count = 1; + let opwidth = if instruction.prefixes.operand_size() { + 4 + } else { + 2 + }; + instruction.operands[0] = read_E(words, instruction, modrm, opwidth)?; + }, + OperandCode::ModRM_0x0f71 => { + if instruction.prefixes.rep() || instruction.prefixes.repnz() { + return Err(DecodeError::InvalidOperand); + } + + instruction.operand_count = 2; + + let modrm = read_modrm(words)?; + if modrm & 0xc0 != 0xc0 { + return Err(DecodeError::InvalidOperand); + } + + let r = (modrm >> 3) & 7; + match r { + 2 => { + instruction.opcode = Opcode::PSRLW; + } + 4 => { + instruction.opcode = Opcode::PSRAW; + } + 6 => { + instruction.opcode = Opcode::PSLLW; + } + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + + if instruction.prefixes.operand_size() { + instruction.regs[1] = RegSpec { bank: RegisterBank::X, num: modrm & 7 }; + } else { + instruction.regs[1] = RegSpec { bank: RegisterBank::MM, num: modrm & 7 }; + } + instruction.operands[0] = OperandSpec::RegMMM; + instruction.imm = read_imm_signed(words, 1)? as u32; + instruction.operands[1] = OperandSpec::ImmU8; + }, + OperandCode::ModRM_0x0f72 => { + if instruction.prefixes.rep() || instruction.prefixes.repnz() { + return Err(DecodeError::InvalidOperand); + } + + instruction.operand_count = 2; + + let modrm = read_modrm(words)?; + if modrm & 0xc0 != 0xc0 { + return Err(DecodeError::InvalidOperand); + } + + let r = (modrm >> 3) & 7; + match r { + 2 => { + instruction.opcode = Opcode::PSRLD; + } + 4 => { + instruction.opcode = Opcode::PSRAD; + } + 6 => { + instruction.opcode = Opcode::PSLLD; + } + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + + if instruction.prefixes.operand_size() { + instruction.regs[1] = RegSpec { bank: RegisterBank::X, num: modrm & 7 }; + } else { + instruction.regs[1] = RegSpec { bank: RegisterBank::MM, num: modrm & 7 }; + } + instruction.operands[0] = OperandSpec::RegMMM; + instruction.imm = read_imm_signed(words, 1)? as u32; + instruction.operands[1] = OperandSpec::ImmU8; + }, + OperandCode::ModRM_0x0f73 => { + if instruction.prefixes.rep() || instruction.prefixes.repnz() { + return Err(DecodeError::InvalidOperand); + } + + instruction.operand_count = 2; + + let modrm = read_modrm(words)?; + if modrm & 0xc0 != 0xc0 { + return Err(DecodeError::InvalidOperand); + } + + let r = (modrm >> 3) & 7; + match r { + 2 => { + instruction.opcode = Opcode::PSRLQ; + } + 3 => { + if !instruction.prefixes.operand_size() { + return Err(DecodeError::InvalidOperand); + } + instruction.opcode = Opcode::PSRLDQ; + } + 6 => { + instruction.opcode = Opcode::PSLLQ; + } + 7 => { + if !instruction.prefixes.operand_size() { + return Err(DecodeError::InvalidOperand); + } + instruction.opcode = Opcode::PSLLDQ; + } + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + + if instruction.prefixes.operand_size() { + instruction.regs[1] = RegSpec { bank: RegisterBank::X, num: modrm & 7 }; + } else { + instruction.regs[1] = RegSpec { bank: RegisterBank::MM, num: modrm & 7 }; + } + instruction.operands[0] = OperandSpec::RegMMM; + instruction.imm = read_imm_signed(words, 1)? as u32; + instruction.operands[1] = OperandSpec::ImmU8; + }, + OperandCode::ModRM_0xf30f38d8 => { + let modrm = read_modrm(words)?; + let r = (modrm >> 3) & 7; + instruction.mem_size = 63; + match r { + 0b000 => { + if modrm >= 0b11_000_000 { + return Err(DecodeError::InvalidOperand); + } + instruction.mem_size = 48; + instruction.opcode = Opcode::AESENCWIDE128KL; + instruction.operands[0] = read_M(words, instruction, modrm)?; + return Ok(()); + } + 0b001 => { + if modrm >= 0b11_000_000 { + return Err(DecodeError::InvalidOperand); + } + instruction.mem_size = 48; + instruction.opcode = Opcode::AESDECWIDE128KL; + instruction.operands[0] = read_M(words, instruction, modrm)?; + return Ok(()); + } + 0b010 => { + if modrm >= 0b11_000_000 { + return Err(DecodeError::InvalidOperand); + } + instruction.mem_size = 64; + instruction.opcode = Opcode::AESENCWIDE256KL; + instruction.operands[0] = read_M(words, instruction, modrm)?; + return Ok(()); + } + 0b011 => { + if modrm >= 0b11_000_000 { + return Err(DecodeError::InvalidOperand); + } + instruction.mem_size = 64; + instruction.opcode = Opcode::AESDECWIDE256KL; + instruction.operands[0] = read_M(words, instruction, modrm)?; + return Ok(()); + } + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + } + OperandCode::ModRM_0xf30f38dc => { + read_operands(decoder, words, instruction, OperandCode::G_E_xmm)?; + if let OperandSpec::RegMMM = instruction.operands[1] { + instruction.opcode = Opcode::LOADIWKEY; + } else { + instruction.mem_size = 48; + instruction.opcode = Opcode::AESENC128KL; + } + } + OperandCode::ModRM_0xf30f38dd => { + read_operands(decoder, words, instruction, OperandCode::G_E_xmm)?; + if let OperandSpec::RegMMM = instruction.operands[1] { + return Err(DecodeError::InvalidOperand); + } else { + instruction.mem_size = 48; + instruction.opcode = Opcode::AESDEC128KL; + } + } + OperandCode::ModRM_0xf30f38de => { + read_operands(decoder, words, instruction, OperandCode::G_E_xmm)?; + if let OperandSpec::RegMMM = instruction.operands[1] { + return Err(DecodeError::InvalidOperand); + } else { + instruction.mem_size = 64; + instruction.opcode = Opcode::AESENC256KL; + } + } + OperandCode::ModRM_0xf30f38df => { + read_operands(decoder, words, instruction, OperandCode::G_E_xmm)?; + if let OperandSpec::RegMMM = instruction.operands[1] { + return Err(DecodeError::InvalidOperand); + } else { + instruction.mem_size = 64; + instruction.opcode = Opcode::AESDEC256KL; + } + } + OperandCode::ModRM_0xf30f38fa => { + instruction.opcode = Opcode::ENCODEKEY128; + read_operands(decoder, words, instruction, OperandCode::G_U_xmm)?; + instruction.regs[0].bank = RegisterBank::D; + instruction.regs[1].bank = RegisterBank::D; + } + OperandCode::ModRM_0xf30f38fb => { + instruction.opcode = Opcode::ENCODEKEY256; + read_operands(decoder, words, instruction, OperandCode::G_U_xmm)?; + instruction.regs[0].bank = RegisterBank::D; + instruction.regs[1].bank = RegisterBank::D; + } + OperandCode::ModRM_0xf30f3af0 => { + let modrm = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; + if modrm & 0xc0 != 0xc0 { + return Err(DecodeError::InvalidOpcode); + // invalid + } + instruction.opcode = Opcode::HRESET; + instruction.imm = read_num(words, 1)?; + instruction.operands[0] = OperandSpec::ImmU8; + } + OperandCode::G_mm_Ed => { + instruction.regs[0].bank = RegisterBank::MM; + instruction.regs[0].num &= 0b111; + if mem_oper == OperandSpec::RegMMM { + instruction.regs[1].bank = RegisterBank::D; + } else { + instruction.mem_size = 4; + } + } + OperandCode::G_mm_E => { + instruction.regs[0].bank = RegisterBank::MM; + instruction.regs[0].num &= 0b111; + if mem_oper == OperandSpec::RegMMM { + instruction.regs[1].bank = RegisterBank::MM; + instruction.regs[1].num &= 0b111; + } else { + instruction.mem_size = 8; + } + } + OperandCode::Ed_G_mm => { + instruction.operands[1] = instruction.operands[0]; + instruction.operands[0] = mem_oper; + instruction.regs[0].bank = RegisterBank::MM; + instruction.regs[0].num &= 0b111; + if mem_oper == OperandSpec::RegMMM { + instruction.regs[1].bank = RegisterBank::D; + } else { + instruction.mem_size = 4; + } + } + OperandCode::Ed_G_xmm => { + instruction.operands[1] = instruction.operands[0]; + instruction.operands[0] = mem_oper; + instruction.regs[0].bank = RegisterBank::Y; + if mem_oper == OperandSpec::RegMMM { + instruction.regs[1].bank = RegisterBank::D; + } else { + instruction.mem_size = 4; + } + } + OperandCode::E_G_mm => { + instruction.operands[1] = instruction.operands[0]; + instruction.operands[0] = mem_oper; + instruction.regs[0].bank = RegisterBank::MM; + instruction.regs[0].num &= 0b111; + if mem_oper == OperandSpec::RegMMM { + instruction.regs[1].bank = RegisterBank::MM; + instruction.regs[1].num &= 0b111; + } else { + instruction.mem_size = 8; + } + } + OperandCode::G_xmm_Ew_Ib => { + instruction.operands[2] = OperandSpec::ImmU8; + instruction.operand_count = 3; + instruction.imm = + read_num(words, 1)?; + instruction.regs[0].bank = RegisterBank::X; + if mem_oper == OperandSpec::RegMMM { + instruction.regs[1].bank = RegisterBank::D; + } else { + instruction.mem_size = 2; + } + }, + OperandCode::G_xmm_Ed => { + instruction.regs[0].bank = RegisterBank::X; + if mem_oper == OperandSpec::RegMMM { + instruction.regs[1].bank = RegisterBank::D; + } else { + instruction.mem_size = 4; + } + }, + OperandCode::G_mm_E_xmm => { + instruction.regs[0].bank = RegisterBank::MM; + instruction.regs[0].num &= 0b111; + if mem_oper == OperandSpec::RegMMM { + instruction.regs[1].bank = RegisterBank::X; + } else { + instruction.mem_size = 16; + } + }, + op @ OperandCode::G_xmm_U_mm | + op @ OperandCode::G_xmm_E_mm => { + instruction.regs[0].bank = RegisterBank::X; + if mem_oper == OperandSpec::RegMMM { + instruction.regs[1].bank = RegisterBank::MM; + instruction.regs[1].num &= 0b111; + } else { + if op == OperandCode::G_xmm_U_mm { + return Err(DecodeError::InvalidOperand); + } else { + instruction.mem_size = 8; + } + } + }, + OperandCode::Rv_Gmm_Ib => { + instruction.operands[2] = OperandSpec::ImmU8; + instruction.operand_count = 3; + instruction.imm = + read_num(words, 1)?; + instruction.regs[0].bank = RegisterBank::D; + if mem_oper == OperandSpec::RegMMM { + instruction.regs[1].bank = RegisterBank::MM; + instruction.regs[1].num &= 0b111; + } else { + return Err(DecodeError::InvalidOperand); + } + } + OperandCode::U_mm_G_xmm => { + instruction.regs[1].bank = RegisterBank::X; + if mem_oper == OperandSpec::RegMMM { + instruction.regs[0].bank = RegisterBank::MM; + instruction.regs[0].num &= 0b111; + } else { + return Err(DecodeError::InvalidOperand); + } + } + // sure hope these aren't backwards huh + OperandCode::AL_Xb => { + instruction.regs[0] = RegSpec::al(); + instruction.regs[1] = RegSpec::esi(); + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::Deref; + instruction.mem_size = 1; + instruction.operand_count = 2; + } + OperandCode::Yb_Xb => { + instruction.operands[0] = OperandSpec::Deref_edi; + instruction.operands[1] = OperandSpec::Deref_esi; + instruction.mem_size = 1; + instruction.operand_count = 2; + } + OperandCode::Yb_AL => { + instruction.regs[0] = RegSpec::al(); + instruction.regs[1] = RegSpec::esi(); + instruction.operands[0] = OperandSpec::Deref; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.mem_size = 1; + instruction.operand_count = 2; + } + OperandCode::AX_Xv => { + instruction.regs[0] = if instruction.prefixes.operand_size() { + instruction.mem_size = 2; + RegSpec::ax() + } else { + instruction.mem_size = 4; + RegSpec::eax() + }; + instruction.regs[1] = RegSpec::esi(); + instruction.operands[1] = OperandSpec::Deref; + } + OperandCode::Yv_AX => { + instruction.regs[0] = if !instruction.prefixes.operand_size() { + instruction.mem_size = 2; + RegSpec::ax() + } else { + instruction.mem_size = 4; + RegSpec::eax() + }; + if instruction.prefixes.address_size() { + instruction.operands[0] = OperandSpec::Deref_edi; + } else { + instruction.operands[0] = OperandSpec::Deref_di; + } + instruction.operands[1] = OperandSpec::RegRRR; + } + OperandCode::Yv_Xv => { + instruction.mem_size = if !instruction.prefixes.operand_size() { + 2 + } else { + 4 + }; + if instruction.prefixes.address_size() { + instruction.operands[0] = OperandSpec::Deref_edi; + instruction.operands[1] = OperandSpec::Deref_esi; + } else { + instruction.operands[0] = OperandSpec::Deref_di; + instruction.operands[1] = OperandSpec::Deref_si; + } + } + OperandCode::ModRM_0x0f12 => { + instruction.regs[0].bank = RegisterBank::X; + instruction.operands[1] = mem_oper; + if instruction.operands[1] == OperandSpec::RegMMM { + if instruction.prefixes.operand_size() { + return Err(DecodeError::InvalidOpcode); + } + instruction.regs[1].bank = RegisterBank::X; + instruction.opcode = Opcode::MOVHLPS; + } else { + instruction.mem_size = 8; + if instruction.prefixes.operand_size() { + instruction.opcode = Opcode::MOVLPD; + } else { + instruction.opcode = Opcode::MOVLPS; + } + } + } + OperandCode::ModRM_0x0f16 => { + instruction.regs[0].bank = RegisterBank::X; + instruction.operands[1] = mem_oper; + if instruction.operands[1] == OperandSpec::RegMMM { + instruction.regs[1].bank = RegisterBank::X; + if instruction.prefixes.operand_size() { + return Err(DecodeError::InvalidOpcode); + } + instruction.opcode = Opcode::MOVLHPS; + } else { + instruction.mem_size = 8; + if instruction.prefixes.operand_size() { + instruction.opcode = Opcode::MOVHPD; + } else { + instruction.opcode = Opcode::MOVHPS; + } + } + } + OperandCode::ModRM_0x0f18 => { + let rrr = instruction.regs[0].num & 0b111; + instruction.operands[0] = mem_oper; + instruction.operand_count = 1; + instruction.opcode = if mem_oper == OperandSpec::RegMMM && rrr < 4 { + Opcode::NOP + } else { + match rrr { + 0 => Opcode::PREFETCHNTA, + 1 => Opcode::PREFETCH0, + 2 => Opcode::PREFETCH1, + 3 => Opcode::PREFETCH2, + _ => Opcode::NOP, + } + }; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 64; + } + } + OperandCode::Gd_U_xmm => { + if instruction.operands[1] != OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.regs[0].bank = RegisterBank::D; + instruction.regs[1].bank = RegisterBank::X; + } + OperandCode::Gv_E_xmm => { + // in real-mode the reigster is always dword, regardless of prefixing + instruction.regs[0].bank = RegisterBank::D; + if instruction.operands[1] == OperandSpec::RegMMM { + instruction.regs[1].bank = RegisterBank::X; + } else { + instruction.mem_size = 4; + } + } + OperandCode::M_G_xmm => { + // in real-mode the reigster is always dword, regardless of prefixing + instruction.regs[0].bank = RegisterBank::D; + instruction.operands[1] = instruction.operands[0]; + instruction.operands[0] = mem_oper; + if instruction.operands[0] == OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } else { + if instruction.opcode == Opcode::MOVNTSS { + instruction.mem_size = 4; + } else if instruction.opcode == Opcode::MOVNTPD || instruction.opcode == Opcode::MOVNTDQ || instruction.opcode == Opcode::MOVNTPS { + instruction.mem_size = 16; + } else { + instruction.mem_size = 8; + } + } + instruction.regs[0].bank = RegisterBank::X; + } + OperandCode::Ew_Gw => { + let modrm = read_modrm(words)?; + + instruction.regs[0] = + RegSpec { bank: RegisterBank::W, num: (modrm >> 3) & 7 }; + instruction.operands[0] = read_E(words, instruction, modrm, 2)?; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.mem_size = 2; + instruction.operand_count = 2; + }, + OperandCode::Ew_Sw => { + let opwidth = 2; + let modrm = read_modrm(words)?; + + // check r + if ((modrm >> 3) & 7) > 5 { + // return Err(()); //Err("Invalid r".to_owned()); + return Err(DecodeError::InvalidOperand); + } + + instruction.regs[0] = + RegSpec { bank: RegisterBank::S, num: (modrm >> 3) & 7 }; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.operand_count = 2; + + let mod_bits = modrm >> 6; + if mod_bits == 0b11 { + instruction.regs[1] = + RegSpec { bank: RegisterBank::W, num: modrm & 7}; + instruction.operands[0] = OperandSpec::RegMMM; + } else { + instruction.operands[0] = read_E(words, instruction, modrm, opwidth)?; + instruction.mem_size = 2; + } + }, + OperandCode::Sw_Ew => { + let modrm = read_modrm(words)?; + + // check r + if ((modrm >> 3) & 7) > 5 { + // return Err(()); // Err("Invalid r".to_owned()); + return Err(DecodeError::InvalidOperand); + } + + instruction.regs[0] = + RegSpec { bank: RegisterBank::S, num: (modrm >> 3) & 7 }; + + // quoth the manual: + // ``` + // The MOV instruction cannot be used to load the CS register. Attempting to do so + // results in an invalid opcode excep-tion (#UD). To load the CS register, use the far + // JMP, CALL, or RET instruction. + // ``` + if instruction.regs[0].num == 1 { + return Err(DecodeError::InvalidOperand); + } + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operand_count = 2; + + let mod_bits = modrm >> 6; + if mod_bits == 0b11 { + instruction.regs[1] = + RegSpec { bank: RegisterBank::W, num: modrm & 7}; + instruction.operands[1] = OperandSpec::RegMMM; + } else { + instruction.operands[1] = read_M(words, instruction, modrm)?; + instruction.mem_size = 2; + } + }, + OperandCode::CVT_AA => { + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + instruction.opcode = if instruction.prefixes.operand_size() { + Opcode::CWDE + } else { + Opcode::CBW + }; + } + OperandCode::CVT_DA => { + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + instruction.opcode = if instruction.prefixes.operand_size() { + Opcode::CDQ + } else { + Opcode::CWD + }; + } + OperandCode::Ib => { + instruction.operands[0] = OperandSpec::ImmU8; + instruction.operand_count = 1; + } + OperandCode::Iw => { + instruction.imm = + read_imm_unsigned(words, 2)?; + instruction.operands[0] = OperandSpec::ImmU16; + instruction.operand_count = 1; + } + OperandCode::ModRM_0x0f00 => { + instruction.operand_count = 1; + let modrm = read_modrm(words)?; + let r = (modrm >> 3) & 7; + if r == 0 { + instruction.opcode = Opcode::SLDT; + } else if r == 1 { + instruction.opcode = Opcode::STR; + } else if r == 2 { + instruction.opcode = Opcode::LLDT; + } else if r == 3 { + instruction.opcode = Opcode::LTR; + } else if r == 4 { + instruction.opcode = Opcode::VERR; + } else if r == 5 { + instruction.opcode = Opcode::VERW; + } else if r == 6 { + // TODO: this would be jmpe for x86-on-itanium systems. + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + return Err(DecodeError::InvalidOperand); + } else if r == 7 { + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + return Err(DecodeError::InvalidOperand); + } else { + unreachable!("r <= 8"); + } + instruction.operands[0] = read_E(words, instruction, modrm, 2)?; + if instruction.operands[0] != OperandSpec::RegMMM { + instruction.mem_size = 2; + } + } + OperandCode::ModRM_0x0f01 => { + let opwidth = if instruction.prefixes.operand_size() { + 2 + } else { + 4 + }; + let modrm = read_modrm(words)?; + let r = (modrm >> 3) & 7; + if r == 0 { + let mod_bits = modrm >> 6; + let m = modrm & 7; + if mod_bits == 0b11 { + if instruction.prefixes.rep() || instruction.prefixes.repnz() || instruction.prefixes.operand_size() { + return Err(DecodeError::InvalidOperand); + } + + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + match m { + 0b000 => { + instruction.opcode = Opcode::ENCLV; + }, + 0b001 => { + instruction.opcode = Opcode::VMCALL; + }, + 0b010 => { + instruction.opcode = Opcode::VMLAUNCH; + }, + 0b011 => { + instruction.opcode = Opcode::VMRESUME; + }, + 0b100 => { + instruction.opcode = Opcode::VMXOFF; + }, + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + } else { + instruction.opcode = Opcode::SGDT; + instruction.operand_count = 1; + instruction.mem_size = 63; + instruction.operands[0] = read_E(words, instruction, modrm, opwidth)?; + } + } else if r == 1 { + let mod_bits = modrm >> 6; + let m = modrm & 7; + if mod_bits == 0b11 { + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + if instruction.prefixes.rep() || instruction.prefixes.repnz() { + return Err(DecodeError::InvalidOpcode); + } + if instruction.prefixes.operand_size() { + match m { + 0b100 => { + instruction.opcode = Opcode::TDCALL; + } + 0b101 => { + instruction.opcode = Opcode::SEAMRET; + } + 0b110 => { + instruction.opcode = Opcode::SEAMOPS; + } + 0b111 => { + instruction.opcode = Opcode::SEAMCALL; + } + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + } else { + match m { + 0b000 => { + instruction.opcode = Opcode::MONITOR; + } + 0b001 => { + instruction.opcode = Opcode::MWAIT; + }, + 0b010 => { + instruction.opcode = Opcode::CLAC; + } + 0b011 => { + instruction.opcode = Opcode::STAC; + } + 0b111 => { + instruction.opcode = Opcode::ENCLS; + } + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + } + } else { + instruction.opcode = Opcode::SIDT; + instruction.operand_count = 1; + instruction.mem_size = 63; + instruction.operands[0] = read_E(words, instruction, modrm, opwidth)?; + } + } else if r == 2 { + let mod_bits = modrm >> 6; + let m = modrm & 7; + if mod_bits == 0b11 { + if instruction.prefixes.rep() || instruction.prefixes.repnz() || instruction.prefixes.operand_size() { + return Err(DecodeError::InvalidOperand); + } + + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + match m { + 0b000 => { + instruction.opcode = Opcode::XGETBV; + } + 0b001 => { + instruction.opcode = Opcode::XSETBV; + } + 0b100 => { + instruction.opcode = Opcode::VMFUNC; + } + 0b101 => { + instruction.opcode = Opcode::XEND; + } + 0b110 => { + instruction.opcode = Opcode::XTEST; + } + 0b111 => { + instruction.opcode = Opcode::ENCLU; + } + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + } else { + instruction.opcode = Opcode::LGDT; + instruction.operand_count = 1; + instruction.mem_size = 63; + instruction.operands[0] = read_E(words, instruction, modrm, opwidth)?; + } + } else if r == 3 { + let mod_bits = modrm >> 6; + let m = modrm & 7; + if mod_bits == 0b11 { + match m { + 0b000 => { + instruction.opcode = Opcode::VMRUN; + instruction.operand_count = 1; + instruction.regs[0] = RegSpec::ax(); + instruction.operands[0] = OperandSpec::RegRRR; + }, + 0b001 => { + instruction.opcode = Opcode::VMMCALL; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + }, + 0b010 => { + instruction.opcode = Opcode::VMLOAD; + instruction.operand_count = 1; + instruction.regs[0] = RegSpec::ax(); + instruction.operands[0] = OperandSpec::RegRRR; + }, + 0b011 => { + instruction.opcode = Opcode::VMSAVE; + instruction.operand_count = 1; + instruction.regs[0] = RegSpec::ax(); + instruction.operands[0] = OperandSpec::RegRRR; + }, + 0b100 => { + instruction.opcode = Opcode::STGI; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + }, + 0b101 => { + instruction.opcode = Opcode::CLGI; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + }, + 0b110 => { + instruction.opcode = Opcode::SKINIT; + instruction.operand_count = 1; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.regs[0] = RegSpec::eax(); + }, + 0b111 => { + instruction.opcode = Opcode::INVLPGA; + instruction.operand_count = 2; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::RegMMM; + instruction.regs[0] = RegSpec::ax(); + instruction.regs[1] = RegSpec::ecx(); + }, + _ => { + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + return Err(DecodeError::InvalidOperand); + } + } + } else { + instruction.opcode = Opcode::LIDT; + instruction.operand_count = 1; + instruction.mem_size = 63; + instruction.operands[0] = read_E(words, instruction, modrm, opwidth)?; + } + } else if r == 4 { + // TODO: this permits storing only to word-size registers + // spec suggets this might do something different for f.ex rdi? + instruction.opcode = Opcode::SMSW; + instruction.operand_count = 1; + instruction.mem_size = 2; + instruction.operands[0] = read_E(words, instruction, modrm, 2)?; + } else if r == 5 { + let mod_bits = modrm >> 6; + if mod_bits != 0b11 { + if !instruction.prefixes.rep() { + return Err(DecodeError::InvalidOpcode); + } + instruction.opcode = Opcode::RSTORSSP; + instruction.operands[0] = read_E(words, instruction, modrm, 4)?; + instruction.mem_size = 8; + instruction.operand_count = 1; + return Ok(()); + } + + let m = modrm & 7; + match m { + 0b000 => { + if instruction.prefixes.repnz() { + instruction.opcode = Opcode::XSUSLDTRK; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + return Ok(()); + } + if !instruction.prefixes.rep() || instruction.prefixes.repnz() { + return Err(DecodeError::InvalidOpcode); + } + instruction.opcode = Opcode::SETSSBSY; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + } + 0b001 => { + if instruction.prefixes.repnz() { + instruction.opcode = Opcode::XRESLDTRK; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + return Ok(()); + } else { + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + return Err(DecodeError::InvalidOpcode); + } + } + 0b010 => { + if !instruction.prefixes.rep() || instruction.prefixes.repnz() { + return Err(DecodeError::InvalidOpcode); + } + instruction.opcode = Opcode::SAVEPREVSSP; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + } + 0b100 => { + if instruction.prefixes.rep() { + instruction.opcode = Opcode::UIRET; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + } else { + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + return Err(DecodeError::InvalidOpcode); + } + } + 0b101 => { + if instruction.prefixes.rep() { + instruction.opcode = Opcode::TESTUI; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + } else { + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + return Err(DecodeError::InvalidOpcode); + } + } + 0b110 => { + if instruction.prefixes.rep() { + instruction.opcode = Opcode::CLUI; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + return Ok(()); + } else if instruction.prefixes.operand_size() || instruction.prefixes.repnz() { + return Err(DecodeError::InvalidOpcode); + } + instruction.opcode = Opcode::RDPKRU; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + } + 0b111 => { + if instruction.prefixes.rep() { + instruction.opcode = Opcode::STUI; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + return Ok(()); + } else if instruction.prefixes.operand_size() || instruction.prefixes.repnz() { + return Err(DecodeError::InvalidOpcode); + } + instruction.opcode = Opcode::WRPKRU; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + } + _ => { + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + return Err(DecodeError::InvalidOpcode); + } + } + } else if r == 6 { + instruction.opcode = Opcode::LMSW; + instruction.operand_count = 1; + instruction.mem_size = 2; + instruction.operands[0] = read_E(words, instruction, modrm, 2)?; + } else if r == 7 { + let mod_bits = modrm >> 6; + let m = modrm & 7; + if mod_bits == 0b11 { + if m == 0 { + // swapgs is not valid in modes other than 64-bit + return Err(DecodeError::InvalidOpcode); + } else if m == 1 { + instruction.opcode = Opcode::RDTSCP; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + } else if m == 2 { + instruction.opcode = Opcode::MONITORX; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + } else if m == 3 { + instruction.opcode = Opcode::MWAITX; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + } else if m == 4 { + instruction.opcode = Opcode::CLZERO; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + } else if m == 5 { + instruction.opcode = Opcode::RDPRU; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.regs[0] = RegSpec::ecx(); + instruction.operand_count = 1; + } else if m == 6 { + if instruction.prefixes.rep() { + if instruction.prefixes.repnz() || instruction.prefixes.operand_size() { + return Err(DecodeError::InvalidOperand); + } + instruction.opcode = Opcode::RMPADJUST; + instruction.operand_count = 0; + return Ok(()); + } else if instruction.prefixes.repnz() { + if instruction.prefixes.rep() || instruction.prefixes.operand_size() { + return Err(DecodeError::InvalidOperand); + } + instruction.opcode = Opcode::RMPUPDATE; + instruction.operand_count = 0; + return Ok(()); + } else if instruction.prefixes.operand_size() { + return Err(DecodeError::InvalidOperand); + } + + instruction.opcode = Opcode::INVLPGB; + instruction.operand_count = 3; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::RegMMM; + instruction.operands[2] = OperandSpec::RegVex; + instruction.regs[0] = RegSpec::eax(); + instruction.regs[1] = RegSpec::edx(); + instruction.regs[3] = RegSpec::ecx(); + } else if m == 7 { + if instruction.prefixes.rep() { + if instruction.prefixes.repnz() || instruction.prefixes.operand_size() { + return Err(DecodeError::InvalidOperand); + } + instruction.opcode = Opcode::PSMASH; + instruction.operand_count = 0; + return Ok(()); + } else if instruction.prefixes.repnz() { + if instruction.prefixes.rep() || instruction.prefixes.operand_size() { + return Err(DecodeError::InvalidOperand); + } + instruction.opcode = Opcode::PVALIDATE; + instruction.operand_count = 0; + return Ok(()); + } else if instruction.prefixes.operand_size() { + return Err(DecodeError::InvalidOperand); + } + + instruction.opcode = Opcode::TLBSYNC; + instruction.operand_count = 0; + } else { + return Err(DecodeError::InvalidOpcode); + } + } else { + instruction.opcode = Opcode::INVLPG; + instruction.operand_count = 1; + instruction.mem_size = 1; + instruction.operands[0] = read_E(words, instruction, modrm, opwidth)?; + } + } else { + unreachable!("r <= 8"); + } + } + OperandCode::ModRM_0x0fae => { + let modrm = read_modrm(words)?; + let r = (modrm >> 3) & 7; + let m = modrm & 7; + + if instruction.prefixes.operand_size() && !(instruction.prefixes.rep() || instruction.prefixes.repnz()) { + instruction.prefixes.unset_operand_size(); + if modrm < 0xc0 { + instruction.opcode = match (modrm >> 3) & 7 { + 6 => { + Opcode::CLWB + } + 7 => { + Opcode::CLFLUSHOPT + } + _ => { + return Err(DecodeError::InvalidOpcode); + } + }; + instruction.operands[0] = read_E(words, instruction, modrm, 1 /* opwidth */)?; + instruction.mem_size = 64; + instruction.operand_count = 1; + } else { + instruction.opcode = match (modrm >> 3) & 7 { + 6 => { + Opcode::TPAUSE + } + _ => { + return Err(DecodeError::InvalidOpcode); + } + }; + instruction.operands[0] = read_E(words, instruction, modrm, 4)?; + instruction.operand_count = 1; + } + + return Ok(()); + } + + if instruction.prefixes.repnz() { + if (modrm & 0xc0) == 0xc0 { + match r { + 6 => { + instruction.opcode = Opcode::UMWAIT; + instruction.regs[0] = RegSpec { + bank: RegisterBank::D, + num: m, + }; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operand_count = 1; + } + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + return Ok(()); + } + } + + if instruction.prefixes.rep() { + if r == 4 { + if instruction.prefixes.operand_size() { + // xed specifically rejects this. seeems out of line since rep takes + // precedence elsewhere, but ok i guess + return Err(DecodeError::InvalidOpcode); + } + instruction.opcode = Opcode::PTWRITE; + instruction.operands[0] = read_E(words, instruction, modrm, 4)?; + if instruction.operands[0] != OperandSpec::RegMMM { + instruction.mem_size = 4; + } + instruction.operand_count = 1; + return Ok(()); + } + if (modrm & 0xc0) == 0xc0 { + match r { + 0 => { + instruction.opcode = Opcode::RDFSBASE; + instruction.regs[1] = RegSpec::from_parts(m, RegisterBank::D); + instruction.operands[0] = OperandSpec::RegMMM; + instruction.operand_count = 1; + } + 1 => { + instruction.opcode = Opcode::RDGSBASE; + instruction.regs[1] = RegSpec::from_parts(m, RegisterBank::D); + instruction.operands[0] = OperandSpec::RegMMM; + instruction.operand_count = 1; + + } + 2 => { + instruction.opcode = Opcode::WRFSBASE; + instruction.regs[1] = RegSpec::from_parts(m, RegisterBank::D); + instruction.operands[0] = OperandSpec::RegMMM; + instruction.operand_count = 1; + } + 3 => { + instruction.opcode = Opcode::WRGSBASE; + instruction.regs[1] = RegSpec::from_parts(m, RegisterBank::D); + instruction.operands[0] = OperandSpec::RegMMM; + instruction.operand_count = 1; + } + 5 => { + instruction.opcode = Opcode::INCSSP; + instruction.regs[1] = RegSpec::from_parts(m, RegisterBank::D); + instruction.operands[0] = OperandSpec::RegMMM; + instruction.operand_count = 1; + } + 6 => { + instruction.opcode = Opcode::UMONITOR; + if !instruction.prefixes.address_size() { + instruction.regs[1] = RegSpec::from_parts(m, RegisterBank::W); + } else { + instruction.regs[1] = RegSpec::from_parts(m, RegisterBank::D); + }; + instruction.operands[0] = OperandSpec::RegMMM; + instruction.operand_count = 1; + } + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + return Ok(()); + } else { + match r { + 6 => { + instruction.opcode = Opcode::CLRSSBSY; + instruction.operands[0] = read_E(words, instruction, modrm, 4)?; + instruction.operand_count = 1; + instruction.mem_size = 8; + return Ok(()); + } + _ => { + return Err(DecodeError::InvalidOperand); + } + } + } + } + + let mod_bits = modrm >> 6; + + // all the 0b11 instructions are err or no-operands + if mod_bits == 0b11 { + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + match r { + // invalid rrr for 0x0fae, mod: 11 + 0 | 1 | 2 | 3 | 4 => { + return Err(DecodeError::InvalidOpcode); + }, + 5 => { + instruction.opcode = Opcode::LFENCE; + // Intel's manual accepts m != 0, AMD supports m != 0 though the manual + // doesn't say (tested on threadripper) + if !decoder.amd_quirks() && !decoder.intel_quirks() { + if m != 0 { + return Err(DecodeError::InvalidOperand); + } + } + }, + 6 => { + instruction.opcode = Opcode::MFENCE; + // Intel's manual accepts m != 0, AMD supports m != 0 though the manual + // doesn't say (tested on threadripper) + if !decoder.amd_quirks() && !decoder.intel_quirks() { + if m != 0 { + return Err(DecodeError::InvalidOperand); + } + } + }, + 7 => { + instruction.opcode = Opcode::SFENCE; + // Intel's manual accepts m != 0, AMD supports m != 0 though the manual + // doesn't say (tested on threadripper) + if !decoder.amd_quirks() && !decoder.intel_quirks() { + if m != 0 { + return Err(DecodeError::InvalidOperand); + } + } + }, + _ => { unsafe { unreachable_unchecked() } /* r <=7 */ } + } + } else { + // these can't be prefixed, so says `xed` i guess. + if instruction.prefixes.operand_size() || instruction.prefixes.rep() || instruction.prefixes.repnz() { + return Err(DecodeError::InvalidOperand); + } + instruction.operand_count = 1; + let (opcode, mem_size) = [ + (Opcode::FXSAVE, 63), + (Opcode::FXRSTOR, 63), + (Opcode::LDMXCSR, 4), + (Opcode::STMXCSR, 4), + (Opcode::XSAVE, 63), + (Opcode::XRSTOR, 63), + (Opcode::XSAVEOPT, 63), + (Opcode::CLFLUSH, 64), + ][r as usize]; + instruction.opcode = opcode; + instruction.mem_size = mem_size; + instruction.operands[0] = read_M(words, instruction, modrm)?; + } + }, + OperandCode::ModRM_0x0fba => { + let opwidth = if instruction.prefixes.operand_size() { + 4 + } else { + 2 + }; + let modrm = read_modrm(words)?; + let r = (modrm >> 3) & 7; + match r { + 0 | 1 | 2 | 3 => { + return Err(DecodeError::InvalidOpcode); + }, + 4 => { + instruction.opcode = Opcode::BT; + } + 5 => { + instruction.opcode = Opcode::BTS; + } + 6 => { + instruction.opcode = Opcode::BTR; + } + 7 => { + instruction.opcode = Opcode::BTC; + } + _ => { + unreachable!("r < 8"); + } + } + + instruction.operands[0] = read_E(words, instruction, modrm, opwidth)?; + if instruction.operands[0] != OperandSpec::RegMMM { + instruction.mem_size = opwidth; + } + + instruction.imm = read_imm_signed(words, 1)? as u32; + instruction.operands[1] = OperandSpec::ImmI8; + instruction.operand_count = 2; + } + op @ OperandCode::Rq_Cq_0 | + op @ OperandCode::Rq_Dq_0 | + op @ OperandCode::Cq_Rq_0 | + op @ OperandCode::Dq_Rq_0 => { + let modrm = read_modrm(words)?; + let m = modrm & 7; + let r = (modrm >> 3) & 7; + + let bank = match op { + OperandCode::Rq_Cq_0 | + OperandCode::Cq_Rq_0 => { + if r != 0 && r != 2 && r != 3 && r != 4 { + return Err(DecodeError::InvalidOperand); + } + RegisterBank::CR + }, + OperandCode::Rq_Dq_0 | + OperandCode::Dq_Rq_0 => { + if r > 7 { // unreachable but mirrors x86_64 code + return Err(DecodeError::InvalidOperand); + } + RegisterBank::DR + }, + _ => unsafe { unreachable_unchecked() } + }; + let (rrr, mmm) = match op { + OperandCode::Rq_Cq_0 | + OperandCode::Rq_Dq_0 => (1, 0), + OperandCode::Cq_Rq_0 | + OperandCode::Dq_Rq_0 => (0, 1), + _ => unsafe { unreachable_unchecked() } + }; + + instruction.regs[0] = + RegSpec { bank: bank, num: r }; + instruction.regs[1] = + RegSpec { bank: RegisterBank::D, num: m }; + instruction.operands[mmm] = OperandSpec::RegMMM; + instruction.operands[rrr] = OperandSpec::RegRRR; + instruction.operand_count = 2; + } + OperandCode::FS => { + instruction.regs[0] = RegSpec::fs(); + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operand_count = 1; + } + OperandCode::GS => { + instruction.regs[0] = RegSpec::gs(); + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operand_count = 1; + } + OperandCode::CS => { + instruction.regs[0] = RegSpec::cs(); + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operand_count = 1; + } + OperandCode::DS => { + instruction.regs[0] = RegSpec::ds(); + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operand_count = 1; + } + OperandCode::ES => { + instruction.regs[0] = RegSpec::es(); + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operand_count = 1; + } + OperandCode::SS => { + instruction.regs[0] = RegSpec::ss(); + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operand_count = 1; + } + OperandCode::AL_Ib => { + instruction.regs[0] = + RegSpec::al(); + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::ImmU8; + instruction.operand_count = 2; + } + OperandCode::AX_Ib => { + instruction.regs[0] = if !instruction.prefixes.operand_size() { + RegSpec::ax() + } else { + RegSpec::eax() + }; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::ImmU8; + instruction.operand_count = 2; + } + OperandCode::Ib_AL => { + instruction.regs[0] = + RegSpec::al(); + instruction.operands[0] = OperandSpec::ImmU8; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.operand_count = 2; + } + OperandCode::Ib_AX => { + instruction.regs[0] = if !instruction.prefixes.operand_size() { + RegSpec::ax() + } else { + RegSpec::eax() + }; + instruction.operands[0] = OperandSpec::ImmU8; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.operand_count = 2; + } + OperandCode::AX_DX => { + instruction.regs[0] = if !instruction.prefixes.operand_size() { + RegSpec::ax() + } else { + RegSpec::eax() + }; + instruction.regs[1] = RegSpec::dx(); + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::RegMMM; + instruction.operand_count = 2; + } + OperandCode::AL_DX => { + instruction.regs[0] = RegSpec::al(); + instruction.regs[1] = RegSpec::dx(); + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::RegMMM; + instruction.operand_count = 2; + } + OperandCode::DX_AX => { + instruction.regs[0] = if !instruction.prefixes.operand_size() { + RegSpec::ax() + } else { + RegSpec::eax() + }; + instruction.regs[1] = RegSpec::dx(); + instruction.operands[0] = OperandSpec::RegMMM; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.operand_count = 2; + } + OperandCode::DX_AL => { + instruction.regs[0] = RegSpec::al(); + instruction.regs[1] = RegSpec::dx(); + instruction.operands[0] = OperandSpec::RegMMM; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.operand_count = 2; + } + OperandCode::Yb_DX => { + instruction.regs[0] = RegSpec::dl(); + instruction.regs[1] = RegSpec::edi(); + instruction.operands[0] = OperandSpec::Deref; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.operand_count = 2; + instruction.mem_size = 1; + } + OperandCode::Yv_DX => { + instruction.regs[0] = RegSpec::dx(); + instruction.regs[1] = RegSpec::edi(); + instruction.operands[0] = OperandSpec::Deref; + instruction.operands[1] = OperandSpec::RegRRR; + if instruction.prefixes.operand_size() { + instruction.mem_size = 4; + } else { + instruction.mem_size = 2; + } + instruction.operand_count = 2; + } + OperandCode::DX_Xb => { + instruction.regs[0] = RegSpec::dl(); + instruction.regs[1] = RegSpec::esi(); + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::Deref; + instruction.operand_count = 2; + instruction.mem_size = 1; + } + OperandCode::AH => { + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + } + OperandCode::DX_Xv => { + instruction.regs[0] = RegSpec::dx(); + instruction.regs[1] = RegSpec::esi(); + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::Deref; + if instruction.prefixes.operand_size() { + instruction.mem_size = 4; + } else { + instruction.mem_size = 2; + } + instruction.operand_count = 2; + } + OperandCode::x87_d8 | + OperandCode::x87_d9 | + OperandCode::x87_da | + OperandCode::x87_db | + OperandCode::x87_dc | + OperandCode::x87_dd | + OperandCode::x87_de | + OperandCode::x87_df => { + return decode_x87(words, instruction, operand_code); + } + OperandCode::M_Gv => { + // `lea` operands (`Gv_M`) opportunistically reject a register form of `mmm` early, but + // leaves `M_Gv` to test memory-ness of the `mmm` operand directly. also, swap + // operands. + if let OperandSpec::RegMMM = instruction.operands[1] { + return Err(DecodeError::InvalidOperand); + } + let temp = instruction.operands[1]; + instruction.operands[1] = instruction.operands[0]; + instruction.operands[0] = temp; + } + OperandCode::ModRM_0x62 => { + let modrm = read_modrm(words)?; + + if modrm < 0xc0 { + instruction.regs[0] = + RegSpec { bank: RegisterBank::D, num: (modrm >> 3) & 7 }; + if instruction.prefixes.operand_size() { + instruction.regs[0].bank = RegisterBank::W; + instruction.mem_size = 4; + } else { + instruction.mem_size = 8; + } + + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = read_M(words, instruction, modrm)?; + instruction.operand_count = 2; + } else { + let prefixes = &instruction.prefixes; + if prefixes.lock() || prefixes.operand_size() || prefixes.rep_any() { + return Err(DecodeError::InvalidPrefixes); + } else { + evex::read_evex(words, instruction, Some(modrm))?; + } + } + } + _ => { + // TODO: this should be unreachable - safe to panic now? + // can't simply delete this arm because the non-unlikely operands are handled outside + // here, and some operands are entirely decoded before reaching match in the first + // place. + // perhaps fully-decoded operands could be a return here? they would be jump table + // entries anyway, so no extra space for the dead arms. + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + return Err(DecodeError::InvalidOperand); + } + }; + Ok(()) +} + +fn decode_x87::Address, ::Word>>(words: &mut T, instruction: &mut Instruction, operand_code: OperandCode) -> Result<(), DecodeError> { + #[allow(non_camel_case_types)] + enum OperandCodeX87 { + Est, + St_Est, + St_Edst, + St_Eqst, + St_Ew, + St_Mw, + St_Md, + St_Mq, + St_Mm, + Ew, + Est_St, + Edst_St, + Eqst_St, + Ed_St, + Mw_St, + Md_St, + Mq_St, + Mm_St, + Ex87S, + Nothing, + } + + // every x87 instruction is conditional on rrr bits + let modrm = read_modrm(words)?; + let r = (modrm >> 3) & 0b111; + + let (opcode, x87_operands) = match operand_code { + OperandCode::x87_d8 => { + match r { + 0 => (Opcode::FADD, OperandCodeX87::St_Edst), + 1 => (Opcode::FMUL, OperandCodeX87::St_Edst), + 2 => (Opcode::FCOM, OperandCodeX87::St_Edst), + 3 => (Opcode::FCOMP, OperandCodeX87::St_Edst), + 4 => (Opcode::FSUB, OperandCodeX87::St_Edst), + 5 => (Opcode::FSUBR, OperandCodeX87::St_Edst), + 6 => (Opcode::FDIV, OperandCodeX87::St_Edst), + 7 => (Opcode::FDIVR, OperandCodeX87::St_Edst), + _ => { unreachable!("impossible r"); } + } + } + OperandCode::x87_d9 => { + match r { + 0 => (Opcode::FLD, OperandCodeX87::St_Edst), + 1 => { + if modrm >= 0xc0 { + (Opcode::FXCH, OperandCodeX87::St_Est) + } else { + return Err(DecodeError::InvalidOpcode); + } + }, + 2 => { + if modrm >= 0xc0 { + if modrm == 0xd0 { + (Opcode::FNOP, OperandCodeX87::Nothing) + } else { + return Err(DecodeError::InvalidOpcode); + } + } else { + (Opcode::FST, OperandCodeX87::Ed_St) + } + } + 3 => { + if modrm >= 0xc0 { + (Opcode::FSTPNCE, OperandCodeX87::Est_St) + } else { + (Opcode::FSTP, OperandCodeX87::Edst_St) + } + }, + 4 => { + if modrm >= 0xc0 { + match modrm { + 0xe0 => (Opcode::FCHS, OperandCodeX87::Nothing), + 0xe1 => (Opcode::FABS, OperandCodeX87::Nothing), + 0xe2 => { return Err(DecodeError::InvalidOpcode); }, + 0xe3 => { return Err(DecodeError::InvalidOpcode); }, + 0xe4 => (Opcode::FTST, OperandCodeX87::Nothing), + 0xe5 => (Opcode::FXAM, OperandCodeX87::Nothing), + 0xe6 => { return Err(DecodeError::InvalidOpcode); }, + 0xe7 => { return Err(DecodeError::InvalidOpcode); }, + _ => { unreachable!("invalid modrm"); } + } + } else { + (Opcode::FLDENV, OperandCodeX87::Ex87S) // x87 state + } + }, + 5 => { + if modrm >= 0xc0 { + match modrm { + 0xe8 => (Opcode::FLD1, OperandCodeX87::Nothing), + 0xe9 => (Opcode::FLDL2T, OperandCodeX87::Nothing), + 0xea => (Opcode::FLDL2E, OperandCodeX87::Nothing), + 0xeb => (Opcode::FLDPI, OperandCodeX87::Nothing), + 0xec => (Opcode::FLDLG2, OperandCodeX87::Nothing), + 0xed => (Opcode::FLDLN2, OperandCodeX87::Nothing), + 0xee => (Opcode::FLDZ, OperandCodeX87::Nothing), + 0xef => (Opcode::Invalid, OperandCodeX87::Nothing), + _ => { unreachable!("invalid modrm"); } + } + } else { + (Opcode::FLDCW, OperandCodeX87::Ew) + } + } + 6 => { + if modrm >= 0xc0 { + match modrm { + 0xf0 => (Opcode::F2XM1, OperandCodeX87::Nothing), + 0xf1 => (Opcode::FYL2X, OperandCodeX87::Nothing), + 0xf2 => (Opcode::FPTAN, OperandCodeX87::Nothing), + 0xf3 => (Opcode::FPATAN, OperandCodeX87::Nothing), + 0xf4 => (Opcode::FXTRACT, OperandCodeX87::Nothing), + 0xf5 => (Opcode::FPREM1, OperandCodeX87::Nothing), + 0xf6 => (Opcode::FDECSTP, OperandCodeX87::Nothing), + 0xf7 => (Opcode::FINCSTP, OperandCodeX87::Nothing), + _ => { unreachable!("invalid modrm"); } + } + } else { + (Opcode::FNSTENV, OperandCodeX87::Ex87S) // x87 state + } + } + 7 => { + if modrm >= 0xc0 { + match modrm { + 0xf8 => (Opcode::FPREM, OperandCodeX87::Nothing), + 0xf9 => (Opcode::FYL2XP1, OperandCodeX87::Nothing), + 0xfa => (Opcode::FSQRT, OperandCodeX87::Nothing), + 0xfb => (Opcode::FSINCOS, OperandCodeX87::Nothing), + 0xfc => (Opcode::FRNDINT, OperandCodeX87::Nothing), + 0xfd => (Opcode::FSCALE, OperandCodeX87::Nothing), + 0xfe => (Opcode::FSIN, OperandCodeX87::Nothing), + 0xff => (Opcode::FCOS, OperandCodeX87::Nothing), + _ => { unreachable!("invalid modrm"); } + } + } else { + (Opcode::FNSTCW, OperandCodeX87::Ew) + } + } + _ => { unreachable!("impossible r"); } + } + } + OperandCode::x87_da => { + if modrm >= 0xc0 { + match r { + 0 => (Opcode::FCMOVB, OperandCodeX87::St_Est), + 1 => (Opcode::FCMOVE, OperandCodeX87::St_Est), + 2 => (Opcode::FCMOVBE, OperandCodeX87::St_Est), + 3 => (Opcode::FCMOVU, OperandCodeX87::St_Est), + _ => { + if modrm == 0xe9 { + (Opcode::FUCOMPP, OperandCodeX87::Nothing) + } else { + return Err(DecodeError::InvalidOpcode); + } + } + } + } else { + match r { + 0 => (Opcode::FIADD, OperandCodeX87::St_Md), // 0xd9d0 -> fnop + 1 => (Opcode::FIMUL, OperandCodeX87::St_Md), + 2 => (Opcode::FICOM, OperandCodeX87::St_Md), // FCMOVE + 3 => (Opcode::FICOMP, OperandCodeX87::St_Md), // FCMOVBE + 4 => (Opcode::FISUB, OperandCodeX87::St_Md), + 5 => (Opcode::FISUBR, OperandCodeX87::St_Md), // FUCOMPP + 6 => (Opcode::FIDIV, OperandCodeX87::St_Md), + 7 => (Opcode::FIDIVR, OperandCodeX87::St_Md), + _ => { unreachable!("impossible r"); } + } + } + } + OperandCode::x87_db => { + if modrm >= 0xc0 { + match r { + 0 => (Opcode::FCMOVNB, OperandCodeX87::St_Est), + 1 => (Opcode::FCMOVNE, OperandCodeX87::St_Est), + 2 => (Opcode::FCMOVNBE, OperandCodeX87::St_Est), + 3 => (Opcode::FCMOVNU, OperandCodeX87::St_Est), + 4 => { + match modrm { + 0xe0 => (Opcode::FENI8087_NOP, OperandCodeX87::Nothing), + 0xe1 => (Opcode::FDISI8087_NOP, OperandCodeX87::Nothing), + 0xe2 => (Opcode::FNCLEX, OperandCodeX87::Nothing), + 0xe3 => (Opcode::FNINIT, OperandCodeX87::Nothing), + 0xe4 => (Opcode::FSETPM287_NOP, OperandCodeX87::Nothing), + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + } + 5 => (Opcode::FUCOMI, OperandCodeX87::St_Est), + 6 => (Opcode::FCOMI, OperandCodeX87::St_Est), + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + } else { + match r { + 0 => (Opcode::FILD, OperandCodeX87::St_Md), + 1 => (Opcode::FISTTP, OperandCodeX87::Md_St), + 2 => (Opcode::FIST, OperandCodeX87::Md_St), + 3 => (Opcode::FISTP, OperandCodeX87::Md_St), + 5 => (Opcode::FLD, OperandCodeX87::St_Mm), // 80bit + 7 => (Opcode::FSTP, OperandCodeX87::Mm_St), // 80bit + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + } + + } + OperandCode::x87_dc => { + // mod=11 swaps operand order for some instructions + if modrm >= 0xc0 { + match r { + 0 => (Opcode::FADD, OperandCodeX87::Eqst_St), + 1 => (Opcode::FMUL, OperandCodeX87::Eqst_St), + 2 => (Opcode::FCOM, OperandCodeX87::St_Eqst), + 3 => (Opcode::FCOMP, OperandCodeX87::St_Eqst), + 4 => (Opcode::FSUBR, OperandCodeX87::Eqst_St), + 5 => (Opcode::FSUB, OperandCodeX87::Eqst_St), + 6 => (Opcode::FDIVR, OperandCodeX87::Eqst_St), + 7 => (Opcode::FDIV, OperandCodeX87::Eqst_St), + _ => { unreachable!("impossible r"); } + } + } else { + match r { + 0 => (Opcode::FADD, OperandCodeX87::St_Eqst), + 1 => (Opcode::FMUL, OperandCodeX87::St_Eqst), + 2 => (Opcode::FCOM, OperandCodeX87::St_Eqst), + 3 => (Opcode::FCOMP, OperandCodeX87::St_Eqst), + 4 => (Opcode::FSUB, OperandCodeX87::St_Eqst), + 5 => (Opcode::FSUBR, OperandCodeX87::St_Eqst), + 6 => (Opcode::FDIV, OperandCodeX87::St_Eqst), + 7 => (Opcode::FDIVR, OperandCodeX87::St_Eqst), + _ => { unreachable!("impossible r"); } + } + } + } + OperandCode::x87_dd => { + if modrm >= 0xc0 { + match r { + 0 => (Opcode::FFREE, OperandCodeX87::Est), + 1 => (Opcode::FXCH, OperandCodeX87::St_Est), + 2 => (Opcode::FST, OperandCodeX87::Est_St), + 3 => (Opcode::FSTP, OperandCodeX87::Est_St), + 4 => (Opcode::FUCOM, OperandCodeX87::St_Est), + 5 => (Opcode::FUCOMP, OperandCodeX87::St_Est), + 6 => (Opcode::Invalid, OperandCodeX87::Nothing), + 7 => (Opcode::Invalid, OperandCodeX87::Nothing), + _ => { unreachable!("impossible r"); } + } + } else { + match r { + 0 => (Opcode::FLD, OperandCodeX87::St_Eqst), + 1 => (Opcode::FISTTP, OperandCodeX87::Eqst_St), + 2 => (Opcode::FST, OperandCodeX87::Eqst_St), + 3 => (Opcode::FSTP, OperandCodeX87::Eqst_St), + 4 => (Opcode::FRSTOR, OperandCodeX87::Ex87S), + 5 => (Opcode::Invalid, OperandCodeX87::Nothing), + 6 => (Opcode::FNSAVE, OperandCodeX87::Ex87S), + 7 => (Opcode::FNSTSW, OperandCodeX87::Ew), + _ => { unreachable!("impossible r"); } + } + } + } + OperandCode::x87_de => { + if modrm >= 0xc0 { + match r { + 0 => (Opcode::FADDP, OperandCodeX87::Est_St), + 1 => (Opcode::FMULP, OperandCodeX87::Est_St), + // undocumented in intel manual, argument order inferred from + // by xed and capstone. TODO: check amd manual. + 2 => (Opcode::FCOMP, OperandCodeX87::St_Est), + 3 => { + if modrm == 0xd9 { + (Opcode::FCOMPP, OperandCodeX87::Nothing) + } else { + return Err(DecodeError::InvalidOperand); + } + }, + 4 => (Opcode::FSUBRP, OperandCodeX87::Est_St), + 5 => (Opcode::FSUBP, OperandCodeX87::Est_St), + 6 => (Opcode::FDIVRP, OperandCodeX87::Est_St), + 7 => (Opcode::FDIVP, OperandCodeX87::Est_St), + _ => { unreachable!("impossible r"); } + } + } else { + match r { + 0 => (Opcode::FIADD, OperandCodeX87::St_Ew), + 1 => (Opcode::FIMUL, OperandCodeX87::St_Ew), + 2 => (Opcode::FICOM, OperandCodeX87::St_Ew), + 3 => (Opcode::FICOMP, OperandCodeX87::St_Ew), + 4 => (Opcode::FISUB, OperandCodeX87::St_Ew), + 5 => (Opcode::FISUBR, OperandCodeX87::St_Ew), + 6 => (Opcode::FIDIV, OperandCodeX87::St_Ew), + 7 => (Opcode::FIDIVR, OperandCodeX87::St_Ew), + _ => { unreachable!("impossible r"); } + } + } + } + OperandCode::x87_df => { + if modrm >= 0xc0 { + match r { + 0 => (Opcode::FFREEP, OperandCodeX87::Est), + 1 => (Opcode::FXCH, OperandCodeX87::St_Est), + 2 => (Opcode::FSTP, OperandCodeX87::Est_St), + 3 => (Opcode::FSTP, OperandCodeX87::Est_St), + 4 => { + if modrm == 0xe0 { + (Opcode::FNSTSW, OperandCodeX87::Ew) + } else { + return Err(DecodeError::InvalidOpcode); + } + }, + 5 => (Opcode::FUCOMIP, OperandCodeX87::St_Est), + 6 => (Opcode::FCOMIP, OperandCodeX87::St_Est), + 7 => { + return Err(DecodeError::InvalidOpcode); + }, + _ => { unreachable!("impossible r"); } + } + } else { + match r { + 0 => (Opcode::FILD, OperandCodeX87::St_Mw), + 1 => (Opcode::FISTTP, OperandCodeX87::Mw_St), + 2 => (Opcode::FIST, OperandCodeX87::Mw_St), + 3 => (Opcode::FISTP, OperandCodeX87::Mw_St), + 4 => (Opcode::FBLD, OperandCodeX87::St_Mm), + 5 => (Opcode::FILD, OperandCodeX87::St_Mq), + 6 => (Opcode::FBSTP, OperandCodeX87::Mm_St), + 7 => (Opcode::FISTP, OperandCodeX87::Mq_St), + _ => { unreachable!("impossible r"); } + } + } + } + other => { + panic!("invalid x87 operand dispatch, operand code is {:?}", other); + } + }; + instruction.opcode = opcode; + if instruction.opcode == Opcode::Invalid { + return Err(DecodeError::InvalidOpcode); + } + + match x87_operands { + OperandCodeX87::Est => { + instruction.operands[0] = read_E_st(words, instruction, modrm)?; + instruction.operand_count = 1; + } + OperandCodeX87::St_Est => { + instruction.operands[0] = OperandSpec::RegRRR; + instruction.regs[0] = RegSpec::st(0); + instruction.operands[1] = read_E_st(words, instruction, modrm)?; + instruction.operand_count = 2; + } + OperandCodeX87::St_Edst => { + instruction.operands[0] = OperandSpec::RegRRR; + instruction.regs[0] = RegSpec::st(0); + instruction.operands[1] = read_E_st(words, instruction, modrm)?; + if instruction.operands[1] != OperandSpec::RegMMM { + instruction.mem_size = 4; + } + instruction.operand_count = 2; + } + OperandCodeX87::St_Eqst => { + instruction.operands[0] = OperandSpec::RegRRR; + instruction.regs[0] = RegSpec::st(0); + instruction.operands[1] = read_E_st(words, instruction, modrm)?; + if instruction.operands[1] != OperandSpec::RegMMM { + instruction.mem_size = 8; + } + instruction.operand_count = 2; + } + OperandCodeX87::St_Ew => { + instruction.operands[0] = OperandSpec::RegRRR; + instruction.regs[0] = RegSpec::st(0); + instruction.operands[1] = read_E(words, instruction, modrm, 2)?; + if instruction.operands[1] != OperandSpec::RegMMM { + instruction.mem_size = 2; + } + instruction.operand_count = 2; + } + OperandCodeX87::St_Mm => { + instruction.operands[0] = OperandSpec::RegRRR; + instruction.regs[0] = RegSpec::st(0); + instruction.operands[1] = read_E(words, instruction, modrm, 4)?; + if instruction.operands[1] == OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.mem_size = 10; + instruction.operand_count = 2; + } + OperandCodeX87::St_Mq => { + instruction.operands[0] = OperandSpec::RegRRR; + instruction.regs[0] = RegSpec::st(0); + instruction.operands[1] = read_E(words, instruction, modrm, 4)?; + if instruction.operands[1] == OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.mem_size = 8; + instruction.operand_count = 2; + } + OperandCodeX87::St_Md => { + instruction.operands[0] = OperandSpec::RegRRR; + instruction.regs[0] = RegSpec::st(0); + instruction.operands[1] = read_E(words, instruction, modrm, 4)?; + if instruction.operands[1] == OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.mem_size = 4; + instruction.operand_count = 2; + } + OperandCodeX87::St_Mw => { + instruction.operands[0] = OperandSpec::RegRRR; + instruction.regs[0] = RegSpec::st(0); + instruction.operands[1] = read_E(words, instruction, modrm, 4)?; + if instruction.operands[1] == OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.mem_size = 2; + instruction.operand_count = 2; + } + OperandCodeX87::Ew => { + instruction.operands[0] = read_E(words, instruction, modrm, 2)?; + instruction.operand_count = 1; + if instruction.operands[0] != OperandSpec::RegMMM { + instruction.mem_size = 2; + } + } + OperandCodeX87::Est_St => { + instruction.operands[0] = read_E_st(words, instruction, modrm)?; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.regs[0] = RegSpec::st(0); + instruction.operand_count = 2; + } + OperandCodeX87::Edst_St => { + instruction.operands[0] = read_E_st(words, instruction, modrm)?; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.regs[0] = RegSpec::st(0); + instruction.operand_count = 2; + if instruction.operands[0] != OperandSpec::RegMMM { + instruction.mem_size = 4; + } + } + OperandCodeX87::Eqst_St => { + instruction.operands[0] = read_E_st(words, instruction, modrm)?; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.regs[0] = RegSpec::st(0); + instruction.operand_count = 2; + if instruction.operands[0] != OperandSpec::RegMMM { + instruction.mem_size = 8; + } + } + OperandCodeX87::Ed_St => { + instruction.operands[0] = read_E_st(words, instruction, modrm)?; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.regs[0] = RegSpec::st(0); + if instruction.operands[0] != OperandSpec::RegMMM { + instruction.mem_size = 4; + } + instruction.operand_count = 2; + } + OperandCodeX87::Mm_St => { + instruction.operands[0] = read_E(words, instruction, modrm, 4)?; + if instruction.operands[0] == OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.mem_size = 10; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.regs[0] = RegSpec::st(0); + instruction.operand_count = 2; + } + OperandCodeX87::Mq_St => { + instruction.operands[0] = read_E(words, instruction, modrm, 4)?; + if instruction.operands[0] == OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.mem_size = 8; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.regs[0] = RegSpec::st(0); + instruction.operand_count = 2; + } + OperandCodeX87::Md_St => { + instruction.operands[0] = read_E(words, instruction, modrm, 4)?; + if instruction.operands[0] == OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.mem_size = 4; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.regs[0] = RegSpec::st(0); + instruction.operand_count = 2; + } + OperandCodeX87::Mw_St => { + instruction.operands[0] = read_E(words, instruction, modrm, 4)?; + if instruction.operands[0] == OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.mem_size = 2; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.regs[0] = RegSpec::st(0); + instruction.operand_count = 2; + } + OperandCodeX87::Ex87S => { + instruction.operands[0] = read_E(words, instruction, modrm, 4)?; + instruction.operand_count = 1; + if instruction.operands[0] == OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.mem_size = 63; + } + OperandCodeX87::Nothing => { + instruction.operand_count = 0; + }, + } + + Ok(()) +} + +#[inline] +fn read_num::Address, ::Word>>(bytes: &mut T, width: u8) -> Result { + match width { + 1 => { bytes.next().ok().ok_or(DecodeError::ExhaustedInput).map(|x| x as u32) } + 2 => { + let mut buf = [0u8; 2]; + bytes.next_n(&mut buf).ok().ok_or(DecodeError::ExhaustedInput)?; + Ok(u16::from_le_bytes(buf) as u32) + } + 4 => { + let mut buf = [0u8; 4]; + bytes.next_n(&mut buf).ok().ok_or(DecodeError::ExhaustedInput)?; + Ok(u32::from_le_bytes(buf) as u32) + } + _ => { + unsafe { unreachable_unchecked(); } + } + } +} + +#[inline] +fn read_imm_signed::Address, ::Word>>(bytes: &mut T, num_width: u8) -> Result { + if num_width == 1 { + Ok(read_num(bytes, 1)? as i8 as i32) + } else if num_width == 2 { + Ok(read_num(bytes, 2)? as i16 as i32) + } else { + Ok(read_num(bytes, 4)? as i32) + } +} + +#[inline] +fn read_imm_unsigned::Address, ::Word>>(bytes: &mut T, width: u8) -> Result { + read_num(bytes, width) +} + +#[inline] +fn read_modrm::Address, ::Word>>(words: &mut T) -> Result { + words.next().ok().ok_or(DecodeError::ExhaustedInput) +} diff --git a/src/real_mode/uarch.rs b/src/real_mode/uarch.rs new file mode 100644 index 0000000..0aeaa34 --- /dev/null +++ b/src/real_mode/uarch.rs @@ -0,0 +1,226 @@ +pub mod amd { + //! most information about instruction set extensions for microarchitectures here was sourced + //! from + //! [https://en.wikipedia.org/wiki/AMD_Accelerated_Processing_Unit#Feature_overview](https://docs.rs/yaxpeax-x86/0.0.12/yaxpeax_x86/real_mode/uarch/intel/index.html) + //! and + //! [https://en.wikipedia.org/wiki/Template:AMD_x86_CPU_features](https://docs.rs/yaxpeax-x86/0.0.12/yaxpeax_x86/real_mode/uarch/intel/index.html). + //! these mappings are best-effort but fairly unused, so a critical eye should be kept towards + //! these decoders rejecting instructions they should not, or incorrectly accepting + //! instructions. + //! + //! microarchitectures as defined here are with respect to flags reported by CPUID. notably, + //! `Zen` does not report `FMA4` support by `CPUID`, but instructions in that extension + //! reportedly function correctly (agner p217). + //! + //! [agner](https://www.agner.org/optimize/microarchitecture.pdf) + //! as retrieved 2020 may 19, + //! `sha256: 87ff152ae18c017dcbfb9f7ee6e88a9f971f6250fd15a70a3dd87c3546323bd5` + + use long_mode::InstDecoder; + + /// `k8` was the first AMD microarchitecture to implement x86_64, launched in 2003. while later + /// `k8`-based processors supported SSE3, these predefined decoders pick the lower end of + /// support - SSE2 and no later. + pub fn k8() -> InstDecoder { + InstDecoder::minimal() + } + + /// `k10` was the successor to `k8`, launched in 2007. `k10` cores extended SSE support through + /// to SSE4.2a, as well as consistent `cmov` support, among other features. + pub fn k10() -> InstDecoder { + k8() + .with_cmov() + .with_cmpxchg16b() + .with_svm() + .with_abm() + .with_lahfsahf() + .with_sse3() + .with_ssse3() + .with_sse4() + .with_sse4_2() + .with_sse4a() + } + + /// `Bulldozer` was the successor to `K10`, launched in 2011. `Bulldozer` cores include AVX + /// support among other extensions, and are notable for including `AESNI`. + pub fn bulldozer() -> InstDecoder { + k10() + .with_bmi1() + .with_aesni() + .with_pclmulqdq() + .with_f16c() + .with_avx() + .with_fma4() + .with_xop() + } + + /// `Piledriver` was the successor to `Bulldozer`, launched in 2012. + pub fn piledriver() -> InstDecoder { + bulldozer() + .with_tbm() + .with_fma3() + .with_fma4() + } + + /// `Steamroller` was the successor to `Piledriver`, launched in 2014. unlike `Piledriver` + /// cores, these cores do not support `TBM` or `FMA3`. + pub fn steamroller() -> InstDecoder { + bulldozer() + } + + /// `Excavator` was the successor to `Steamroller`, launched in 2015. + pub fn excavator() -> InstDecoder { + steamroller() + .with_movbe() + .with_bmi2() + .with_rdrand() + .with_avx() + .with_xop() + .with_bmi2() + .with_sha() + .with_rdrand() + .with_avx2() + } + + /// `Zen` was the successor to `Excavator`, launched in 2017. `Zen` cores extend SIMD + /// instructions to AVX2 and discarded FMA4, TBM, and XOP extensions. they also gained ADX, + /// SHA, RDSEED, and other extensions. + pub fn zen() -> InstDecoder { + k10() + .with_avx() + .with_avx2() + .with_bmi1() + .with_aesni() + .with_pclmulqdq() + .with_f16c() + .with_movbe() + .with_bmi2() + .with_rdrand() + .with_adx() + .with_sha() + .with_rdseed() + .with_fma3() + // TODO: XSAVEC, XSAVES, XRSTORS, CLFLUSHOPT, CLZERO? + } +} + +pub mod intel { + //! sourced by walking wikipedia pages. seriously! this stuff is kinda hard to figure out! + + use long_mode::InstDecoder; + + /// `Netburst` was the first Intel microarchitecture to implement x86_64, beginning with the + /// `Prescott` family launched in 2004. while the wider `Netburst` family launched in 2000 + /// with only SSE2, the first `x86_64`-supporting incarnation was `Prescott` which indeed + /// included SSE3. + pub fn netburst() -> InstDecoder { + InstDecoder::minimal() + .with_cmov() + .with_sse3() + } + + /// `Core` was the successor to `Netburst`, launched in 2006. it included up to SSE4, with + /// processors using this architecture shipped under the names "Merom", "Conroe", and + /// "Woodcrest", for mobile, desktop, and server processors respectively. not to be confused + /// with the later `Nehalem` microarchitecture that introduced the `Core i*` product lines, + /// `Core 2 *` processors used the `Core` architecture. + pub fn core() -> InstDecoder { + netburst() + .with_ssse3() + .with_sse4() + } + + /// `Penryn` was the successor to `Core`, launched in early 2008. it added SSE4.1, along with + /// virtualization extensions. + pub fn penryn() -> InstDecoder { + core() + .with_sse4_1() + } + + /// `Nehalem` was the successor to `Penryn`, launched in late 2008. not to be confused with the + /// earlier `Core` microarchitecture, the `Core i*` products were based on `Nehalem` cores. + /// `Nehalem` added SSE4.2 extensions, along with the `POPCNT` instruction. + pub fn nehalem() -> InstDecoder { + penryn() + .with_sse4_2() + .with_popcnt() + } + + /// `Westmere` was the successor to `Nehalem`, launched in 2010. it added AES-NI and CLMUL + /// extensions. + pub fn westmere() -> InstDecoder { + nehalem() + .with_aesni() + .with_pclmulqdq() + } + + /// `Sandy Bridge` was the successor to `Westmere`, launched in 2011. it added AVX + /// instructions. + pub fn sandybridge() -> InstDecoder { + westmere() + .with_avx() + } + + /// `Ivy Bridge` was the successor to `Sandy Bridge`, launched in 2012. it added F16C + /// extensions for 16-bit floating point conversion, and the RDRAND instruction. + pub fn ivybridge() -> InstDecoder { + sandybridge() + .with_f16c() + .with_rdrand() + } + + /// `Haswell` was the successor to `Ivy Bridge`, launched in 2013. it added several instruction + /// set extensions: AVX2, BMI1, BMI2, ABM, and FMA3. + pub fn haswell() -> InstDecoder { + ivybridge() + .with_bmi1() + .with_bmi2() + .with_abm() + .with_fma3() + .with_avx2() + } + + /// `Haswell-EX` was a variant of `Haswell` launched in 2015 with functional TSX. these cores + /// were shipped as `E7-48xx/E7-88xx v3` models of processors. + pub fn haswell_ex() -> InstDecoder { + haswell() + .with_tsx() + } + + /// `Broadwell` was the successor to `Haswell`, launched in late 2014. it added ADX, RDSEED, + /// and PREFETCHW, as well as broadly rolling out TSX. TSX is enabled on this decoder because + /// some chips of this microarchitecture rolled out with TSX, and lack of TSX seems to be + /// reported as an errata (for example, the `Broadwell-Y` line of parts). + pub fn broadwell() -> InstDecoder { + haswell_ex() + .with_adx() + .with_rdseed() + .with_prefetchw() + } + + /// `Skylake` was the successor to `Broadwell`, launched in mid 2015. it added MPX and SGX + /// extensions, as well as a mixed rollout of AVX512 in different subsets for different product + /// lines. + /// + /// AVX512 is not enabled on this decoder by default because there doesn't seem to be a lowest + /// common denominator: if you want a `Skylake` decoder with AVX512, something like the + /// following: + /// ``` + /// yaxpeax_x86::real_mode::uarch::intel::skylake() + /// .with_avx512_f() + /// .with_avx512_dq(); + /// ``` + /// is likely your best option. + pub fn skylake() -> InstDecoder { + broadwell() + .with_mpx() + .with_sgx() + } + + /// `Kaby Lake` was the successor to `Sky Lake`, launched in 2016. it adds no extensions to + /// x86_64 implementaiton beyond `skylake`. + pub fn kabylake() -> InstDecoder { + skylake() + } + // ice lake is shipping so that should probably be included... +} diff --git a/src/real_mode/vex.rs b/src/real_mode/vex.rs new file mode 100644 index 0000000..8e69032 --- /dev/null +++ b/src/real_mode/vex.rs @@ -0,0 +1,3356 @@ +use yaxpeax_arch::Reader; + +use crate::real_mode::Arch; +use crate::real_mode::OperandSpec; +use crate::real_mode::DecodeError; +use crate::real_mode::RegSpec; +use crate::real_mode::RegisterBank; +use crate::real_mode::Instruction; +use crate::real_mode::Opcode; +use crate::real_mode::read_modrm; +use crate::real_mode::read_E; +use crate::real_mode::read_E_xmm; +use crate::real_mode::read_E_ymm; +use crate::real_mode::read_imm_unsigned; + +#[derive(Debug)] +enum VEXOpcodeMap { + Map0F, + Map0F38, + Map0F3A, +} + +#[derive(Debug)] +enum VEXOpcodePrefix { + None, + Prefix66, + PrefixF3, + PrefixF2, +} + +#[allow(non_camel_case_types)] +#[derive(Debug)] +enum VEXOperandCode { + Nothing, + VPS_71, + VPS_71_L, + VPS_72, + VPS_72_L, + VPS_73, + VPS_73_L, + VMOVSS_10, + VMOVSD_10, + VMOVSD_11, + VMOVSS_11, + VMOVLPS_12, + VMOVHPS_16, + E_G_xmm, + M_G_xmm, + G_M_xmm, + G_U_xmm, + Gd_U_xmm, + E_G_xmm_imm8, + Ud_G_xmm_imm8, + Ud_G_xmm, + Ud_G_ymm, + E_G_ymm, + M_G_ymm, + G_E_ymm, + G_M_ymm, + Gd_U_ymm, + E_xmm_G_ymm_imm8, + Ev_G_xmm_imm8, + G_Ex_V_xmm, + G_Ey_V_xmm, + G_Ey_V_ymm, + G_E_xmm, + G_E_xmm_imm8, + G_E_ymm_imm8, + G_xmm_E_xmm, + G_xmm_E_ymm, + G_ymm_E_xmm, + G_ymm_M_xmm, + G_ymm_E_ymm, + G_V_ymm_E_xmm, + M_V_G_xmm, + M_V_G_ymm, + G_V_xmm_Ed, + G_V_E_xmm, + G_V_E_xmm_imm8, + G_V_E_xmm_xmm4, + G_V_E_ymm, + G_V_E_ymm_imm8, + G_V_E_ymm_ymm4, + G_V_M_xmm, + G_V_M_ymm, + G_ymm_V_ymm_E_xmm_imm8, + G_V_xmm_Ev_imm8, + Ed_G_xmm, + G_xmm_Ed, + G_E_V, + G_V_E, + G_E_Ib, + VCVT_Gd_Ed_xmm, + VCVT_Gd_Eq_xmm, + BMI1_F3, + MXCSR, +} + +#[inline(never)] +pub(crate) fn three_byte_vex::Address, ::Word>>(words: &mut T, vex_byte_one: u8, instruction: &mut Instruction) -> Result<(), DecodeError> { + let vex_byte_two = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; + let p = vex_byte_two & 0x03; + let p = match p { + 0x00 => VEXOpcodePrefix::None, + 0x01 => VEXOpcodePrefix::Prefix66, + 0x02 => VEXOpcodePrefix::PrefixF3, + 0x03 => VEXOpcodePrefix::PrefixF2, + _ => { unreachable!("p is two bits"); } + }; + let m = vex_byte_one & 0b11111; + let m = match m { + 0b00001 => VEXOpcodeMap::Map0F, + 0b00010 => VEXOpcodeMap::Map0F38, + 0b00011 => VEXOpcodeMap::Map0F3A, + _ => { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } + }; + instruction.regs[3] = RegSpec { + bank: RegisterBank::X, + num: ((vex_byte_two >> 3) & 0b1111) ^ 0b1111, + }; + instruction.prefixes.vex_from_c4(vex_byte_one, vex_byte_two); + + read_vex_instruction(m, words, instruction, p)?; + instruction.length = words.offset() as u8; + instruction.regs[3].num &= 0b0111; // ignore bit 4 in 32-bit mode + Ok(()) +} + +pub(crate) fn two_byte_vex::Address, ::Word>>(words: &mut T, vex_byte: u8, instruction: &mut Instruction) -> Result<(), DecodeError> { + let p = vex_byte & 0x03; + let p = match p { + 0x00 => VEXOpcodePrefix::None, + 0x01 => VEXOpcodePrefix::Prefix66, + 0x02 => VEXOpcodePrefix::PrefixF3, + 0x03 => VEXOpcodePrefix::PrefixF2, + _ => { unreachable!("p is two bits"); } + }; + instruction.regs[3] = RegSpec { + bank: RegisterBank::X, + num: ((vex_byte >> 3) & 0b1111) ^ 0b1111, + }; + instruction.prefixes.vex_from_c5(vex_byte); + + read_vex_instruction(VEXOpcodeMap::Map0F, words, instruction, p)?; + instruction.length = words.offset() as u8; + instruction.regs[3].num &= 0b0111; // ignore bit 4 in 32-bit mode + Ok(()) +} + +fn read_vex_operands::Address, ::Word>>(words: &mut T, instruction: &mut Instruction, operand_code: VEXOperandCode) -> Result<(), DecodeError> { +// println!("operand code: {:?}", operand_code); + match operand_code { + VEXOperandCode::VPS_71 => { + let modrm = read_modrm(words)?; + if modrm & 0xc0 != 0xc0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + match (modrm >> 3) & 0b111 { + 0b010 => { + instruction.opcode = Opcode::VPSRLW; + } + 0b100 => { + instruction.opcode = Opcode::VPSRAW; + } + 0b110 => { + instruction.opcode = Opcode::VPSLLW; + } + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + instruction.regs[0] = + RegSpec::from_parts(modrm & 7, RegisterBank::X); + instruction.regs[3].bank = RegisterBank::X; + instruction.operands[0] = OperandSpec::RegVex; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.imm = read_imm_unsigned(words, 1)?; + instruction.operands[2] = OperandSpec::ImmI8; + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::VPS_71_L => { + let modrm = read_modrm(words)?; + if modrm & 0xc0 != 0xc0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + match (modrm >> 3) & 0b111 { + 0b001 => { + instruction.opcode = Opcode::VPSLLW; + } + 0b010 => { + instruction.opcode = Opcode::VPSRLW; + } + 0b100 => { + instruction.opcode = Opcode::VPSRAW; + } + 0b110 => { + instruction.opcode = Opcode::VPSLLW; + } + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + instruction.regs[0] = + RegSpec::from_parts(modrm & 7, RegisterBank::Y); + instruction.regs[3].bank = RegisterBank::Y; + instruction.operands[0] = OperandSpec::RegVex; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.imm = read_imm_unsigned(words, 1)?; + instruction.operands[2] = OperandSpec::ImmI8; + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::VPS_72 => { + let modrm = read_modrm(words)?; + if modrm & 0xc0 != 0xc0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + match (modrm >> 3) & 0b111 { + 0b010 => { + instruction.opcode = Opcode::VPSRLD; + } + 0b100 => { + instruction.opcode = Opcode::VPSRAD; + } + 0b110 => { + instruction.opcode = Opcode::VPSLLD; + } + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + instruction.regs[0] = + RegSpec::from_parts(modrm & 7, RegisterBank::X); + instruction.regs[3].bank = RegisterBank::X; + instruction.operands[0] = OperandSpec::RegVex; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.imm = read_imm_unsigned(words, 1)?; + instruction.operands[2] = OperandSpec::ImmI8; + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::VPS_72_L => { + let modrm = read_modrm(words)?; + if modrm & 0xc0 != 0xc0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + match (modrm >> 3) & 0b111 { + 0b010 => { + instruction.opcode = Opcode::VPSRLD; + } + 0b100 => { + instruction.opcode = Opcode::VPSRAD; + } + 0b110 => { + instruction.opcode = Opcode::VPSLLD; + } + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + instruction.regs[0] = + RegSpec::from_parts(modrm & 7, RegisterBank::Y); + instruction.regs[3].bank = RegisterBank::Y; + instruction.operands[0] = OperandSpec::RegVex; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.imm = read_imm_unsigned(words, 1)?; + instruction.operands[2] = OperandSpec::ImmI8; + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::VPS_73 => { + let modrm = read_modrm(words)?; + if modrm & 0xc0 != 0xc0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + match (modrm >> 3) & 0b111 { + 0b010 => { + instruction.opcode = Opcode::VPSRLQ; + } + 0b011 => { + instruction.opcode = Opcode::VPSRLDQ; + } + 0b110 => { + instruction.opcode = Opcode::VPSLLQ; + } + 0b111 => { + instruction.opcode = Opcode::VPSLLDQ; + } + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + instruction.regs[0] = + RegSpec::from_parts(modrm & 7, RegisterBank::X); + instruction.regs[3].bank = RegisterBank::X; + instruction.operands[0] = OperandSpec::RegVex; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.imm = read_imm_unsigned(words, 1)?; + instruction.operands[2] = OperandSpec::ImmI8; + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::VPS_73_L => { + let modrm = read_modrm(words)?; + if modrm & 0xc0 != 0xc0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + match (modrm >> 3) & 0b111 { + 0b000 | + 0b001 | + 0b100 | + 0b101 => { + return Err(DecodeError::InvalidOpcode); + } + 0b010 => { + instruction.opcode = Opcode::VPSRLQ; + } + 0b011 => { + instruction.opcode = Opcode::VPSRLDQ; + } + 0b110 => { + instruction.opcode = Opcode::VPSLLQ; + } + 0b111 => { + instruction.opcode = Opcode::VPSLLDQ; + } + _ => { + unreachable!("r is only three bits"); + } + } + instruction.regs[0] = + RegSpec::from_parts(modrm & 7, RegisterBank::Y); + instruction.regs[3].bank = RegisterBank::Y; + instruction.operands[0] = OperandSpec::RegVex; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.imm = read_imm_unsigned(words, 1)?; + instruction.operands[2] = OperandSpec::ImmI8; + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::VMOVSS_10 | + VEXOperandCode::VMOVSD_10 => { + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + let mem_oper = read_E_xmm(words, instruction, modrm)?; + instruction.operands[0] = OperandSpec::RegRRR; + match mem_oper { + OperandSpec::RegMMM => { + instruction.operands[1] = OperandSpec::RegVex; + instruction.operands[2] = OperandSpec::RegMMM; + instruction.operand_count = 3; + }, + other => { + if instruction.regs[3].num != 0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + if instruction.opcode == Opcode::VMOVSS { + instruction.mem_size = 4; + } else { + instruction.mem_size = 8; + } + instruction.operands[1] = other; + instruction.operand_count = 2; + } + } + Ok(()) + }, + VEXOperandCode::VMOVSS_11 | + VEXOperandCode::VMOVSD_11 => { + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + let mem_oper = read_E_xmm(words, instruction, modrm)?; + instruction.operands[2] = OperandSpec::RegRRR; + match mem_oper { + OperandSpec::RegMMM => { + instruction.operands[0] = OperandSpec::RegMMM; + instruction.operands[1] = OperandSpec::RegVex; + instruction.operand_count = 3; + }, + other => { + if instruction.regs[3].num != 0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + if instruction.opcode == Opcode::VMOVSS { + instruction.mem_size = 4; + } else { + instruction.mem_size = 8; + } + instruction.operands[0] = other; + instruction.operands[1] = instruction.operands[2]; + instruction.operand_count = 2; + } + } + Ok(()) + }, + VEXOperandCode::VMOVLPS_12 => { + let modrm = read_modrm(words)?; + instruction.opcode = if modrm & 0xc0 == 0xc0 { + Opcode::VMOVHLPS + } else { + instruction.mem_size = 8; + Opcode::VMOVLPS + }; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::RegVex; + instruction.operands[2] = read_E_xmm(words, instruction, modrm)?; + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::VMOVHPS_16 => { + let modrm = read_modrm(words)?; + instruction.opcode = if modrm & 0xc0 == 0xc0 { + Opcode::VMOVLHPS + } else { + instruction.mem_size = 8; + Opcode::VMOVHPS + }; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::RegVex; + instruction.operands[2] = read_E_xmm(words, instruction, modrm)?; + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::Nothing => { + instruction.operand_count = 0; + Ok(()) + }, + VEXOperandCode::Ev_G_xmm_imm8 => { + if instruction.regs[3].num != 0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + let mem_oper = read_E(words, instruction, modrm, 4)?; + instruction.operands[0] = mem_oper; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.operands[2] = OperandSpec::ImmU8; + if mem_oper != OperandSpec::RegMMM { + match instruction.opcode { + Opcode::VPEXTRB => { + instruction.mem_size = 1; + } + Opcode::VPEXTRW => { + instruction.mem_size = 2; + } + Opcode::VEXTRACTPS | + Opcode::VPEXTRD => { + instruction.mem_size = 4; + } + _ => { + instruction.mem_size = 8; + } + } + } + instruction.operand_count = 3; + instruction.imm = read_imm_unsigned(words, 1)?; + Ok(()) + }, + VEXOperandCode::G_xmm_Ed => { + if instruction.regs[3].num != 0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + let mem_oper = read_E(words, instruction, modrm, 4)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = mem_oper; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 4; + } + instruction.operand_count = 2; + Ok(()) + } + VEXOperandCode::Ed_G_xmm => { + if instruction.regs[3].num != 0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + let mem_oper = read_E(words, instruction, modrm, 4)?; + instruction.operands[0] = mem_oper; + instruction.operands[1] = OperandSpec::RegRRR; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 4; + } + instruction.operand_count = 2; + Ok(()) + } + VEXOperandCode::VCVT_Gd_Ed_xmm => { + if instruction.regs[3].num != 0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D); + let mem_oper = read_E(words, instruction, modrm, 4)?; + if let OperandSpec::RegMMM = mem_oper { + instruction.regs[1].bank = RegisterBank::X; + } else { + instruction.mem_size = 4; + } + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = mem_oper; + instruction.operand_count = 2; + Ok(()) + } + VEXOperandCode::VCVT_Gd_Eq_xmm => { + if instruction.regs[3].num != 0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D); + let mem_oper = read_E(words, instruction, modrm, 4)?; + if let OperandSpec::RegMMM = mem_oper { + instruction.regs[1].bank = RegisterBank::X; + } else { + instruction.mem_size = 8; + } + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = mem_oper; + instruction.operand_count = 2; + Ok(()) + } + op @ VEXOperandCode::E_G_xmm | + op @ VEXOperandCode::M_G_xmm => { + if instruction.regs[3].num != 0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + let mem_oper = read_E_xmm(words, instruction, modrm)?; + match (op, mem_oper) { + (VEXOperandCode::E_G_xmm, OperandSpec::RegMMM) => { + /* this is the only accepted operand */ + } + (VEXOperandCode::M_G_xmm, OperandSpec::RegMMM) => { + return Err(DecodeError::InvalidOperand); + } + (VEXOperandCode::M_G_xmm, _) | // otherwise it's memory-constrained and a memory operand + (_, _) => { // ... or unconstrained + /* and this is always accepted */ + } + } + if mem_oper != OperandSpec::RegMMM { + if instruction.opcode == Opcode::VMOVLPD || instruction.opcode == Opcode::VMOVHPD || instruction.opcode == Opcode::VMOVHPS { + instruction.mem_size = 8; + } else { + instruction.mem_size = 16; + } + } + instruction.operands[0] = mem_oper; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.operand_count = 2; + Ok(()) + } + VEXOperandCode::Ud_G_xmm => { + if instruction.regs[3].num != 0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D); + let mem_oper = read_E_xmm(words, instruction, modrm)?; + if mem_oper != OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = mem_oper; + instruction.operand_count = 2; + Ok(()) + } + VEXOperandCode::Ud_G_ymm => { + if instruction.regs[3].num != 0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D); + let mem_oper = read_E_ymm(words, instruction, modrm)?; + if mem_oper != OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = mem_oper; + instruction.operand_count = 2; + Ok(()) + } + VEXOperandCode::Ud_G_xmm_imm8 => { + if instruction.regs[3].num != 0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D); + let mem_oper = read_E_xmm(words, instruction, modrm)?; + if mem_oper != OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = mem_oper; + instruction.imm = read_imm_unsigned(words, 1)?; + instruction.operands[2] = OperandSpec::ImmU8; + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::E_G_xmm_imm8 => { + if instruction.regs[3].num != 0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + let mem_oper = read_E_xmm(words, instruction, modrm)?; + instruction.operands[0] = mem_oper; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.imm = read_imm_unsigned(words, 1)?; + instruction.operands[2] = OperandSpec::ImmU8; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 16; + } + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::E_xmm_G_ymm_imm8 => { + if instruction.regs[3].num != 0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::Y); + let mem_oper = read_E_xmm(words, instruction, modrm)?; + instruction.operands[0] = mem_oper; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.imm = read_imm_unsigned(words, 1)?; + instruction.operands[2] = OperandSpec::ImmU8; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 16; + } + instruction.operand_count = 3; + Ok(()) + } + + VEXOperandCode::Gd_U_xmm => { + if instruction.regs[3].num != 0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D); + let mem_oper = read_E_xmm(words, instruction, modrm)?; + if mem_oper != OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = mem_oper; + instruction.operand_count = 2; + Ok(()) + } + VEXOperandCode::Gd_U_ymm => { + if instruction.regs[3].num != 0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D); + let mem_oper = read_E_ymm(words, instruction, modrm)?; + if mem_oper != OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = mem_oper; + instruction.operand_count = 2; + Ok(()) + } + + op @ VEXOperandCode::G_M_xmm | + op @ VEXOperandCode::G_U_xmm | + op @ VEXOperandCode::G_E_xmm => { + if instruction.regs[3].num != 0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + let modrm = read_modrm(words)?; + match (op, modrm & 0xc0) { + (VEXOperandCode::G_U_xmm, 0xc0) => { + /* this is the only accepted operand */ + } + (VEXOperandCode::G_U_xmm, _) | + (VEXOperandCode::G_M_xmm, 0xc0) => { + return Err(DecodeError::InvalidOperand); + } + (VEXOperandCode::G_M_xmm, _) | // otherwise it's memory-constrained and a memory operand + (_, _) => { // ... or unconstrained + /* and this is always accepted */ + } + } + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + let mem_oper = read_E_xmm(words, instruction, modrm)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = mem_oper; + if mem_oper != OperandSpec::RegMMM { + if [Opcode::VBROADCASTSS, Opcode::VUCOMISS, Opcode::VCOMISS].contains(&instruction.opcode) { + instruction.mem_size = 4; + } else if [Opcode::VMOVDDUP, Opcode::VUCOMISD, Opcode::VCOMISD, Opcode::VCVTPS2PD, Opcode::VMOVQ].contains(&instruction.opcode) { + instruction.mem_size = 8; + } else { + instruction.mem_size = 16; + }; + } + instruction.operand_count = 2; + Ok(()) + } + VEXOperandCode::G_xmm_E_xmm => { + if instruction.regs[3].num != 0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + let mem_oper = read_E_xmm(words, instruction, modrm)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = mem_oper; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 16; + } + instruction.operand_count = 2; + Ok(()) + } + VEXOperandCode::G_xmm_E_ymm => { + if instruction.regs[3].num != 0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + let mem_oper = read_E_ymm(words, instruction, modrm)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = mem_oper; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 32; + } + instruction.operand_count = 2; + Ok(()) + } + op @ VEXOperandCode::G_ymm_M_xmm | + op @ VEXOperandCode::G_ymm_E_xmm => { + if instruction.regs[3].num != 0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + let modrm = read_modrm(words)?; + if modrm & 0xc0 == 0xc0 { + if let VEXOperandCode::G_ymm_M_xmm = op { + return Err(DecodeError::InvalidOperand); + } + } + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::Y); + let mem_oper = read_E_xmm(words, instruction, modrm)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = mem_oper; + if mem_oper != OperandSpec::RegMMM { + if [Opcode::VBROADCASTSS].contains(&instruction.opcode) { + instruction.mem_size = 4; + } else if [Opcode::VBROADCASTSD].contains(&instruction.opcode) { + instruction.mem_size = 8; + } else { + instruction.mem_size = 16; + } + } + instruction.operand_count = 2; + Ok(()) + } + VEXOperandCode::G_ymm_E_ymm => { + if instruction.regs[3].num != 0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::Y); + let mem_oper = read_E_ymm(words, instruction, modrm)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = mem_oper; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 32; + } + instruction.operand_count = 2; + Ok(()) + } + + op @ VEXOperandCode::E_G_ymm | + op @ VEXOperandCode::M_G_ymm => { + if instruction.regs[3].num != 0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + let modrm = read_modrm(words)?; + match (op, modrm & 0xc0) { + (VEXOperandCode::M_G_ymm, 0xc0) => { + return Err(DecodeError::InvalidOperand); + } + (VEXOperandCode::M_G_ymm, _) | // otherwise it's memory-constrained and a memory operand + (_, _) => { // ... or unconstrained + /* and this is always accepted */ + } + } + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::Y); + let mem_oper = read_E_ymm(words, instruction, modrm)?; + instruction.operands[0] = mem_oper; + instruction.operands[1] = OperandSpec::RegRRR; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 32; + } + instruction.operand_count = 2; + Ok(()) + } + + op @ VEXOperandCode::G_M_ymm | + op @ VEXOperandCode::G_E_ymm => { + if instruction.regs[3].num != 0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); + } + let modrm = read_modrm(words)?; + match (op, modrm & 0xc0) { + (VEXOperandCode::G_M_ymm, 0xc0) => { + return Err(DecodeError::InvalidOperand); + } + (VEXOperandCode::G_M_ymm, _) | // otherwise it's memory-constrained and a memory operand + (_, _) => { // ... or unconstrained + /* and this is always accepted */ + } + } + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::Y); + let mem_oper = read_E_ymm(words, instruction, modrm)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = mem_oper; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 32; + } + instruction.operand_count = 2; + Ok(()) + } + op @ VEXOperandCode::G_V_E_ymm | + op @ VEXOperandCode::G_V_M_ymm => { + let modrm = read_modrm(words)?; + if let VEXOperandCode::G_V_M_ymm = op { + if modrm & 0xc0 == 0xc0 { + return Err(DecodeError::InvalidOperand); + } + } + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::Y); + instruction.regs[3].bank = RegisterBank::Y; + let mem_oper = read_E_ymm(words, instruction, modrm)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::RegVex; + instruction.operands[2] = mem_oper; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 32; + } + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::G_V_E_ymm_imm8 => { + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::Y); + instruction.regs[3].bank = RegisterBank::Y; + let mem_oper = read_E_ymm(words, instruction, modrm)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::RegVex; + instruction.operands[2] = mem_oper; + instruction.imm = read_imm_unsigned(words, 1)?; + instruction.operands[3] = OperandSpec::ImmU8; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 32; + } + instruction.operand_count = 4; + Ok(()) + } + VEXOperandCode::M_V_G_ymm => { + let modrm = read_modrm(words)?; + if modrm & 0xc0 == 0xc0 { + return Err(DecodeError::InvalidOperand); + } + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::Y); + instruction.regs[3].bank = RegisterBank::Y; + let mem_oper = read_E_ymm(words, instruction, modrm)?; + instruction.operands[0] = mem_oper; + instruction.operands[1] = OperandSpec::RegVex; + instruction.operands[2] = OperandSpec::RegRRR; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 32; + } + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::G_V_M_xmm => { + let modrm = read_modrm(words)?; + if modrm & 0xc0 == 0xc0 { + return Err(DecodeError::InvalidOperand); + } + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + let mem_oper = read_E_xmm(words, instruction, modrm)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::RegVex; + instruction.operands[2] = mem_oper; + if mem_oper != OperandSpec::RegMMM { + if instruction.opcode == Opcode::VMOVLPD || instruction.opcode == Opcode::VMOVHPD { + instruction.mem_size = 8; + } else { + instruction.mem_size = 16; + } + } + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::G_V_E_xmm => { + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + let mem_oper = read_E_xmm(words, instruction, modrm)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::RegVex; + instruction.operands[2] = mem_oper; + if mem_oper != OperandSpec::RegMMM { + if [Opcode::VSQRTSS, Opcode::VADDSS, Opcode::VMULSS, Opcode::VSUBSS, Opcode::VMINSS, Opcode::VDIVSS, Opcode::VMAXSS].contains(&instruction.opcode) { + instruction.mem_size = 4; + } else if [Opcode::VSQRTSD, Opcode::VADDSD, Opcode::VMULSD, Opcode::VSUBSD, Opcode::VMINSD, Opcode::VDIVSD, Opcode::VMAXSD].contains(&instruction.opcode) { + instruction.mem_size = 8; + } else { + instruction.mem_size = 16; + } + } + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::G_V_xmm_Ed => { + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + let mem_oper = read_E(words, instruction, modrm, 4)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::RegVex; + instruction.operands[2] = mem_oper; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 4; + } + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::G_V_E_xmm_imm8 => { + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + let mem_oper = read_E_xmm(words, instruction, modrm)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::RegVex; + instruction.operands[2] = mem_oper; + instruction.imm = read_imm_unsigned(words, 1)?; + instruction.operands[3] = OperandSpec::ImmU8; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 16; + } + instruction.operand_count = 4; + Ok(()) + } + VEXOperandCode::G_ymm_V_ymm_E_xmm_imm8 => { + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::Y); + instruction.regs[3].bank = RegisterBank::Y; + let mem_oper = read_E_xmm(words, instruction, modrm)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::RegVex; + instruction.operands[2] = mem_oper; + instruction.imm = read_imm_unsigned(words, 1)?; + instruction.operands[3] = OperandSpec::ImmU8; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 16; + } + instruction.operand_count = 4; + Ok(()) + } + VEXOperandCode::M_V_G_xmm => { + let modrm = read_modrm(words)?; + if modrm & 0xc0 == 0xc0 { + return Err(DecodeError::InvalidOperand); + } + + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + let mem_oper = read_E_xmm(words, instruction, modrm)?; + instruction.operands[0] = mem_oper; + instruction.operands[1] = OperandSpec::RegVex; + instruction.operands[2] = OperandSpec::RegRRR; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 16; + } + instruction.operand_count = 3; + Ok(()) + } + + VEXOperandCode::G_Ex_V_xmm => { + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + let mem_oper = read_E_xmm(words, instruction, modrm)?; + instruction.regs[2].bank = RegisterBank::X; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = mem_oper; + instruction.operands[2] = OperandSpec::RegVex; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 4; + } + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::G_Ey_V_xmm => { + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + let mem_oper = read_E_ymm(words, instruction, modrm)?; + instruction.regs[3].bank = RegisterBank::X; + instruction.regs[2].bank = RegisterBank::Y; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = mem_oper; + instruction.operands[2] = OperandSpec::RegVex; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 4; + } + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::G_Ey_V_ymm => { + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::Y); + let mem_oper = read_E_ymm(words, instruction, modrm)?; + instruction.regs[3].bank = RegisterBank::Y; + instruction.regs[2].bank = RegisterBank::Y; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = mem_oper; + instruction.operands[2] = OperandSpec::RegVex; + if mem_oper != OperandSpec::RegMMM { + if instruction.opcode == Opcode::VPGATHERDD { + instruction.mem_size = 4; + } else { + instruction.mem_size = 8; + } + } + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::G_V_E => { + let modrm = read_modrm(words)?; + let (opwidth, bank) = (4, RegisterBank::D); + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, bank); + instruction.regs[3].bank = bank; + let mem_oper = read_E(words, instruction, modrm, opwidth)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::RegVex; + instruction.operands[2] = mem_oper; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = opwidth; + } + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::G_E_V => { + let modrm = read_modrm(words)?; + let (opwidth, bank) = (4, RegisterBank::D); + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, bank); + instruction.regs[3].bank = bank; + let mem_oper = read_E(words, instruction, modrm, opwidth)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = mem_oper; + instruction.operands[2] = OperandSpec::RegVex; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = opwidth; + } + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::G_E_Ib => { + let modrm = read_modrm(words)?; + let (opwidth, bank) = (4, RegisterBank::D); + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, bank); + let mem_oper = read_E(words, instruction, modrm, opwidth)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = mem_oper; + instruction.imm = read_imm_unsigned(words, 1)?; + instruction.operands[2] = OperandSpec::ImmI8; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = opwidth; + } + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::BMI1_F3 => { + let modrm = read_modrm(words)?; + instruction.opcode = match (modrm >> 3) & 7 { + 1 => { + Opcode::BLSR + } + 2 => { + Opcode::BLSMSK + } + 3 => { + Opcode::BLSI + } + _ => { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } + }; + let (opwidth, bank) = (4, RegisterBank::D); + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, bank); + let mem_oper = read_E(words, instruction, modrm, opwidth)?; + instruction.operands[0] = OperandSpec::RegVex; + instruction.operands[1] = mem_oper; + instruction.operand_count = 2; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = opwidth; + } + instruction.regs[3].bank = bank; + Ok(()) + } + VEXOperandCode::MXCSR => { + let modrm = read_modrm(words)?; + instruction.opcode = match (modrm >> 3) & 7 { + 2 => { + Opcode::VLDMXCSR + } + 3 => { + Opcode::VSTMXCSR + } + _ => { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } + }; + let mem_oper = read_E(words, instruction, modrm, 4)?; + if let OperandSpec::RegMMM = mem_oper { + return Err(DecodeError::InvalidOperand); + } + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 4; + } + instruction.operands[0] = mem_oper; + instruction.operand_count = 1; + Ok(()) + } + VEXOperandCode::G_E_xmm_imm8 => { + if instruction.regs[3].num != 0 { + return Err(DecodeError::InvalidOperand); + } + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + let mem_oper = read_E_xmm(words, instruction, modrm)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = mem_oper; + instruction.imm = read_imm_unsigned(words, 1)?; + instruction.operands[2] = OperandSpec::ImmU8; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 16; + } + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::G_E_ymm_imm8 => { + if instruction.regs[3].num != 0 { + return Err(DecodeError::InvalidOperand); + } + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::Y); + let mem_oper = read_E_ymm(words, instruction, modrm)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = mem_oper; + instruction.imm = read_imm_unsigned(words, 1)?; + instruction.operands[2] = OperandSpec::ImmU8; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 32; + } + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::G_V_E_ymm_ymm4 => { + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::Y); + instruction.regs[3].bank = RegisterBank::Y; + let mem_oper = read_E_ymm(words, instruction, modrm)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::RegVex; + instruction.operands[2] = mem_oper; + instruction.imm = read_imm_unsigned(words, 1)? >> 4; + instruction.operands[3] = OperandSpec::Reg4; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 32; + } + instruction.operand_count = 4; + Ok(()) + } + VEXOperandCode::G_V_E_xmm_xmm4 => { + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + instruction.regs[3].bank = RegisterBank::X; + let mem_oper = read_E_xmm(words, instruction, modrm)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::RegVex; + instruction.operands[2] = mem_oper; + instruction.imm = read_imm_unsigned(words, 1)? >> 4; + instruction.operands[3] = OperandSpec::Reg4; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 16; + } + instruction.operand_count = 4; + Ok(()) + } + VEXOperandCode::G_V_ymm_E_xmm => { + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::Y); + instruction.regs[3].bank = RegisterBank::Y; + let mem_oper = read_E_xmm(words, instruction, modrm)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::RegVex; + instruction.operands[2] = mem_oper; + if mem_oper != OperandSpec::RegMMM { + instruction.mem_size = 16; + } + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::G_V_xmm_Ev_imm8 => { + let modrm = read_modrm(words)?; + instruction.regs[0] = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + instruction.regs[3].bank = RegisterBank::X; + // TODO: but the memory access is word-sized + let mem_oper = read_E(words, instruction, modrm, 4)?; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::RegVex; + instruction.operands[2] = mem_oper; + instruction.imm = read_imm_unsigned(words, 1)?; + instruction.operands[3] = OperandSpec::ImmI8; + if mem_oper != OperandSpec::RegMMM { + match instruction.opcode { + Opcode::VPINSRB => { + instruction.mem_size = 1; + } + Opcode::VPINSRW => { + instruction.mem_size = 2; + } + Opcode::VINSERTPS | + Opcode::VPINSRD => { + instruction.mem_size = 4; + } + _ => { + instruction.mem_size = 8; + } + } + } + instruction.operand_count = 4; + Ok(()) + } + + } +} + +fn read_vex_instruction::Address, ::Word>>(opcode_map: VEXOpcodeMap, words: &mut T, instruction: &mut Instruction, p: VEXOpcodePrefix) -> Result<(), DecodeError> { + let opc = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; + + // the name of this bit is `L` in the documentation, so use the same name here. + #[allow(non_snake_case)] + let L = instruction.prefixes.vex_unchecked().l(); + +// println!("reading vex instruction from opcode prefix {:?}, L: {}, opc: {:#x}, map:{:?}", p, L, opc, opcode_map); +// println!("w? {}", instruction.prefixes.vex_unchecked().w()); + + // several combinations simply have no instructions. check for those first. + let (opcode, operand_code) = match opcode_map { + VEXOpcodeMap::Map0F => { + match p { + VEXOpcodePrefix::None => { + match opc { + 0x10 => (Opcode::VMOVUPS, if L { VEXOperandCode::G_E_ymm } else { VEXOperandCode::G_E_xmm }), + 0x11 => (Opcode::VMOVUPS, if L { VEXOperandCode::E_G_ymm } else { VEXOperandCode::E_G_xmm }), + 0x12 => (Opcode::Invalid, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::VMOVLPS_12 + }), + 0x13 => (Opcode::VMOVLPS, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::M_G_xmm + }), + 0x14 => (Opcode::VUNPCKLPS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x15 => (Opcode::VUNPCKHPS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x16 => (Opcode::Invalid, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::VMOVHPS_16 + }), + 0x17 => (Opcode::VMOVHPS, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::M_G_xmm + }), + 0x28 => (Opcode::VMOVAPS, if L { + VEXOperandCode::G_E_ymm + } else { + VEXOperandCode::G_E_xmm + }), + 0x29 => (Opcode::VMOVAPS, if L { + VEXOperandCode::E_G_ymm + } else { + VEXOperandCode::E_G_xmm + }), + 0x2B => (Opcode::VMOVNTPS, if L { + VEXOperandCode::M_G_ymm + } else { + VEXOperandCode::M_G_xmm + }), + 0x2e => (Opcode::VUCOMISS, VEXOperandCode::G_E_xmm), + 0x2f => (Opcode::VCOMISS, VEXOperandCode::G_E_xmm), + 0x50 => (Opcode::VMOVMSKPS, if L { + VEXOperandCode::Ud_G_ymm + } else { + VEXOperandCode::Ud_G_xmm + }), + 0x51 => (Opcode::VSQRTPS, if L { + VEXOperandCode::G_E_ymm + } else { + VEXOperandCode::G_E_xmm + }), + 0x52 => (Opcode::VRSQRTPS, if L { + VEXOperandCode::G_E_ymm + } else { + VEXOperandCode::G_E_xmm + }), + 0x53 => (Opcode::VRCPPS, if L { + VEXOperandCode::G_E_ymm + } else { + VEXOperandCode::G_E_xmm + }), + 0x54 => (Opcode::VANDPS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x55 => (Opcode::VANDNPS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x56 => (Opcode::VORPS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x57 => (Opcode::VXORPS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x58 => (Opcode::VADDPS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x59 => (Opcode::VMULPS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x5A => (Opcode::VCVTPS2PD, if L { + VEXOperandCode::G_ymm_E_xmm + } else { + VEXOperandCode::G_E_xmm + }), + 0x5B => (Opcode::VCVTDQ2PS, if L { + VEXOperandCode::G_E_ymm + } else { + VEXOperandCode::G_E_xmm + }), + 0x5C => (Opcode::VSUBPS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x5D => (Opcode::VMINPS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x5E => (Opcode::VDIVPS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x5F => (Opcode::VMAXPS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x77 => (Opcode::VZEROUPPER, VEXOperandCode::Nothing), + 0xAE => (Opcode::Invalid, if L { + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::MXCSR + }), + 0xC2 => (Opcode::VCMPPS, if L { + VEXOperandCode::G_V_E_ymm_imm8 + } else { + VEXOperandCode::G_V_E_xmm_imm8 + }), + 0xC6 => (Opcode::VSHUFPS, if L { + VEXOperandCode::G_V_E_ymm_imm8 + } else { + VEXOperandCode::G_V_E_xmm_imm8 + }), + _ => { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } + } + }, + VEXOpcodePrefix::Prefix66 => { + match opc { +// 0x0a => (Opcode::VROUNDSS, VEXOperandCode::G_V_E_xmm_imm8), +// 0x0b => (Opcode::VROUNDSD, VEXOperandCode::G_V_E_xmm_imm8), + 0x10 => (Opcode::VMOVUPD, if L { + VEXOperandCode::G_E_ymm + } else { + VEXOperandCode::G_E_xmm + }), + 0x11 => (Opcode::VMOVUPD, if L { + VEXOperandCode::G_E_ymm + } else { + VEXOperandCode::G_E_xmm + }), + 0x12 => (Opcode::VMOVLPD, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_V_M_xmm + }), + 0x13 => (Opcode::VMOVLPD, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::M_G_xmm + }), + 0x14 => (Opcode::VUNPCKLPD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x15 => (Opcode::VUNPCKHPD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x16 => (Opcode::VMOVHPD, if L { + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_V_M_xmm + }), + 0x17 => (Opcode::VMOVHPD, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::M_G_xmm + }), + 0x28 => (Opcode::VMOVAPD, if L { + VEXOperandCode::G_E_ymm + } else { + VEXOperandCode::G_E_xmm + }), + 0x29 => (Opcode::VMOVAPD, if L { + VEXOperandCode::E_G_ymm + } else { + VEXOperandCode::E_G_xmm + }), + 0x2B => (Opcode::VMOVNTPD, if L { + VEXOperandCode::M_G_ymm + } else { + VEXOperandCode::M_G_xmm + }), + 0x2e => (Opcode::VUCOMISD, VEXOperandCode::G_E_xmm), + 0x2f => (Opcode::VCOMISD, VEXOperandCode::G_E_xmm), + 0x50 => (Opcode::VMOVMSKPD, if L { + VEXOperandCode::Gd_U_ymm + } else { + VEXOperandCode::Gd_U_xmm + }), + 0x51 => (Opcode::VSQRTPD, if L { + VEXOperandCode::G_E_ymm + } else { + VEXOperandCode::G_E_xmm + }), + 0x54 => (Opcode::VANDPD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x55 => (Opcode::VANDNPD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x56 => (Opcode::VORPD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x57 => (Opcode::VXORPD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x58 => (Opcode::VADDPD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x59 => (Opcode::VMULPD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x5A => (Opcode::VCVTPD2PS, if L { + VEXOperandCode::G_xmm_E_ymm + } else { + VEXOperandCode::G_xmm_E_xmm + }), + 0x5B => (Opcode::VCVTPS2DQ, if L { + VEXOperandCode::G_E_ymm + } else { + VEXOperandCode::G_E_xmm + }), + 0x5C => (Opcode::VSUBPD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x5D => (Opcode::VMINPD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x5E => (Opcode::VDIVPD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x5F => (Opcode::VMAXPD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x60 => (Opcode::VPUNPCKLBW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x61 => (Opcode::VPUNPCKLWD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x62 => (Opcode::VPUNPCKLDQ, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x63 => (Opcode::VPACKSSWB, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x64 => (Opcode::VPCMPGTB, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x65 => (Opcode::VPCMPGTW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x66 => (Opcode::VPCMPGTD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x67 => (Opcode::VPACKUSWB, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x68 => (Opcode::VPUNPCKHBW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x69 => (Opcode::VPUNPCKHWD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x6A => (Opcode::VPUNPCKHDQ, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x6B => (Opcode::VPACKSSDW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x6C => (Opcode::VPUNPCKLQDQ, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x6D => (Opcode::VPUNPCKHQDQ, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x6E => if instruction.prefixes.vex_unchecked().w() { + (Opcode::VMOVD, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_xmm_Ed + }) + } else { + (Opcode::VMOVD, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_xmm_Ed + }) + }, + 0x6F => (Opcode::VMOVDQA, if L { + VEXOperandCode::G_E_ymm + } else { + VEXOperandCode::G_E_xmm + }), + 0x70 => (Opcode::VPSHUFD, if L { + VEXOperandCode::G_E_ymm_imm8 + } else { + VEXOperandCode::G_E_xmm_imm8 + }), + 0x71 => (Opcode::Invalid, if L { + VEXOperandCode::VPS_71_L + } else { + VEXOperandCode::VPS_71 + }), + 0x72 => (Opcode::Invalid, if L { + VEXOperandCode::VPS_72_L + } else { + VEXOperandCode::VPS_72 + }), + 0x73 => (Opcode::Invalid, if L { + VEXOperandCode::VPS_73_L + } else { + VEXOperandCode::VPS_73 + }), + 0x74 => (Opcode::VPCMPEQB, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x75 => (Opcode::VPCMPEQW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x76 => (Opcode::VPCMPEQD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x7C => (Opcode::VHADDPD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x7D => (Opcode::VHSUBPD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x7E => if instruction.prefixes.vex_unchecked().w() { + (Opcode::VMOVD, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::Ed_G_xmm + }) + } else { + (Opcode::VMOVD, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::Ed_G_xmm + }) + } + 0x7F => (Opcode::VMOVDQA, if L { + VEXOperandCode::E_G_ymm + } else { + VEXOperandCode::E_G_xmm + }), + 0xC2 => (Opcode::VCMPPD, if L { + VEXOperandCode::G_V_E_ymm_imm8 + } else { + VEXOperandCode::G_V_E_xmm_imm8 + }), + 0xC4 => (Opcode::VPINSRW, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_V_xmm_Ev_imm8 + }), + 0xC5 => (Opcode::VPEXTRW, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::Ud_G_xmm_imm8 + }), + 0xC6 => (Opcode::VSHUFPD, if L { + VEXOperandCode::G_V_E_ymm_imm8 + } else { + VEXOperandCode::G_V_E_xmm_imm8 + }), + 0xD0 => (Opcode::VADDSUBPD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xD1 => (Opcode::VPSRLW, if L { + VEXOperandCode::G_V_ymm_E_xmm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xD2 => (Opcode::VPSRLD, if L { + VEXOperandCode::G_V_ymm_E_xmm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xD3 => (Opcode::VPSRLQ, if L { + VEXOperandCode::G_V_ymm_E_xmm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xD4 => (Opcode::VPADDQ, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xD5 => (Opcode::VPMULLW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xD6 => (Opcode::VMOVQ, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_E_xmm + }), + 0xD7 => (Opcode::VPMOVMSKB, if L { + VEXOperandCode::Ud_G_ymm + } else { + VEXOperandCode::Ud_G_xmm + }), + 0xD8 => (Opcode::VPSUBUSB, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xD9 => (Opcode::VPSUBUSW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xDA => (Opcode::VPMINUB, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xDB => (Opcode::VPAND, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xDC => (Opcode::VPADDUSB, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xDD => (Opcode::VPADDUSW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xDE => (Opcode::VPMAXUB, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xDF => (Opcode::VPANDN, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xE0 => (Opcode::VPAVGB, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xE1 => (Opcode::VPSRAW, if L { + VEXOperandCode::G_V_ymm_E_xmm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xE2 => (Opcode::VPSRAD, if L { + VEXOperandCode::G_V_ymm_E_xmm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xE3 => (Opcode::VPAVGW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xE4 => (Opcode::VPMULHUW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xE5 => (Opcode::VPMULHW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xE6 => (Opcode::VCVTTPD2DQ, if L { + VEXOperandCode::G_xmm_E_ymm + } else { + VEXOperandCode::G_E_xmm + }), + 0xE7 => (Opcode::VMOVNTDQ, if L { + VEXOperandCode::M_G_ymm + } else { + VEXOperandCode::M_G_xmm + }), + 0xE8 => (Opcode::VPSUBSB, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xE9 => (Opcode::VPSUBSW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xEA => (Opcode::VPMINSW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xEB => (Opcode::VPOR, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xEC => (Opcode::VPADDSB, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xED => (Opcode::VPADDSW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xEE => (Opcode::VPMAXSW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xEF => (Opcode::VPXOR, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xF1 => (Opcode::VPSLLW, if L { + VEXOperandCode::G_V_ymm_E_xmm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xF2 => (Opcode::VPSLLD, if L { + VEXOperandCode::G_V_ymm_E_xmm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xF3 => (Opcode::VPSLLQ, if L { + VEXOperandCode::G_V_ymm_E_xmm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xF4 => (Opcode::VPMULUDQ, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xF5 => (Opcode::VPMADDWD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xF6 => (Opcode::VPSADBW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xF7 => (Opcode::VMASKMOVDQU, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_U_xmm + }), + 0xF8 => (Opcode::VPSUBB, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xF9 => (Opcode::VPSUBW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xFA => (Opcode::VPSUBD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xFB => (Opcode::VPSUBQ, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xFC => (Opcode::VPADDB, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xFD => (Opcode::VPADDW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xFE => (Opcode::VPADDD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + _ => { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } + } + } + VEXOpcodePrefix::PrefixF2 => { + match opc { + 0x10 => (Opcode::VMOVSD, VEXOperandCode::VMOVSD_10), + 0x11 => (Opcode::VMOVSD, VEXOperandCode::VMOVSD_11), + 0x12 => (Opcode::VMOVDDUP, if L { + VEXOperandCode::G_E_ymm + } else { + VEXOperandCode::G_E_xmm + }), + 0x2a => (Opcode::VCVTSI2SD, if instruction.prefixes.vex_unchecked().w() { + VEXOperandCode::G_V_xmm_Ed // 32-bit last operand + } else { + VEXOperandCode::G_V_xmm_Ed // 32-bit last operand + }), + 0x2c => (Opcode::VCVTTSD2SI, if instruction.prefixes.vex_unchecked().w() { + VEXOperandCode::VCVT_Gd_Eq_xmm + } else { + VEXOperandCode::VCVT_Gd_Eq_xmm + }), + 0x2d => (Opcode::VCVTSD2SI, if instruction.prefixes.vex_unchecked().w() { + VEXOperandCode::VCVT_Gd_Eq_xmm + } else { + VEXOperandCode::VCVT_Gd_Eq_xmm + }), + 0x51 => (Opcode::VSQRTSD, VEXOperandCode::G_V_E_xmm), + 0x58 => (Opcode::VADDSD, VEXOperandCode::G_V_E_xmm), + 0x59 => (Opcode::VMULSD, VEXOperandCode::G_V_E_xmm), + 0x5a => (Opcode::VCVTSD2SS, VEXOperandCode::G_V_E_xmm), + 0x5c => (Opcode::VSUBSD, VEXOperandCode::G_V_E_xmm), + 0x5d => (Opcode::VMINSD, VEXOperandCode::G_V_E_xmm), + 0x5e => (Opcode::VDIVSD, VEXOperandCode::G_V_E_xmm), + 0x5f => (Opcode::VMAXSD, VEXOperandCode::G_V_E_xmm), + 0x70 => (Opcode::VPSHUFLW, if L { + VEXOperandCode::G_E_ymm_imm8 + } else { + VEXOperandCode::G_E_xmm_imm8 + }), + 0x7c => (Opcode::VHADDPS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x7d => (Opcode::VHSUBPS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xc2 => (Opcode::VCMPSD, VEXOperandCode::G_V_E_xmm_imm8), + 0xd0 => (Opcode::VADDSUBPS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xe6 => (Opcode::VCVTPD2DQ, if L { + VEXOperandCode::G_xmm_E_ymm + } else { + VEXOperandCode::G_xmm_E_xmm + }), + 0xf0 => (Opcode::VLDDQU, if L { + VEXOperandCode::G_M_ymm + } else { + VEXOperandCode::G_M_xmm + }), + _ => { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } + } + } + VEXOpcodePrefix::PrefixF3 => { + match opc { + 0x10 => (Opcode::VMOVSS, VEXOperandCode::VMOVSS_10), + 0x11 => (Opcode::VMOVSS, VEXOperandCode::VMOVSS_11), + 0x12 => (Opcode::VMOVSLDUP, if L { VEXOperandCode::G_E_ymm } else { VEXOperandCode::G_E_xmm }), + 0x16 => (Opcode::VMOVSHDUP, if L { VEXOperandCode::G_E_ymm } else { VEXOperandCode::G_E_xmm }), + 0x2a => (Opcode::VCVTSI2SS, if instruction.prefixes.vex_unchecked().w() { + VEXOperandCode::G_V_xmm_Ed + } else { + VEXOperandCode::G_V_xmm_Ed + }), + 0x2c => (Opcode::VCVTTSS2SI, if instruction.prefixes.vex_unchecked().w() { + VEXOperandCode::VCVT_Gd_Ed_xmm // 32-bit + } else { + VEXOperandCode::VCVT_Gd_Ed_xmm // 32-bit + }), + 0x2d => (Opcode::VCVTSS2SI, if instruction.prefixes.vex_unchecked().w() { + VEXOperandCode::VCVT_Gd_Ed_xmm // 32-bit + } else { + VEXOperandCode::VCVT_Gd_Ed_xmm // 32-bit + }), + 0x51 => (Opcode::VSQRTSS, VEXOperandCode::G_V_E_xmm), + 0x52 => (Opcode::VRSQRTSS, VEXOperandCode::G_V_E_xmm), + 0x53 => (Opcode::VRCPSS, VEXOperandCode::G_V_E_xmm), + 0x58 => (Opcode::VADDSS, VEXOperandCode::G_V_E_xmm), + 0x59 => (Opcode::VMULSS, VEXOperandCode::G_V_E_xmm), + 0x5a => (Opcode::VCVTSS2SD, VEXOperandCode::G_V_E_xmm), + 0x5b => (Opcode::VCVTTPS2DQ, if L { VEXOperandCode::G_ymm_E_ymm } else { VEXOperandCode::G_xmm_E_xmm }), + 0x5c => (Opcode::VSUBSS, VEXOperandCode::G_V_E_xmm), + 0x5d => (Opcode::VMINSS, VEXOperandCode::G_V_E_xmm), + 0x5e => (Opcode::VDIVSS, VEXOperandCode::G_V_E_xmm), + 0x5f => (Opcode::VMAXSS, VEXOperandCode::G_V_E_xmm), + 0x6f => (Opcode::VMOVDQU, if L { VEXOperandCode::G_E_ymm } else { VEXOperandCode::G_E_xmm }), + 0x70 => (Opcode::VPSHUFHW, if L { + VEXOperandCode::G_E_ymm_imm8 + } else { + VEXOperandCode::G_E_xmm_imm8 + }), + 0x7e => (Opcode::VMOVQ, if L { instruction.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); } else { VEXOperandCode::G_E_xmm }), + 0x7f => (Opcode::VMOVDQU, if L { VEXOperandCode::E_G_ymm } else { VEXOperandCode::E_G_xmm }), + 0xc2 => (Opcode::VCMPSS, VEXOperandCode::G_V_E_xmm_imm8), + 0xe6 => (Opcode::VCVTDQ2PD, if L { VEXOperandCode::G_ymm_E_xmm } else { VEXOperandCode::G_xmm_E_xmm }), + _ => { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } + } + } + } + } + VEXOpcodeMap::Map0F38 => { + // TODO: verify rejecting invalid W bit + if let VEXOpcodePrefix::Prefix66 = p { + // possibly valid! + match opc { + 0x00 => (Opcode::VPSHUFB, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x01 => (Opcode::VPHADDW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x02 => (Opcode::VPHADDD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x03 => (Opcode::VPHADDSW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x04 => (Opcode::VPMADDUBSW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x05 => (Opcode::VPHSUBW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x06 => (Opcode::VPHSUBD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x07 => (Opcode::VPHSUBSW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x08 => (Opcode::VPSIGNB, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x09 => (Opcode::VPSIGNW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x0A => (Opcode::VPSIGND, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x0B => (Opcode::VPMULHRSW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x0C => (Opcode::VPERMILPS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x0D => (Opcode::VPERMILPD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x0E => (Opcode::VTESTPS, if L { + VEXOperandCode::G_E_ymm + } else { + VEXOperandCode::G_E_xmm + }), + 0x0F => (Opcode::VTESTPD, if L { + VEXOperandCode::G_E_ymm + } else { + VEXOperandCode::G_E_xmm + }), + 0x13 => (Opcode::VCVTPH2PS, if L { + VEXOperandCode::G_E_ymm + } else { + VEXOperandCode::G_E_xmm + }), + 0x16 => (Opcode::VPERMPS, if L { + if instruction.prefixes.vex_unchecked().w() { + return Err(DecodeError::InvalidOpcode); + } + VEXOperandCode::G_V_E_ymm + } else { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + }), + 0x17 => (Opcode::VPTEST, if L { + VEXOperandCode::G_E_ymm + } else { + VEXOperandCode::G_E_xmm + }), + 0x18 => if instruction.prefixes.vex_unchecked().w() { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + (Opcode::VBROADCASTSS, if L { + VEXOperandCode::G_ymm_E_xmm + } else { + VEXOperandCode::G_E_xmm + }) + }, + 0x19 => if instruction.prefixes.vex_unchecked().w() { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + (Opcode::VBROADCASTSD, if L { + VEXOperandCode::G_ymm_E_xmm + } else { + VEXOperandCode::G_E_xmm + }) + } + 0x1A => (Opcode::VBROADCASTF128, if L { + VEXOperandCode::G_ymm_M_xmm + } else { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + }), + 0x1C => (Opcode::VPABSB, if L { + VEXOperandCode::G_E_ymm + } else { + VEXOperandCode::G_E_xmm + }), + 0x1D => (Opcode::VPABSW, if L { + VEXOperandCode::G_E_ymm + } else { + VEXOperandCode::G_E_xmm + }), + 0x1E => (Opcode::VPABSD, if L { + VEXOperandCode::G_E_ymm + } else { + VEXOperandCode::G_E_xmm + }), + 0x20 => (Opcode::VPMOVSXBW, if L { + VEXOperandCode::G_ymm_E_xmm + } else { + VEXOperandCode::G_E_xmm + }), + 0x21 => (Opcode::VPMOVSXBD, if L { + VEXOperandCode::G_ymm_E_xmm + } else { + VEXOperandCode::G_E_xmm + }), + 0x22 => (Opcode::VPMOVSXBQ, if L { + VEXOperandCode::G_ymm_E_xmm + } else { + VEXOperandCode::G_E_xmm + }), + 0x23 => (Opcode::VPMOVSXWD, if L { + VEXOperandCode::G_ymm_E_xmm + } else { + VEXOperandCode::G_E_xmm + }), + 0x24 => (Opcode::VPMOVSXWQ, if L { + VEXOperandCode::G_ymm_E_xmm + } else { + VEXOperandCode::G_E_xmm + }), + 0x25 => (Opcode::VPMOVSXDQ, if L { + VEXOperandCode::G_ymm_E_xmm + } else { + VEXOperandCode::G_E_xmm + }), + 0x28 => (Opcode::VPMULDQ, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x29 => (Opcode::VPCMPEQQ, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x2A => (Opcode::VMOVNTDQA, if L { + VEXOperandCode::G_M_ymm + } else { + VEXOperandCode::G_M_xmm + }), + 0x2B => (Opcode::VPACKUSDW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x2C => (Opcode::VMASKMOVPS, if L { + VEXOperandCode::G_V_M_ymm + } else { + VEXOperandCode::G_V_M_xmm + }), + 0x2D => (Opcode::VMASKMOVPD, if L { + VEXOperandCode::G_V_M_ymm + } else { + VEXOperandCode::G_V_M_xmm + }), + 0x2E => (Opcode::VMASKMOVPS, if L { + VEXOperandCode::M_V_G_ymm + } else { + VEXOperandCode::M_V_G_xmm + }), + 0x2F => (Opcode::VMASKMOVPD, if L { + VEXOperandCode::M_V_G_ymm + } else { + VEXOperandCode::M_V_G_xmm + }), + 0x30 => (Opcode::VPMOVZXBW, if L { + VEXOperandCode::G_ymm_E_xmm + } else { + VEXOperandCode::G_E_xmm + }), + 0x31 => (Opcode::VPMOVZXBD, if L { + VEXOperandCode::G_ymm_E_xmm + } else { + VEXOperandCode::G_E_xmm + }), + 0x32 => (Opcode::VPMOVZXBQ, if L { + VEXOperandCode::G_ymm_E_xmm + } else { + VEXOperandCode::G_E_xmm + }), + 0x33 => (Opcode::VPMOVZXWD, if L { + VEXOperandCode::G_ymm_E_xmm + } else { + VEXOperandCode::G_E_xmm + }), + 0x34 => (Opcode::VPMOVZXWQ, if L { + VEXOperandCode::G_ymm_E_xmm + } else { + VEXOperandCode::G_E_xmm + }), + 0x35 => (Opcode::VPMOVZXDQ, if L { + VEXOperandCode::G_ymm_E_xmm + } else { + VEXOperandCode::G_E_xmm + }), + 0x36 => (Opcode::VPERMD, if L { + VEXOperandCode::G_V_E_ymm + } else { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + }), + 0x37 => (Opcode::VPCMPGTQ, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x38 => (Opcode::VPMINSB, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x39 => (Opcode::VPMINSD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x3A => (Opcode::VPMINUW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x3B => (Opcode::VPMINUD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x3C => (Opcode::VPMAXSB, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x3D => (Opcode::VPMAXSD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x3E => (Opcode::VPMAXUW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x3F => (Opcode::VPMAXUD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x40 => (Opcode::VPMULLD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0x41 => (Opcode::VPHMINPOSUW, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_E_xmm + }), + 0x45 => if instruction.prefixes.vex_unchecked().w() { + (Opcode::VPSRLVQ, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }) + } else { + (Opcode::VPSRLVD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }) + }, + 0x46 => (Opcode::VPSRAVD, if L { + if instruction.prefixes.vex_unchecked().w() { + return Err(DecodeError::InvalidOpcode); + } + VEXOperandCode::G_V_E_ymm + } else { + if instruction.prefixes.vex_unchecked().w() { + return Err(DecodeError::InvalidOpcode); + } + VEXOperandCode::G_V_E_xmm + }), + 0x47 => if instruction.prefixes.vex_unchecked().w() { + (Opcode::VPSLLVQ, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }) + } else { + (Opcode::VPSLLVD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }) + }, + 0x58 => (Opcode::VPBROADCASTD, if L { + VEXOperandCode::G_E_ymm + } else { + VEXOperandCode::G_E_xmm + }), + 0x59 => (Opcode::VPBROADCASTQ, if L { + VEXOperandCode::G_E_ymm + } else { + VEXOperandCode::G_E_xmm + }), + 0x5A => (Opcode::VBROADCASTI128, if L { + if instruction.prefixes.vex_unchecked().w() { + return Err(DecodeError::InvalidOpcode); + } + VEXOperandCode::G_ymm_M_xmm + } else { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + }), + 0x78 => (Opcode::VPBROADCASTB, if L { + VEXOperandCode::G_E_ymm + } else { + VEXOperandCode::G_E_ymm + }), + 0x79 => (Opcode::VPBROADCASTW, if L { + VEXOperandCode::G_E_ymm + } else { + VEXOperandCode::G_E_ymm + }), + 0x8C => { + if instruction.prefixes.vex_unchecked().w() { + (Opcode::VPMASKMOVQ, if L { + VEXOperandCode::G_V_M_ymm + } else { + VEXOperandCode::G_V_M_xmm + }) + } else { + (Opcode::VPMASKMOVD, if L { + VEXOperandCode::G_V_M_ymm + } else { + VEXOperandCode::G_V_M_xmm + }) + } + }, + 0x8E => { + if instruction.prefixes.vex_unchecked().w() { + (Opcode::VPMASKMOVQ, if L { + VEXOperandCode::M_V_G_ymm + } else { + VEXOperandCode::M_V_G_xmm + }) + } else { + (Opcode::VPMASKMOVD, if L { + VEXOperandCode::M_V_G_ymm + } else { + VEXOperandCode::M_V_G_xmm + }) + } + }, + 0x90 => { + if instruction.prefixes.vex_unchecked().w() { + (Opcode::VPGATHERDQ, if L { + VEXOperandCode::G_Ey_V_ymm + } else { + VEXOperandCode::G_Ex_V_xmm + }) + } else { + (Opcode::VPGATHERDD, if L { + VEXOperandCode::G_Ey_V_ymm + } else { + VEXOperandCode::G_Ex_V_xmm + }) + } + }, + 0x91 => { + if instruction.prefixes.vex_unchecked().w() { + (Opcode::VPGATHERQQ, if L { + VEXOperandCode::G_Ey_V_ymm + } else { + VEXOperandCode::G_Ex_V_xmm + }) + } else { + (Opcode::VPGATHERQD, if L { + VEXOperandCode::G_Ey_V_xmm + } else { + VEXOperandCode::G_Ex_V_xmm + }) + } + }, + 0x92 => { + if instruction.prefixes.vex_unchecked().w() { + (Opcode::VGATHERDPD, if L { + VEXOperandCode::G_Ey_V_ymm + } else { + VEXOperandCode::G_Ex_V_xmm + }) + } else { + (Opcode::VGATHERDPS, if L { + VEXOperandCode::G_Ey_V_ymm + } else { + VEXOperandCode::G_Ex_V_xmm + }) + } + }, + 0x93 => { + if instruction.prefixes.vex_unchecked().w() { + (Opcode::VGATHERQPD, if L { + VEXOperandCode::G_Ey_V_ymm + } else { + VEXOperandCode::G_Ex_V_xmm + }) + } else { + (Opcode::VGATHERQPS, if L { + VEXOperandCode::G_Ey_V_ymm + } else { + VEXOperandCode::G_Ex_V_xmm + }) + } + }, + 0x96 => { + if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFMADDSUB132PD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } else { + (Opcode::VFMADDSUB132PS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } + }, + 0x97 => { + if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFMSUBADD132PD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } else { + (Opcode::VFMSUBADD132PS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } + }, + 0x98 => { + if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFMADD132PD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } else { + (Opcode::VFMADD132PS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } + }, + 0x99 => if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFMADD132SD, VEXOperandCode::G_V_E_xmm /* 64bit */) + } else { + (Opcode::VFMADD132SS, VEXOperandCode::G_V_E_xmm /* 64bit */) + }, + 0x9A => { + if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFMSUB132PD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } else { + (Opcode::VFMSUB132PS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } + }, + 0x9B => if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFMSUB132SD, VEXOperandCode::G_V_E_xmm /* 64bit */) + } else { + (Opcode::VFMSUB132SS, VEXOperandCode::G_V_E_xmm /* 64bit */) + }, + 0x9C => { + if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFNMADD132PD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } else { + (Opcode::VFNMADD132PS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } + }, + 0x9D => if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFNMADD132SD, VEXOperandCode::G_V_E_xmm /* 64bit */) + } else { + (Opcode::VFNMADD132SS, VEXOperandCode::G_V_E_xmm /* 64bit */) + }, + 0x9E => { + if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFNMSUB132PD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } else { + (Opcode::VFNMSUB132PS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } + }, + 0x9F => if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFNMSUB132SD, VEXOperandCode::G_V_E_xmm /* 64bit */) + } else { + (Opcode::VFNMSUB132SS, VEXOperandCode::G_V_E_xmm /* 64bit */) + }, + 0xA6 => { + if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFMADDSUB213PD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } else { + (Opcode::VFMADDSUB213PS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } + }, + 0xA7 => { + if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFMSUBADD213PD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } else { + (Opcode::VFMSUBADD213PS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } + }, + 0xA8 => { + if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFMADD213PD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } else { + (Opcode::VFMADD213PS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } + }, + 0xA9 => if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFMADD231SD, VEXOperandCode::G_V_E_xmm /* 64bit */) + } else { + (Opcode::VFMADD231SS, VEXOperandCode::G_V_E_xmm /* 64bit */) + }, + 0xAA => { + if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFMSUB213PD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } else { + (Opcode::VFMSUB213PS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } + }, + 0xAB => if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFMSUB231SD, VEXOperandCode::G_V_E_xmm /* 64bit */) + } else { + (Opcode::VFMSUB231SS, VEXOperandCode::G_V_E_xmm /* 64bit */) + }, + 0xAC => { + if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFNMADD213PD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } else { + (Opcode::VFNMADD213PS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } + }, + 0xAD => if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFNMADD213SD, VEXOperandCode::G_V_E_xmm /* 64bit */) + } else { + (Opcode::VFNMADD213SS, VEXOperandCode::G_V_E_xmm /* 64bit */) + }, + 0xAE => { + if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFNMSUB213PD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } else { + (Opcode::VFNMSUB213PS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } + }, + 0xAF => if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFNMSUB213SD, VEXOperandCode::G_V_E_xmm /* 64bit */) + } else { + (Opcode::VFNMSUB213SS, VEXOperandCode::G_V_E_xmm /* 64bit */) + }, + 0xB6 => { + if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFMADDSUB231PD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } else { + (Opcode::VFMADDSUB231PS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } + }, + 0xB7 => { + if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFMSUBADD231PD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } else { + (Opcode::VFMSUBADD231PS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } + }, + 0xB8 => { + if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFMADD231PD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } else { + (Opcode::VFMADD231PS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } + }, + 0xB9 => if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFMADD231SD, VEXOperandCode::G_V_E_xmm /* 64bit */) + } else { + (Opcode::VFMADD231SS, VEXOperandCode::G_V_E_xmm /* 64bit */) + }, + 0xBA => { + if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFMSUB231PD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } else { + (Opcode::VFMSUB231PS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } + }, + 0xBB => if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFMSUB231SD, VEXOperandCode::G_V_E_xmm /* 64bit */) + } else { + (Opcode::VFMSUB231SS, VEXOperandCode::G_V_E_xmm /* 64bit */) + }, + 0xBC => { + if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFNMADD231PD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } else { + (Opcode::VFNMADD231PS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } + }, + 0xBD => if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFNMADD231SD, VEXOperandCode::G_V_E_xmm /* 64bit */) + } else { + (Opcode::VFNMADD231SS, VEXOperandCode::G_V_E_xmm /* 64bit */) + }, + 0xBE => { + if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFNMSUB231PD, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } else { + (Opcode::VFNMSUB231PS, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_ymm + }) + } + }, + 0xBF => if instruction.prefixes.vex_unchecked().w() { + (Opcode::VFNMSUB231SD, VEXOperandCode::G_V_E_xmm /* 64bit */) + } else { + (Opcode::VFNMSUB231SS, VEXOperandCode::G_V_E_xmm /* 64bit */) + }, + 0xDB => (Opcode::VAESIMC, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_E_xmm + }), + 0xDC => (Opcode::VAESENC, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xDD => (Opcode::VAESENCLAST, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xDE => (Opcode::VAESDEC, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xDF => (Opcode::VAESDECLAST, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), + 0xF7 => (Opcode::SHLX, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_E_V + }), + _ => { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } + } + } else if let VEXOpcodePrefix::PrefixF2 = p { + match opc { + 0xF5 => (Opcode::PDEP, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_V_E + }), + 0xF6 => (Opcode::MULX, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_V_E + }), + 0xF7 => (Opcode::SHRX, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_E_V + }), + _ => { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } + } + } else if let VEXOpcodePrefix::PrefixF3 = p { + match opc { + 0xF5 => (Opcode::PEXT, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_V_E + }), + 0xF7 => (Opcode::SARX, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_E_V + }), + _ => { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } + } + } else { + match opc { + 0xF2 => (Opcode::ANDN, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_V_E + }), + 0xF3 => (Opcode::Invalid, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::BMI1_F3 + }), + 0xF5 => (Opcode::BZHI, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_E_V + }), + 0xF7 => (Opcode::BEXTR, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_E_V + }), + _ => { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } + } + } + } + VEXOpcodeMap::Map0F3A => { + if let VEXOpcodePrefix::Prefix66 = p { + // possibly valid! + match opc { + 0x00 => (Opcode::VPERMQ, if L { + if !instruction.prefixes.vex_unchecked().w() { + return Err(DecodeError::InvalidOpcode); + } + VEXOperandCode::G_E_ymm_imm8 + } else { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + }), + 0x01 => (Opcode::VPERMPD, if L { + if !instruction.prefixes.vex_unchecked().w() { + return Err(DecodeError::InvalidOpcode); + } + VEXOperandCode::G_E_ymm_imm8 + } else { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + }), + 0x02 => (Opcode::VPBLENDD, if L { + if instruction.prefixes.vex_unchecked().w() { + return Err(DecodeError::InvalidOpcode); + } + VEXOperandCode::G_V_E_ymm_imm8 + } else { + if instruction.prefixes.vex_unchecked().w() { + return Err(DecodeError::InvalidOpcode); + } + VEXOperandCode::G_V_E_xmm_imm8 + }), + 0x04 => (Opcode::VPERMILPS, if L { + VEXOperandCode::G_E_ymm_imm8 + } else { + VEXOperandCode::G_E_xmm_imm8 + }), + 0x05 => (Opcode::VPERMILPD, if L { + VEXOperandCode::G_E_ymm_imm8 + } else { + VEXOperandCode::G_E_xmm_imm8 + }), + 0x06 => (Opcode::VPERM2F128, if L { + if instruction.prefixes.vex_unchecked().w() { + return Err(DecodeError::InvalidOpcode); + } + VEXOperandCode::G_V_E_ymm_imm8 + } else { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + }), + 0x08 => (Opcode::VROUNDPS, if L { + VEXOperandCode::G_E_ymm_imm8 + } else { + VEXOperandCode::G_E_xmm_imm8 + }), + 0x09 => (Opcode::VROUNDPD, if L { + VEXOperandCode::G_E_ymm_imm8 + } else { + VEXOperandCode::G_E_xmm_imm8 + }), + 0x0A => (Opcode::VROUNDSS, if L { + VEXOperandCode::G_V_E_xmm_imm8 + } else { + VEXOperandCode::G_V_E_xmm_imm8 + }), + 0x0B => (Opcode::VROUNDSD, if L { + VEXOperandCode::G_V_E_xmm_imm8 + } else { + VEXOperandCode::G_V_E_xmm_imm8 + }), + 0x0C => (Opcode::VBLENDPS, if L { + VEXOperandCode::G_V_E_ymm_imm8 + } else { + VEXOperandCode::G_V_E_xmm_imm8 + }), + 0x0D => (Opcode::VBLENDPD, if L { + VEXOperandCode::G_V_E_ymm_imm8 + } else { + VEXOperandCode::G_V_E_xmm_imm8 + }), + 0x0E => (Opcode::VPBLENDW, if L { + VEXOperandCode::G_V_E_ymm_imm8 + } else { + VEXOperandCode::G_V_E_xmm_imm8 + }), + 0x0F => (Opcode::VPALIGNR, if L { + VEXOperandCode::G_V_E_ymm_imm8 + } else { + VEXOperandCode::G_V_E_xmm_imm8 + }), + 0x14 => (Opcode::VPEXTRB, if L || instruction.prefixes.vex_unchecked().w() { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::Ev_G_xmm_imm8 + }), + 0x15 => (Opcode::VPEXTRW, if L || instruction.prefixes.vex_unchecked().w() { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::Ev_G_xmm_imm8 + }), + 0x16 => { + (Opcode::VPEXTRD, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + // varies on W + VEXOperandCode::Ev_G_xmm_imm8 + }) + }, + 0x17 => (Opcode::VEXTRACTPS, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::Ev_G_xmm_imm8 + }), + 0x18 => if instruction.prefixes.vex_unchecked().w() { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + (Opcode::VINSERTF128, if L { + VEXOperandCode::G_ymm_V_ymm_E_xmm_imm8 + } else { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + }) + }, + 0x19 => if instruction.prefixes.vex_unchecked().w() { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + (Opcode::VEXTRACTF128, if L { + VEXOperandCode::E_xmm_G_ymm_imm8 + } else { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + }) + }, + 0x1D => (Opcode::VCVTPS2PH, if L { + VEXOperandCode::E_xmm_G_ymm_imm8 + } else { + VEXOperandCode::E_G_xmm_imm8 + }), + 0x20 => (Opcode::VPINSRB, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_V_xmm_Ev_imm8 + }), + 0x21 => (Opcode::VINSERTPS, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_V_E_xmm_imm8 + }), + 0x22 => { + (Opcode::VPINSRD, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_V_xmm_Ev_imm8 + }) + }, + 0x38 => (Opcode::VINSERTI128, if L { + VEXOperandCode::G_ymm_V_ymm_E_xmm_imm8 + } else { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + }), + 0x39 => (Opcode::VEXTRACTI128, if L { + VEXOperandCode::E_xmm_G_ymm_imm8 + } else { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + }), + 0x40 => (Opcode::VDPPS, if L { + VEXOperandCode::G_V_E_ymm_imm8 + } else { + VEXOperandCode::G_V_E_xmm_imm8 + }), + 0x41 => (Opcode::VDPPD, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_V_E_xmm_imm8 + }), + 0x42 => (Opcode::VMPSADBW, if L { + VEXOperandCode::G_V_E_ymm_imm8 + } else { + VEXOperandCode::G_V_E_xmm_imm8 + }), + 0x44 => (Opcode::VPCLMULQDQ, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_V_E_xmm_imm8 + }), + 0x46 => (Opcode::VPERM2I128, if L { + if instruction.prefixes.vex_unchecked().w() { + return Err(DecodeError::InvalidOpcode); + } + VEXOperandCode::G_V_E_ymm_imm8 + } else { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + }), + 0x4A => (Opcode::VBLENDVPS, if L { + VEXOperandCode::G_V_E_ymm_ymm4 + } else { + VEXOperandCode::G_V_E_xmm_xmm4 + }), + 0x4B => (Opcode::VBLENDVPD, if L { + VEXOperandCode::G_V_E_ymm_ymm4 + } else { + VEXOperandCode::G_V_E_xmm_xmm4 + }), + 0x4C => if instruction.prefixes.vex_unchecked().w() { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + (Opcode::VPBLENDVB, if L { + VEXOperandCode::G_V_E_ymm_ymm4 + } else { + VEXOperandCode::G_V_E_xmm_xmm4 + }) + }, + 0x60 => (Opcode::VPCMPESTRM, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_E_xmm_imm8 + }), + 0x61 => (Opcode::VPCMPESTRI, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_E_xmm_imm8 + }), + 0x62 => (Opcode::VPCMPISTRM, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_E_xmm_imm8 + }), + 0x63 => (Opcode::VPCMPISTRI, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_E_xmm_imm8 + }), + 0xDF => (Opcode::VAESKEYGENASSIST, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_E_xmm_imm8 + }), + _ => { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } + } + } else if let VEXOpcodePrefix::PrefixF2 = p { + match opc { + 0xF0 => (Opcode::RORX, if L { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } else { + VEXOperandCode::G_E_Ib + }), + _ => { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } + } + } else { + // the only VEX* 0f3a instructions have an implied 66 prefix. + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } + } + }; + instruction.opcode = opcode; + read_vex_operands(words, instruction, operand_code) +} -- cgit v1.1