diff options
Diffstat (limited to 'src/real_mode')
| -rw-r--r-- | src/real_mode/display.rs | 3729 | ||||
| -rw-r--r-- | src/real_mode/evex.rs | 18 | ||||
| -rw-r--r-- | src/real_mode/mod.rs | 10677 | ||||
| -rw-r--r-- | src/real_mode/uarch.rs | 226 | ||||
| -rw-r--r-- | src/real_mode/vex.rs | 3356 | 
5 files changed, 18005 insertions, 1 deletions
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, "<all features>"); +        } else if self == &InstDecoder::minimal() { +            return write!(f, "<no features>"); +        } +        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 <T: fmt::Write, Y: YaxColors> Colorize<T, Y> 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 <T: fmt::Write, Y: YaxColors> Colorize<T, Y> 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<T, Y> 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<T: fmt::Write>(&self, out: &mut T) -> fmt::Result { +        self.display_with(DisplayStyle::Intel).contextualize(&NoColors, 0, Some(&NoContext), out) +    } +} + +fn contextualize_intel<T: fmt::Write, Y: YaxColors>(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<T: fmt::Write, Y: YaxColors>(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<u32, NoContext, T, Y> 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 <T: fmt::Write, Y: YaxColors> ShowContextual<u64, [Option<alloc::string::String>], T, Y> for Instruction { +    fn contextualize(&self, colors: &Y, _address: u64, context: Option<&[Option<alloc::string::String>]>, 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<H: Hasher>(&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<bool> 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<u8> { +        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::<OperandSpec>(), 1); +    assert_eq!(core::mem::size_of::<RegSpec>(), 2); +    // assert_eq!(core::mem::size_of::<Prefixes>(), 4); +    // assert_eq!(core::mem::size_of::<Instruction>(), 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<T> 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<u32>; +    #[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<Mutex<InstDecoder>>`, 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<Instruction, DecodeError> { +        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<Arch> for InstDecoder { +    fn decode<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>>(&self, words: &mut T) -> Result<Instruction, <Arch as yaxpeax_arch::Arch>::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<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>>(&self, instr: &mut Instruction, words: &mut T) -> Result<(), <Arch as yaxpeax_arch::Arch>::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<ConditionCode> { +        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<MemoryAccessSize> { +        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<Segment> { +        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<PrefixVex> { +        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<PrefixEvex> { +        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<ZOperandInstructions, EmbeddedOperandInstructions> { +        // 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::<OpcodeRecord>(), 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<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8, width: u8) -> Result<OperandSpec, DecodeError> { +    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<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8) -> Result<OperandSpec, DecodeError> { +    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<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8) -> Result<OperandSpec, DecodeError> { +    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<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8) -> Result<OperandSpec, DecodeError> { +    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<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8) -> Result<OperandSpec, DecodeError> { +    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<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8, bank: RegisterBank) -> Result<OperandSpec, DecodeError> { +    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<OperandSpec, DecodeError> { +    instr.regs[1] = RegSpec::from_parts(modrm & 7, reg_bank); +    Ok(OperandSpec::RegMMM) +} + +#[allow(non_snake_case)] +fn read_sib<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8) -> Result<OperandSpec, DecodeError> { +    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<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8) -> Result<OperandSpec, DecodeError> { +    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<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8) -> Result<OperandSpec, DecodeError> { +    // 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<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::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<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::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<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::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<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::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<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>>(bytes: &mut T, width: u8) -> Result<u32, DecodeError> { +    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<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>>(bytes: &mut T, num_width: u8) -> Result<i32, DecodeError> { +    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<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>>(bytes: &mut T, width: u8) -> Result<u32, DecodeError> { +    read_num(bytes, width) +} + +#[inline] +fn read_modrm<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>>(words: &mut T) -> Result<u8, DecodeError> { +    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<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::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<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::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<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::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<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::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) +}  | 
