diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/long_mode/display.rs | 310 | ||||
| -rw-r--r-- | src/long_mode/mod.rs | 199 | 
2 files changed, 482 insertions, 27 deletions
| diff --git a/src/long_mode/display.rs b/src/long_mode/display.rs index 1a31073..5237868 100644 --- a/src/long_mode/display.rs +++ b/src/long_mode/display.rs @@ -349,6 +349,257 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Operand {      }  } +struct ColorizingOperandVisitor<'a, T, Y> { +    instr: &'a Instruction, +    op_nr: u8, +    colors: &'a Y, +    f: &'a mut T, +} + +impl <T: fmt::Write, Y: YaxColors> crate::long_mode::OperandVisitor for ColorizingOperandVisitor<'_, T, Y> { +    type Ok = (); +    type Error = core::fmt::Error; + +    fn visit_u8(&mut self, imm: u8) -> Result<Self::Ok, Self::Error> { +        write!(self.f, "{}", self.colors.number(u8_hex(imm))) +    } +    fn visit_i8(&mut self, imm: i8) -> Result<Self::Ok, Self::Error> { +        write!(self.f, "{}", +            self.colors.number(signed_i8_hex(imm))) +    } +    fn visit_u16(&mut self, imm: u16) -> Result<Self::Ok, Self::Error> { +        write!(self.f, "{}", self.colors.number(u16_hex(imm))) +    } +    fn visit_i16(&mut self, imm: i16) -> Result<Self::Ok, Self::Error> { +        write!(self.f, "{}", +            self.colors.number(signed_i16_hex(imm))) +    } +    fn visit_u32(&mut self, imm: u32) -> Result<Self::Ok, Self::Error> { +        write!(self.f, "{}", self.colors.number(u32_hex(imm))) +    } +    fn visit_i32(&mut self, imm: i32) -> Result<Self::Ok, Self::Error> { +        write!(self.f, "{}", +            self.colors.number(signed_i32_hex(imm))) +    } +    fn visit_u64(&mut self, imm: u64) -> Result<Self::Ok, Self::Error> { +        write!(self.f, "{}", self.colors.number(u64_hex(imm))) +    } +    fn visit_i64(&mut self, imm: i64) -> Result<Self::Ok, Self::Error> { +        write!(self.f, "{}", +            self.colors.number(signed_i64_hex(imm))) +    } +    fn visit_reg(&mut self, reg: RegSpec) -> Result<Self::Ok, Self::Error> { +        self.f.write_str(regspec_label(®)) +    } +    fn visit_reg_mask_merge(&mut self, spec: RegSpec, mask: RegSpec, merge_mode: MergeMode) -> Result<Self::Ok, Self::Error> { +        self.f.write_str(regspec_label(&spec))?; +        if mask.num != 0 { +            self.f.write_str("{")?; +            self.f.write_str(regspec_label(&mask))?; +            self.f.write_str("}")?; +        } +        if let MergeMode::Zero = merge_mode { +            self.f.write_str("{z}")?; +        } +        Ok(()) +    } +    fn visit_reg_mask_merge_sae(&mut self, spec: RegSpec, mask: RegSpec, merge_mode: MergeMode, sae_mode: crate::long_mode::SaeMode) -> Result<Self::Ok, Self::Error> { +        self.f.write_str(regspec_label(&spec))?; +        if mask.num != 0 { +            self.f.write_str("{")?; +            self.f.write_str(regspec_label(&mask))?; +            self.f.write_str("}")?; +        } +        if let MergeMode::Zero = merge_mode { +            self.f.write_str("{z}")?; +        } +        self.f.write_str(sae_mode.label())?; +        Ok(()) +    } +    fn visit_reg_mask_merge_sae_noround(&mut self, spec: RegSpec, mask: RegSpec, merge_mode: MergeMode) -> Result<Self::Ok, Self::Error> { +        self.f.write_str(regspec_label(&spec))?; +        if mask.num != 0 { +            self.f.write_str("{")?; +            self.f.write_str(regspec_label(&mask))?; +            self.f.write_str("}")?; +        } +        if let MergeMode::Zero = merge_mode { +            self.f.write_str("{z}")?; +        } +        self.f.write_str("{sae}")?; +        Ok(()) +    } +    fn visit_abs_u32(&mut self, imm: u32) -> Result<Self::Ok, Self::Error> { +        self.f.write_str(MEM_SIZE_STRINGS[self.instr.mem_size as usize])?; +        self.f.write_str(" ")?; +        if let Some(prefix) = self.instr.segment_override_for_op(self.op_nr) { +            write!(self.f, "{}:", prefix)?; +        } +        write!(self.f, "[{}]", self.colors.address(u32_hex(imm))) +    } +    fn visit_abs_u64(&mut self, imm: u64) -> Result<Self::Ok, Self::Error> { +        self.f.write_str(MEM_SIZE_STRINGS[self.instr.mem_size as usize])?; +        self.f.write_str(" ")?; +        if let Some(prefix) = self.instr.segment_override_for_op(self.op_nr) { +            write!(self.f, "{}:", prefix)?; +        } +        write!(self.f, "[{}]", self.colors.address(u64_hex(imm))) +    } +    fn visit_disp(&mut self, reg: RegSpec, disp: i32) -> Result<Self::Ok, Self::Error> { +        self.f.write_str(MEM_SIZE_STRINGS[self.instr.mem_size as usize])?; +        self.f.write_str(" ")?; +        if let Some(prefix) = self.instr.segment_override_for_op(self.op_nr) { +            write!(self.f, "{}:", prefix)?; +        } +        write!(self.f, "[{} ", regspec_label(®))?; +        format_number_i32(self.colors, self.f, disp, NumberStyleHint::HexSignedWithSignSplit)?; +        write!(self.f, "]") +    } +    fn visit_deref(&mut self, reg: RegSpec) -> Result<Self::Ok, Self::Error> { +        self.f.write_str(MEM_SIZE_STRINGS[self.instr.mem_size as usize])?; +        self.f.write_str(" ")?; +        if let Some(prefix) = self.instr.segment_override_for_op(self.op_nr) { +            write!(self.f, "{}:", prefix)?; +        } +        self.f.write_str("[")?; +        self.f.write_str(regspec_label(®))?; +        self.f.write_str("]") +    } +    fn visit_reg_scale(&mut self, reg: RegSpec, scale: u8) -> Result<Self::Ok, Self::Error> { +        self.f.write_str(MEM_SIZE_STRINGS[self.instr.mem_size as usize])?; +        self.f.write_str(" ")?; +        if let Some(prefix) = self.instr.segment_override_for_op(self.op_nr) { +            write!(self.f, "{}:", prefix)?; +        } +        write!(self.f, "[{} * {}]", +            regspec_label(®), +            self.colors.number(scale) +        ) +    } +    fn visit_reg_scale_disp(&mut self, reg: RegSpec, scale: u8, disp: i32) -> Result<Self::Ok, Self::Error> { +        self.f.write_str(MEM_SIZE_STRINGS[self.instr.mem_size as usize])?; +        self.f.write_str(" ")?; +        if let Some(prefix) = self.instr.segment_override_for_op(self.op_nr) { +            write!(self.f, "{}:", prefix)?; +        } +        write!(self.f, "[{} * {} ", +            regspec_label(®), +            self.colors.number(scale), +        )?; +        format_number_i32(self.colors, self.f, disp, NumberStyleHint::HexSignedWithSignSplit)?; +        write!(self.f, "]") +    } +    fn visit_index_base_scale(&mut self, base: RegSpec, index: RegSpec, scale: u8) -> Result<Self::Ok, Self::Error> { +        self.f.write_str(MEM_SIZE_STRINGS[self.instr.mem_size as usize])?; +        self.f.write_str(" ")?; +        if let Some(prefix) = self.instr.segment_override_for_op(self.op_nr) { +            write!(self.f, "{}:", prefix)?; +        } +        write!(self.f, "[{} + {} * {}]", +            regspec_label(&base), +            regspec_label(&index), +            self.colors.number(scale) +        ) +    } +    fn visit_index_base_scale_disp(&mut self, base: RegSpec, index: RegSpec, scale: u8, disp: i32) -> Result<Self::Ok, Self::Error> { +        self.f.write_str(MEM_SIZE_STRINGS[self.instr.mem_size as usize])?; +        self.f.write_str(" ")?; +        if let Some(prefix) = self.instr.segment_override_for_op(self.op_nr) { +            write!(self.f, "{}:", prefix)?; +        } +        write!(self.f, "[{} + {} * {} ", +            regspec_label(&base), +            regspec_label(&index), +            self.colors.number(scale), +        )?; +        format_number_i32(self.colors, self.f, disp, NumberStyleHint::HexSignedWithSignSplit)?; +        write!(self.f, "]") +    } +    fn visit_reg_disp_masked(&mut self, spec: RegSpec, disp: i32, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error> { +        self.f.write_str(MEM_SIZE_STRINGS[self.instr.mem_size as usize])?; +        self.f.write_str(" ")?; +        write!(self.f, "[{} ", regspec_label(&spec))?; +        format_number_i32(self.colors, self.f, disp, NumberStyleHint::HexSignedWithSignSplit)?; +        write!(self.f, "]")?; +        write!(self.f, "{{{}}}", regspec_label(&mask_reg)) +    } +    fn visit_reg_deref_masked(&mut self, spec: RegSpec, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error> { +        self.f.write_str(MEM_SIZE_STRINGS[self.instr.mem_size as usize])?; +        self.f.write_str(" ")?; +        self.f.write_str("[")?; +        self.f.write_str(regspec_label(&spec))?; +        self.f.write_str("]")?; +        write!(self.f, "{{{}}}", regspec_label(&mask_reg)) +    } +    fn visit_reg_scale_masked(&mut self, spec: RegSpec, scale: u8, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error> { +        self.f.write_str(MEM_SIZE_STRINGS[self.instr.mem_size as usize])?; +        self.f.write_str(" ")?; +        write!(self.f, "[{} * {}]", +            regspec_label(&spec), +            self.colors.number(scale) +        )?; +        write!(self.f, "{{{}}}", regspec_label(&mask_reg)) +    } +    fn visit_reg_scale_disp_masked(&mut self, spec: RegSpec, scale: u8, disp: i32, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error> { +        self.f.write_str(MEM_SIZE_STRINGS[self.instr.mem_size as usize])?; +        self.f.write_str(" ")?; +        write!(self.f, "[{} * {} ", +            regspec_label(&spec), +            self.colors.number(scale), +        )?; +        format_number_i32(self.colors, self.f, disp, NumberStyleHint::HexSignedWithSignSplit)?; +        write!(self.f, "]")?; +        write!(self.f, "{{{}}}", regspec_label(&mask_reg)) +    } +    fn visit_index_base_masked(&mut self, base: RegSpec, index: RegSpec, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error> { +        self.f.write_str(MEM_SIZE_STRINGS[self.instr.mem_size as usize])?; +        self.f.write_str(" ")?; +        self.f.write_str("[")?; +        self.f.write_str(regspec_label(&base))?; +        self.f.write_str(" + ")?; +        self.f.write_str(regspec_label(&index))?; +        self.f.write_str("]")?; +        write!(self.f, "{{{}}}", regspec_label(&mask_reg)) +    } +    fn visit_index_base_disp_masked(&mut self, base: RegSpec, index: RegSpec, disp: i32, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error> { +        self.f.write_str(MEM_SIZE_STRINGS[self.instr.mem_size as usize])?; +        self.f.write_str(" ")?; +        write!(self.f, "[{} + {} ", +            regspec_label(&base), +            regspec_label(&index), +        )?; +        format_number_i32(self.colors, self.f, disp, NumberStyleHint::HexSignedWithSignSplit)?; +        write!(self.f, "]")?; +        write!(self.f, "{{{}}}", regspec_label(&mask_reg)) +    } +    fn visit_index_base_scale_masked(&mut self, base: RegSpec, index: RegSpec, scale: u8, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error> { +        self.f.write_str(MEM_SIZE_STRINGS[self.instr.mem_size as usize])?; +        self.f.write_str(" ")?; +        write!(self.f, "[{} + {} * {}]", +            regspec_label(&base), +            regspec_label(&index), +            self.colors.number(scale) +        )?; +        write!(self.f, "{{{}}}", regspec_label(&mask_reg)) +    } +    fn visit_index_base_scale_disp_masked(&mut self, base: RegSpec, index: RegSpec, scale: u8, disp: i32, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error> { +        self.f.write_str(MEM_SIZE_STRINGS[self.instr.mem_size as usize])?; +        self.f.write_str(" ")?; +        write!(self.f, "[{} + {} * {} ", +            regspec_label(&base), +            regspec_label(&index), +            self.colors.number(scale), +        )?; +        format_number_i32(self.colors, self.f, disp, NumberStyleHint::HexSignedWithSignSplit)?; +        write!(self.f, "]")?; +        write!(self.f, "{{{}}}", regspec_label(&mask_reg)) +    } + +    fn visit_other(&mut self) -> Result<Self::Ok, Self::Error> { +        Ok(()) +    } +} +  impl fmt::Display for Opcode {      fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {          f.write_str(self.name()) @@ -3381,8 +3632,6 @@ 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]); -          const RELATIVE_BRANCHES: [Opcode; 21] = [              Opcode::JMP, Opcode::JRCXZ,              Opcode::LOOP, Opcode::LOOPZ, Opcode::LOOPNZ, @@ -3398,6 +3647,8 @@ fn contextualize_intel<T: fmt::Write, Y: YaxColors>(instr: &Instruction, colors:          if instr.operands[0] == OperandSpec::ImmI8 || instr.operands[0] == OperandSpec::ImmI32 {              if RELATIVE_BRANCHES.contains(&instr.opcode) { +                let x = Operand::from_spec(instr, instr.operands[0]); +                  return match x {                      Operand::ImmediateI8(rel) => {                          if rel >= 0 { @@ -3418,15 +3669,13 @@ fn contextualize_intel<T: fmt::Write, Y: YaxColors>(instr: &Instruction, colors:              }          } -        if x.is_memory() { -            out.write_str(MEM_SIZE_STRINGS[instr.mem_size as usize])?; -            out.write_str(" ")?; -        } - -        if let Some(prefix) = instr.segment_override_for_op(0) { -            write!(out, "{}:", prefix)?; -        } -        x.colorize(colors, out)?; +        let mut displayer = ColorizingOperandVisitor { +            instr, +            op_nr: 0, +            f: out, +            colors, +        }; +        instr.visit_operand(0 as u8, &mut displayer)?;          for i in 1..instr.operand_count {              match instr.opcode { @@ -3437,16 +3686,15 @@ 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])?; -                                out.write_str(" ")?; -                            } -                            if let Some(prefix) = instr.segment_override_for_op(i) { -                                write!(out, "{}:", prefix)?; -                            } -                            x.colorize(colors, out)?; +                            let mut displayer = ColorizingOperandVisitor { +                                instr, +                                op_nr: i, +                                f: out, +                                colors, +                            }; +                            instr.visit_operand(i as u8, &mut displayer)?;                              if let Some(evex) = instr.prefixes.evex() { +                                let x = Operand::from_spec(instr, instr.operands[i as usize]);                                  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 { @@ -3889,8 +4137,14 @@ impl <T: fmt::Write, Y: YaxColors> ShowContextual<u64, [Option<alloc::string::St                          }                      }                  } -                let x = Operand::from_spec(self, self.operands[0]); -                x.colorize(colors, out)?; + +                let mut displayer = ColorizingOperandVisitor { +                    instr: self, +                    op_nr: 0, +                    f: out, +                    colors, +                }; +                self.visit_operand(0, &mut displayer)?;              }          };          for i in 1..self.operand_count { @@ -3904,11 +4158,13 @@ impl <T: fmt::Write, Y: YaxColors> ShowContextual<u64, [Option<alloc::string::St                          },                          _ => {                              write!(out, ", ")?; -                            if let Some(prefix) = self.segment_override_for_op(1) { -                                write!(out, "{}:", prefix)?; -                            } -                            let x = Operand::from_spec(self, self.operands[i]); -                            x.colorize(colors, out)? +                            let mut displayer = ColorizingOperandVisitor { +                                instr: self, +                                op_nr: i as u8, +                                f: out, +                                colors, +                            }; +                            self.visit_operand(i as u8, &mut displayer)?;                          }                      }                  } diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs index 5bdd786..7aab852 100644 --- a/src/long_mode/mod.rs +++ b/src/long_mode/mod.rs @@ -541,6 +541,43 @@ impl SaeMode {          SAE_MODES[idx]      }  } + +pub trait OperandVisitor { +    type Ok; +    type Error; + +    fn visit_reg(&mut self, reg: RegSpec) -> Result<Self::Ok, Self::Error>; +    fn visit_deref(&mut self, reg: RegSpec) -> Result<Self::Ok, Self::Error>; +    fn visit_disp(&mut self, reg: RegSpec, disp: i32) -> Result<Self::Ok, Self::Error>; +    fn visit_reg_scale(&mut self, reg: RegSpec, scale: u8) -> Result<Self::Ok, Self::Error>; +    fn visit_index_base_scale(&mut self, base: RegSpec, index: RegSpec, scale: u8) -> Result<Self::Ok, Self::Error>; +    fn visit_index_base_scale_disp(&mut self, base: RegSpec, index: RegSpec, scale: u8, disp: i32) -> Result<Self::Ok, Self::Error>; +    fn visit_reg_scale_disp(&mut self, reg: RegSpec, scale: u8, disp: i32) -> Result<Self::Ok, Self::Error>; +    fn visit_i8(&mut self, imm: i8) -> Result<Self::Ok, Self::Error>; +    fn visit_u8(&mut self, imm: u8) -> Result<Self::Ok, Self::Error>; +    fn visit_i16(&mut self, imm: i16) -> Result<Self::Ok, Self::Error>; +    fn visit_u16(&mut self, imm: u16) -> Result<Self::Ok, Self::Error>; +    fn visit_i32(&mut self, imm: i32) -> Result<Self::Ok, Self::Error>; +    fn visit_u32(&mut self, imm: u32) -> Result<Self::Ok, Self::Error>; +    fn visit_i64(&mut self, imm: i64) -> Result<Self::Ok, Self::Error>; +    fn visit_u64(&mut self, imm: u64) -> Result<Self::Ok, Self::Error>; +    fn visit_abs_u32(&mut self, imm: u32) -> Result<Self::Ok, Self::Error>; +    fn visit_abs_u64(&mut self, imm: u64) -> Result<Self::Ok, Self::Error>; +    fn visit_reg_mask_merge(&mut self, base: RegSpec, mask: RegSpec, merge_mode: MergeMode) -> Result<Self::Ok, Self::Error>; +    fn visit_reg_mask_merge_sae(&mut self, base: RegSpec, mask: RegSpec, merge_mode: MergeMode, sae_mode: SaeMode) -> Result<Self::Ok, Self::Error>; +    fn visit_reg_mask_merge_sae_noround(&mut self, base: RegSpec, mask: RegSpec, merge_mode: MergeMode) -> Result<Self::Ok, Self::Error>; +    fn visit_reg_disp_masked(&mut self, base: RegSpec, disp: i32, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error>; +    fn visit_reg_deref_masked(&mut self, base: RegSpec, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error>; +    fn visit_reg_scale_masked(&mut self, base: RegSpec, scale: u8, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error>; +    fn visit_reg_scale_disp_masked(&mut self, base: RegSpec, scale: u8, disp: i32, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error>; +    fn visit_index_base_masked(&mut self, base: RegSpec, index: RegSpec, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error>; +    fn visit_index_base_disp_masked(&mut self, base: RegSpec, index: RegSpec, disp: i32, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error>; +    fn visit_index_base_scale_masked(&mut self, base: RegSpec, index: RegSpec, scale: u8, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error>; +    fn visit_index_base_scale_disp_masked(&mut self, base: RegSpec, index: RegSpec, scale: u8, disp: i32, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error>; + +    fn visit_other(&mut self) -> Result<Self::Ok, Self::Error>; +} +  impl Operand {      fn from_spec(inst: &Instruction, spec: OperandSpec) -> Operand {          match spec { @@ -4323,6 +4360,168 @@ 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. +    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_esi => { +//                visitor.visit_other() +                visitor.visit_deref(RegSpec::esi()) +            } +            OperandSpec::Deref_edi => { +//                visitor.visit_other() +                visitor.visit_deref(RegSpec::edi()) +            } +            OperandSpec::Deref_rsi => { +//                visitor.visit_other() +                visitor.visit_deref(RegSpec::rsi()) +            } +            OperandSpec::Deref_rdi => { +//                visitor.visit_other() +                visitor.visit_deref(RegSpec::rdi()) +            } +            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::ImmI64 => visitor.visit_i64(self.imm as i64), +            OperandSpec::ImmInDispField => visitor.visit_u16(self.disp as u16), +            OperandSpec::DispU32 => visitor.visit_abs_u32(self.disp as u32), +            OperandSpec::DispU64 => visitor.visit_abs_u64(self.disp as u64), +            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) +                } +            } +        } +    } +      /// get the number of operands in this instruction. useful in iterating an instruction's      /// operands generically.      pub fn operand_count(&self) -> u8 { | 
