diff options
| author | iximeow <me@iximeow.net> | 2026-05-08 01:19:33 +0000 |
|---|---|---|
| committer | iximeow <me@iximeow.net> | 2026-05-08 01:19:33 +0000 |
| commit | 2378c1361c729da9f9cbd982142837b3d164106c (patch) | |
| tree | f75d02beaf81999bba0390f9eeebadf33c24266f /src/shared/evex.in | |
| parent | 904fa19dd7dba76cc206b70628efedf8ddb128d1 (diff) | |
working through a bunch of avx512 stuff..
Diffstat (limited to 'src/shared/evex.in')
| -rw-r--r-- | src/shared/evex.in | 158 |
1 files changed, 137 insertions, 21 deletions
diff --git a/src/shared/evex.in b/src/shared/evex.in index 0aa7d95..a15b59b 100644 --- a/src/shared/evex.in +++ b/src/shared/evex.in @@ -1,6 +1,7 @@ use super::OperandSpec; use super::FieldDescription; use super::InnerDescription; +use super::Prefixes; use yaxpeax_arch::annotation::DescriptionSink; @@ -312,6 +313,23 @@ fn check_mask_reg(inst: &Instruction) -> Result<(), DecodeError> { } #[inline(always)] +fn check_allowed_zero_merge(prefixes: &Prefixes, oper: OperandSpec) -> Result<(), DecodeError> { + if prefixes.evex_unchecked().merge() { + // if evex.z is set + + if oper.is_memory() { + // quoth APM, + // > 3.2.4 Exceptions Caused by Illegal EVEX encodings + // > .. + // > EVEX.z == 1 ... Instructions that do not specify {z} ... #UD + return Err(DecodeError::InvalidOperand); + } + } + + Ok(()) +} + +#[inline(always)] fn apply_broadcast(inst: &mut Instruction, item_size: u8, reg_size: u8) { if inst.prefixes.evex_unchecked().broadcast() { inst.mem_size = item_size; @@ -436,6 +454,8 @@ pub(crate) fn read_evex_operands< if instruction.prefixes.evex_unchecked().vex().w() { if instruction.opcode == Opcode::VRSQRT14SS { instruction.opcode = Opcode::VRSQRT14SD; + } else if instruction.opcode == Opcode::VRCP14SS { + instruction.opcode = Opcode::VRCP14SD; } } @@ -471,6 +491,10 @@ pub(crate) fn read_evex_operands< } else { if instruction.prefixes.evex_unchecked().broadcast() { return Err(DecodeError::InvalidOpcode); + } else { + if instruction.prefixes.evex_unchecked().lp() && instruction.prefixes.evex_unchecked().vex().l() { + return Err(DecodeError::InvalidOpcode); + } } instruction.mem_size = 8; } @@ -488,12 +512,6 @@ pub(crate) fn read_evex_operands< instruction.operand_count = 3; - if instruction.prefixes.evex_unchecked().vex().w() { - if instruction.opcode == Opcode::VGETEXPSS { - instruction.opcode = Opcode::VGETEXPSD; - } - } - if let OperandSpec::RegMMM = mem_oper { if instruction.prefixes.evex_unchecked().broadcast() { instruction.operands[0] = OperandSpec::RegRRR_maskmerge_sae_noround; @@ -900,6 +918,9 @@ pub(crate) fn read_evex_operands< instruction.operands[0] = OperandSpec::RegRRR_maskmerge; instruction.operands[1] = OperandSpec::RegVex; instruction.operands[2] = mem_oper; + if mem_oper == OperandSpec::RegMMM { + deny_broadcast(instruction)?; + } instruction.operand_count = 3; set_reg_sizes_from_ll(instruction)?; @@ -945,12 +966,14 @@ pub(crate) fn read_evex_operands< deny_vex_reg(instruction)?; check_mask_reg(instruction)?; ensure_W(instruction, 1)?; + deny_broadcast(instruction)?; instruction.mem_size = regs_size(instruction); let modrm = read_modrm(words)?; set_rrr(instruction, modrm); let mem_oper = read_E_vex(words, instruction, modrm, RegisterBank::Y, sink)?; + check_allowed_zero_merge(&instruction.prefixes, mem_oper)?; instruction.operands[0] = mem_oper.masked(); instruction.operands[1] = OperandSpec::RegRRR; instruction.operand_count = 2; @@ -981,7 +1004,7 @@ pub(crate) fn read_evex_operands< } generated::EVEXOperandCode::Gm_Eq_xmm_sae_W1 => { deny_vex_reg(instruction)?; - check_mask_reg(instruction)?; + deny_mask_reg(instruction)?; // vucomisd and vcomisd both are W=1 ensure_W(instruction, 1)?; @@ -1005,6 +1028,7 @@ pub(crate) fn read_evex_operands< deny_vex_reg(instruction)?; check_mask_reg(instruction)?; ensure_W(instruction, 1)?; + deny_broadcast(instruction)?; instruction.mem_size = regs_size(instruction); @@ -1126,7 +1150,7 @@ pub(crate) fn read_evex_operands< } } else { instruction.operands[0] = OperandSpec::RegRRR_maskmerge; - apply_broadcast(instruction, 8, sz); + apply_broadcast(instruction, 4, sz); set_reg_sizes_from_ll(instruction)?; } } @@ -1444,6 +1468,9 @@ pub(crate) fn read_evex_operands< let modrm = read_modrm(words)?; set_rrr(instruction, modrm); let mem_oper = read_E_vex(words, instruction, modrm, RegisterBank::Y, sink)?; + if instruction.prefixes.evex_unchecked().broadcast() && !mem_oper.is_memory() { + return Err(DecodeError::InvalidOpcode); + } instruction.operands[0] = OperandSpec::RegRRR_maskmerge; instruction.operands[1] = OperandSpec::RegVex; instruction.operands[2] = mem_oper; @@ -1571,6 +1598,9 @@ pub(crate) fn read_evex_operands< set_rrr(instruction, modrm); let mem_oper = read_E_vex(words, instruction, modrm, RegisterBank::X, sink)?; if instruction.prefixes.evex_unchecked().broadcast() { + if mem_oper.is_memory() { + return Err(DecodeError::InvalidOperand); + } instruction.operands[0] = OperandSpec::RegRRR_maskmerge_sae_noround; } else { if instruction.prefixes.evex_unchecked().lp() && instruction.prefixes.evex_unchecked().vex().l() { @@ -1595,8 +1625,6 @@ pub(crate) fn read_evex_operands< if instruction.prefixes.evex_unchecked().vex().w() { if instruction.opcode == Opcode::VSCALEFSS { instruction.opcode = Opcode::VSCALEFSD; - } else if instruction.opcode == Opcode::VRCP14SS { - instruction.opcode = Opcode::VRCP14SD; } } @@ -1604,6 +1632,9 @@ pub(crate) fn read_evex_operands< set_rrr(instruction, modrm); let mem_oper = read_E_vex(words, instruction, modrm, RegisterBank::X, sink)?; if instruction.prefixes.evex_unchecked().broadcast() { + if mem_oper.is_memory() { + return Err(DecodeError::InvalidOpcode); + }; instruction.operands[0] = OperandSpec::RegRRR_maskmerge_sae; } else { if instruction.prefixes.evex_unchecked().lp() && instruction.prefixes.evex_unchecked().vex().l() { @@ -1626,6 +1657,44 @@ pub(crate) fn read_evex_operands< } set_reg_sizes(instruction, RegisterBank::X); } + generated::EVEXOperandCode::Gm_V_Ed_xmm_sae_noround => { + check_mask_reg(instruction)?; + + if instruction.prefixes.evex_unchecked().vex().w() { + if instruction.opcode == Opcode::VGETEXPSS { + instruction.opcode = Opcode::VGETEXPSD; + } + } + + let modrm = read_modrm(words)?; + set_rrr(instruction, modrm); + let mem_oper = read_E_vex(words, instruction, modrm, RegisterBank::X, sink)?; + if instruction.prefixes.evex_unchecked().broadcast() { + if mem_oper.is_memory() { + return Err(DecodeError::InvalidOpcode); + }; + instruction.operands[0] = OperandSpec::RegRRR_maskmerge_sae_noround; + } else { + if instruction.prefixes.evex_unchecked().lp() && instruction.prefixes.evex_unchecked().vex().l() { + return Err(DecodeError::InvalidOperand); + } + instruction.operands[0] = OperandSpec::RegRRR_maskmerge; + } + instruction.operands[1] = OperandSpec::RegVex; + instruction.operands[2] = mem_oper; + instruction.operand_count = 3; + + if mem_oper == OperandSpec::RegMMM { + instruction.mem_size = 0; + } else { + if instruction.prefixes.evex_unchecked().vex().w() { + instruction.mem_size = 8; + } else { + instruction.mem_size = 4; + } + } + set_reg_sizes(instruction, RegisterBank::X); + } generated::EVEXOperandCode::Gm_V_Ed_xmm_sae_W0 => { check_mask_reg(instruction)?; ensure_W(instruction, 0)?; @@ -1966,6 +2035,7 @@ pub(crate) fn read_evex_operands< check_mask_reg(instruction)?; deny_vex_reg(instruction)?; deny_broadcast(instruction)?; + ensure_W(instruction, 0)?; let modrm = read_modrm(words)?; set_rrr(instruction, modrm); @@ -2001,8 +2071,8 @@ pub(crate) fn read_evex_operands< generated::EVEXOperandCode::Gm_ymm_E_xmm_W0 => { check_mask_reg(instruction)?; deny_vex_reg(instruction)?; - ensure_W(instruction, 0)?; deny_broadcast(instruction)?; + ensure_W(instruction, 0)?; let modrm = read_modrm(words)?; set_rrr(instruction, modrm); @@ -2039,6 +2109,7 @@ pub(crate) fn read_evex_operands< check_mask_reg(instruction)?; deny_vex_reg(instruction)?; deny_broadcast(instruction)?; + ensure_W(instruction, 0)?; let modrm = read_modrm(words)?; set_rrr(instruction, modrm); @@ -2080,6 +2151,7 @@ pub(crate) fn read_evex_operands< let modrm = read_modrm(words)?; set_rrr(instruction, modrm); let mem_oper = read_E_vex(words, instruction, modrm, RegisterBank::Y, sink)?; + check_allowed_zero_merge(&instruction.prefixes, mem_oper)?; instruction.regs[0].bank = RegisterBank::Z; instruction.mem_size = 32; instruction.operands[0] = mem_oper.masked(); @@ -2095,6 +2167,7 @@ pub(crate) fn read_evex_operands< let modrm = read_modrm(words)?; set_rrr(instruction, modrm); let mem_oper = read_E_vex(words, instruction, modrm, RegisterBank::X, sink)?; + check_allowed_zero_merge(&instruction.prefixes, mem_oper)?; instruction.regs[0].bank = RegisterBank::Z; instruction.mem_size = 16; instruction.operands[0] = mem_oper.masked(); @@ -2110,6 +2183,7 @@ pub(crate) fn read_evex_operands< let modrm = read_modrm(words)?; set_rrr(instruction, modrm); let mem_oper = read_E_vex(words, instruction, modrm, RegisterBank::X, sink)?; + check_allowed_zero_merge(&instruction.prefixes, mem_oper)?; instruction.regs[0].bank = RegisterBank::Y; instruction.mem_size = 16; instruction.operands[0] = mem_oper.masked(); @@ -2125,6 +2199,7 @@ pub(crate) fn read_evex_operands< let modrm = read_modrm(words)?; set_rrr(instruction, modrm); let mem_oper = read_E_vex(words, instruction, modrm, RegisterBank::X, sink)?; + check_allowed_zero_merge(&instruction.prefixes, mem_oper)?; instruction.regs[0].bank = RegisterBank::Z; instruction.mem_size = 8; instruction.operands[0] = mem_oper.masked(); @@ -2140,6 +2215,7 @@ pub(crate) fn read_evex_operands< let modrm = read_modrm(words)?; set_rrr(instruction, modrm); let mem_oper = read_E_vex(words, instruction, modrm, RegisterBank::X, sink)?; + check_allowed_zero_merge(&instruction.prefixes, mem_oper)?; instruction.regs[0].bank = RegisterBank::X; instruction.mem_size = 8; instruction.operands[0] = mem_oper.masked(); @@ -2155,6 +2231,7 @@ pub(crate) fn read_evex_operands< let modrm = read_modrm(words)?; set_rrr(instruction, modrm); let mem_oper = read_E_vex(words, instruction, modrm, RegisterBank::X, sink)?; + check_allowed_zero_merge(&instruction.prefixes, mem_oper)?; instruction.regs[0].bank = RegisterBank::Y; instruction.mem_size = 4; instruction.operands[0] = mem_oper.masked(); @@ -2170,6 +2247,7 @@ pub(crate) fn read_evex_operands< let modrm = read_modrm(words)?; set_rrr(instruction, modrm); let mem_oper = read_E_vex(words, instruction, modrm, RegisterBank::X, sink)?; + check_allowed_zero_merge(&instruction.prefixes, mem_oper)?; instruction.regs[0].bank = RegisterBank::X; instruction.mem_size = 4; instruction.operands[0] = mem_oper.masked(); @@ -2185,6 +2263,7 @@ pub(crate) fn read_evex_operands< let modrm = read_modrm(words)?; set_rrr(instruction, modrm); let mem_oper = read_E_vex(words, instruction, modrm, RegisterBank::X, sink)?; + check_allowed_zero_merge(&instruction.prefixes, mem_oper)?; instruction.regs[0].bank = RegisterBank::X; instruction.mem_size = 2; instruction.operands[0] = mem_oper.masked(); @@ -2200,6 +2279,7 @@ pub(crate) fn read_evex_operands< let modrm = read_modrm(words)?; set_rrr(instruction, modrm); let mem_oper = read_E_vex(words, instruction, modrm, RegisterBank::X, sink)?; + check_allowed_zero_merge(&instruction.prefixes, mem_oper)?; instruction.regs[0].bank = RegisterBank::Y; instruction.mem_size = 8; instruction.operands[0] = mem_oper.masked(); @@ -2659,6 +2739,11 @@ pub(crate) fn read_evex_operands< } generated::EVEXOperandCode::Mask_V_E_LL_bcast => { check_mask_reg(instruction)?; + deny_z(instruction)?; + + if instruction.opcode == Opcode::VP2INTERSECTD { + deny_mask_reg(instruction)?; + } let sz = regs_size(instruction); @@ -2680,6 +2765,7 @@ pub(crate) fn read_evex_operands< let mem_oper = read_E_vex(words, instruction, modrm, RegisterBank::X, sink)?; if mem_oper == OperandSpec::RegMMM { instruction.mem_size = 0; + deny_broadcast(instruction)?; } instruction.operands[0] = OperandSpec::RegRRR_maskmerge; instruction.operands[1] = OperandSpec::RegVex; @@ -2696,6 +2782,7 @@ pub(crate) fn read_evex_operands< generated::EVEXOperandCode::Mask_V_E_LL_bcast_W1 => { check_mask_reg(instruction)?; ensure_W(instruction, 1)?; + deny_z(instruction)?; let sz = regs_size(instruction); @@ -2704,7 +2791,9 @@ pub(crate) fn read_evex_operands< let modrm = read_modrm(words)?; set_rrr(instruction, modrm); let mem_oper = read_E_vex(words, instruction, modrm, RegisterBank::X, sink)?; + check_allowed_zero_merge(&instruction.prefixes, mem_oper)?; if mem_oper == OperandSpec::RegMMM { + deny_broadcast(instruction)?; instruction.mem_size = 0; } instruction.operands[0] = OperandSpec::RegRRR_maskmerge; @@ -2722,6 +2811,7 @@ pub(crate) fn read_evex_operands< generated::EVEXOperandCode::Mask_V_E_LL_bcast_W0 => { check_mask_reg(instruction)?; ensure_W(instruction, 0)?; + deny_z(instruction)?; let sz = regs_size(instruction); @@ -2731,6 +2821,7 @@ pub(crate) fn read_evex_operands< set_rrr(instruction, modrm); let mem_oper = read_E_vex(words, instruction, modrm, RegisterBank::X, sink)?; if mem_oper == OperandSpec::RegMMM { + deny_broadcast(instruction)?; instruction.mem_size = 0; } instruction.operands[0] = OperandSpec::RegRRR_maskmerge; @@ -2773,6 +2864,7 @@ pub(crate) fn read_evex_operands< let modrm = read_modrm(words)?; set_rrr(instruction, modrm); let mem_oper = read_E_vex(words, instruction, modrm, RegisterBank::X, sink)?; + check_allowed_zero_merge(&instruction.prefixes, mem_oper)?; if mem_oper == OperandSpec::RegMMM { instruction.mem_size = 0; } @@ -2959,6 +3051,7 @@ pub(crate) fn read_evex_operands< let modrm = read_modrm(words)?; set_rrr(instruction, modrm); let mem_oper = read_E_vex(words, instruction, modrm, RegisterBank::X, sink)?; + check_allowed_zero_merge(&instruction.prefixes, mem_oper)?; if mem_oper == OperandSpec::RegMMM { instruction.mem_size = 0; } @@ -2990,6 +3083,7 @@ pub(crate) fn read_evex_operands< }; instruction.regs[0].bank = r_sz; if mem_oper == OperandSpec::RegMMM { + deny_broadcast(instruction)?; instruction.mem_size = 0; instruction.regs[1].bank = m_sz; } else { @@ -3007,6 +3101,8 @@ pub(crate) fn read_evex_operands< instruction.opcode = Opcode::VPLZCNTQ; } else if instruction.opcode == Opcode::VRCP14PS { instruction.opcode = Opcode::VRCP14PD; + } else if instruction.opcode == Opcode::VRSQRT14PS { + instruction.opcode = Opcode::VRSQRT14PD; } else if instruction.opcode == Opcode::VPOPCNTD { instruction.opcode = Opcode::VPOPCNTQ; } else if instruction.opcode == Opcode::VPCONFLICTD { @@ -3086,6 +3182,7 @@ pub(crate) fn read_evex_operands< generated::EVEXOperandCode::Gm_LL_Ud => { check_mask_reg(instruction)?; deny_vex_reg(instruction)?; + deny_broadcast(instruction)?; if instruction.prefixes.evex_unchecked().vex().w() && isa_has_qwords() { if instruction.opcode == Opcode::VPBROADCASTD { @@ -3120,6 +3217,7 @@ pub(crate) fn read_evex_operands< check_mask_reg(instruction)?; deny_vex_reg(instruction)?; ensure_W(instruction, 0)?; + deny_broadcast(instruction)?; let sz = regs_size(instruction); @@ -3355,8 +3453,6 @@ pub(crate) fn read_evex_operands< if instruction.prefixes.evex_unchecked().vex().w() { if instruction.opcode == Opcode::VGETEXPPS { instruction.opcode = Opcode::VGETEXPPD; - } else if instruction.opcode == Opcode::VRSQRT14PS { - instruction.opcode = Opcode::VRSQRT14PD; } } @@ -3380,11 +3476,7 @@ pub(crate) fn read_evex_operands< 4 }, sz); } else { - if instruction.opcode == Opcode::VSQRTPS || instruction.opcode == Opcode::VCVTPS2DQ { - instruction.operands[0] = OperandSpec::RegRRR_maskmerge_sae; - } else { - instruction.operands[0] = OperandSpec::RegRRR_maskmerge_sae_noround; - } + instruction.operands[0] = OperandSpec::RegRRR_maskmerge_sae_noround; set_reg_sizes(instruction, RegisterBank::Z); } } else { @@ -3520,6 +3612,7 @@ pub(crate) fn read_evex_operands< check_mask_reg(instruction)?; ensure_W(instruction, 0)?; deny_broadcast(instruction)?; + deny_z(instruction)?; let sz = regs_size(instruction); @@ -3546,6 +3639,7 @@ pub(crate) fn read_evex_operands< generated::EVEXOperandCode::Mask_V_E_LL => { check_mask_reg(instruction)?; deny_broadcast(instruction)?; + deny_z(instruction)?; let sz = regs_size(instruction); @@ -4235,6 +4329,7 @@ pub(crate) fn read_evex_operands< } generated::EVEXOperandCode::VCVTPH2PS => { check_mask_reg(instruction)?; + ensure_W(instruction, 0)?; deny_vex_reg(instruction)?; if instruction.opcode == Opcode::VCVTPS2PD { @@ -4248,6 +4343,9 @@ pub(crate) fn read_evex_operands< let modrm = read_modrm(words)?; set_rrr(instruction, modrm); let mem_oper = read_E_vex(words, instruction, modrm, RegisterBank::X, sink)?; + if instruction.opcode == Opcode::VCVTPH2PS && mem_oper.is_memory() { + deny_broadcast(instruction)?; + } instruction.operands[0] = OperandSpec::RegRRR_maskmerge; instruction.operands[1] = mem_oper; instruction.operand_count = 2; @@ -4527,6 +4625,15 @@ pub(crate) fn read_evex_operands< let modrm = read_modrm(words)?; set_rrr(instruction, modrm); let mem_oper = read_E_vex(words, instruction, modrm, RegisterBank::X, sink)?; + if !instruction.prefixes.evex_unchecked().broadcast() { + if instruction.prefixes.evex_unchecked().lp() { + if instruction.prefixes.evex_unchecked().vex().l() { + return Err(DecodeError::InvalidOperand); + } + } + } else if mem_oper.is_memory() { + return Err(DecodeError::InvalidOperand); + } instruction.operands[0] = OperandSpec::RegRRR_maskmerge; instruction.operands[1] = OperandSpec::RegVex; @@ -4918,6 +5025,7 @@ pub(crate) fn read_evex_operands< generated::EVEXOperandCode::VMOVSD_10 => { check_mask_reg(instruction)?; ensure_W(instruction, 1)?; + deny_broadcast(instruction)?; let modrm = read_modrm(words)?; set_rrr(instruction, modrm); @@ -4940,10 +5048,12 @@ pub(crate) fn read_evex_operands< generated::EVEXOperandCode::VMOVSD_11 => { check_mask_reg(instruction)?; ensure_W(instruction, 1)?; + deny_broadcast(instruction)?; let modrm = read_modrm(words)?; set_rrr(instruction, modrm); let mem_oper = read_E_vex(words, instruction, modrm, RegisterBank::X, sink)?; + check_allowed_zero_merge(&instruction.prefixes, mem_oper)?; instruction.operands[0] = mem_oper.masked(); if mem_oper == OperandSpec::RegMMM { instruction.operands[1] = OperandSpec::RegVex; @@ -4962,12 +5072,16 @@ pub(crate) fn read_evex_operands< generated::EVEXOperandCode::VMOVSS_10 => { check_mask_reg(instruction)?; ensure_W(instruction, 0)?; + deny_broadcast(instruction)?; let modrm = read_modrm(words)?; set_rrr(instruction, modrm); let mem_oper = read_E_vex(words, instruction, modrm, RegisterBank::X, sink)?; instruction.operands[0] = OperandSpec::RegRRR_maskmerge; if mem_oper == OperandSpec::RegMMM { + if instruction.prefixes.evex_unchecked().broadcast() { + return Err(DecodeError::InvalidOpcode); + } instruction.operands[1] = OperandSpec::RegVex; instruction.operands[2] = mem_oper; instruction.operand_count = 3; @@ -4984,10 +5098,12 @@ pub(crate) fn read_evex_operands< generated::EVEXOperandCode::VMOVSS_11 => { check_mask_reg(instruction)?; ensure_W(instruction, 0)?; + deny_broadcast(instruction)?; let modrm = read_modrm(words)?; set_rrr(instruction, modrm); let mem_oper = read_E_vex(words, instruction, modrm, RegisterBank::X, sink)?; + check_allowed_zero_merge(&instruction.prefixes, mem_oper)?; instruction.operands[0] = mem_oper.masked(); if mem_oper == OperandSpec::RegMMM { instruction.operands[1] = OperandSpec::RegVex; @@ -5004,7 +5120,7 @@ pub(crate) fn read_evex_operands< set_reg_sizes(instruction, RegisterBank::X); } generated::EVEXOperandCode::VCVTSI2SS => { - check_mask_reg(instruction)?; + deny_mask_reg(instruction)?; deny_z(instruction)?; let modrm = read_modrm(words)?; @@ -5049,7 +5165,7 @@ pub(crate) fn read_evex_operands< } } generated::EVEXOperandCode::VCVTTSS2SI => { - check_mask_reg(instruction)?; + deny_mask_reg(instruction)?; deny_z(instruction)?; let modrm = read_modrm(words)?; @@ -5076,7 +5192,7 @@ pub(crate) fn read_evex_operands< instruction.operand_count = 2; } generated::EVEXOperandCode::VCVTSS2SI => { - check_mask_reg(instruction)?; + deny_mask_reg(instruction)?; deny_z(instruction)?; let modrm = read_modrm(words)?; |
