diff options
Diffstat (limited to 'src/long_mode')
| -rw-r--r-- | src/long_mode/behavior.rs | 762 |
1 files changed, 498 insertions, 264 deletions
diff --git a/src/long_mode/behavior.rs b/src/long_mode/behavior.rs index a5e5757..c95480d 100644 --- a/src/long_mode/behavior.rs +++ b/src/long_mode/behavior.rs @@ -29,7 +29,7 @@ pub struct InstBehavior<'inst> { impl Instruction { pub fn behavior<'inst>(&'inst self) -> InstBehavior<'inst> { - let behavior = if let Some(behavior) = opcode2behavior(&self.opcode) { + let mut behavior = if let Some(behavior) = opcode2behavior(&self.opcode) { behavior } else { // mul and imul are incredibly frustrating, with multiple behaviors corresponding to @@ -109,11 +109,51 @@ impl Instruction { .set_operand(0, Access::ReadWrite) .set_operand(1, Access::Read) .set_implicit_ops(ops_idx) + } else if self.opcode == Opcode::VMOVLPS || self.opcode == Opcode::VMOVHPS || + self.opcode == Opcode::VMOVLPD || self.opcode == Opcode::VMOVHPD { + let mut base_digest = BehaviorDigest::empty() + .set_pl_any() + .set_operand(1, Access::Read); + + if self.operand_count == 2 { + base_digest = base_digest + .set_operand(0, Access::ReadWrite); + } else { + base_digest = base_digest + .set_operand(0, Access::Write) + .set_operand(2, Access::Read); + } + + base_digest } else { // TODO: words unreachable!(); } }; + if behavior.is_nontrivial() { + if self.opcode() == Opcode::MULX { + // `mulx` is always vex-encoded. + if self.prefixes.vex_unchecked().w() { + behavior = behavior + .set_implicit_ops(MULX_64B_IDX); + } else { + behavior = behavior + .set_implicit_ops(MULX_32B_IDX); + } + } else if self.opcode() == Opcode::VMASKMOVDQU { + // in 64-bit mode, 67 overrides 64-bit addressing down to 32-bit. + if self.prefixes.address_size() { + behavior = behavior + .set_implicit_ops(EDI_MEMWRITE_IDX); + } else { + behavior = behavior + .set_implicit_ops(RDI_MEMWRITE_IDX); + } + } else { + // TODO: words + unreachable!(); + } + } InstBehavior { inst: self, behavior @@ -439,6 +479,62 @@ impl<'inst> InstBehavior<'inst> { exceptions } + fn as_complex_op(&self) -> Option<ComplexOp> { + // if the behavior is not complex, it is *definitely* not complex. if the behavior is + // complex, it's really a "depending on the specific instruction and operands it might + // be"... + if !self.behavior.is_complex() { + return None; + } + + // TODO: all of these should be a `set_complex` bit. + if self.inst.opcode == Opcode::WRMSR { + Some(ComplexOp::WRMSR) + } else if self.inst.opcode == Opcode::PREFETCHNTA { + Some(ComplexOp::PREFETCHNTA) + } else if self.inst.opcode == Opcode::PREFETCH2 { + Some(ComplexOp::PREFETCHT2) + } else if self.inst.opcode == Opcode::PREFETCH1 { + Some(ComplexOp::PREFETCHT1) + } else if self.inst.opcode == Opcode::PREFETCH0 { + Some(ComplexOp::PREFETCHT0) + } else if self.inst.opcode == Opcode::BT && self.inst.operands[0] != OperandSpec::RegMMM { + Some(ComplexOp::BT) + } else if self.inst.opcode == Opcode::BTS && self.inst.operands[0] != OperandSpec::RegMMM { + Some(ComplexOp::BTS) + } else if self.inst.opcode == Opcode::BTR && self.inst.operands[0] != OperandSpec::RegMMM { + Some(ComplexOp::BTR) + } else if self.inst.opcode == Opcode::BTC && self.inst.operands[0] != OperandSpec::RegMMM { + Some(ComplexOp::BTC) + } else if self.inst.opcode == Opcode::VPGATHERDD { + Some(ComplexOp::VPGATHERDD) + } else if self.inst.opcode == Opcode::VPGATHERDQ { + Some(ComplexOp::VPGATHERDQ) + } else if self.inst.opcode == Opcode::VPGATHERQD { + Some(ComplexOp::VPGATHERQD) + } else if self.inst.opcode == Opcode::VPGATHERQQ { + Some(ComplexOp::VPGATHERQQ) + } else if self.inst.opcode == Opcode::VGATHERDPD { + Some(ComplexOp::VGATHERDPD) + } else if self.inst.opcode == Opcode::VGATHERDPS { + Some(ComplexOp::VGATHERDPS) + } else if self.inst.opcode == Opcode::VGATHERQPD { + Some(ComplexOp::VGATHERQPD) + } else if self.inst.opcode == Opcode::VGATHERQPS { + Some(ComplexOp::VGATHERQPS) + } else if self.inst.opcode == Opcode::VPSCATTERDD { + Some(ComplexOp::VPSCATTERDD) + } else if self.inst.opcode == Opcode::VPSCATTERDQ { + Some(ComplexOp::VPSCATTERDQ) + } else if self.inst.opcode == Opcode::VPSCATTERQD { + Some(ComplexOp::VPSCATTERQD) + } else if self.inst.opcode == Opcode::VPSCATTERQQ { + Some(ComplexOp::VPSCATTERQQ) + } else { + None + } + } + /// produce an `InstOperands` describing the explicit and implicit operands of this /// instruction. /// @@ -450,6 +546,10 @@ impl<'inst> InstBehavior<'inst> { /// Intel SDM or AMD APM. instead, it is provided by `yaxpeax-x86` to try providing an answer /// to some common queries about instructions . pub fn all_operands(&self) -> Result<InstOperands<'inst>, ComplexOp> { + if let Some(op) = self.as_complex_op() { + return Err(op); + } + Ok(InstOperands { inst: *self, // TODO: actually select an implicit operands array based on... something from the @@ -483,22 +583,8 @@ impl<'inst> InstBehavior<'inst> { } pub fn visit_accesses<T: AccessVisitor>(&self, v: &mut T) -> Result<(), ComplexOp> { - if self.inst.opcode == Opcode::WRMSR { - return Err(ComplexOp::WRMSR); - } else if self.inst.opcode == Opcode::PREFETCHNTA { - return Err(ComplexOp::PREFETCHNTA); - } else if self.inst.opcode == Opcode::PREFETCH2 { - return Err(ComplexOp::PREFETCHT2); - } else if self.inst.opcode == Opcode::PREFETCH1 { - return Err(ComplexOp::PREFETCHT1); - } else if self.inst.opcode == Opcode::PREFETCH0 { - return Err(ComplexOp::PREFETCHT0); - } else if self.inst.opcode == Opcode::BT && self.inst.operands[0] != OperandSpec::RegMMM { - return Err(ComplexOp::BT); - } else if self.inst.opcode == Opcode::BTS && self.inst.operands[0] != OperandSpec::RegMMM { - return Err(ComplexOp::BTS); - } else if self.inst.opcode == Opcode::BTC && self.inst.operands[0] != OperandSpec::RegMMM { - return Err(ComplexOp::BTC); + if let Some(op) = self.as_complex_op() { + return Err(op); } fn compute_addr<T: AccessVisitor>(v: &mut T, inst: &Instruction, op_spec: OperandSpec) -> Option<u64> { @@ -690,6 +776,13 @@ impl<'inst> InstBehavior<'inst> { } } +/// a description of how an operand is used. +/// +/// `Access::ReadWrite` can be processed in the same manner as that operand listed as +/// `Access::Read` followed by that same operand listed as `Access::Write`. +/// +/// **important**: the meaning of `Access` is different for `flags`/`eflags`/`rflags` than other +/// operands! these differences are documented on enum variants below. #[derive(Copy, Clone, Debug, PartialEq)] pub enum Access { /// the corresponding operand is read. @@ -701,15 +794,35 @@ pub enum Access { /// /// for memory operands, this describes the referenced memory; implicitly the registers used in /// the operand's address calculation are also read. + /// + /// for flags/eflags/rflags, "write" refers to some subset of flag bits as appropriate for the + /// instruction, and implies that the instruction does not depend on the initial state of those + /// bits. this is in contrast to `Write` for other operands, where it implies a full write of + /// the corresponding operand. as a concrete example, `add` reports the flags register as a + /// `Write` since the resulting flag bits are purely a function of the `add` register/memory + /// operands. Write = 0b10, /// the corresponding operand is read and written. /// + /// in some cases `Access::ReadWrite` is chosen in particular to represent a parital-write; + /// this is especially true with SIMD instructions as `yaxpeax-x86` does not currently have the + /// ability to express individual SIMD lane read/write operations. the `vmov{h,l}{ps,pd}` + /// instructions are more common examples of this access form. this kind of partial-write + /// access is reported as `Access::Write` for flags/eflags/rflags. + /// + /// for flags/eflags/rflags, "read-write" refers to some subset of flag bits as appropriate for the + /// instruction, and implies that the instruction does depends on the initial state of those + /// bits as well as modifying some (possibly different) bits in flags as a result. + /// as a concrete example, `adc` reports the flags register as a `ReadWrite` because the + /// initial state of `cf` is an input to the addition, and the normal arithmetic flags are + /// written based on the result. + /// /// for memory operands, this describes the referenced memory; implicitly the registers used in /// the operand's address calculation are also read. ReadWrite = 0b11, /// the corresponding operand is not actually accessed for reading or writing. /// - /// this is only used to describe the operand of `nop` instructions. + /// this is only used to describe the operand of `nop` or `ud1` instructions. None = 0b00, } @@ -741,10 +854,11 @@ pub struct BehaviorDigest { // laid out like: // // |7 6|5 4|3 2|1 0| - // |imp_ops|FL |PL | + // |_ _ C N|FL |PL | // - // imp_ops: selector for a `&'static [Operand]` of additional "implicit" operands for the - // instruction. + // C: complex (this instruction *may* N: non-trivial (implementation detail of constructing + // the instruction's behavior digest) + // N: non-trivial (implementation detail of constructing the instruction's behavior digest) // FL: access bits for {,e,r}flags // PL: privilege level this instruction can be executed. // 00 -> all levels @@ -758,6 +872,7 @@ pub struct BehaviorDigest { // describes validity of these bits: fields left `00` must not have a corresponding operand at // that offset. fields with no corresponding operand may have bits set. operand_access: u8, + // selector for a `&'static [Operand]` of additional "implicit" operands for the instruction. extra: u16, } @@ -810,11 +925,25 @@ impl BehaviorDigest { self } - const fn set_complex(mut self, state: bool) -> Self { + const fn set_nontrivial(mut self, state: bool) -> Self { self.behavior &= 0b11_10_11_11; self.behavior |= (state as u8) << 4; self } + + const fn is_nontrivial(&self) -> bool { + (self.behavior & (1 << 4)) != 0 + } + + const fn set_complex(mut self, state: bool) -> Self { + self.behavior &= 0b11_01_11_11; + self.behavior |= (state as u8) << 5; + self + } + + const fn is_complex(&self) -> bool { + (self.behavior & (1 << 5)) != 0 + } } /// a subset of [`Opcode`] where access patterns cannot be expressed as a simple stream of reads or @@ -870,7 +999,8 @@ impl BehaviorDigest { /// /// ### AVX512 scatter/gather instructions /// -/// this section applies for all of `vpscatter{dd,dq,qd,qq}` and `vpgather{dd,dq,qd,qq}`. +/// this section applies for all of `vpscatter{dd,dq,qd,qq}` and `vpgather{dd,dq,qd,qq}`. TODO: and +/// dpd, and qpd, and dps, and qps, /// /// these instructions are considered "complex" because their memory access characteristics are /// actually to many memory addresses using the lanes of the vector register used as an index in @@ -968,10 +1098,27 @@ pub enum ComplexOp { PREFETCHT1, PREFETCHT0, - /// bit test/set/clear instructions are conditionally comple depending on their destination - /// operand form, as described in the enum doc comment.. + /// scatter/gather instructions are considered "complex" for reasons described in the enum doc + /// comment. + VPGATHERDD, + VPGATHERDQ, + VPGATHERQD, + VPGATHERQQ, + VGATHERDPD, + VGATHERDPS, + VGATHERQPD, + VGATHERQPS, + + VPSCATTERDD, + VPSCATTERDQ, + VPSCATTERQD, + VPSCATTERQQ, + + /// bit test/set/reset/complement instructions are conditionally complex depending on their + /// destination operand form, as described in the enum doc comment. BT, BTC, + BTR, BTS, /// TODO: document @@ -1213,7 +1360,7 @@ const GENERAL_W_R: BehaviorDigest = GENERAL_RW_R /// many vex/evex-encoded instructions const GENERAL_W_R_R: BehaviorDigest = GENERAL_W_R - .set_operand(2, Access::Write); + .set_operand(2, Access::Read); /// shld const GENERAL_RW_R_R: BehaviorDigest = GENERAL_W_R_R @@ -2251,6 +2398,42 @@ static SHA256RNDS2_OPS: &'static [ImplicitOperand] = &[ }, ]; +static MULX_64B_OPS: &'static [ImplicitOperand] = &[ + ImplicitOperand { + spec: OperandSpec::RegRRR, + reg: RegSpec::rdx(), + disp: 0i32, + write: false, + }, +]; + +static MULX_32B_OPS: &'static [ImplicitOperand] = &[ + ImplicitOperand { + spec: OperandSpec::RegRRR, + reg: RegSpec::edx(), + disp: 0i32, + write: false, + }, +]; + +static EDI_MEMWRITE_OPS: &'static [ImplicitOperand] = &[ + ImplicitOperand { + spec: OperandSpec::Deref, + reg: RegSpec::edi(), + disp: 0i32, + write: false, + }, +]; + +static RDI_MEMWRITE_OPS: &'static [ImplicitOperand] = &[ + ImplicitOperand { + spec: OperandSpec::Deref, + reg: RegSpec::rdi(), + disp: 0i32, + write: false, + }, +]; + const PUSH_OPS_IDX: u16 = 1; const POP_OPS_IDX: u16 = 2; const JCC_OPS_IDX: u16 = 3; @@ -2300,8 +2483,12 @@ const RDTSCP_IDX: u16 = 46; const MASKMOVQ_IDX: u16 = 47; const MONITOR_IDX: u16 = 48; const SHA256RNDS2_IDX: u16 = 49; +const MULX_64B_IDX: u16 = 50; +const MULX_32B_IDX: u16 = 51; +const EDI_MEMWRITE_IDX: u16 = 52; +const RDI_MEMWRITE_IDX: u16 = 53; -static IMPLICIT_OPS_LIST: [&[ImplicitOperand]; 50] = [ +static IMPLICIT_OPS_LIST: [&[ImplicitOperand]; 54] = [ &[], // implicit ops list 0 is not used PUSH_OPS, POP_OPS, @@ -2352,6 +2539,10 @@ static IMPLICIT_OPS_LIST: [&[ImplicitOperand]; 50] = [ MASKMOVQ_OPS, MONITOR_OPS, SHA256RNDS2_OPS, + MULX_64B_OPS, + MULX_32B_OPS, + EDI_MEMWRITE_OPS, + RDI_MEMWRITE_OPS, ]; #[inline(never)] @@ -2361,6 +2552,10 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { if opc == &MUL || opc == &IMUL || opc == &DIV || opc == &IDIV || opc == &NOP || opc == &CMPXCHG { return None; } + if opc == &VMOVHPS || opc == &VMOVHPD || opc == &VMOVLPS || opc == &VMOVLPD { + return None; + } + let behavior = match opc { ADD => GENERAL_RW_R_FLAGWRITE, OR => GENERAL_RW_R_FLAGWRITE, @@ -2378,9 +2573,12 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { SHR => GENERAL_RW_R_FLAGWRITE, SAL => GENERAL_RW_R_FLAGWRITE, SAR => GENERAL_RW_R_FLAGWRITE, - BTC => GENERAL_RW_R_FLAGWRITE, - BTR => GENERAL_RW_R_FLAGWRITE, - BTS => GENERAL_RW_R_FLAGWRITE, + BTC => GENERAL_RW_R_FLAGWRITE + .set_complex(true), + BTR => GENERAL_RW_R_FLAGWRITE + .set_complex(true), + BTS => GENERAL_RW_R_FLAGWRITE + .set_complex(true), CMPXCHG => GENERAL_RW_R_FLAGWRITE, CMPXCHG8B => GENERAL_RW_R_FLAGWRITE .set_implicit_ops(CMPXCHG8B_IDX), @@ -2407,7 +2605,8 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { OUTS => GENERAL_R_R, Invalid => { panic!("todo: invalid"); }, - BT => GENERAL_R_R_FLAGWRITE, + BT => GENERAL_R_R_FLAGWRITE + .set_complex(true), BSF => GENERAL_RW_R_FLAGWRITE, BSR => GENERAL_RW_R_FLAGWRITE, TZCNT => GENERAL_RW_R_FLAGWRITE, @@ -2707,11 +2906,13 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { RSQRTSS => GENERAL_RW_R, RCPSS => GENERAL_RW_R, - ANDN => { panic!("todo: andn"); }, - BEXTR => { panic!("todo: bextr"); }, - BLSI => { panic!("todo: blsi"); }, - BLSMSK => { panic!("todo: blsmsk"); }, - BLSR => { panic!("todo: blsr"); }, + ANDN => GENERAL_W_R_R + .set_flags_access(Access::Write), + BEXTR => GENERAL_W_R_R + .set_flags_access(Access::Write), + BLSI => GENERAL_W_R_FLAGWRITE, + BLSMSK => GENERAL_W_R_FLAGWRITE, + BLSR => GENERAL_W_R_FLAGWRITE, VMCLEAR => { panic!("todo: vmclear"); }, VMXON => { panic!("todo: vmxon"); }, VMCALL => { panic!("todo: vmcall"); }, @@ -2913,9 +3114,9 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { VPSHUFHW => { panic!("todo: vpshufhw"); }, VHADDPS => GENERAL_W_R_R, VHSUBPS => GENERAL_W_R_R, - VADDSUBPS => { panic!("todo: vaddsubps"); }, - VCVTPD2DQ => { panic!("todo: vcvtpd2dq"); }, - VLDDQU => { panic!("todo: vlddqu"); }, + VADDSUBPS => GENERAL_W_R_R, + VCVTPD2DQ => GENERAL_W_R, + VLDDQU => GENERAL_W_R, VCOMISD => GENERAL_R_R_FLAGWRITE, VCOMISS => GENERAL_R_R_FLAGWRITE, @@ -2923,23 +3124,23 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { VUCOMISS => GENERAL_R_R_FLAGWRITE, VADDPD => GENERAL_W_R_R, VADDPS => GENERAL_W_R_R, - VADDSD => { panic!("todo: vaddsd"); }, - VADDSS => { panic!("todo: vaddss"); }, - VADDSUBPD => { panic!("todo: vaddsubpd"); }, - VAESDEC => { panic!("todo: vaesdec"); }, - VAESDECLAST => { panic!("todo: vaesdeclast"); }, - VAESENC => { panic!("todo: vaesenc"); }, - VAESENCLAST => { panic!("todo: vaesenclast"); }, - VAESIMC => { panic!("todo: vaesimc"); }, - VAESKEYGENASSIST => { panic!("todo: vaeskeygenassist"); }, + VADDSD => GENERAL_W_R_R, + VADDSS => GENERAL_W_R_R, + VADDSUBPD => GENERAL_W_R_R, + VAESDEC => GENERAL_W_R_R, + VAESDECLAST => GENERAL_W_R_R, + VAESENC => GENERAL_W_R_R, + VAESENCLAST => GENERAL_W_R_R, + VAESIMC => GENERAL_W_R, + VAESKEYGENASSIST => GENERAL_W_R_R, VBLENDPD => { panic!("todo: vblendpd"); }, VBLENDPS => { panic!("todo: vblendps"); }, VBLENDVPD => { panic!("todo: vblendvpd"); }, VBLENDVPS => { panic!("todo: vblendvps"); }, - VBROADCASTF128 => { panic!("todo: vbroadcastf128"); }, - VBROADCASTI128 => { panic!("todo: vbroadcasti128"); }, - VBROADCASTSD => { panic!("todo: vbroadcastsd"); }, - VBROADCASTSS => { panic!("todo: vbroadcastss"); }, + VBROADCASTF128 => GENERAL_W_R, + VBROADCASTI128 => GENERAL_W_R, + VBROADCASTSD => GENERAL_W_R, + VBROADCASTSS => GENERAL_W_R, VCMPSD => { panic!("todo: vcmpsd"); }, VCMPSS => GENERAL_W_R_R .set_operand(3, Access::Read), @@ -2947,129 +3148,141 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { .set_operand(3, Access::Read), VCMPPS => GENERAL_W_R_R .set_operand(3, Access::Read), - VCVTDQ2PD => { panic!("todo: vcvtdq2pd"); }, + // TODO: SUPER suspicious about the RW_R/W_R confusion here. + // vcvtss2si says that dest[0:63] are written but omits bits 64 and up. + // vcvtsd2si says taht dest[0:63] are written and upper bits are taken from src1. + // is src1 used generally? + VCVTDQ2PD => GENERAL_W_R, VCVTDQ2PS => GENERAL_W_R, - VCVTPD2PS => { panic!("todo: vcvtpd2ps"); }, - VCVTPH2PS => { panic!("todo: vcvtph2ps"); }, - VCVTPS2DQ => { panic!("todo: vcvtps2dq"); }, - VCVTPS2PD => { panic!("todo: vcvtps2pd"); }, - VCVTSS2SD => { panic!("todo: vcvtss2sd"); }, - VCVTSI2SS => { panic!("todo: vcvtsi2ss"); }, - VCVTSI2SD => { panic!("todo: vcvtsi2sd"); }, - VCVTSD2SI => { panic!("todo: vcvtsd2si"); }, - VCVTSD2SS => { panic!("todo: vcvtsd2ss"); }, - VCVTPS2PH => { panic!("todo: vcvtps2ph"); }, - VCVTSS2SI => { panic!("todo: vcvtss2si"); }, - VCVTTPD2DQ => { panic!("todo: vcvttpd2dq"); }, - VCVTTPS2DQ => { panic!("todo: vcvttps2dq"); }, - VCVTTSS2SI => { panic!("todo: vcvttss2si"); }, - VCVTTSD2SI => { panic!("todo: vcvttsd2si"); }, + VCVTPD2PS => GENERAL_W_R, + VCVTPH2PS => GENERAL_W_R, + VCVTPS2DQ => GENERAL_W_R, + VCVTPS2PD => GENERAL_W_R, + VCVTSS2SD => GENERAL_W_R_R, + VCVTSI2SS => GENERAL_W_R_R, + VCVTSI2SD => GENERAL_W_R_R, + VCVTSD2SI => GENERAL_RW_R, + VCVTSD2SS => GENERAL_W_R_R, + VCVTPS2PH => GENERAL_W_R, + VCVTSS2SI => GENERAL_RW_R, + VCVTTPD2DQ => GENERAL_W_R, + VCVTTPS2DQ => GENERAL_W_R, + VCVTTSS2SI => GENERAL_RW_R, + VCVTTSD2SI => GENERAL_RW_R, VDIVPD => GENERAL_W_R_R, VDIVPS => GENERAL_W_R_R, - VDIVSD => { panic!("todo: vdivsd"); }, - VDIVSS => { panic!("todo: vdivss"); }, - VDPPD => { panic!("todo: vdppd"); }, - VDPPS => { panic!("todo: vdpps"); }, + VDIVSD => GENERAL_W_R_R, + VDIVSS => GENERAL_W_R_R, + VDPPD => GENERAL_W_R_R + .set_operand(3, Access::Read), + VDPPS => GENERAL_W_R_R + .set_operand(3, Access::Read), VEXTRACTF128 => { panic!("todo: vextractf128"); }, VEXTRACTI128 => { panic!("todo: vextracti128"); }, VEXTRACTPS => { panic!("todo: vextractps"); }, - VFMADD132PD => { panic!("todo: vfmadd132pd"); }, - VFMADD132PS => { panic!("todo: vfmadd132ps"); }, - VFMADD132SD => { panic!("todo: vfmadd132sd"); }, - VFMADD132SS => { panic!("todo: vfmadd132ss"); }, - VFMADD213PD => { panic!("todo: vfmadd213pd"); }, - VFMADD213PS => { panic!("todo: vfmadd213ps"); }, - VFMADD213SD => { panic!("todo: vfmadd213sd"); }, - VFMADD213SS => { panic!("todo: vfmadd213ss"); }, - VFMADD231PD => { panic!("todo: vfmadd231pd"); }, - VFMADD231PS => { panic!("todo: vfmadd231ps"); }, - VFMADD231SD => { panic!("todo: vfmadd231sd"); }, - VFMADD231SS => { panic!("todo: vfmadd231ss"); }, - VFMADDSUB132PD => { panic!("todo: vfmaddsub132pd"); }, - VFMADDSUB132PS => { panic!("todo: vfmaddsub132ps"); }, - VFMADDSUB213PD => { panic!("todo: vfmaddsub213pd"); }, - VFMADDSUB213PS => { panic!("todo: vfmaddsub213ps"); }, - VFMADDSUB231PD => { panic!("todo: vfmaddsub231pd"); }, - VFMADDSUB231PS => { panic!("todo: vfmaddsub231ps"); }, - VFMSUB132PD => { panic!("todo: vfmsub132pd"); }, - VFMSUB132PS => { panic!("todo: vfmsub132ps"); }, - VFMSUB132SD => { panic!("todo: vfmsub132sd"); }, - VFMSUB132SS => { panic!("todo: vfmsub132ss"); }, - VFMSUB213PD => { panic!("todo: vfmsub213pd"); }, - VFMSUB213PS => { panic!("todo: vfmsub213ps"); }, - VFMSUB213SD => { panic!("todo: vfmsub213sd"); }, - VFMSUB213SS => { panic!("todo: vfmsub213ss"); }, - VFMSUB231PD => { panic!("todo: vfmsub231pd"); }, - VFMSUB231PS => { panic!("todo: vfmsub231ps"); }, - VFMSUB231SD => { panic!("todo: vfmsub231sd"); }, - VFMSUB231SS => { panic!("todo: vfmsub231ss"); }, - VFMSUBADD132PD => { panic!("todo: vfmsubadd132pd"); }, - VFMSUBADD132PS => { panic!("todo: vfmsubadd132ps"); }, - VFMSUBADD213PD => { panic!("todo: vfmsubadd213pd"); }, - VFMSUBADD213PS => { panic!("todo: vfmsubadd213ps"); }, - VFMSUBADD231PD => { panic!("todo: vfmsubadd231pd"); }, - VFMSUBADD231PS => { panic!("todo: vfmsubadd231ps"); }, - VFNMADD132PD => { panic!("todo: vfnmadd132pd"); }, - VFNMADD132PS => { panic!("todo: vfnmadd132ps"); }, - VFNMADD132SD => { panic!("todo: vfnmadd132sd"); }, - VFNMADD132SS => { panic!("todo: vfnmadd132ss"); }, - VFNMADD213PD => { panic!("todo: vfnmadd213pd"); }, - VFNMADD213PS => { panic!("todo: vfnmadd213ps"); }, - VFNMADD213SD => { panic!("todo: vfnmadd213sd"); }, - VFNMADD213SS => { panic!("todo: vfnmadd213ss"); }, - VFNMADD231PD => { panic!("todo: vfnmadd231pd"); }, - VFNMADD231PS => { panic!("todo: vfnmadd231ps"); }, - VFNMADD231SD => { panic!("todo: vfnmadd231sd"); }, - VFNMADD231SS => { panic!("todo: vfnmadd231ss"); }, - VFNMSUB132PD => { panic!("todo: vfnmsub132pd"); }, - VFNMSUB132PS => { panic!("todo: vfnmsub132ps"); }, - VFNMSUB132SD => { panic!("todo: vfnmsub132sd"); }, - VFNMSUB132SS => { panic!("todo: vfnmsub132ss"); }, - VFNMSUB213PD => { panic!("todo: vfnmsub213pd"); }, - VFNMSUB213PS => { panic!("todo: vfnmsub213ps"); }, - VFNMSUB213SD => { panic!("todo: vfnmsub213sd"); }, - VFNMSUB213SS => { panic!("todo: vfnmsub213ss"); }, - VFNMSUB231PD => { panic!("todo: vfnmsub231pd"); }, - VFNMSUB231PS => { panic!("todo: vfnmsub231ps"); }, - VFNMSUB231SD => { panic!("todo: vfnmsub231sd"); }, - VFNMSUB231SS => { panic!("todo: vfnmsub231ss"); }, - VGATHERDPD => { panic!("todo: vgatherdpd"); }, - VGATHERDPS => { panic!("todo: vgatherdps"); }, - VGATHERQPD => { panic!("todo: vgatherqpd"); }, - VGATHERQPS => { panic!("todo: vgatherqps"); }, + VFMADD132PD => GENERAL_RW_R_R, + VFMADD132PS => GENERAL_RW_R_R, + VFMADD132SD => GENERAL_RW_R_R, + VFMADD132SS => GENERAL_RW_R_R, + VFMADD213PD => GENERAL_RW_R_R, + VFMADD213PS => GENERAL_RW_R_R, + VFMADD213SD => GENERAL_RW_R_R, + VFMADD213SS => GENERAL_RW_R_R, + VFMADD231PD => GENERAL_RW_R_R, + VFMADD231PS => GENERAL_RW_R_R, + VFMADD231SD => GENERAL_RW_R_R, + VFMADD231SS => GENERAL_RW_R_R, + VFMADDSUB132PD => GENERAL_RW_R_R, + VFMADDSUB132PS => GENERAL_RW_R_R, + VFMADDSUB213PD => GENERAL_RW_R_R, + VFMADDSUB213PS => GENERAL_RW_R_R, + VFMADDSUB231PD => GENERAL_RW_R_R, + VFMADDSUB231PS => GENERAL_RW_R_R, + VFMSUB132PD => GENERAL_RW_R_R, + VFMSUB132PS => GENERAL_RW_R_R, + VFMSUB132SD => GENERAL_RW_R_R, + VFMSUB132SS => GENERAL_RW_R_R, + VFMSUB213PD => GENERAL_RW_R_R, + VFMSUB213PS => GENERAL_RW_R_R, + VFMSUB213SD => GENERAL_RW_R_R, + VFMSUB213SS => GENERAL_RW_R_R, + VFMSUB231PD => GENERAL_RW_R_R, + VFMSUB231PS => GENERAL_RW_R_R, + VFMSUB231SD => GENERAL_RW_R_R, + VFMSUB231SS => GENERAL_RW_R_R, + VFMSUBADD132PD => GENERAL_RW_R_R, + VFMSUBADD132PS => GENERAL_RW_R_R, + VFMSUBADD213PD => GENERAL_RW_R_R, + VFMSUBADD213PS => GENERAL_RW_R_R, + VFMSUBADD231PD => GENERAL_RW_R_R, + VFMSUBADD231PS => GENERAL_RW_R_R, + VFNMADD132PD => GENERAL_RW_R_R, + VFNMADD132PS => GENERAL_RW_R_R, + VFNMADD132SD => GENERAL_RW_R_R, + VFNMADD132SS => GENERAL_RW_R_R, + VFNMADD213PD => GENERAL_RW_R_R, + VFNMADD213PS => GENERAL_RW_R_R, + VFNMADD213SD => GENERAL_RW_R_R, + VFNMADD213SS => GENERAL_RW_R_R, + VFNMADD231PD => GENERAL_RW_R_R, + VFNMADD231PS => GENERAL_RW_R_R, + VFNMADD231SD => GENERAL_RW_R_R, + VFNMADD231SS => GENERAL_RW_R_R, + VFNMSUB132PD => GENERAL_RW_R_R, + VFNMSUB132PS => GENERAL_RW_R_R, + VFNMSUB132SD => GENERAL_RW_R_R, + VFNMSUB132SS => GENERAL_RW_R_R, + VFNMSUB213PD => GENERAL_RW_R_R, + VFNMSUB213PS => GENERAL_RW_R_R, + VFNMSUB213SD => GENERAL_RW_R_R, + VFNMSUB213SS => GENERAL_RW_R_R, + VFNMSUB231PD => GENERAL_RW_R_R, + VFNMSUB231PS => GENERAL_RW_R_R, + VFNMSUB231SD => GENERAL_RW_R_R, + VFNMSUB231SS => GENERAL_RW_R_R, + VGATHERDPD => BehaviorDigest::empty() + .set_complex(true), + VGATHERDPS => BehaviorDigest::empty() + .set_complex(true), + VGATHERQPD => BehaviorDigest::empty() + .set_complex(true), + VGATHERQPS => BehaviorDigest::empty() + .set_complex(true), VHADDPD => GENERAL_W_R_R, VHSUBPD => GENERAL_W_R_R, VINSERTF128 => { panic!("todo: vinsertf128"); }, VINSERTI128 => { panic!("todo: vinserti128"); }, VINSERTPS => { panic!("todo: vinsertps"); }, - VMASKMOVDQU => { panic!("todo: vmaskmovdqu"); }, - VMASKMOVPD => { panic!("todo: vmaskmovpd"); }, - VMASKMOVPS => { panic!("todo: vmaskmovps"); }, + VMASKMOVDQU => GENERAL_R_R + .set_nontrivial(true), + VMASKMOVPD => GENERAL_W_R_R, + VMASKMOVPS => GENERAL_W_R_R, VMAXPD => GENERAL_W_R_R, VMAXPS => GENERAL_W_R_R, - VMAXSD => { panic!("todo: vmaxsd"); }, - VMAXSS => { panic!("todo: vmaxss"); }, + VMAXSD => GENERAL_W_R_R, + VMAXSS => GENERAL_W_R_R, VMINPD => GENERAL_W_R_R, VMINPS => GENERAL_W_R_R, - VMINSD => { panic!("todo: vminsd"); }, - VMINSS => { panic!("todo: vminss"); }, - VMOVAPD => { panic!("todo: vmovapd"); }, - VMOVAPS => { panic!("todo: vmovaps"); }, + VMINSD => GENERAL_W_R_R, + VMINSS => GENERAL_W_R_R, + VMOVAPD => GENERAL_W_R, + VMOVAPS => GENERAL_W_R, VMOVD => GENERAL_W_R, - VMOVDQA => { panic!("todo: vmovdqa"); }, - VMOVDQU => { panic!("todo: vmovdqu"); }, + VMOVDQA => GENERAL_W_R, + VMOVDQU => GENERAL_W_R, VMOVHLPS => GENERAL_W_R_R, - VMOVHPD => GENERAL_W_R, - VMOVHPS => GENERAL_W_R, VMOVLHPS => GENERAL_W_R_R, - VMOVLPD => GENERAL_W_R, - VMOVLPS => GENERAL_W_R, - VMOVMSKPD => { panic!("todo: vmovmskpd"); }, - VMOVMSKPS => { panic!("todo: vmovmskps"); }, - VMOVNTDQ => { panic!("todo: vmovntdq"); }, - VMOVNTDQA => { panic!("todo: vmovntdqa"); }, - VMOVNTPD => { panic!("todo: vmovntpd"); }, - VMOVNTPS => { panic!("todo: vmovntps"); }, + // these four are not actually reached due to check above + VMOVHPD => BehaviorDigest::empty(), + VMOVHPS => BehaviorDigest::empty(), + VMOVLPD => BehaviorDigest::empty(), + VMOVLPS => BehaviorDigest::empty(), + VMOVMSKPD => GENERAL_W_R, + VMOVMSKPS => GENERAL_W_R, + VMOVNTDQ => GENERAL_W_R, + VMOVNTDQA => GENERAL_W_R, + VMOVNTPD => GENERAL_W_R, + VMOVNTPS => GENERAL_W_R, VMOVQ => GENERAL_W_R, VMOVSS => GENERAL_W_R_R, VMOVSD => GENERAL_W_R_R, @@ -3077,14 +3290,15 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { VMOVSLDUP => GENERAL_W_R, VMOVUPD => GENERAL_W_R, VMOVUPS => GENERAL_W_R, - VMPSADBW => { panic!("todo: vmpsadbw"); }, + VMPSADBW => GENERAL_W_R_R + .set_operand(3, Access::Read), VMULPD => GENERAL_W_R_R, VMULPS => GENERAL_W_R_R, - VMULSD => { panic!("todo: vmulsd"); }, - VMULSS => { panic!("todo: vmulss"); }, - VPABSB => { panic!("todo: vpabsb"); }, - VPABSD => { panic!("todo: vpabsd"); }, - VPABSW => { panic!("todo: vpabsw"); }, + VMULSD => GENERAL_W_R_R, + VMULSS => GENERAL_W_R_R, + VPABSB => GENERAL_W_R, + VPABSD => GENERAL_W_R, + VPABSW => GENERAL_W_R, VPACKSSDW => GENERAL_W_R_R, VPACKUSDW => GENERAL_W_R_R, VPACKSSWB => GENERAL_W_R_R, @@ -3092,8 +3306,8 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { VPADDB => GENERAL_W_R_R, VPADDD => GENERAL_W_R_R, VPADDQ => GENERAL_W_R_R, - VPADDSB => { panic!("todo: vpaddsb"); }, - VPADDSW => { panic!("todo: vpaddsw"); }, + VPADDSB => GENERAL_W_R_R, + VPADDSW => GENERAL_W_R_R, VPADDUSB => GENERAL_W_R_R, VPADDUSW => GENERAL_W_R_R, VPADDW => GENERAL_W_R_R, @@ -3108,14 +3322,15 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { VPANDN => GENERAL_W_R_R, VPAVGB => GENERAL_W_R_R, VPAVGW => GENERAL_W_R_R, - VPBLENDD => { panic!("todo: vpblendd"); }, - VPBLENDVB => { panic!("todo: vpblendvb"); }, - VPBLENDW => { panic!("todo: vpblendw"); }, - VPBROADCASTB => { panic!("todo: vpbroadcastb"); }, - VPBROADCASTD => { panic!("todo: vpbroadcastd"); }, - VPBROADCASTQ => { panic!("todo: vpbroadcastq"); }, - VPBROADCASTW => { panic!("todo: vpbroadcastw"); }, - VPCLMULQDQ => { panic!("todo: vpclmulqdq"); }, + VPBLENDD => GENERAL_W_R_R, + VPBLENDVB => GENERAL_W_R_R, + VPBLENDW => GENERAL_W_R_R, + VPBROADCASTB => GENERAL_W_R, + VPBROADCASTD => GENERAL_W_R, + VPBROADCASTQ => GENERAL_W_R, + VPBROADCASTW => GENERAL_W_R, + VPCLMULQDQ => GENERAL_W_R_R + .set_operand(3, Access::Read), VPCMPEQB => GENERAL_W_R_R, VPCMPEQD => GENERAL_W_R_R, VPCMPEQQ => GENERAL_W_R_R, @@ -3130,99 +3345,108 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { VPCMPISTRM => { panic!("todo: vpcmpistrm"); }, VPERM2F128 => { panic!("todo: vperm2f128"); }, VPERM2I128 => { panic!("todo: vperm2i128"); }, - VPERMD => { panic!("todo: vpermd"); }, + VPERMD => GENERAL_W_R_R, VPERMILPD => GENERAL_W_R_R, VPERMILPS => GENERAL_W_R_R, VPERMPD => GENERAL_W_R_R, VPERMPS => GENERAL_W_R_R, - VPERMQ => { panic!("todo: vpermq"); }, + VPERMQ => GENERAL_W_R_R, VPEXTRB => { panic!("todo: vpextrb"); }, VPEXTRD => { panic!("todo: vpextrd"); }, VPEXTRQ => { panic!("todo: vpextrq"); }, VPEXTRW => { panic!("todo: vpextrw"); }, - VPGATHERDD => { panic!("todo: vpgatherdd"); }, - VPGATHERDQ => { panic!("todo: vpgatherdq"); }, - VPGATHERQD => { panic!("todo: vpgatherqd"); }, - VPGATHERQQ => { panic!("todo: vpgatherqq"); }, + // TODO: complex + VPGATHERDD => BehaviorDigest::empty() + .set_complex(true), + VPGATHERDQ => BehaviorDigest::empty() + .set_complex(true), + VPGATHERQD => BehaviorDigest::empty() + .set_complex(true), + VPGATHERQQ => BehaviorDigest::empty() + .set_complex(true), VPHADDD => GENERAL_W_R_R, VPHADDSW => GENERAL_W_R_R, VPHADDW => GENERAL_W_R_R, VPMADDUBSW => GENERAL_W_R_R, - VPHMINPOSUW => { panic!("todo: vphminposuw"); }, + VPHMINPOSUW => GENERAL_W_R, VPHSUBD => GENERAL_W_R_R, VPHSUBSW => GENERAL_W_R_R, VPHSUBW => GENERAL_W_R_R, - VPINSRB => { panic!("todo: vpinsrb"); }, - VPINSRD => { panic!("todo: vpinsrd"); }, - VPINSRQ => { panic!("todo: vpinsrq"); }, - VPINSRW => { panic!("todo: vpinsrw"); }, - VPMADDWD => { panic!("todo: vpmaddwd"); }, - VPMASKMOVD => { panic!("todo: vpmaskmovd"); }, - VPMASKMOVQ => { panic!("todo: vpmaskmovq"); }, - VPMAXSB => { panic!("todo: vpmaxsb"); }, - VPMAXSD => { panic!("todo: vpmaxsd"); }, - VPMAXSW => { panic!("todo: vpmaxsw"); }, + VPINSRB => GENERAL_W_R_R + .set_operand(3, Access::Read), + VPINSRD => GENERAL_W_R_R + .set_operand(3, Access::Read), + VPINSRQ => GENERAL_W_R_R + .set_operand(3, Access::Read), + VPINSRW => GENERAL_W_R_R + .set_operand(3, Access::Read), + VPMADDWD => GENERAL_W_R_R, + VPMASKMOVD => GENERAL_W_R_R, + VPMASKMOVQ => GENERAL_W_R_R, + VPMAXSB => GENERAL_W_R_R, + VPMAXSD => GENERAL_W_R_R, + VPMAXSW => GENERAL_W_R_R, VPMAXUB => GENERAL_W_R_R, VPMAXUW => GENERAL_W_R_R, VPMAXUD => GENERAL_W_R_R, - VPMINSB => { panic!("todo: vpminsb"); }, - VPMINSW => { panic!("todo: vpminsw"); }, - VPMINSD => { panic!("todo: vpminsd"); }, + VPMINSB => GENERAL_W_R_R, + VPMINSW => GENERAL_W_R_R, + VPMINSD => GENERAL_W_R_R, VPMINUB => GENERAL_W_R_R, VPMINUW => GENERAL_W_R_R, VPMINUD => GENERAL_W_R_R, - VPMOVMSKB => { panic!("todo: vpmovmskb"); }, - VPMOVSXBD => { panic!("todo: vpmovsxbd"); }, - VPMOVSXBQ => { panic!("todo: vpmovsxbq"); }, - VPMOVSXBW => { panic!("todo: vpmovsxbw"); }, - VPMOVSXDQ => { panic!("todo: vpmovsxdq"); }, - VPMOVSXWD => { panic!("todo: vpmovsxwd"); }, - VPMOVSXWQ => { panic!("todo: vpmovsxwq"); }, - VPMOVZXBD => { panic!("todo: vpmovzxbd"); }, - VPMOVZXBQ => { panic!("todo: vpmovzxbq"); }, - VPMOVZXBW => { panic!("todo: vpmovzxbw"); }, - VPMOVZXDQ => { panic!("todo: vpmovzxdq"); }, - VPMOVZXWD => { panic!("todo: vpmovzxwd"); }, - VPMOVZXWQ => { panic!("todo: vpmovzxwq"); }, - VPMULDQ => { panic!("todo: vpmuldq"); }, + VPMOVMSKB => GENERAL_W_R, + VPMOVSXBD => GENERAL_W_R, + VPMOVSXBQ => GENERAL_W_R, + VPMOVSXBW => GENERAL_W_R, + VPMOVSXDQ => GENERAL_W_R, + VPMOVSXWD => GENERAL_W_R, + VPMOVSXWQ => GENERAL_W_R, + VPMOVZXBD => GENERAL_W_R, + VPMOVZXBQ => GENERAL_W_R, + VPMOVZXBW => GENERAL_W_R, + VPMOVZXDQ => GENERAL_W_R, + VPMOVZXWD => GENERAL_W_R, + VPMOVZXWQ => GENERAL_W_R, + VPMULDQ => GENERAL_W_R_R, VPMULHRSW => GENERAL_W_R_R, VPMULHUW => GENERAL_W_R_R, - VPMULHW => { panic!("todo: vpmulhw"); }, + VPMULHW => GENERAL_W_R_R, VPMULLQ => GENERAL_W_R_R, VPMULLD => GENERAL_W_R_R, VPMULLW => GENERAL_W_R_R, - VPMULUDQ => { panic!("todo: vpmuludq"); }, - VPOR => { panic!("todo: vpor"); }, - VPSADBW => { panic!("todo: vpsadbw"); }, + VPMULUDQ => GENERAL_W_R_R, + VPOR => GENERAL_W_R_R, + VPSADBW => GENERAL_W_R_R, VPSHUFB => GENERAL_W_R_R, VPSHUFD => GENERAL_W_R_R, VPSIGNB => GENERAL_W_R_R, VPSIGND => GENERAL_W_R_R, VPSIGNW => GENERAL_W_R_R, - VPSLLD => { panic!("todo: vpslld"); }, - VPSLLDQ => { panic!("todo: vpslldq"); }, - VPSLLQ => { panic!("todo: vpsllq"); }, - VPSLLVD => { panic!("todo: vpsllvd"); }, - VPSLLVQ => { panic!("todo: vpsllvq"); }, - VPSLLW => { panic!("todo: vpsllw"); }, - VPSRAD => { panic!("todo: vpsrad"); }, - VPSRAVD => { panic!("todo: vpsravd"); }, + VPSLLD => GENERAL_W_R_R, + VPSLLDQ => GENERAL_W_R_R, + VPSLLQ => GENERAL_W_R_R, + VPSLLVD => GENERAL_W_R_R, + VPSLLVQ => GENERAL_W_R_R, + VPSLLW => GENERAL_W_R_R, + VPSRAD => GENERAL_W_R_R, + VPSRAVD => GENERAL_W_R_R, VPSRAW => GENERAL_W_R_R, VPSRLD => GENERAL_W_R_R, - VPSRLDQ => { panic!("todo: vpsrldq"); }, + VPSRLDQ => GENERAL_W_R_R, VPSRLQ => GENERAL_W_R_R, - VPSRLVD => { panic!("todo: vpsrlvd"); }, - VPSRLVQ => { panic!("todo: vpsrlvq"); }, + VPSRLVD => GENERAL_W_R_R, + VPSRLVQ => GENERAL_W_R_R, VPSRLW => GENERAL_W_R_R, VPSUBB => GENERAL_W_R_R, VPSUBD => GENERAL_W_R_R, VPSUBQ => GENERAL_W_R_R, - VPSUBSB => { panic!("todo: vpsubsb"); }, - VPSUBSW => { panic!("todo: vpsubsw"); }, + VPSUBSB => GENERAL_W_R_R, + VPSUBSW => GENERAL_W_R_R, VPSUBUSB => GENERAL_W_R_R, VPSUBUSW => GENERAL_W_R_R, VPSUBW => GENERAL_W_R_R, - VPTEST => { panic!("todo: vptest"); }, + VPTEST => GENERAL_R_R_FLAGWRITE, VPUNPCKHBW => GENERAL_W_R_R, VPUNPCKHDQ => GENERAL_W_R_R, VPUNPCKHQDQ => GENERAL_W_R_R, @@ -3233,33 +3457,33 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { VPUNPCKLWD => GENERAL_W_R_R, VPXOR => GENERAL_W_R_R, VRCPPS => GENERAL_W_R, - VROUNDPD => { panic!("todo: vroundpd"); }, - VROUNDPS => { panic!("todo: vroundps"); }, - VROUNDSD => { panic!("todo: vroundsd"); }, - VROUNDSS => { panic!("todo: vroundss"); }, + VROUNDPD => GENERAL_W_R_R, + VROUNDPS => GENERAL_W_R_R, + VROUNDSD => GENERAL_W_R_R, + VROUNDSS => GENERAL_W_R_R, VRSQRTPS => GENERAL_W_R, - VRSQRTSS => GENERAL_RW_R, - VRCPSS => { panic!("todo: vrcpss"); }, + VRSQRTSS => GENERAL_W_R_R, + VRCPSS => GENERAL_W_R_R, VSHUFPD => GENERAL_W_R_R .set_operand(3, Access::Read), VSHUFPS => GENERAL_W_R_R .set_operand(3, Access::Read), VSQRTPD => GENERAL_W_R, VSQRTPS => GENERAL_W_R, - VSQRTSS => GENERAL_RW_R, - VSQRTSD => { panic!("todo: vsqrtsd"); }, - VSUBPD => { panic!("todo: vsubpd"); }, - VSUBPS => { panic!("todo: vsubps"); }, - VSUBSD => { panic!("todo: vsubsd"); }, - VSUBSS => { panic!("todo: vsubss"); }, + VSQRTSS => GENERAL_W_R_R, + VSQRTSD => GENERAL_W_R_R, + VSUBPD => GENERAL_W_R_R, + VSUBPS => GENERAL_W_R_R, + VSUBSD => GENERAL_W_R_R, + VSUBSS => GENERAL_W_R_R, VTESTPD => GENERAL_R_R .set_flags_access(Access::Write), VTESTPS => GENERAL_R_R .set_flags_access(Access::Write), - VUNPCKHPD => { panic!("todo: vunpckhpd"); }, - VUNPCKHPS => { panic!("todo: vunpckhps"); }, - VUNPCKLPD => { panic!("todo: vunpcklpd"); }, - VUNPCKLPS => { panic!("todo: vunpcklps"); }, + VUNPCKHPD => GENERAL_W_R_R, + VUNPCKHPS => GENERAL_W_R_R, + VUNPCKLPD => GENERAL_W_R_R, + VUNPCKLPS => GENERAL_W_R_R, VXORPD => GENERAL_W_R_R, VXORPS => GENERAL_W_R_R, VZEROUPPER => { panic!("todo: vzeroupper"); }, @@ -3390,14 +3614,19 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { VMPTRLD => { panic!("todo: vmptrld"); }, VMPTRST => { panic!("todo: vmptrst"); }, - BZHI => { panic!("todo: bzhi"); }, - MULX => { panic!("todo: mulx"); }, - SHLX => { panic!("todo: shlx"); }, - SHRX => { panic!("todo: shrx"); }, - SARX => { panic!("todo: sarx"); }, - PDEP => { panic!("todo: pdep"); }, - PEXT => { panic!("todo: pext"); }, - RORX => { panic!("todo: rorx"); }, + BZHI => GENERAL_W_R_R + .set_flags_access(Access::Write), + MULX => BehaviorDigest::empty() + .set_operand(0, Access::Write) + .set_operand(1, Access::Write) + .set_operand(2, Access::Read) + .set_nontrivial(true), + SHLX => GENERAL_W_R_R, + SHRX => GENERAL_W_R_R, + SARX => GENERAL_W_R_R, + PDEP => GENERAL_W_R_R, + PEXT => GENERAL_W_R_R, + RORX => GENERAL_W_R_R, XRSTORS => { panic!("todo: xrstors"); }, XRSTORS64 => { panic!("todo: xrstors64"); }, XSAVEC => { panic!("todo: xsavec"); }, @@ -3769,10 +3998,15 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { VPRORQ => { panic!("todo: vprorq"); }, VPRORRD => { panic!("todo: vprorrd"); }, VPRORRQ => { panic!("todo: vprorrq"); }, - VPSCATTERDD => { panic!("todo: vpscatterdd"); }, - VPSCATTERDQ => { panic!("todo: vpscatterdq"); }, - VPSCATTERQD => { panic!("todo: vpscatterqd"); }, - VPSCATTERQQ => { panic!("todo: vpscatterqq"); }, + // TODO: complex + VPSCATTERDD => BehaviorDigest::empty() + .set_complex(true), + VPSCATTERDQ => BehaviorDigest::empty() + .set_complex(true), + VPSCATTERQD => BehaviorDigest::empty() + .set_complex(true), + VPSCATTERQQ => BehaviorDigest::empty() + .set_complex(true), VPSRAQ => { panic!("todo: vpsraq"); }, VPSRAVQ => { panic!("todo: vpsravq"); }, VPTESTNMD => { panic!("todo: vptestnmd"); }, @@ -3974,16 +4208,16 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { VPSHLDQ => { panic!("todo: vpshldq"); }, VPSHLDD => { panic!("todo: vpshldd"); }, VPSHLDW => { panic!("todo: vpshldw"); }, - VBROADCASTF32X8 => { panic!("todo: vbroadcastf32x8"); }, - VBROADCASTF64X4 => { panic!("todo: vbroadcastf64x4"); }, - VBROADCASTF32X4 => { panic!("todo: vbroadcastf32x4"); }, - VBROADCASTF64X2 => { panic!("todo: vbroadcastf64x2"); }, - VBROADCASTF32X2 => { panic!("todo: vbroadcastf32x2"); }, - VBROADCASTI32X8 => { panic!("todo: vbroadcasti32x8"); }, - VBROADCASTI64X4 => { panic!("todo: vbroadcasti64x4"); }, - VBROADCASTI32X4 => { panic!("todo: vbroadcasti32x4"); }, - VBROADCASTI64X2 => { panic!("todo: vbroadcasti64x2"); }, - VBROADCASTI32X2 => { panic!("todo: vbroadcasti32x2"); }, + VBROADCASTF32X8 => GENERAL_W_R, + VBROADCASTF64X4 => GENERAL_W_R, + VBROADCASTF32X4 => GENERAL_W_R, + VBROADCASTF64X2 => GENERAL_W_R, + VBROADCASTF32X2 => GENERAL_W_R, + VBROADCASTI32X8 => GENERAL_W_R, + VBROADCASTI64X4 => GENERAL_W_R, + VBROADCASTI32X4 => GENERAL_W_R, + VBROADCASTI64X2 => GENERAL_W_R, + VBROADCASTI32X2 => GENERAL_W_R, VEXTRACTI32X8 => { panic!("todo: vextracti32x8"); }, VEXTRACTF32X8 => { panic!("todo: vextractf32x8"); }, VINSERTI32X8 => { panic!("todo: vinserti32x8"); }, @@ -4019,7 +4253,7 @@ fn opcode2behavior(opc: &Opcode) -> Option<BehaviorDigest> { VPERMB => { panic!("todo: vpermb"); }, VPEXPANDD => { panic!("todo: vpexpandd"); }, VPEXPANDQ => { panic!("todo: vpexpandq"); }, - VPABSQ => { panic!("todo: vpabsq"); }, + VPABSQ => GENERAL_W_R, VPRORVD => { panic!("todo: vprorvd"); }, VPRORVQ => { panic!("todo: vprorvq"); }, VPMULTISHIFTQB => { panic!("todo: vpmultishiftqb"); }, |
