diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/long_mode/evex.rs | 11 | ||||
| -rw-r--r-- | src/long_mode/mod.rs | 2 | ||||
| -rw-r--r-- | src/protected_mode/display.rs | 982 | ||||
| -rw-r--r-- | src/protected_mode/evex.rs | 17 | ||||
| -rw-r--r-- | src/protected_mode/mod.rs | 834 | ||||
| -rw-r--r-- | src/protected_mode/vex.rs | 2 | ||||
| -rw-r--r-- | src/shared/evex.in | 102 | 
7 files changed, 1851 insertions, 99 deletions
diff --git a/src/long_mode/evex.rs b/src/long_mode/evex.rs index adfd014..483747b 100644 --- a/src/long_mode/evex.rs +++ b/src/long_mode/evex.rs @@ -2,5 +2,16 @@  use crate::long_mode::{DecodeError, RegSpec, RegisterBank, Instruction, Opcode};  use crate::long_mode::{read_modrm, read_E_vex, read_imm_unsigned}; +const DEFAULT_EVEX_REGISTER_SIZE: RegisterBank = RegisterBank::Q; +const DEFAULT_EVEX_REGISTER_WIDTH: u8 = 8; + +fn isa_has_qwords() -> bool { +    true +} + +fn apply_disp_scale(inst: &mut Instruction) { +    inst.disp *= inst.mem_size as u64; +} +  include!("../shared/generated_evex.in");  include!("../shared/evex.in"); diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs index 59bb321..1039260 100644 --- a/src/long_mode/mod.rs +++ b/src/long_mode/mod.rs @@ -7047,7 +7047,7 @@ fn read_instr<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T, in                      return Err(DecodeError::InvalidPrefixes);                  } else {                      instruction.prefixes = prefixes; -                    evex::read_evex(&mut bytes_iter, instruction, length)?; +                    evex::read_evex(&mut bytes_iter, instruction, length, None)?;                      if decoder != &InstDecoder::default() {                          decoder.revise_instruction(instruction)?;                      } diff --git a/src/protected_mode/display.rs b/src/protected_mode/display.rs index e51d2dc..f258bad 100644 --- a/src/protected_mode/display.rs +++ b/src/protected_mode/display.rs @@ -5,7 +5,7 @@ use core::fmt;  use yaxpeax_arch::{Colorize, ShowContextual, NoColors, YaxColors};  use yaxpeax_arch::display::*; -use crate::protected_mode::{RegSpec, Opcode, Operand, InstDecoder, Instruction, Segment, PrefixVex, OperandSpec}; +use crate::protected_mode::{RegSpec, Opcode, Operand, MergeMode, InstDecoder, Instruction, Segment, PrefixVex, OperandSpec};  impl fmt::Display for InstDecoder {      fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -166,6 +166,44 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Operand {              &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)))              } @@ -227,6 +265,69 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Operand {                  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(()) },          }      } @@ -655,6 +756,7 @@ const MNEMONICS: &[&'static str] = &[      "xorpd",      "vmovddup",      "vpshuflw", +    "vpshufhw",      "vhaddps",      "vhsubps",      "vaddsubps", @@ -826,6 +928,7 @@ const MNEMONICS: &[&'static str] = &[      "vpabsd",      "vpabsw",      "vpackssdw", +    "vpackusdw",      "vpacksswb",      "vpackuswb",      "vpaddb", @@ -837,12 +940,12 @@ const MNEMONICS: &[&'static str] = &[      "vpaddusw",      "vpaddw",      "vpalignr", -    "vandps",      "vandpd", -    "vorps", +    "vandps",      "vorpd", -    "vandnps", +    "vorps",      "vandnpd", +    "vandnps",      "vpand",      "vpandn",      "vpavgb", @@ -863,6 +966,8 @@ const MNEMONICS: &[&'static str] = &[      "vpcmpgtd",      "vpcmpgtq",      "vpcmpgtw", +    "vpcmpestri", +    "vpcmpestrm",      "vpcmpistri",      "vpcmpistrm",      "vperm2f128", @@ -884,7 +989,7 @@ const MNEMONICS: &[&'static str] = &[      "vphaddd",      "vphaddsw",      "vphaddw", -    "vphaddubsw", +    "vpmaddubsw",      "vphminposuw",      "vphsubd",      "vphsubsw", @@ -902,8 +1007,11 @@ const MNEMONICS: &[&'static str] = &[      "vpmaxub",      "vpmaxuw",      "vpmaxud", +    "vpminsb",      "vpminsw",      "vpminsd", +    "vpminub", +    "vpminuw",      "vpminud",      "vpmovmskb",      "vpmovsxbd", @@ -922,6 +1030,7 @@ const MNEMONICS: &[&'static str] = &[      "vpmulhrsw",      "vpmulhuw",      "vpmulhw", +    "vpmullq",      "vpmulld",      "vpmullw",      "vpmuludq", @@ -992,6 +1101,9 @@ const MNEMONICS: &[&'static str] = &[      "vxorpd",      "vxorps",      "vzeroupper", +    "vzeroall", +    "vldmxcsr", +    "vstmxcsr",      "pclmulqdq",      "aeskeygenassist",      "aesimc", @@ -1219,6 +1331,7 @@ const MNEMONICS: &[&'static str] = &[      "jrcxz",      "pusha",      "popa", +    "bound",      "arpl",      "aas",      "aaa", @@ -1315,6 +1428,378 @@ const MNEMONICS: &[&'static str] = &[      // 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",  ];  impl Opcode { @@ -1328,6 +1813,95 @@ impl Opcode {  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 | @@ -1434,6 +2008,7 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode {              Opcode::VPMULHRSW |              Opcode::VPMULHUW |              Opcode::VPMULHW | +            Opcode::VPMULLQ |              Opcode::VPMULLD |              Opcode::VPMULLW |              Opcode::VPMULUDQ | @@ -1451,6 +2026,34 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode {              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 | @@ -1470,13 +2073,14 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode {              Opcode::VSQRTSS |              Opcode::VPSADBW |              Opcode::VMPSADBW | +            Opcode::VDBPSADBW |              Opcode::VPHADDD |              Opcode::VPHADDSW |              Opcode::VPHADDW |              Opcode::VPHSUBD |              Opcode::VPHSUBSW |              Opcode::VPHSUBW | -            Opcode::VPHADDUBSW | +            Opcode::VPMADDUBSW |              Opcode::VPMADDWD |              Opcode::VDPPD |              Opcode::VDPPS | @@ -1499,6 +2103,19 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode {              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 | @@ -1584,6 +2201,8 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode {              Opcode::SUB |              Opcode::POPCNT |              Opcode::LZCNT | +            Opcode::VPLZCNTD | +            Opcode::VPLZCNTQ |              Opcode::BT |              Opcode::BTS |              Opcode::BTR | @@ -1702,12 +2321,48 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode {              Opcode::FXTRACT |              Opcode::FYL2X |              Opcode::FYL2XP1 | -            Opcode::AAS |              Opcode::AAA | +            Opcode::AAS |              Opcode::DAS |              Opcode::DAA |              Opcode::ADX |              Opcode::AMX | +            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 | @@ -1786,12 +2441,43 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode {              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 | @@ -1803,6 +2489,7 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode {              Opcode::VBROADCASTI128 |              Opcode::VBROADCASTSD |              Opcode::VBROADCASTSS | +            Opcode::VPBROADCASTM |              Opcode::VEXTRACTF128 |              Opcode::VEXTRACTI128 |              Opcode::VEXTRACTPS | @@ -1811,10 +2498,49 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode {              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 | @@ -1845,6 +2571,32 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode {              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 | @@ -1883,6 +2635,9 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode {              Opcode::PMOVZXDQ |              Opcode::PMOVZXWD |              Opcode::PMOVZXWQ | +            Opcode::KUNPCKBW | +            Opcode::KUNPCKWD | +            Opcode::KUNPCKDQ |              Opcode::VUNPCKHPD |              Opcode::VUNPCKHPS |              Opcode::VUNPCKLPD | @@ -1898,9 +2653,12 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode {              Opcode::VSHUFPD |              Opcode::VSHUFPS |              Opcode::VPACKSSDW | +            Opcode::VPACKUSDW |              Opcode::PACKUSDW |              Opcode::VPACKSSWB |              Opcode::VPACKUSWB | +            Opcode::VALIGND | +            Opcode::VALIGNQ |              Opcode::VPALIGNR |              Opcode::PALIGNR |              Opcode::VPERM2F128 | @@ -1911,6 +2669,17 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode {              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 | @@ -1929,11 +2698,34 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode {              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 | @@ -2001,6 +2793,11 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode {              Opcode::SHUFPD |              Opcode::SHUFPS |              Opcode::PMOVMSKB | +            Opcode::KMOVB | +            Opcode::KMOVW | +            Opcode::KMOVD | +            Opcode::KMOVQ | +            Opcode::BNDMOV |              Opcode::LDDQU |              Opcode::CMC |              Opcode::CLC | @@ -2117,6 +2914,32 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode {              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 | @@ -2125,6 +2948,10 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode {              Opcode::VMAXPS |              Opcode::VMAXSD |              Opcode::VMAXSS | +            Opcode::VPMAXSQ | +            Opcode::VPMAXUQ | +            Opcode::VPMINSQ | +            Opcode::VPMINUQ |              Opcode::VMINPD |              Opcode::VMINPS |              Opcode::VMINSD | @@ -2137,6 +2964,8 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode {              Opcode::VPCMPGTD |              Opcode::VPCMPGTQ |              Opcode::VPCMPGTW | +            Opcode::VPCMPESTRI | +            Opcode::VPCMPESTRM |              Opcode::VPCMPISTRI |              Opcode::VPCMPISTRM |              Opcode::VPMAXSB | @@ -2145,9 +2974,22 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode {              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 | @@ -2228,6 +3070,8 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode {              Opcode::FXRSTOR |              Opcode::LDMXCSR |              Opcode::STMXCSR | +            Opcode::VLDMXCSR | +            Opcode::VSTMXCSR |              Opcode::XSAVE |              Opcode::XSAVEC |              Opcode::XSAVES | @@ -2337,7 +3181,14 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode {              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 | @@ -2462,6 +3313,17 @@ impl Instruction {      }  } +const MEM_SIZE_STRINGS: [&'static str; 64] = [ +    "byte", "word", "BUG", "dword", "BUG", "BUG", "BUG", "qword", +    "far", "mword", "BUG", "BUG", "BUG", "BUG", "BUG", "xmmword", +    "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", +    "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "ymmword", +    "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", +    "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", +    "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", +    "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "ptr", "zmmword", +]; +  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 ")?; @@ -2469,11 +3331,8 @@ fn contextualize_intel<T: fmt::Write, Y: YaxColors>(instr: &Instruction, colors:      if instr.prefixes.rep_any() {          if [Opcode::MOVS, Opcode::CMPS, Opcode::LODS, Opcode::STOS, Opcode::INS, Opcode::OUTS].contains(&instr.opcode) { -            // only a few of you actually use the prefix...              if instr.prefixes.rep() {                  write!(out, "rep ")?; -            } else if instr.prefixes.repz() { -                write!(out, "repz ")?;              } else if instr.prefixes.repnz() {                  write!(out, "repnz ")?;              } @@ -2489,53 +3348,19 @@ fn contextualize_intel<T: fmt::Write, Y: YaxColors>(instr: &Instruction, colors:      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)?;          } - -        let x = Operand::from_spec(instr, instr.operands[0]);          x.colorize(colors, out)?;          for i in 1..instr.operand_count {              match instr.opcode { -                Opcode::MOVSX_b | -                Opcode::MOVZX_b => { -                    match &instr.operands[i as usize] { -                        &OperandSpec::Nothing => { -                            return Ok(()); -                        }, -                        &OperandSpec::RegMMM => { -                            out.write_str(", ")?; -                        } -                        _ => { -                            out.write_str(", byte ")?; -                            if let Some(prefix) = instr.segment_override_for_op(i) { -                                write!(out, "{}:", prefix)?; -                            } -                        } -                    } -                    let x = Operand::from_spec(instr, instr.operands[i as usize]); -                    x.colorize(colors, out)? -                }, -                Opcode::MOVSX_w | -                Opcode::MOVZX_w => { -                    match &instr.operands[i as usize] { -                        &OperandSpec::Nothing => { -                            return Ok(()); -                        }, -                        &OperandSpec::RegMMM => { -                            out.write_str(", ")?; -                        } -                        _ => { -                            out.write_str(", word ")?; -                            if let Some(prefix) = instr.segment_override_for_op(i) { -                                write!(out, "{}:", prefix)?; -                            } -                        } -                    } -                    let x = Operand::from_spec(instr, instr.operands[i as usize]); -                    x.colorize(colors, out)? -                },                  _ => {                      match &instr.operands[i as usize] {                          &OperandSpec::Nothing => { @@ -2543,11 +3368,57 @@ fn contextualize_intel<T: fmt::Write, Y: YaxColors>(instr: &Instruction, colors:                          },                          _ => {                              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)?;                              } -                            let x = Operand::from_spec(instr, instr.operands[i as usize]); -                            x.colorize(colors, out)? +                            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 { +                                        Operand::from_spec(instr, instr.operands[i as usize - 1]).width() / instr.mem_size +                                    }; +                                    write!(out, "{{1to{}}}", scale)?; +                                } +                            }                          }                      }                  } @@ -2578,8 +3449,6 @@ fn contextualize_c<T: fmt::Write, Y: YaxColors>(instr: &Instruction, _colors: &Y              // only a few of you actually use the prefix...              if instr.prefixes.rep() {                  out.write_str("rep ")?; -            } else if instr.prefixes.repz() { -                out.write_str("repz ")?;              } else if instr.prefixes.repnz() {                  out.write_str("repnz ")?;              } // TODO: other rep kinds? @@ -2804,8 +3673,6 @@ impl <T: fmt::Write, Y: YaxColors> ShowContextual<u64, [Option<alloc::string::St              // only a few of you actually use the prefix...              if self.prefixes.rep() {                  write!(out, "rep ")?; -            } else if self.prefixes.repz() { -                write!(out, "repz ")?;              } else if self.prefixes.repnz() {                  write!(out, "repnz ")?;              } @@ -2831,7 +3698,8 @@ impl <T: fmt::Write, Y: YaxColors> ShowContextual<u64, [Option<alloc::string::St                  x.colorize(colors, out)?;              }          }; -        for i in 1..4 { +        for i in 1..self.operand_count { +            let i = i as usize;              match self.opcode {                  Opcode::MOVSX_b |                  Opcode::MOVZX_b => { diff --git a/src/protected_mode/evex.rs b/src/protected_mode/evex.rs new file mode 100644 index 0000000..9d2a093 --- /dev/null +++ b/src/protected_mode/evex.rs @@ -0,0 +1,17 @@ +// use crate::long_mode::{OperandSpec, DecodeError, RegSpec, RegisterBank, Instruction, Opcode}; +use crate::protected_mode::{DecodeError, RegSpec, RegisterBank, Instruction, Opcode}; +use crate::protected_mode::{read_modrm, read_E_vex, read_imm_unsigned}; + +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/protected_mode/mod.rs b/src/protected_mode/mod.rs index bbcb9cb..dec7c86 100644 --- a/src/protected_mode/mod.rs +++ b/src/protected_mode/mod.rs @@ -1,4 +1,5 @@  mod vex; +mod evex;  #[cfg(feature = "fmt")]  mod display;  pub mod uarch; @@ -131,6 +132,19 @@ impl RegSpec {          }      } +    /// 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 { @@ -378,6 +392,9 @@ pub enum Operand {      ImmediateU32(u32),      ImmediateI32(i32),      Register(RegSpec), +    RegisterMaskMerge(RegSpec, RegSpec, MergeMode), +    RegisterMaskMergeSae(RegSpec, RegSpec, MergeMode, SaeMode), +    RegisterMaskMergeSaeNoround(RegSpec, RegSpec, MergeMode),      DisplacementU16(u16),      DisplacementU32(u32),      RegDeref(RegSpec), @@ -388,10 +405,32 @@ pub enum Operand {      RegScaleDisp(RegSpec, u8, i32),      RegIndexBaseScale(RegSpec, RegSpec, u8),      RegIndexBaseScaleDisp(RegSpec, RegSpec, u8, i32), +    RegDerefMasked(RegSpec, RegSpec), +    RegDispMasked(RegSpec, i32, RegSpec), +    RegScaleMasked(RegSpec, u8, RegSpec), +    RegIndexBaseMasked(RegSpec, RegSpec, RegSpec), +    RegIndexBaseDispMasked(RegSpec, RegSpec, i32, RegSpec), +    RegScaleDispMasked(RegSpec, u8, i32, RegSpec), +    RegIndexBaseScaleMasked(RegSpec, RegSpec, u8, RegSpec), +    RegIndexBaseScaleDispMasked(RegSpec, RegSpec, u8, i32, RegSpec),      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::RegIndexBaseScale => OperandSpec::RegIndexBaseScale_mask, +            OperandSpec::RegIndexBaseScaleDisp => OperandSpec::RegIndexBaseScaleDisp_mask, +            o => o, +        } +    }      pub fn is_memory(&self) -> bool {          match self {              OperandSpec::DispU16 | @@ -405,7 +444,13 @@ impl OperandSpec {              OperandSpec::RegIndexBaseDisp |              OperandSpec::RegScaleDisp |              OperandSpec::RegIndexBaseScale | -            OperandSpec::RegIndexBaseScaleDisp => { +            OperandSpec::RegIndexBaseScaleDisp | +            OperandSpec::Deref_mask | +            OperandSpec::RegDisp_mask | +            OperandSpec::RegScale_mask | +            OperandSpec::RegScaleDisp_mask | +            OperandSpec::RegIndexBaseScale_mask | +            OperandSpec::RegIndexBaseScaleDisp_mask => {                  true              },              OperandSpec::ImmI8 | @@ -414,8 +459,14 @@ impl OperandSpec {              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 => { @@ -424,6 +475,54 @@ impl OperandSpec {          }      }  } +#[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 +        } +    } +} +#[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 { +    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 { @@ -434,13 +533,56 @@ impl Operand {              OperandSpec::RegRRR => {                  Operand::Register(inst.modrm_rrr)              } +            OperandSpec::RegRRR_maskmerge => { +                Operand::RegisterMaskMerge( +                    inst.modrm_rrr, +                    RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg()), +                    MergeMode::from(inst.prefixes.evex_unchecked().merge()), +                ) +            } +            OperandSpec::RegRRR_maskmerge_sae => { +                Operand::RegisterMaskMergeSae( +                    inst.modrm_rrr, +                    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.modrm_rrr, +                    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.modrm_mmm)              } +            OperandSpec::RegMMM_maskmerge => { +                Operand::RegisterMaskMerge( +                    inst.modrm_mmm, +                    RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg()), +                    MergeMode::from(inst.prefixes.evex_unchecked().merge()), +                ) +            } +            OperandSpec::RegMMM_maskmerge_sae_noround => { +                Operand::RegisterMaskMergeSaeNoround( +                    inst.modrm_mmm, +                    RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg()), +                    MergeMode::from(inst.prefixes.evex_unchecked().merge()), +                ) +            }              OperandSpec::RegVex => {                  Operand::Register(inst.vex_reg)              } +            OperandSpec::RegVex_maskmerge => { +                Operand::RegisterMaskMerge( +                    inst.vex_reg, +                    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.vex_reg.bank })              } @@ -482,6 +624,48 @@ impl Operand {              OperandSpec::RegIndexBaseScaleDisp => {                  Operand::RegIndexBaseScaleDisp(inst.modrm_mmm, inst.sib_index, inst.scale, inst.disp as i32)              } +            OperandSpec::Deref_mask => { +                if inst.prefixes.evex_unchecked().mask_reg() != 0 { +                    Operand::RegDerefMasked(inst.modrm_mmm, RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) +                } else { +                    Operand::RegDeref(inst.modrm_mmm) +                } +            } +            OperandSpec::RegDisp_mask => { +                if inst.prefixes.evex_unchecked().mask_reg() != 0 { +                    Operand::RegDispMasked(inst.modrm_mmm, inst.disp as i32, RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) +                } else { +                    Operand::RegDisp(inst.modrm_mmm, inst.disp as i32) +                } +            } +            OperandSpec::RegScale_mask => { +                if inst.prefixes.evex_unchecked().mask_reg() != 0 { +                    Operand::RegScaleMasked(inst.sib_index, inst.scale, RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) +                } else { +                    Operand::RegScale(inst.sib_index, inst.scale) +                } +            } +            OperandSpec::RegScaleDisp_mask => { +                if inst.prefixes.evex_unchecked().mask_reg() != 0 { +                    Operand::RegScaleDispMasked(inst.sib_index, inst.scale, inst.disp as i32, RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) +                } else { +                    Operand::RegScaleDisp(inst.sib_index, inst.scale, inst.disp as i32) +                } +            } +            OperandSpec::RegIndexBaseScale_mask => { +                if inst.prefixes.evex_unchecked().mask_reg() != 0 { +                    Operand::RegIndexBaseScaleMasked(inst.modrm_mmm, inst.sib_index, inst.scale, RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) +                } else { +                    Operand::RegIndexBaseScale(inst.modrm_mmm, inst.sib_index, inst.scale) +                } +            } +            OperandSpec::RegIndexBaseScaleDisp_mask => { +                if inst.prefixes.evex_unchecked().mask_reg() != 0 { +                    Operand::RegIndexBaseScaleDispMasked(inst.modrm_mmm, inst.sib_index, inst.scale, inst.disp as i32, RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) +                } else { +                    Operand::RegIndexBaseScaleDisp(inst.modrm_mmm, inst.sib_index, inst.scale, inst.disp as i32) +                } +            }          }      }      pub fn is_memory(&self) -> bool { @@ -495,7 +679,15 @@ impl Operand {              Operand::RegIndexBaseDisp(_, _, _) |              Operand::RegScaleDisp(_, _, _) |              Operand::RegIndexBaseScale(_, _, _) | -            Operand::RegIndexBaseScaleDisp(_, _, _, _) => { +            Operand::RegIndexBaseScaleDisp(_, _, _, _) | +            Operand::RegDerefMasked(_, _) | +            Operand::RegDispMasked(_, _, _) | +            Operand::RegScaleMasked(_, _, _) | +            Operand::RegIndexBaseMasked(_, _, _) | +            Operand::RegIndexBaseDispMasked(_, _, _, _) | +            Operand::RegScaleDispMasked(_, _, _, _) | +            Operand::RegIndexBaseScaleMasked(_, _, _, _) | +            Operand::RegIndexBaseScaleDispMasked(_, _, _, _, _) => {                  true              },              Operand::ImmediateI8(_) | @@ -505,6 +697,9 @@ impl Operand {              Operand::ImmediateU32(_) |              Operand::ImmediateI32(_) |              Operand::Register(_) | +            Operand::RegisterMaskMerge(_, _, _) | +            Operand::RegisterMaskMergeSae(_, _, _, _) | +            Operand::RegisterMaskMergeSaeNoround(_, _, _) |              Operand::Nothing => {                  false              } @@ -523,6 +718,9 @@ impl Operand {              Operand::Register(reg) => {                  reg.width()              } +            Operand::RegisterMaskMerge(reg, _, _) => { +                reg.width() +            }              Operand::ImmediateI8(_) |              Operand::ImmediateU8(_) => {                  1 @@ -1186,6 +1384,7 @@ pub enum Opcode {      VMOVDDUP,      VPSHUFLW, +    VPSHUFHW,      VHADDPS,      VHSUBPS,      VADDSUBPS, @@ -1358,6 +1557,7 @@ pub enum Opcode {      VPABSD,      VPABSW,      VPACKSSDW, +    VPACKUSDW,      VPACKSSWB,      VPACKUSWB,      VPADDB, @@ -1395,6 +1595,8 @@ pub enum Opcode {      VPCMPGTD,      VPCMPGTQ,      VPCMPGTW, +    VPCMPESTRI, +    VPCMPESTRM,      VPCMPISTRI,      VPCMPISTRM,      VPERM2F128, @@ -1416,7 +1618,7 @@ pub enum Opcode {      VPHADDD,      VPHADDSW,      VPHADDW, -    VPHADDUBSW, +    VPMADDUBSW,      VPHMINPOSUW,      VPHSUBD,      VPHSUBSW, @@ -1434,8 +1636,11 @@ pub enum Opcode {      VPMAXUB,      VPMAXUW,      VPMAXUD, +    VPMINSB,      VPMINSW,      VPMINSD, +    VPMINUB, +    VPMINUW,      VPMINUD,      VPMOVMSKB,      VPMOVSXBD, @@ -1454,6 +1659,7 @@ pub enum Opcode {      VPMULHRSW,      VPMULHUW,      VPMULHW, +    VPMULLQ,      VPMULLD,      VPMULLW,      VPMULUDQ, @@ -1524,6 +1730,9 @@ pub enum Opcode {      VXORPD,      VXORPS,      VZEROUPPER, +    VZEROALL, +    VLDMXCSR, +    VSTMXCSR,      PCLMULQDQ,      AESKEYGENASSIST, @@ -1763,6 +1972,7 @@ pub enum Opcode {      PUSHA,      POPA, +    BOUND,      ARPL,      AAS,      AAA, @@ -1863,6 +2073,376 @@ pub enum Opcode {      // 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,  }  #[derive(Debug)] @@ -1889,7 +2469,7 @@ impl yaxpeax_arch::Instruction for Instruction {      }  } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)]  #[non_exhaustive]  pub enum DecodeError {      ExhaustedInput, @@ -1912,10 +2492,24 @@ 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, @@ -1940,7 +2534,13 @@ enum OperandSpec {      RegIndexBaseDisp,      RegScaleDisp,      RegIndexBaseScale, -    RegIndexBaseScaleDisp +    RegIndexBaseScaleDisp, +    Deref_mask, +    RegDisp_mask, +    RegScale_mask, +    RegScaleDisp_mask, +    RegIndexBaseScale_mask, +    RegIndexBaseScaleDisp_mask,  }  // the Hash, Eq, and PartialEq impls here are possibly misleading. @@ -2460,6 +3060,47 @@ impl InstDecoder {          self      } +    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 +    } + +    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      } @@ -2659,6 +3300,13 @@ impl InstDecoder {      /// 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() { @@ -2835,6 +3483,7 @@ impl InstDecoder {              // AVX...              Opcode::VMOVDDUP |              Opcode::VPSHUFLW | +            Opcode::VPSHUFHW |              Opcode::VHADDPS |              Opcode::VHSUBPS |              Opcode::VADDSUBPS | @@ -2998,6 +3647,7 @@ impl InstDecoder {              Opcode::VPABSD |              Opcode::VPABSW |              Opcode::VPACKSSDW | +            Opcode::VPACKUSDW |              Opcode::VPACKSSWB |              Opcode::VPACKUSWB |              Opcode::VPADDB | @@ -3056,7 +3706,7 @@ impl InstDecoder {              Opcode::VPHADDD |              Opcode::VPHADDSW |              Opcode::VPHADDW | -            Opcode::VPHADDUBSW | +            Opcode::VPMADDUBSW |              Opcode::VPHMINPOSUW |              Opcode::VPHSUBD |              Opcode::VPHSUBSW | @@ -3094,6 +3744,7 @@ impl InstDecoder {              Opcode::VPMULHRSW |              Opcode::VPMULHUW |              Opcode::VPMULHW | +            Opcode::VPMULLQ |              Opcode::VPMULLD |              Opcode::VPMULLW |              Opcode::VPMULUDQ | @@ -3525,15 +4176,51 @@ impl Instruction {      }  } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct EvexData { +    // data: present, z, b, Lp, Rp. aaa +    bits: u8, +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)]  pub struct Prefixes {      bits: u8,      vex: PrefixVex,      segment: Segment, -    _pad: u8, +    evex_data: EvexData, +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct PrefixEvex { +    vex: PrefixVex, +    evex_data: EvexData,  } -#[derive(Debug, Copy, Clone)] +impl PrefixEvex { +    fn present(&self) -> bool { +        self.evex_data.present() +    } +    fn vex(&self) -> &PrefixVex { +        &self.vex +    } +    fn mask_reg(&self) -> u8 { +        self.evex_data.aaa() +    } +    fn broadcast(&self) -> bool { +        self.evex_data.b() +    } +    fn merge(&self) -> bool { +        self.evex_data.z() +    } +    fn lp(&self) -> bool { +        self.evex_data.lp() +    } +    fn rp(&self) -> bool { +        self.evex_data.rp() +    } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)]  pub struct PrefixVex {      bits: u8,  } @@ -3552,6 +4239,8 @@ impl PrefixVex {      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)] @@ -3561,7 +4250,7 @@ impl Prefixes {              bits: bits,              vex: PrefixVex { bits: 0 },              segment: Segment::DS, -            _pad: 0, +            evex_data: EvexData { bits: 0 },          }      }      fn vex_from(&mut self, bits: u8) { @@ -3623,6 +4312,26 @@ impl Prefixes {      fn set_ss(&mut self) { self.segment = Segment::SS }      #[inline]      fn vex(&self) -> PrefixVex { PrefixVex { bits: self.vex.bits } } +    #[inline] +    fn evex_unchecked(&self) -> PrefixEvex { PrefixEvex { vex: PrefixVex { bits: self.vex.bits }, evex_data: self.evex_data } } +    #[inline] +    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) { @@ -3640,8 +4349,65 @@ impl Prefixes {          let rxb = (high >> 5) ^ 0x07;          let wrxb = rxb | w >> 4;          let l = (low & 0x04) << 2; -        let synthetic_rex = wrxb | l | 0x80; -        self.vex = PrefixVex { bits: synthetic_rex }; +        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      }  } @@ -4179,6 +4945,7 @@ enum OperandCode {      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(),  }  const LOCKABLE_INSTRUCTIONS: &[Opcode] = &[ @@ -4345,7 +5112,7 @@ const OPCODES: [OpcodeRecord; 256] = [  // 0x60      OpcodeRecord(Interpretation::Instruction(Opcode::PUSHA), OperandCode::Nothing),      OpcodeRecord(Interpretation::Instruction(Opcode::POPA), OperandCode::Nothing), -    OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), 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), @@ -4567,6 +5334,18 @@ pub(self) fn read_E_ymm<T: Iterator<Item=u8>>(bytes_iter: &mut T, instr: &mut In          read_M(bytes_iter, instr, modrm, length)      }  } +#[allow(non_snake_case)] +pub(self) fn read_E_vex<T: Iterator<Item=u8>>(bytes_iter: &mut T, instr: &mut Instruction, modrm: u8, length: &mut u8, bank: RegisterBank) -> Result<OperandSpec, DecodeError> { +    if modrm >= 0b11000000 { +        read_modrm_reg(instr, modrm, bank) +    } else { +        let res = read_M(bytes_iter, instr, modrm, length)?; +        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> { @@ -8679,6 +9458,35 @@ fn unlikely_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter              instruction.operands[1] = instruction.operands[0];              instruction.operands[0] = temp;          } +        OperandCode::ModRM_0x62 => { +            let modrm = read_modrm(&mut bytes_iter, length)?; + +            if modrm < 0xc0 { +                instruction.modrm_rrr = +                    RegSpec { bank: RegisterBank::D, num: (modrm >> 3) & 7 }; +                if instruction.prefixes.operand_size() { +                    instruction.modrm_rrr.bank = RegisterBank::W; +                    instruction.mem_size = 4; +                } else { +                    instruction.mem_size = 8; +                } + +                instruction.operands[0] = OperandSpec::RegRRR; +                instruction.operands[1] = read_M(&mut bytes_iter, instruction, modrm, length)?; +                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(&mut bytes_iter, instruction, *length, Some(modrm))?; +                    // there's an unavoidable `instruction.length = *length;` after +                    // `unlikely_operands`. the current length is correct, so store it back to +                    // length to make the reassignment store a correct length. +                    *length = instruction.length; +                } +            } +        }          _ => {              // TODO: this should be unreachable - safe to panic now?              // can't simply delete this arm because the non-unlikely operands are handled outside diff --git a/src/protected_mode/vex.rs b/src/protected_mode/vex.rs index ce40e6e..5c66654 100644 --- a/src/protected_mode/vex.rs +++ b/src/protected_mode/vex.rs @@ -1685,7 +1685,7 @@ fn read_vex_instruction<T: Iterator<Item=u8>>(opcode_map: VEXOpcodeMap, bytes: &                      } else {                          VEXOperandCode::G_V_E_xmm                      }), -                    0x04 => (Opcode::VPHADDUBSW, if L { +                    0x04 => (Opcode::VPMADDUBSW, if L {                          VEXOperandCode::G_V_E_ymm                      } else {                          VEXOperandCode::G_V_E_xmm diff --git a/src/shared/evex.in b/src/shared/evex.in index 2151d47..4a26003 100644 --- a/src/shared/evex.in +++ b/src/shared/evex.in @@ -1,11 +1,20 @@  use super::OperandSpec; +// `evex_byte_one` is an option because the caller *may* have already read it, +// but may have not. `long_mode` can decide immediately that `0x62` should be read +// as an `EVEX` instruction, but for other modes we can only make this +// determination when reading a `bound`'s `modrm` byte.  #[inline(never)] -pub(crate) fn read_evex<T: Iterator<Item=u8>>(bytes: &mut T, instruction: &mut Instruction, mut length: u8) -> Result<(), DecodeError> { -    let evex_byte_one = bytes.next().ok_or(DecodeError::ExhaustedInput)?; +pub(crate) fn read_evex<T: Iterator<Item=u8>>(bytes: &mut T, instruction: &mut Instruction, mut length: u8, evex_byte_one: Option<u8>) -> Result<(), DecodeError> { +    let evex_byte_one = if let Some(b) = evex_byte_one { +      b +    } else { +      length += 1; +      bytes.next().ok_or(DecodeError::ExhaustedInput)? +    };      let evex_byte_two = bytes.next().ok_or(DecodeError::ExhaustedInput)?;      let evex_byte_three = bytes.next().ok_or(DecodeError::ExhaustedInput)?; -    length += 3; +    length += 2;      let p = evex_byte_two & 0x03;      let m = evex_byte_one & 0x03;      if m == 0 { @@ -58,7 +67,26 @@ pub(crate) fn read_evex<T: Iterator<Item=u8>>(bytes: &mut T, instruction: &mut I        instruction.opcode = opcode;        read_evex_operands(bytes, instruction, operand_code, &mut length)?;        if instruction.prefixes.evex_unchecked().vex().compressed_disp() { -        instruction.disp *= instruction.mem_size as u64; +        let overridden_size = match instruction.opcode { +          Opcode::VPEXPANDB => Some(1), +          Opcode::VPEXPANDW => Some(2), +          Opcode::VPEXPANDD => Some(4), +          Opcode::VPEXPANDQ => Some(8), +          Opcode::VPCOMPRESSB => Some(1), +          Opcode::VPCOMPRESSW => Some(2), +          Opcode::VPCOMPRESSD => Some(4), +          Opcode::VPCOMPRESSQ => Some(8), +          Opcode::VEXPANDPS => Some(4), +          Opcode::VEXPANDPD => Some(8), +          Opcode::VCOMPRESSPS => Some(4), +          Opcode::VCOMPRESSPD => Some(8), +          _ => None +        }; +        if let Some(size) = overridden_size { +          instruction.disp *= size; +        } else { +          apply_disp_scale(instruction); +        }          instruction.prefixes.apply_compressed_disp(false);        }        // TODO: apply rp and bp? @@ -593,7 +621,7 @@ pub(crate) fn read_evex_operands<T: Iterator<Item=u8>>(bytes: &mut T, instructio        deny_z(instruction)?;        let (sz, bank) = if instruction.prefixes.evex_unchecked().vex().w() { -        (8, RegisterBank::Q) +        (DEFAULT_EVEX_REGISTER_WIDTH, DEFAULT_EVEX_REGISTER_SIZE)        } else {          (4, RegisterBank::D)        }; @@ -626,8 +654,10 @@ pub(crate) fn read_evex_operands<T: Iterator<Item=u8>>(bytes: &mut T, instructio        deny_mask_reg(instruction)?;        let (sz, bank) = if instruction.prefixes.evex_unchecked().vex().w() { -        instruction.opcode = Opcode::VPINSRQ; -        (8, RegisterBank::Q) +        if isa_has_qwords() { +          instruction.opcode = Opcode::VPINSRQ; +        } +        (DEFAULT_EVEX_REGISTER_WIDTH, DEFAULT_EVEX_REGISTER_SIZE)        } else {          (4, RegisterBank::D)        }; @@ -2363,11 +2393,13 @@ pub(crate) fn read_evex_operands<T: Iterator<Item=u8>>(bytes: &mut T, instructio        let mem_oper = read_E_vex(bytes, instruction, modrm, length, RegisterBank::X)?;        if instruction.prefixes.evex_unchecked().vex().w() { -        instruction.opcode = Opcode::VMOVQ; +        if isa_has_qwords() { +          instruction.opcode = Opcode::VMOVQ; +        }          if mem_oper == OperandSpec::RegMMM { -          instruction.modrm_mmm.bank = RegisterBank::Q; +          instruction.modrm_mmm.bank = DEFAULT_EVEX_REGISTER_SIZE;          } else { -          instruction.mem_size = 8; +          instruction.mem_size = DEFAULT_EVEX_REGISTER_WIDTH;          }        } else {          if mem_oper == OperandSpec::RegMMM { @@ -2391,11 +2423,13 @@ pub(crate) fn read_evex_operands<T: Iterator<Item=u8>>(bytes: &mut T, instructio        let mem_oper = read_E_vex(bytes, instruction, modrm, length, RegisterBank::X)?;        if instruction.prefixes.evex_unchecked().vex().w() { -        instruction.opcode = Opcode::VMOVQ; +        if isa_has_qwords() { +          instruction.opcode = Opcode::VMOVQ; +        }          if mem_oper == OperandSpec::RegMMM { -          instruction.modrm_mmm.bank = RegisterBank::Q; +          instruction.modrm_mmm.bank = DEFAULT_EVEX_REGISTER_SIZE;          } else { -          instruction.mem_size = 8; +          instruction.mem_size = DEFAULT_EVEX_REGISTER_WIDTH;          }        } else {          if mem_oper == OperandSpec::RegMMM { @@ -2822,7 +2856,7 @@ pub(crate) fn read_evex_operands<T: Iterator<Item=u8>>(bytes: &mut T, instructio        check_mask_reg(instruction)?;        deny_vex_reg(instruction)?; -      if instruction.prefixes.evex_unchecked().vex().w() { +      if instruction.prefixes.evex_unchecked().vex().w() && isa_has_qwords() {          if instruction.opcode == Opcode::VPBROADCASTD {            instruction.opcode = Opcode::VPBROADCASTQ;          } @@ -2843,7 +2877,7 @@ pub(crate) fn read_evex_operands<T: Iterator<Item=u8>>(bytes: &mut T, instructio        if mem_oper == OperandSpec::RegMMM {          instruction.mem_size = 0;          if instruction.prefixes.evex_unchecked().vex().w() { -          instruction.modrm_mmm.bank = RegisterBank::Q; +          instruction.modrm_mmm.bank = DEFAULT_EVEX_REGISTER_SIZE;          } else {            instruction.modrm_mmm.bank = RegisterBank::D;          } @@ -3036,7 +3070,7 @@ pub(crate) fn read_evex_operands<T: Iterator<Item=u8>>(bytes: &mut T, instructio        set_rrr(instruction, modrm);        if instruction.prefixes.evex_unchecked().vex().w() { -        instruction.modrm_rrr.bank = RegisterBank::Q; +        instruction.modrm_rrr.bank = DEFAULT_EVEX_REGISTER_SIZE;        } else {          instruction.modrm_rrr.bank = RegisterBank::D;        } @@ -4409,11 +4443,15 @@ pub(crate) fn read_evex_operands<T: Iterator<Item=u8>>(bytes: &mut T, instructio        instruction.operand_count = 3;        if instruction.prefixes.evex_unchecked().vex().w() { -        instruction.opcode = Opcode::VPEXTRQ; +        if isa_has_qwords() { +          instruction.opcode = Opcode::VPEXTRQ; +        } else { +          instruction.opcode = Opcode::VPEXTRD; +        }          if let OperandSpec::RegMMM = mem_oper { -          instruction.modrm_mmm.bank = RegisterBank::Q; +          instruction.modrm_mmm.bank = DEFAULT_EVEX_REGISTER_SIZE;          } else { -          instruction.mem_size = 8; +          instruction.mem_size = DEFAULT_EVEX_REGISTER_WIDTH;          }        } else {          instruction.opcode = Opcode::VPEXTRD; @@ -4438,13 +4476,15 @@ pub(crate) fn read_evex_operands<T: Iterator<Item=u8>>(bytes: &mut T, instructio        instruction.operands[2] = mem_oper;        if mem_oper == OperandSpec::RegMMM {          if instruction.prefixes.evex_unchecked().vex().w() { -          instruction.modrm_mmm.bank = RegisterBank::Q; +          instruction.modrm_mmm.bank = DEFAULT_EVEX_REGISTER_SIZE;          } else {            instruction.modrm_mmm.bank = RegisterBank::D;          }          if instruction.prefixes.evex_unchecked().vex().w() {            if instruction.prefixes.evex_unchecked().broadcast() { -            instruction.operands[0] = OperandSpec::RegRRR_maskmerge_sae; +            if isa_has_qwords() { +              instruction.operands[0] = OperandSpec::RegRRR_maskmerge_sae; +            }            } else {              if instruction.prefixes.evex_unchecked().lp() || !instruction.prefixes.evex_unchecked().vex().l() {                return Err(DecodeError::InvalidOpcode); @@ -4456,7 +4496,7 @@ pub(crate) fn read_evex_operands<T: Iterator<Item=u8>>(bytes: &mut T, instructio            return Err(DecodeError::InvalidOpcode);          }          if instruction.prefixes.evex_unchecked().vex().w() { -          instruction.mem_size = 8; +          instruction.mem_size = DEFAULT_EVEX_REGISTER_WIDTH;          } else {            instruction.mem_size = 4;          } @@ -4725,7 +4765,7 @@ pub(crate) fn read_evex_operands<T: Iterator<Item=u8>>(bytes: &mut T, instructio        set_rrr(instruction, modrm);        let mem_oper = read_E_vex(bytes, instruction, modrm, length, RegisterBank::X)?;        if instruction.prefixes.evex_unchecked().broadcast() && mem_oper == OperandSpec::RegMMM { -        if !instruction.prefixes.evex_unchecked().vex().w() && instruction.opcode == Opcode::VCVTSI2SD { +        if (!instruction.prefixes.evex_unchecked().vex().w() || !isa_has_qwords()) && instruction.opcode == Opcode::VCVTSI2SD {            instruction.operands[0] = OperandSpec::RegRRR;          } else {            instruction.operands[0] = OperandSpec::RegRRR_maskmerge_sae; @@ -4742,13 +4782,21 @@ pub(crate) fn read_evex_operands<T: Iterator<Item=u8>>(bytes: &mut T, instructio        if mem_oper == OperandSpec::RegMMM {          instruction.mem_size = 0;          if instruction.prefixes.evex_unchecked().vex().w() { -          instruction.modrm_mmm.bank = RegisterBank::Q; +          instruction.modrm_mmm.bank = DEFAULT_EVEX_REGISTER_SIZE;          } else {            instruction.modrm_mmm.bank = RegisterBank::D;          }        } else {          if instruction.prefixes.evex_unchecked().vex().w() { -          instruction.mem_size = 8; +          if isa_has_qwords() { +            instruction.mem_size = 8; +          } else { +            if [Opcode::VCVTSI2SS, Opcode::VCVTSI2SD].contains(&instruction.opcode) { +              instruction.mem_size = 4; +            } else { +              instruction.mem_size = 8; +            } +          }          } else {            instruction.mem_size = 4;          } @@ -4767,7 +4815,7 @@ pub(crate) fn read_evex_operands<T: Iterator<Item=u8>>(bytes: &mut T, instructio          instruction.operands[0] = OperandSpec::RegRRR;        }        if instruction.prefixes.evex_unchecked().vex().w() { -        instruction.modrm_rrr.bank = RegisterBank::Q; +        instruction.modrm_rrr.bank = DEFAULT_EVEX_REGISTER_SIZE;        } else {          instruction.modrm_rrr.bank = RegisterBank::D;        } @@ -4794,7 +4842,7 @@ pub(crate) fn read_evex_operands<T: Iterator<Item=u8>>(bytes: &mut T, instructio          instruction.operands[0] = OperandSpec::RegRRR;        }        if instruction.prefixes.evex_unchecked().vex().w() { -        instruction.modrm_rrr.bank = RegisterBank::Q; +        instruction.modrm_rrr.bank = DEFAULT_EVEX_REGISTER_SIZE;        } else {          instruction.modrm_rrr.bank = RegisterBank::D;        }  | 
