aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2024-04-02 01:52:38 -0700
committeriximeow <me@iximeow.net>2024-04-02 01:56:40 -0700
commit8b79d597dee1fb554eae9057d51f340dd282fa64 (patch)
tree51539b0d5751d9aa092a965834fcb684ec61fe25 /src
parent3291884e4c51cfd93ae0f84681c5dd00e2e8544d (diff)
lets see how a visitor for operands works out here...
Diffstat (limited to 'src')
-rw-r--r--src/long_mode/display.rs310
-rw-r--r--src/long_mode/mod.rs199
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(&reg))
+ }
+ 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(&reg))?;
+ 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(&reg))?;
+ 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(&reg),
+ 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(&reg),
+ 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 {