diff options
Diffstat (limited to 'src/protected_mode/mod.rs')
-rw-r--r-- | src/protected_mode/mod.rs | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/src/protected_mode/mod.rs b/src/protected_mode/mod.rs index 7c7a4c0..74522d9 100644 --- a/src/protected_mode/mod.rs +++ b/src/protected_mode/mod.rs @@ -4332,6 +4332,171 @@ impl Instruction { Operand::from_spec(self, self.operands[i as usize]) } + /// TODO: make public, document, etc... + /// + /// `visit_operand` allows code using operands to better specialize and inline with the logic + /// that would construct an [`Operand`] variant, without having to necessarily construct an + /// `Operand` (including the attendant move of the enum). + /// + /// if the work you expect to do per-operand is very small, constructing an `Operand` and + /// dispatching on tags may be a substantial factor of overall runtime. `visit_operand` can + /// reduce total overhead in such cases. + #[cfg_attr(features="profiling", inline(never))] + fn visit_operand<T: OperandVisitor>(&self, i: u8, visitor: &mut T) -> Result<T::Ok, T::Error> { + assert!(i < 4); + let spec = self.operands[i as usize]; + match spec { + OperandSpec::Nothing => { + visitor.visit_other() + } + OperandSpec::RegRRR => { + visitor.visit_reg(self.regs[0]) + } + OperandSpec::RegMMM => { + visitor.visit_reg(self.regs[1]) + } + OperandSpec::RegVex => { + visitor.visit_reg(self.regs[3]) + } + OperandSpec::Reg4 => { + visitor.visit_reg(RegSpec { num: self.imm as u8, bank: self.regs[3].bank }) + } + OperandSpec::Deref => { + visitor.visit_deref(self.regs[1]) + } + OperandSpec::Deref_si => { +// visitor.visit_other() + visitor.visit_deref(RegSpec::si()) + } + OperandSpec::Deref_di => { +// visitor.visit_other() + visitor.visit_deref(RegSpec::di()) + } + OperandSpec::Deref_esi => { +// visitor.visit_other() + visitor.visit_deref(RegSpec::esi()) + } + OperandSpec::Deref_edi => { +// visitor.visit_other() + visitor.visit_deref(RegSpec::edi()) + } + OperandSpec::RegDisp => { + visitor.visit_disp(self.regs[1], self.disp as i32) + } + OperandSpec::RegRRR_maskmerge => { + visitor.visit_reg_mask_merge( + self.regs[0], + RegSpec::mask(self.prefixes.evex_unchecked().mask_reg()), + MergeMode::from(self.prefixes.evex_unchecked().merge()), + ) + } + OperandSpec::RegRRR_maskmerge_sae => { + visitor.visit_reg_mask_merge_sae( + self.regs[0], + RegSpec::mask(self.prefixes.evex_unchecked().mask_reg()), + MergeMode::from(self.prefixes.evex_unchecked().merge()), + SaeMode::from(self.prefixes.evex_unchecked().vex().l(), self.prefixes.evex_unchecked().lp()), + ) + } + OperandSpec::RegRRR_maskmerge_sae_noround => { + visitor.visit_reg_mask_merge_sae_noround( + self.regs[0], + RegSpec::mask(self.prefixes.evex_unchecked().mask_reg()), + MergeMode::from(self.prefixes.evex_unchecked().merge()), + ) + } + OperandSpec::RegMMM_maskmerge => { + visitor.visit_reg_mask_merge( + self.regs[1], + RegSpec::mask(self.prefixes.evex_unchecked().mask_reg()), + MergeMode::from(self.prefixes.evex_unchecked().merge()), + ) + } + OperandSpec::RegMMM_maskmerge_sae_noround => { + visitor.visit_reg_mask_merge_sae_noround( + self.regs[1], + RegSpec::mask(self.prefixes.evex_unchecked().mask_reg()), + MergeMode::from(self.prefixes.evex_unchecked().merge()), + ) + } + OperandSpec::RegVex_maskmerge => { + visitor.visit_reg_mask_merge( + self.regs[3], + RegSpec::mask(self.prefixes.evex_unchecked().mask_reg()), + MergeMode::from(self.prefixes.evex_unchecked().merge()), + ) + } + OperandSpec::ImmI8 => visitor.visit_i8(self.imm as i8), + OperandSpec::ImmU8 => visitor.visit_u8(self.imm as u8), + OperandSpec::ImmI16 => visitor.visit_i16(self.imm as i16), + OperandSpec::ImmU16 => visitor.visit_u16(self.imm as u16), + OperandSpec::ImmI32 => visitor.visit_i32(self.imm as i32), + OperandSpec::ImmInDispField => visitor.visit_u16(self.disp as u16), + OperandSpec::DispU16 => visitor.visit_abs_u16(self.disp as u16), + OperandSpec::DispU32 => visitor.visit_abs_u32(self.disp as u32), + OperandSpec::RegScale => { + visitor.visit_reg_scale(self.regs[2], self.scale) + } + OperandSpec::RegScaleDisp => { + visitor.visit_reg_scale_disp(self.regs[2], self.scale, self.disp as i32) + } + OperandSpec::RegIndexBaseScale => { + visitor.visit_index_base_scale(self.regs[1], self.regs[2], self.scale) + /* + Operand::RegIndexBaseScale(self.regs[1], self.regs[2], self.scale) + */ + } + OperandSpec::RegIndexBaseScaleDisp => { + visitor.visit_index_base_scale_disp(self.regs[1], self.regs[2], self.scale, self.disp as i32) + } + OperandSpec::Deref_mask => { + if self.prefixes.evex_unchecked().mask_reg() != 0 { + visitor.visit_reg_deref_masked(self.regs[1], RegSpec::mask(self.prefixes.evex_unchecked().mask_reg())) + } else { + visitor.visit_deref(self.regs[1]) + } + } + OperandSpec::RegDisp_mask => { + if self.prefixes.evex_unchecked().mask_reg() != 0 { + visitor.visit_reg_disp_masked(self.regs[1], self.disp as i32, RegSpec::mask(self.prefixes.evex_unchecked().mask_reg())) + } else { + visitor.visit_disp(self.regs[1], self.disp as i32) + } + } + OperandSpec::RegScale_mask => { + if self.prefixes.evex_unchecked().mask_reg() != 0 { + visitor.visit_reg_scale_masked(self.regs[2], self.scale, RegSpec::mask(self.prefixes.evex_unchecked().mask_reg())) + } else { + visitor.visit_reg_scale(self.regs[2], self.scale) + } + } + OperandSpec::RegScaleDisp_mask => { + if self.prefixes.evex_unchecked().mask_reg() != 0 { + visitor.visit_reg_scale_disp_masked(self.regs[2], self.scale, self.disp as i32, RegSpec::mask(self.prefixes.evex_unchecked().mask_reg())) + } else { + visitor.visit_reg_scale_disp(self.regs[2], self.scale, self.disp as i32) + } + } + OperandSpec::RegIndexBaseScale_mask => { + if self.prefixes.evex_unchecked().mask_reg() != 0 { + visitor.visit_index_base_scale_masked(self.regs[1], self.regs[2], self.scale, RegSpec::mask(self.prefixes.evex_unchecked().mask_reg())) + } else { + visitor.visit_index_base_scale(self.regs[1], self.regs[2], self.scale) + } + } + OperandSpec::RegIndexBaseScaleDisp_mask => { + if self.prefixes.evex_unchecked().mask_reg() != 0 { + visitor.visit_index_base_scale_disp_masked(self.regs[1], self.regs[2], self.scale, self.disp as i32, RegSpec::mask(self.prefixes.evex_unchecked().mask_reg())) + } else { + visitor.visit_index_base_scale_disp(self.regs[1], self.regs[2], self.scale, self.disp as i32) + } + } + OperandSpec::AbsoluteFarAddress => { + visitor.visit_absolute_far_address(self.disp as u16, self.imm as u32) + } + } + } + /// get the number of operands in this instruction. useful in iterating an instruction's /// operands generically. pub fn operand_count(&self) -> u8 { |