1use crate::iced_constants::IcedConstants;
5use crate::iced_error::IcedError;
6#[cfg(feature = "instr_info")]
7use crate::info::enums::*;
8use crate::instruction_internal;
9use crate::*;
10#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm", feature = "fast_fmt", feature = "serde"))]
11use core::fmt;
12use core::hash::{Hash, Hasher};
13use core::iter::{ExactSizeIterator, FusedIterator};
14use core::{mem, slice};
15
16pub(crate) struct InstrFlags1;
19#[allow(dead_code)]
20impl InstrFlags1 {
21 pub(crate) const SEGMENT_PREFIX_MASK: u32 = 0x0000_0007;
22 pub(crate) const SEGMENT_PREFIX_SHIFT: u32 = 0x0000_0005;
23 pub(crate) const DATA_LENGTH_MASK: u32 = 0x0000_000F;
24 pub(crate) const DATA_LENGTH_SHIFT: u32 = 0x0000_0008;
25 pub(crate) const ROUNDING_CONTROL_MASK: u32 = 0x0000_0007;
26 pub(crate) const ROUNDING_CONTROL_SHIFT: u32 = 0x0000_000C;
27 pub(crate) const OP_MASK_MASK: u32 = 0x0000_0007;
28 pub(crate) const OP_MASK_SHIFT: u32 = 0x0000_000F;
29 pub(crate) const CODE_SIZE_MASK: u32 = 0x0000_0003;
30 pub(crate) const CODE_SIZE_SHIFT: u32 = 0x0000_0012;
31 pub(crate) const BROADCAST: u32 = 0x0400_0000;
32 pub(crate) const SUPPRESS_ALL_EXCEPTIONS: u32 = 0x0800_0000;
33 pub(crate) const ZEROING_MASKING: u32 = 0x1000_0000;
34 pub(crate) const REPE_PREFIX: u32 = 0x2000_0000;
35 pub(crate) const REPNE_PREFIX: u32 = 0x4000_0000;
36 pub(crate) const LOCK_PREFIX: u32 = 0x8000_0000;
37 pub(crate) const EQUALS_IGNORE_MASK: u32 = 0x000C_0000;
38}
39pub(crate) struct MvexInstrFlags;
44#[allow(dead_code)]
45impl MvexInstrFlags {
46 pub(crate) const MVEX_REG_MEM_CONV_SHIFT: u32 = 0x0000_0010;
47 pub(crate) const MVEX_REG_MEM_CONV_MASK: u32 = 0x0000_001F;
48 pub(crate) const EVICTION_HINT: u32 = 0x8000_0000;
49}
50#[derive(Debug, Default, Copy, Clone)]
57pub struct Instruction {
58 pub(crate) next_rip: u64,
59 pub(crate) mem_displ: u64,
60 pub(crate) flags1: u32, pub(crate) immediate: u32,
62 pub(crate) code: Code,
63 pub(crate) mem_base_reg: Register,
64 pub(crate) mem_index_reg: Register,
65 pub(crate) regs: [Register; 4],
66 pub(crate) op_kinds: [OpKind; 4],
67 pub(crate) scale: InstrScale,
68 pub(crate) displ_size: u8,
69 pub(crate) len: u8,
70 pad: u8,
71}
72#[cfg(test)]
73#[allow(dead_code)]
74pub(crate) const INSTRUCTION_TOTAL_SIZE: usize = 40;
75
76#[allow(clippy::len_without_is_empty)]
77impl Instruction {
78 #[must_use]
80 #[inline]
81 pub fn new() -> Self {
82 Instruction::default()
83 }
84
85 #[must_use]
87 #[allow(trivial_casts)]
88 #[allow(clippy::missing_inline_in_public_items)]
89 pub fn eq_all_bits(&self, other: &Self) -> bool {
90 unsafe {
93 let a: *const u8 = self as *const Self as *const u8;
94 let b: *const u8 = other as *const Self as *const u8;
95 let sa = slice::from_raw_parts(a, mem::size_of::<Self>());
96 let sb = slice::from_raw_parts(b, mem::size_of::<Self>());
97 sa == sb
98 }
99 }
100
101 #[must_use]
105 #[inline]
106 pub const fn ip16(&self) -> u16 {
107 (self.next_rip as u16).wrapping_sub(self.len() as u16)
108 }
109
110 #[inline]
118 pub fn set_ip16(&mut self, new_value: u16) {
119 self.next_rip = (new_value as u64).wrapping_add(self.len() as u64);
120 }
121
122 #[must_use]
126 #[inline]
127 pub const fn ip32(&self) -> u32 {
128 (self.next_rip as u32).wrapping_sub(self.len() as u32)
129 }
130
131 #[inline]
139 pub fn set_ip32(&mut self, new_value: u32) {
140 self.next_rip = (new_value as u64).wrapping_add(self.len() as u64);
141 }
142
143 #[must_use]
147 #[inline]
148 pub const fn ip(&self) -> u64 {
149 self.next_rip.wrapping_sub(self.len() as u64)
150 }
151
152 #[inline]
160 pub fn set_ip(&mut self, new_value: u64) {
161 self.next_rip = new_value.wrapping_add(self.len() as u64);
162 }
163
164 #[must_use]
168 #[inline]
169 pub const fn next_ip16(&self) -> u16 {
170 self.next_rip as u16
171 }
172
173 #[inline]
181 pub fn set_next_ip16(&mut self, new_value: u16) {
182 self.next_rip = new_value as u64;
183 }
184
185 #[must_use]
189 #[inline]
190 pub const fn next_ip32(&self) -> u32 {
191 self.next_rip as u32
192 }
193
194 #[inline]
202 pub fn set_next_ip32(&mut self, new_value: u32) {
203 self.next_rip = new_value as u64;
204 }
205
206 #[must_use]
210 #[inline]
211 pub const fn next_ip(&self) -> u64 {
212 self.next_rip
213 }
214
215 #[inline]
223 pub fn set_next_ip(&mut self, new_value: u64) {
224 self.next_rip = new_value;
225 }
226
227 #[must_use]
230 #[inline]
231 pub fn code_size(&self) -> CodeSize {
232 unsafe { mem::transmute(((self.flags1 >> InstrFlags1::CODE_SIZE_SHIFT) & InstrFlags1::CODE_SIZE_MASK) as CodeSizeUnderlyingType) }
233 }
234
235 #[inline]
242 pub fn set_code_size(&mut self, new_value: CodeSize) {
243 self.flags1 = (self.flags1 & !(InstrFlags1::CODE_SIZE_MASK << InstrFlags1::CODE_SIZE_SHIFT))
244 | (((new_value as u32) & InstrFlags1::CODE_SIZE_MASK) << InstrFlags1::CODE_SIZE_SHIFT);
245 }
246
247 #[must_use]
252 #[inline]
253 pub fn is_invalid(&self) -> bool {
254 self.code == Code::INVALID
255 }
256
257 #[must_use]
261 #[inline]
262 pub const fn code(&self) -> Code {
263 self.code
264 }
265
266 #[inline]
272 pub fn set_code(&mut self, new_value: Code) {
273 self.code = new_value
274 }
275
276 #[must_use]
280 #[inline]
281 pub fn mnemonic(&self) -> Mnemonic {
282 self.code().mnemonic()
283 }
284
285 #[must_use]
300 #[inline]
301 pub fn op_count(&self) -> u32 {
302 instruction_op_counts::OP_COUNT[self.code() as usize] as u32
303 }
304
305 #[must_use]
308 #[inline]
309 pub const fn len(&self) -> usize {
310 self.len as usize
311 }
312
313 #[inline]
320 pub fn set_len(&mut self, new_value: usize) {
321 self.len = new_value as u8
322 }
323
324 #[inline]
325 fn is_xacquire_instr(&self) -> bool {
326 if self.op0_kind() != OpKind::Memory {
329 false
330 } else if self.has_lock_prefix() {
331 self.code() != Code::Cmpxchg16b_m128
332 } else {
333 self.mnemonic() == Mnemonic::Xchg
334 }
335 }
336
337 #[inline]
338 fn is_xrelease_instr(&self) -> bool {
339 if self.op0_kind() != OpKind::Memory {
342 false
343 } else if self.has_lock_prefix() {
344 self.code() != Code::Cmpxchg16b_m128
345 } else {
346 matches!(
347 self.code(),
348 Code::Xchg_rm8_r8
349 | Code::Xchg_rm16_r16
350 | Code::Xchg_rm32_r32
351 | Code::Xchg_rm64_r64
352 | Code::Mov_rm8_r8 | Code::Mov_rm16_r16
353 | Code::Mov_rm32_r32 | Code::Mov_rm64_r64
354 | Code::Mov_rm8_imm8 | Code::Mov_rm16_imm16
355 | Code::Mov_rm32_imm32
356 | Code::Mov_rm64_imm32
357 )
358 }
359 }
360
361 #[must_use]
363 #[inline]
364 pub fn has_xacquire_prefix(&self) -> bool {
365 (self.flags1 & InstrFlags1::REPNE_PREFIX) != 0 && self.is_xacquire_instr()
366 }
367
368 #[inline]
374 pub fn set_has_xacquire_prefix(&mut self, new_value: bool) {
375 if new_value {
376 self.flags1 |= InstrFlags1::REPNE_PREFIX;
377 } else {
378 self.flags1 &= !InstrFlags1::REPNE_PREFIX;
379 }
380 }
381
382 #[must_use]
384 #[inline]
385 pub fn has_xrelease_prefix(&self) -> bool {
386 (self.flags1 & InstrFlags1::REPE_PREFIX) != 0 && self.is_xrelease_instr()
387 }
388
389 #[inline]
395 pub fn set_has_xrelease_prefix(&mut self, new_value: bool) {
396 if new_value {
397 self.flags1 |= InstrFlags1::REPE_PREFIX;
398 } else {
399 self.flags1 &= !InstrFlags1::REPE_PREFIX;
400 }
401 }
402
403 #[must_use]
405 #[inline]
406 pub const fn has_rep_prefix(&self) -> bool {
407 (self.flags1 & InstrFlags1::REPE_PREFIX) != 0
408 }
409
410 #[inline]
416 pub fn set_has_rep_prefix(&mut self, new_value: bool) {
417 if new_value {
418 self.flags1 |= InstrFlags1::REPE_PREFIX;
419 } else {
420 self.flags1 &= !InstrFlags1::REPE_PREFIX;
421 }
422 }
423
424 #[must_use]
426 #[inline]
427 pub const fn has_repe_prefix(&self) -> bool {
428 (self.flags1 & InstrFlags1::REPE_PREFIX) != 0
429 }
430
431 #[inline]
437 pub fn set_has_repe_prefix(&mut self, new_value: bool) {
438 if new_value {
439 self.flags1 |= InstrFlags1::REPE_PREFIX;
440 } else {
441 self.flags1 &= !InstrFlags1::REPE_PREFIX;
442 }
443 }
444
445 #[must_use]
447 #[inline]
448 pub const fn has_repne_prefix(&self) -> bool {
449 (self.flags1 & InstrFlags1::REPNE_PREFIX) != 0
450 }
451
452 #[inline]
458 pub fn set_has_repne_prefix(&mut self, new_value: bool) {
459 if new_value {
460 self.flags1 |= InstrFlags1::REPNE_PREFIX;
461 } else {
462 self.flags1 &= !InstrFlags1::REPNE_PREFIX;
463 }
464 }
465
466 #[must_use]
468 #[inline]
469 pub const fn has_lock_prefix(&self) -> bool {
470 (self.flags1 & InstrFlags1::LOCK_PREFIX) != 0
471 }
472
473 #[inline]
479 pub fn set_has_lock_prefix(&mut self, new_value: bool) {
480 if new_value {
481 self.flags1 |= InstrFlags1::LOCK_PREFIX;
482 } else {
483 self.flags1 &= !InstrFlags1::LOCK_PREFIX;
484 }
485 }
486
487 #[must_use]
492 #[inline]
493 pub const fn op0_kind(&self) -> OpKind {
494 self.op_kinds[0]
495 }
496
497 #[inline]
506 pub fn set_op0_kind(&mut self, new_value: OpKind) {
507 self.op_kinds[0] = new_value
508 }
509
510 #[must_use]
515 #[inline]
516 pub const fn op1_kind(&self) -> OpKind {
517 self.op_kinds[1]
518 }
519
520 #[inline]
529 pub fn set_op1_kind(&mut self, new_value: OpKind) {
530 self.op_kinds[1] = new_value
531 }
532
533 #[must_use]
538 #[inline]
539 pub const fn op2_kind(&self) -> OpKind {
540 self.op_kinds[2]
541 }
542
543 #[inline]
552 pub fn set_op2_kind(&mut self, new_value: OpKind) {
553 self.op_kinds[2] = new_value
554 }
555
556 #[must_use]
561 #[inline]
562 pub const fn op3_kind(&self) -> OpKind {
563 self.op_kinds[3]
564 }
565
566 #[inline]
575 pub fn set_op3_kind(&mut self, new_value: OpKind) {
576 self.op_kinds[3] = new_value
577 }
578
579 #[allow(clippy::unused_self)]
584 #[must_use]
585 #[inline]
586 pub const fn op4_kind(&self) -> OpKind {
587 OpKind::Immediate8
588 }
589
590 #[allow(clippy::unused_self)]
599 #[inline]
600 pub fn set_op4_kind(&mut self, new_value: OpKind) {
601 debug_assert_eq!(new_value, OpKind::Immediate8);
602 }
603
604 #[allow(clippy::unused_self)]
605 #[inline]
606 #[doc(hidden)]
607 pub fn try_set_op4_kind(&mut self, new_value: OpKind) -> Result<(), IcedError> {
608 if new_value != OpKind::Immediate8 {
609 Err(IcedError::new("Invalid opkind"))
610 } else {
611 Ok(())
612 }
613 }
614
615 #[inline]
634 pub fn op_kinds(&self) -> impl Iterator<Item = OpKind> + ExactSizeIterator + FusedIterator {
635 OpKindIterator::new(self)
636 }
637
638 #[must_use]
664 #[inline]
665 pub fn op_kind(&self, operand: u32) -> OpKind {
666 const _: () = assert!(IcedConstants::MAX_OP_COUNT == 5);
667 if let Some(&op_kind) = self.op_kinds.get(operand as usize) {
668 op_kind
669 } else if operand == 4 {
670 self.op4_kind()
671 } else {
672 debug_assert!(false, "Invalid operand: {}", operand);
673 OpKind::default()
674 }
675 }
676
677 #[doc(hidden)]
678 #[inline]
679 pub fn try_op_kind(&self, operand: u32) -> Result<OpKind, IcedError> {
680 const _: () = assert!(IcedConstants::MAX_OP_COUNT == 5);
681 if let Some(&op_kind) = self.op_kinds.get(operand as usize) {
682 Ok(op_kind)
683 } else if operand == 4 {
684 Ok(self.op4_kind())
685 } else {
686 Err(IcedError::new("Invalid operand"))
687 }
688 }
689
690 #[inline]
697 pub fn set_op_kind(&mut self, operand: u32, op_kind: OpKind) {
698 const _: () = assert!(IcedConstants::MAX_OP_COUNT == 5);
699 if let Some(field) = self.op_kinds.get_mut(operand as usize) {
700 *field = op_kind;
701 } else if operand == 4 {
702 self.set_op4_kind(op_kind)
703 } else {
704 debug_assert!(false, "Invalid operand: {}", operand);
705 }
706 }
707
708 #[doc(hidden)]
709 #[inline]
710 pub fn try_set_op_kind(&mut self, operand: u32, op_kind: OpKind) -> Result<(), IcedError> {
711 const _: () = assert!(IcedConstants::MAX_OP_COUNT == 5);
712 if let Some(field) = self.op_kinds.get_mut(operand as usize) {
713 *field = op_kind;
714 Ok(())
715 } else if operand == 4 {
716 self.try_set_op4_kind(op_kind)
717 } else {
718 Err(IcedError::new("Invalid operand"))
719 }
720 }
721
722 #[must_use]
726 #[inline]
727 pub const fn has_segment_prefix(&self) -> bool {
728 ((self.flags1 >> InstrFlags1::SEGMENT_PREFIX_SHIFT) & InstrFlags1::SEGMENT_PREFIX_MASK).wrapping_sub(1) < 6
729 }
730
731 #[must_use]
743 #[inline]
744 pub fn segment_prefix(&self) -> Register {
745 let index = ((self.flags1 >> InstrFlags1::SEGMENT_PREFIX_SHIFT) & InstrFlags1::SEGMENT_PREFIX_MASK).wrapping_sub(1);
746 const _: () = assert!(Register::ES as u32 + 1 == Register::CS as u32);
747 const _: () = assert!(Register::ES as u32 + 2 == Register::SS as u32);
748 const _: () = assert!(Register::ES as u32 + 3 == Register::DS as u32);
749 const _: () = assert!(Register::ES as u32 + 4 == Register::FS as u32);
750 const _: () = assert!(Register::ES as u32 + 5 == Register::GS as u32);
751 if index < 6 {
752 unsafe { mem::transmute((Register::ES as u32 + index) as RegisterUnderlyingType) }
754 } else {
755 Register::None
756 }
757 }
758
759 #[allow(clippy::missing_inline_in_public_items)]
775 pub fn set_segment_prefix(&mut self, new_value: Register) {
776 debug_assert!(new_value == Register::None || (Register::ES <= new_value && new_value <= Register::GS));
777 let enc_value =
778 if new_value == Register::None { 0 } else { (((new_value as u32) - (Register::ES as u32)) + 1) & InstrFlags1::SEGMENT_PREFIX_MASK };
779 self.flags1 = (self.flags1 & !(InstrFlags1::SEGMENT_PREFIX_MASK << InstrFlags1::SEGMENT_PREFIX_SHIFT))
780 | (enc_value << InstrFlags1::SEGMENT_PREFIX_SHIFT);
781 }
782
783 #[must_use]
792 #[allow(clippy::missing_inline_in_public_items)]
793 pub fn memory_segment(&self) -> Register {
794 let seg_reg = self.segment_prefix();
795 if seg_reg != Register::None {
796 return seg_reg;
797 }
798 match self.memory_base() {
799 Register::BP | Register::EBP | Register::ESP | Register::RBP | Register::RSP => Register::SS,
800 _ => Register::DS,
801 }
802 }
803
804 #[must_use]
812 #[inline]
813 pub const fn memory_displ_size(&self) -> u32 {
814 let size = self.displ_size as u32;
815 if size <= 2 {
816 size
817 } else if size == 3 {
818 4
819 } else {
820 8
821 }
822 }
823
824 #[allow(clippy::missing_inline_in_public_items)]
836 pub fn set_memory_displ_size(&mut self, new_value: u32) {
837 self.displ_size = match new_value {
838 0 => 0,
839 1 => 1,
840 2 => 2,
841 4 => 3,
842 _ => 4,
843 };
844 }
845
846 #[must_use]
848 #[inline]
849 pub const fn is_broadcast(&self) -> bool {
850 (self.flags1 & InstrFlags1::BROADCAST) != 0
851 }
852
853 #[inline]
859 pub fn set_is_broadcast(&mut self, new_value: bool) {
860 if new_value {
861 self.flags1 |= InstrFlags1::BROADCAST;
862 } else {
863 self.flags1 &= !InstrFlags1::BROADCAST;
864 }
865 }
866
867 #[must_use]
869 #[inline]
870 #[cfg(feature = "mvex")]
871 pub const fn is_mvex_eviction_hint(&self) -> bool {
872 IcedConstants::is_mvex(self.code()) && (self.immediate & MvexInstrFlags::EVICTION_HINT) != 0
873 }
874
875 #[inline]
881 #[cfg(feature = "mvex")]
882 pub fn set_is_mvex_eviction_hint(&mut self, new_value: bool) {
883 if new_value {
884 self.immediate |= MvexInstrFlags::EVICTION_HINT;
885 } else {
886 self.immediate &= !MvexInstrFlags::EVICTION_HINT;
887 }
888 }
889
890 #[must_use]
892 #[inline]
893 #[cfg(feature = "mvex")]
894 pub fn mvex_reg_mem_conv(&self) -> MvexRegMemConv {
895 if !IcedConstants::is_mvex(self.code()) {
896 MvexRegMemConv::None
897 } else {
898 <MvexRegMemConv as core::convert::TryFrom<_>>::try_from(
899 ((self.immediate >> MvexInstrFlags::MVEX_REG_MEM_CONV_SHIFT) & MvexInstrFlags::MVEX_REG_MEM_CONV_MASK) as usize,
900 )
901 .ok()
902 .unwrap_or_default()
903 }
904 }
905
906 #[inline]
912 #[cfg(feature = "mvex")]
913 pub fn set_mvex_reg_mem_conv(&mut self, new_value: MvexRegMemConv) {
914 self.immediate = (self.immediate & !(MvexInstrFlags::MVEX_REG_MEM_CONV_MASK << MvexInstrFlags::MVEX_REG_MEM_CONV_SHIFT))
915 | ((new_value as u32) << MvexInstrFlags::MVEX_REG_MEM_CONV_SHIFT);
916 }
917
918 #[must_use]
932 #[inline]
933 pub fn memory_size(&self) -> MemorySize {
934 let code = self.code();
935 #[cfg(feature = "mvex")]
936 {
937 if IcedConstants::is_mvex(code) {
938 let mvex = crate::mvex::get_mvex_info(code);
939 const _: () = assert!(MvexRegMemConv::MemConvNone as u32 + 1 == MvexRegMemConv::MemConvBroadcast1 as u32);
940 const _: () = assert!(MvexRegMemConv::MemConvNone as u32 + 2 == MvexRegMemConv::MemConvBroadcast4 as u32);
941 const _: () = assert!(MvexRegMemConv::MemConvNone as u32 + 3 == MvexRegMemConv::MemConvFloat16 as u32);
942 const _: () = assert!(MvexRegMemConv::MemConvNone as u32 + 4 == MvexRegMemConv::MemConvUint8 as u32);
943 const _: () = assert!(MvexRegMemConv::MemConvNone as u32 + 5 == MvexRegMemConv::MemConvSint8 as u32);
944 const _: () = assert!(MvexRegMemConv::MemConvNone as u32 + 6 == MvexRegMemConv::MemConvUint16 as u32);
945 const _: () = assert!(MvexRegMemConv::MemConvNone as u32 + 7 == MvexRegMemConv::MemConvSint16 as u32);
946 let sss = ((self.mvex_reg_mem_conv() as u32).wrapping_sub(MvexRegMemConv::MemConvNone as u32) & 7) as usize;
947 return crate::mvex::mvex_memsz_lut::MVEX_MEMSZ_LUT[(mvex.tuple_type_lut_kind as usize) * 8 + sss];
948 }
949 }
950 if !self.is_broadcast() {
951 instruction_memory_sizes::SIZES_NORMAL[code as usize]
952 } else {
953 instruction_memory_sizes::SIZES_BCST[code as usize]
954 }
955 }
956
957 #[must_use]
961 #[inline]
962 pub const fn memory_index_scale(&self) -> u32 {
963 1 << (self.scale as u8)
964 }
965
966 #[allow(clippy::missing_inline_in_public_items)]
974 pub fn set_memory_index_scale(&mut self, new_value: u32) {
975 match new_value {
976 1 => self.scale = InstrScale::Scale1,
977 2 => self.scale = InstrScale::Scale2,
978 4 => self.scale = InstrScale::Scale4,
979 _ => {
980 debug_assert_eq!(new_value, 8);
981 self.scale = InstrScale::Scale8;
982 }
983 }
984 }
985
986 #[must_use]
992 #[inline]
993 pub const fn memory_displacement32(&self) -> u32 {
994 self.mem_displ as u32
995 }
996
997 #[inline]
1007 pub fn set_memory_displacement32(&mut self, new_value: u32) {
1008 self.mem_displ = new_value as u64;
1009 }
1010
1011 #[must_use]
1017 #[inline]
1018 pub const fn memory_displacement64(&self) -> u64 {
1019 self.mem_displ
1020 }
1021
1022 #[inline]
1032 pub fn set_memory_displacement64(&mut self, new_value: u64) {
1033 self.mem_displ = new_value;
1034 }
1035
1036 #[allow(clippy::missing_inline_in_public_items)]
1050 pub fn try_immediate(&self, operand: u32) -> Result<u64, IcedError> {
1051 Ok(match self.try_op_kind(operand)? {
1052 OpKind::Immediate8 => self.immediate8() as u64,
1053 OpKind::Immediate8_2nd => self.immediate8_2nd() as u64,
1054 OpKind::Immediate16 => self.immediate16() as u64,
1055 OpKind::Immediate32 => self.immediate32() as u64,
1056 OpKind::Immediate64 => self.immediate64(),
1057 OpKind::Immediate8to16 => self.immediate8to16() as u64,
1058 OpKind::Immediate8to32 => self.immediate8to32() as u64,
1059 OpKind::Immediate8to64 => self.immediate8to64() as u64,
1060 OpKind::Immediate32to64 => self.immediate32to64() as u64,
1061 _ => return Err(IcedError::new("Not an immediate operand")),
1062 })
1063 }
1064
1065 #[must_use]
1071 #[inline]
1072 pub fn immediate(&self, operand: u32) -> u64 {
1073 match self.try_immediate(operand) {
1074 Ok(value) => value,
1075 Err(_) => {
1076 debug_assert!(false, "Invalid operand: {}", operand);
1077 0
1078 }
1079 }
1080 }
1081
1082 #[inline]
1089 pub fn set_immediate_i32(&mut self, operand: u32, new_value: i32) {
1090 match self.try_set_immediate_i32(operand, new_value) {
1091 Ok(()) => {}
1092 Err(_) => debug_assert!(false, "Invalid operand: {}", operand),
1093 }
1094 }
1095
1096 #[inline]
1097 #[doc(hidden)]
1098 pub fn try_set_immediate_i32(&mut self, operand: u32, new_value: i32) -> Result<(), IcedError> {
1099 self.try_set_immediate_u64(operand, new_value as u64)
1100 }
1101
1102 #[inline]
1109 pub fn set_immediate_u32(&mut self, operand: u32, new_value: u32) {
1110 match self.try_set_immediate_u32(operand, new_value) {
1111 Ok(()) => {}
1112 Err(_) => debug_assert!(false, "Invalid operand: {}", operand),
1113 }
1114 }
1115
1116 #[inline]
1117 #[doc(hidden)]
1118 pub fn try_set_immediate_u32(&mut self, operand: u32, new_value: u32) -> Result<(), IcedError> {
1119 self.try_set_immediate_u64(operand, new_value as u64)
1120 }
1121
1122 #[inline]
1129 pub fn set_immediate_i64(&mut self, operand: u32, new_value: i64) {
1130 match self.try_set_immediate_i64(operand, new_value) {
1131 Ok(()) => {}
1132 Err(_) => debug_assert!(false, "Invalid operand: {}", operand),
1133 }
1134 }
1135
1136 #[inline]
1137 #[doc(hidden)]
1138 pub fn try_set_immediate_i64(&mut self, operand: u32, new_value: i64) -> Result<(), IcedError> {
1139 self.try_set_immediate_u64(operand, new_value as u64)
1140 }
1141
1142 #[inline]
1149 pub fn set_immediate_u64(&mut self, operand: u32, new_value: u64) {
1150 match self.try_set_immediate_u64(operand, new_value) {
1151 Ok(()) => {}
1152 Err(_) => debug_assert!(false, "Invalid operand: {}", operand),
1153 }
1154 }
1155
1156 #[allow(clippy::missing_inline_in_public_items)]
1157 #[doc(hidden)]
1158 pub fn try_set_immediate_u64(&mut self, operand: u32, new_value: u64) -> Result<(), IcedError> {
1159 match self.try_op_kind(operand)? {
1160 OpKind::Immediate8 => self.set_immediate8(new_value as u8),
1161 OpKind::Immediate8to16 => self.set_immediate8to16(new_value as i16),
1162 OpKind::Immediate8to32 => self.set_immediate8to32(new_value as i32),
1163 OpKind::Immediate8to64 => self.set_immediate8to64(new_value as i64),
1164 OpKind::Immediate8_2nd => self.set_immediate8_2nd(new_value as u8),
1165 OpKind::Immediate16 => self.set_immediate16(new_value as u16),
1166 OpKind::Immediate32to64 => self.set_immediate32to64(new_value as i64),
1167 OpKind::Immediate32 => self.set_immediate32(new_value as u32),
1168 OpKind::Immediate64 => self.set_immediate64(new_value),
1169 _ => return Err(IcedError::new("Not an immediate operand")),
1170 }
1171 Ok(())
1172 }
1173
1174 #[must_use]
1178 #[inline]
1179 pub const fn immediate8(&self) -> u8 {
1180 self.immediate as u8
1181 }
1182
1183 #[inline]
1191 pub fn set_immediate8(&mut self, new_value: u8) {
1192 #[cfg(feature = "mvex")]
1193 {
1194 self.immediate = (self.immediate & 0xFFFF_FF00) | (new_value as u32);
1195 }
1196 #[cfg(not(feature = "mvex"))]
1197 {
1198 self.immediate = new_value as u32;
1199 }
1200 }
1201
1202 #[must_use]
1206 #[inline]
1207 pub const fn immediate8_2nd(&self) -> u8 {
1208 self.mem_displ as u8
1209 }
1210
1211 #[inline]
1219 pub fn set_immediate8_2nd(&mut self, new_value: u8) {
1220 self.mem_displ = new_value as u64;
1221 }
1222
1223 #[must_use]
1227 #[inline]
1228 pub const fn immediate16(&self) -> u16 {
1229 self.immediate as u16
1230 }
1231
1232 #[inline]
1240 pub fn set_immediate16(&mut self, new_value: u16) {
1241 self.immediate = new_value as u32;
1242 }
1243
1244 #[must_use]
1248 #[inline]
1249 pub const fn immediate32(&self) -> u32 {
1250 self.immediate
1251 }
1252
1253 #[inline]
1261 pub fn set_immediate32(&mut self, new_value: u32) {
1262 self.immediate = new_value;
1263 }
1264
1265 #[must_use]
1269 #[inline]
1270 pub const fn immediate64(&self) -> u64 {
1271 (self.mem_displ << 32) | (self.immediate as u64)
1272 }
1273
1274 #[inline]
1282 pub fn set_immediate64(&mut self, new_value: u64) {
1283 self.immediate = new_value as u32;
1284 self.mem_displ = new_value >> 32;
1285 }
1286
1287 #[must_use]
1291 #[inline]
1292 pub const fn immediate8to16(&self) -> i16 {
1293 self.immediate as i8 as i16
1294 }
1295
1296 #[inline]
1304 pub fn set_immediate8to16(&mut self, new_value: i16) {
1305 self.immediate = new_value as i8 as u32;
1306 }
1307
1308 #[must_use]
1312 #[inline]
1313 pub const fn immediate8to32(&self) -> i32 {
1314 self.immediate as i8 as i32
1315 }
1316
1317 #[inline]
1325 pub fn set_immediate8to32(&mut self, new_value: i32) {
1326 self.immediate = new_value as i8 as u32;
1327 }
1328
1329 #[must_use]
1333 #[inline]
1334 pub const fn immediate8to64(&self) -> i64 {
1335 self.immediate as i8 as i64
1336 }
1337
1338 #[inline]
1346 pub fn set_immediate8to64(&mut self, new_value: i64) {
1347 self.immediate = new_value as i8 as u32;
1348 }
1349
1350 #[must_use]
1354 #[inline]
1355 pub const fn immediate32to64(&self) -> i64 {
1356 self.immediate as i32 as i64
1357 }
1358
1359 #[inline]
1367 pub fn set_immediate32to64(&mut self, new_value: i64) {
1368 self.immediate = new_value as u32;
1369 }
1370
1371 #[must_use]
1375 #[inline]
1376 pub const fn near_branch16(&self) -> u16 {
1377 self.mem_displ as u16
1378 }
1379
1380 #[inline]
1388 pub fn set_near_branch16(&mut self, new_value: u16) {
1389 self.mem_displ = new_value as u64;
1390 }
1391
1392 #[must_use]
1396 #[inline]
1397 pub const fn near_branch32(&self) -> u32 {
1398 self.mem_displ as u32
1399 }
1400
1401 #[inline]
1409 pub fn set_near_branch32(&mut self, new_value: u32) {
1410 self.mem_displ = new_value as u64;
1411 }
1412
1413 #[must_use]
1417 #[inline]
1418 pub const fn near_branch64(&self) -> u64 {
1419 self.mem_displ
1420 }
1421
1422 #[inline]
1430 pub fn set_near_branch64(&mut self, new_value: u64) {
1431 self.mem_displ = new_value
1432 }
1433
1434 #[must_use]
1442 #[allow(clippy::missing_inline_in_public_items)]
1443 #[allow(unused_mut)]
1444 pub fn near_branch_target(&self) -> u64 {
1445 let mut op_kind = self.op0_kind();
1446 #[cfg(feature = "mvex")]
1447 {
1448 if self.op_count() == 2 {
1450 op_kind = self.op1_kind();
1451 }
1452 }
1453 match op_kind {
1454 OpKind::NearBranch16 => self.near_branch16() as u64,
1455 OpKind::NearBranch32 => self.near_branch32() as u64,
1456 OpKind::NearBranch64 => self.near_branch64(),
1457 _ => 0,
1458 }
1459 }
1460
1461 #[must_use]
1465 #[inline]
1466 pub const fn far_branch16(&self) -> u16 {
1467 self.immediate as u16
1468 }
1469
1470 #[inline]
1478 pub fn set_far_branch16(&mut self, new_value: u16) {
1479 self.immediate = new_value as u32;
1480 }
1481
1482 #[must_use]
1486 #[inline]
1487 pub const fn far_branch32(&self) -> u32 {
1488 self.immediate
1489 }
1490
1491 #[inline]
1499 pub fn set_far_branch32(&mut self, new_value: u32) {
1500 self.immediate = new_value;
1501 }
1502
1503 #[must_use]
1508 #[inline]
1509 pub const fn far_branch_selector(&self) -> u16 {
1510 self.mem_displ as u16
1511 }
1512
1513 #[inline]
1522 pub fn set_far_branch_selector(&mut self, new_value: u16) {
1523 self.mem_displ = new_value as u64;
1524 }
1525
1526 #[must_use]
1531 #[inline]
1532 pub const fn memory_base(&self) -> Register {
1533 self.mem_base_reg
1534 }
1535
1536 #[inline]
1545 pub fn set_memory_base(&mut self, new_value: Register) {
1546 self.mem_base_reg = new_value;
1547 }
1548
1549 #[must_use]
1554 #[inline]
1555 pub const fn memory_index(&self) -> Register {
1556 self.mem_index_reg
1557 }
1558
1559 #[inline]
1568 pub fn set_memory_index(&mut self, new_value: Register) {
1569 self.mem_index_reg = new_value;
1570 }
1571
1572 #[must_use]
1580 #[inline]
1581 pub const fn op0_register(&self) -> Register {
1582 self.regs[0]
1583 }
1584
1585 #[inline]
1597 pub fn set_op0_register(&mut self, new_value: Register) {
1598 self.regs[0] = new_value;
1599 }
1600
1601 #[must_use]
1609 #[inline]
1610 pub const fn op1_register(&self) -> Register {
1611 self.regs[1]
1612 }
1613
1614 #[inline]
1626 pub fn set_op1_register(&mut self, new_value: Register) {
1627 self.regs[1] = new_value;
1628 }
1629
1630 #[must_use]
1638 #[inline]
1639 pub const fn op2_register(&self) -> Register {
1640 self.regs[2]
1641 }
1642
1643 #[inline]
1655 pub fn set_op2_register(&mut self, new_value: Register) {
1656 self.regs[2] = new_value;
1657 }
1658
1659 #[must_use]
1667 #[inline]
1668 pub const fn op3_register(&self) -> Register {
1669 self.regs[3]
1670 }
1671
1672 #[inline]
1684 pub fn set_op3_register(&mut self, new_value: Register) {
1685 self.regs[3] = new_value;
1686 }
1687
1688 #[allow(clippy::unused_self)]
1696 #[must_use]
1697 #[inline]
1698 pub const fn op4_register(&self) -> Register {
1699 Register::None
1700 }
1701
1702 #[allow(clippy::unused_self)]
1714 #[inline]
1715 pub fn set_op4_register(&mut self, new_value: Register) {
1716 debug_assert_eq!(new_value, Register::None);
1717 }
1718
1719 #[allow(clippy::unused_self)]
1720 #[inline]
1721 #[doc(hidden)]
1722 pub fn try_set_op4_register(&mut self, new_value: Register) -> Result<(), IcedError> {
1723 if new_value != Register::None {
1724 Err(IcedError::new("Invalid register"))
1725 } else {
1726 Ok(())
1727 }
1728 }
1729
1730 #[must_use]
1754 #[inline]
1755 pub fn op_register(&self, operand: u32) -> Register {
1756 const _: () = assert!(IcedConstants::MAX_OP_COUNT == 5);
1757 if let Some(®) = self.regs.get(operand as usize) {
1758 reg
1759 } else if operand == 4 {
1760 self.op4_register()
1761 } else {
1762 debug_assert!(false, "Invalid operand: {}", operand);
1763 Register::default()
1764 }
1765 }
1766
1767 #[inline]
1768 #[doc(hidden)]
1769 pub fn try_op_register(&self, operand: u32) -> Result<Register, IcedError> {
1770 const _: () = assert!(IcedConstants::MAX_OP_COUNT == 5);
1771 if let Some(®) = self.regs.get(operand as usize) {
1772 Ok(reg)
1773 } else if operand == 4 {
1774 Ok(self.op4_register())
1775 } else {
1776 Err(IcedError::new("Invalid operand"))
1777 }
1778 }
1779
1780 #[inline]
1789 pub fn set_op_register(&mut self, operand: u32, new_value: Register) {
1790 const _: () = assert!(IcedConstants::MAX_OP_COUNT == 5);
1791 match operand {
1792 0 => self.set_op0_register(new_value),
1793 1 => self.set_op1_register(new_value),
1794 2 => self.set_op2_register(new_value),
1795 3 => self.set_op3_register(new_value),
1796 4 => self.set_op4_register(new_value),
1797 _ => debug_assert!(false, "Invalid operand: {}", operand),
1798 }
1799 }
1800
1801 #[inline]
1802 #[doc(hidden)]
1803 pub fn try_set_op_register(&mut self, operand: u32, new_value: Register) -> Result<(), IcedError> {
1804 const _: () = assert!(IcedConstants::MAX_OP_COUNT == 5);
1805 match operand {
1806 0 => self.set_op0_register(new_value),
1807 1 => self.set_op1_register(new_value),
1808 2 => self.set_op2_register(new_value),
1809 3 => self.set_op3_register(new_value),
1810 4 => return self.try_set_op4_register(new_value),
1811 _ => return Err(IcedError::new("Invalid operand")),
1812 }
1813 Ok(())
1814 }
1815
1816 #[must_use]
1822 #[inline]
1823 pub fn op_mask(&self) -> Register {
1824 let r = (self.flags1 >> InstrFlags1::OP_MASK_SHIFT) & InstrFlags1::OP_MASK_MASK;
1825 if r == 0 {
1826 Register::None
1827 } else {
1828 const _: () = assert!(InstrFlags1::OP_MASK_MASK == 7);
1829 const _: () = assert!(Register::K0 as u32 + 1 == Register::K1 as u32);
1830 const _: () = assert!(Register::K0 as u32 + 2 == Register::K2 as u32);
1831 const _: () = assert!(Register::K0 as u32 + 3 == Register::K3 as u32);
1832 const _: () = assert!(Register::K0 as u32 + 4 == Register::K4 as u32);
1833 const _: () = assert!(Register::K0 as u32 + 5 == Register::K5 as u32);
1834 const _: () = assert!(Register::K0 as u32 + 6 == Register::K6 as u32);
1835 const _: () = assert!(Register::K0 as u32 + 7 == Register::K7 as u32);
1836 unsafe { mem::transmute((r + Register::K0 as u32) as RegisterUnderlyingType) }
1838 }
1839 }
1840
1841 #[allow(clippy::missing_inline_in_public_items)]
1851 pub fn set_op_mask(&mut self, new_value: Register) {
1852 debug_assert!(new_value == Register::None || (Register::K1 <= new_value && new_value <= Register::K7));
1853 let r = if new_value == Register::None { 0 } else { (new_value as u32 - Register::K0 as u32) & InstrFlags1::OP_MASK_MASK };
1854 self.flags1 = (self.flags1 & !(InstrFlags1::OP_MASK_MASK << InstrFlags1::OP_MASK_SHIFT)) | (r << InstrFlags1::OP_MASK_SHIFT);
1855 }
1856
1857 #[must_use]
1861 #[inline]
1862 pub const fn has_op_mask(&self) -> bool {
1863 (self.flags1 & (InstrFlags1::OP_MASK_MASK << InstrFlags1::OP_MASK_SHIFT)) != 0
1864 }
1865
1866 #[must_use]
1869 #[inline]
1870 pub const fn zeroing_masking(&self) -> bool {
1871 (self.flags1 & InstrFlags1::ZEROING_MASKING) != 0
1872 }
1873
1874 #[inline]
1881 pub fn set_zeroing_masking(&mut self, new_value: bool) {
1882 if new_value {
1883 self.flags1 |= InstrFlags1::ZEROING_MASKING;
1884 } else {
1885 self.flags1 &= !InstrFlags1::ZEROING_MASKING;
1886 }
1887 }
1888
1889 #[must_use]
1892 #[inline]
1893 pub const fn merging_masking(&self) -> bool {
1894 (self.flags1 & InstrFlags1::ZEROING_MASKING) == 0
1895 }
1896
1897 #[inline]
1904 pub fn set_merging_masking(&mut self, new_value: bool) {
1905 if new_value {
1906 self.flags1 &= !InstrFlags1::ZEROING_MASKING;
1907 } else {
1908 self.flags1 |= InstrFlags1::ZEROING_MASKING;
1909 }
1910 }
1911
1912 #[must_use]
1918 #[inline]
1919 pub fn rounding_control(&self) -> RoundingControl {
1920 unsafe {
1921 mem::transmute(
1922 ((self.flags1 >> InstrFlags1::ROUNDING_CONTROL_SHIFT) & InstrFlags1::ROUNDING_CONTROL_MASK) as RoundingControlUnderlyingType,
1923 )
1924 }
1925 }
1926
1927 #[inline]
1937 pub fn set_rounding_control(&mut self, new_value: RoundingControl) {
1938 self.flags1 = (self.flags1 & !(InstrFlags1::ROUNDING_CONTROL_MASK << InstrFlags1::ROUNDING_CONTROL_SHIFT))
1939 | ((new_value as u32) << InstrFlags1::ROUNDING_CONTROL_SHIFT);
1940 }
1941
1942 #[must_use]
1951 #[inline]
1952 pub const fn declare_data_len(&self) -> usize {
1953 (((self.flags1 >> InstrFlags1::DATA_LENGTH_SHIFT) & InstrFlags1::DATA_LENGTH_MASK) + 1) as usize
1954 }
1955
1956 #[inline]
1969 pub fn set_declare_data_len(&mut self, new_value: usize) {
1970 debug_assert!(1 <= new_value && new_value <= 0x10);
1971 self.flags1 = (self.flags1 & !(InstrFlags1::DATA_LENGTH_MASK << InstrFlags1::DATA_LENGTH_SHIFT))
1972 | ((((new_value as u32) - 1) & InstrFlags1::DATA_LENGTH_MASK) << InstrFlags1::DATA_LENGTH_SHIFT);
1973 }
1974
1975 #[inline]
1987 pub fn set_declare_byte_value_i8(&mut self, index: usize, new_value: i8) {
1988 match self.try_set_declare_byte_value_i8(index, new_value) {
1989 Ok(()) => {}
1990 Err(_) => debug_assert!(false, "Invalid index: {}", index),
1991 }
1992 }
1993
1994 #[inline]
2010 pub fn try_set_declare_byte_value_i8(&mut self, index: usize, new_value: i8) -> Result<(), IcedError> {
2011 self.try_set_declare_byte_value(index, new_value as u8)
2012 }
2013
2014 #[inline]
2026 pub fn set_declare_byte_value(&mut self, index: usize, new_value: u8) {
2027 match self.try_set_declare_byte_value(index, new_value) {
2028 Ok(()) => {}
2029 Err(_) => debug_assert!(false, "Invalid index: {}", index),
2030 }
2031 }
2032
2033 #[allow(clippy::missing_inline_in_public_items)]
2034 #[doc(hidden)]
2035 pub fn try_set_declare_byte_value(&mut self, index: usize, new_value: u8) -> Result<(), IcedError> {
2036 match index {
2037 0 => self.regs[0] = Register::from_u8(new_value),
2038 1 => self.regs[1] = Register::from_u8(new_value),
2039 2 => self.regs[2] = Register::from_u8(new_value),
2040 3 => self.regs[3] = Register::from_u8(new_value),
2041 4 => self.immediate = (self.immediate & 0xFFFF_FF00) | new_value as u32,
2042 5 => self.immediate = (self.immediate & 0xFFFF_00FF) | ((new_value as u32) << 8),
2043 6 => self.immediate = (self.immediate & 0xFF00_FFFF) | ((new_value as u32) << 16),
2044 7 => self.immediate = (self.immediate & 0x00FF_FFFF) | ((new_value as u32) << 24),
2045 8 => self.mem_displ = (self.mem_displ & 0xFFFF_FFFF_FFFF_FF00) | new_value as u64,
2046 9 => self.mem_displ = (self.mem_displ & 0xFFFF_FFFF_FFFF_00FF) | ((new_value as u64) << 8),
2047 10 => self.mem_displ = (self.mem_displ & 0xFFFF_FFFF_FF00_FFFF) | ((new_value as u64) << 16),
2048 11 => self.mem_displ = (self.mem_displ & 0xFFFF_FFFF_00FF_FFFF) | ((new_value as u64) << 24),
2049 12 => self.mem_displ = (self.mem_displ & 0xFFFF_FF00_FFFF_FFFF) | ((new_value as u64) << 32),
2050 13 => self.mem_displ = (self.mem_displ & 0xFFFF_00FF_FFFF_FFFF) | ((new_value as u64) << 40),
2051 14 => self.mem_displ = (self.mem_displ & 0xFF00_FFFF_FFFF_FFFF) | ((new_value as u64) << 48),
2052 15 => self.mem_displ = (self.mem_displ & 0x00FF_FFFF_FFFF_FFFF) | ((new_value as u64) << 56),
2053 _ => return Err(IcedError::new("Invalid index")),
2054 }
2055 Ok(())
2056 }
2057
2058 #[must_use]
2069 #[inline]
2070 pub fn get_declare_byte_value(&self, index: usize) -> u8 {
2071 match self.try_get_declare_byte_value(index) {
2072 Ok(value) => value,
2073 Err(_) => {
2074 debug_assert!(false, "Invalid index: {}", index);
2075 0
2076 }
2077 }
2078 }
2079
2080 #[allow(clippy::missing_inline_in_public_items)]
2081 #[doc(hidden)]
2082 pub const fn try_get_declare_byte_value(&self, index: usize) -> Result<u8, IcedError> {
2083 Ok(match index {
2084 0 => self.regs[0] as u8,
2085 1 => self.regs[1] as u8,
2086 2 => self.regs[2] as u8,
2087 3 => self.regs[3] as u8,
2088 4 => self.immediate as u8,
2089 5 => (self.immediate >> 8) as u8,
2090 6 => (self.immediate >> 16) as u8,
2091 7 => (self.immediate >> 24) as u8,
2092 8 => self.mem_displ as u8,
2093 9 => ((self.mem_displ as u32) >> 8) as u8,
2094 10 => ((self.mem_displ as u32) >> 16) as u8,
2095 11 => ((self.mem_displ as u32) >> 24) as u8,
2096 12 => (self.mem_displ >> 32) as u8,
2097 13 => (self.mem_displ >> 40) as u8,
2098 14 => (self.mem_displ >> 48) as u8,
2099 15 => (self.mem_displ >> 56) as u8,
2100 _ => return Err(IcedError::new("Invalid index")),
2101 })
2102 }
2103
2104 #[inline]
2116 pub fn set_declare_word_value_i16(&mut self, index: usize, new_value: i16) {
2117 match self.try_set_declare_word_value_i16(index, new_value) {
2118 Ok(()) => {}
2119 Err(_) => debug_assert!(false, "Invalid index: {}", index),
2120 }
2121 }
2122
2123 #[inline]
2124 #[doc(hidden)]
2125 pub fn try_set_declare_word_value_i16(&mut self, index: usize, new_value: i16) -> Result<(), IcedError> {
2126 self.try_set_declare_word_value(index, new_value as u16)
2127 }
2128
2129 #[inline]
2141 pub fn set_declare_word_value(&mut self, index: usize, new_value: u16) {
2142 match self.try_set_declare_word_value(index, new_value) {
2143 Ok(()) => {}
2144 Err(_) => debug_assert!(false, "Invalid index: {}", index),
2145 }
2146 }
2147
2148 #[allow(clippy::missing_inline_in_public_items)]
2149 #[doc(hidden)]
2150 pub fn try_set_declare_word_value(&mut self, index: usize, new_value: u16) -> Result<(), IcedError> {
2151 match index {
2152 0 => {
2153 self.regs[0] = Register::from_u8(new_value as u8);
2154 self.regs[1] = Register::from_u8((new_value >> 8) as u8);
2155 }
2156 1 => {
2157 self.regs[2] = Register::from_u8(new_value as u8);
2158 self.regs[3] = Register::from_u8((new_value >> 8) as u8);
2159 }
2160 2 => self.immediate = (self.immediate & 0xFFFF_0000) | new_value as u32,
2161 3 => self.immediate = self.immediate as u16 as u32 | (new_value as u32) << 16,
2162 4 => self.mem_displ = (self.mem_displ & 0xFFFF_FFFF_FFFF_0000) | new_value as u64,
2163 5 => self.mem_displ = (self.mem_displ & 0xFFFF_FFFF_0000_FFFF) | ((new_value as u64) << 16),
2164 6 => self.mem_displ = (self.mem_displ & 0xFFFF_0000_FFFF_FFFF) | ((new_value as u64) << 32),
2165 7 => self.mem_displ = (self.mem_displ & 0x0000_FFFF_FFFF_FFFF) | ((new_value as u64) << 48),
2166 _ => return Err(IcedError::new("Invalid index")),
2167 }
2168 Ok(())
2169 }
2170
2171 #[must_use]
2182 #[inline]
2183 pub fn get_declare_word_value(&self, index: usize) -> u16 {
2184 match self.try_get_declare_word_value(index) {
2185 Ok(value) => value,
2186 Err(_) => {
2187 debug_assert!(false, "Invalid index: {}", index);
2188 0
2189 }
2190 }
2191 }
2192
2193 #[allow(clippy::missing_inline_in_public_items)]
2194 #[doc(hidden)]
2195 pub const fn try_get_declare_word_value(&self, index: usize) -> Result<u16, IcedError> {
2196 Ok(match index {
2197 0 => self.regs[0] as u16 | ((self.regs[1] as u16) << 8),
2198 1 => self.regs[2] as u16 | ((self.regs[3] as u16) << 8),
2199 2 => self.immediate as u16,
2200 3 => (self.immediate >> 16) as u16,
2201 4 => self.mem_displ as u16,
2202 5 => ((self.mem_displ as u32) >> 16) as u16,
2203 6 => (self.mem_displ >> 32) as u16,
2204 7 => (self.mem_displ >> 48) as u16,
2205 _ => return Err(IcedError::new("Invalid index")),
2206 })
2207 }
2208
2209 #[inline]
2221 pub fn set_declare_dword_value_i32(&mut self, index: usize, new_value: i32) {
2222 match self.try_set_declare_dword_value_i32(index, new_value) {
2223 Ok(()) => {}
2224 Err(_) => debug_assert!(false, "Invalid index: {}", index),
2225 }
2226 }
2227
2228 #[inline]
2229 #[doc(hidden)]
2230 pub fn try_set_declare_dword_value_i32(&mut self, index: usize, new_value: i32) -> Result<(), IcedError> {
2231 self.try_set_declare_dword_value(index, new_value as u32)
2232 }
2233
2234 #[inline]
2246 pub fn set_declare_dword_value(&mut self, index: usize, new_value: u32) {
2247 match self.try_set_declare_dword_value(index, new_value) {
2248 Ok(()) => {}
2249 Err(_) => debug_assert!(false, "Invalid index: {}", index),
2250 }
2251 }
2252
2253 #[allow(clippy::missing_inline_in_public_items)]
2254 #[doc(hidden)]
2255 pub fn try_set_declare_dword_value(&mut self, index: usize, new_value: u32) -> Result<(), IcedError> {
2256 match index {
2257 0 => {
2258 self.regs[0] = Register::from_u8(new_value as u8);
2259 self.regs[1] = Register::from_u8((new_value >> 8) as u8);
2260 self.regs[2] = Register::from_u8((new_value >> 16) as u8);
2261 self.regs[3] = Register::from_u8((new_value >> 24) as u8);
2262 }
2263 1 => self.immediate = new_value,
2264 2 => self.mem_displ = (self.mem_displ & 0xFFFF_FFFF_0000_0000) | new_value as u64,
2265 3 => self.mem_displ = (self.mem_displ & 0x0000_0000_FFFF_FFFF) | (new_value as u64) << 32,
2266 _ => return Err(IcedError::new("Invalid index")),
2267 }
2268 Ok(())
2269 }
2270
2271 #[must_use]
2282 #[inline]
2283 pub fn get_declare_dword_value(&self, index: usize) -> u32 {
2284 match self.try_get_declare_dword_value(index) {
2285 Ok(value) => value,
2286 Err(_) => {
2287 debug_assert!(false, "Invalid index: {}", index);
2288 0
2289 }
2290 }
2291 }
2292
2293 #[allow(clippy::missing_inline_in_public_items)]
2294 #[doc(hidden)]
2295 pub const fn try_get_declare_dword_value(&self, index: usize) -> Result<u32, IcedError> {
2296 Ok(match index {
2297 0 => self.regs[0] as u32 | ((self.regs[1] as u32) << 8) | ((self.regs[2] as u32) << 16) | ((self.regs[3] as u32) << 24),
2298 1 => self.immediate,
2299 2 => self.mem_displ as u32,
2300 3 => (self.mem_displ >> 32) as u32,
2301 _ => return Err(IcedError::new("Invalid index")),
2302 })
2303 }
2304
2305 #[inline]
2317 pub fn set_declare_qword_value_i64(&mut self, index: usize, new_value: i64) {
2318 match self.try_set_declare_qword_value_i64(index, new_value) {
2319 Ok(()) => {}
2320 Err(_) => debug_assert!(false, "Invalid index: {}", index),
2321 }
2322 }
2323
2324 #[inline]
2325 #[doc(hidden)]
2326 pub fn try_set_declare_qword_value_i64(&mut self, index: usize, new_value: i64) -> Result<(), IcedError> {
2327 self.try_set_declare_qword_value(index, new_value as u64)
2328 }
2329
2330 #[inline]
2342 pub fn set_declare_qword_value(&mut self, index: usize, new_value: u64) {
2343 match self.try_set_declare_qword_value(index, new_value) {
2344 Ok(()) => {}
2345 Err(_) => debug_assert!(false, "Invalid index: {}", index),
2346 }
2347 }
2348
2349 #[allow(clippy::missing_inline_in_public_items)]
2350 #[doc(hidden)]
2351 pub fn try_set_declare_qword_value(&mut self, index: usize, new_value: u64) -> Result<(), IcedError> {
2352 match index {
2353 0 => {
2354 self.regs[0] = Register::from_u8(new_value as u8);
2355 self.regs[1] = Register::from_u8((new_value >> 8) as u8);
2356 self.regs[2] = Register::from_u8((new_value >> 16) as u8);
2357 self.regs[3] = Register::from_u8((new_value >> 24) as u8);
2358 self.immediate = (new_value >> 32) as u32;
2359 }
2360 1 => self.mem_displ = new_value,
2361 _ => return Err(IcedError::new("Invalid index")),
2362 }
2363 Ok(())
2364 }
2365
2366 #[must_use]
2377 #[inline]
2378 pub fn get_declare_qword_value(&self, index: usize) -> u64 {
2379 match self.try_get_declare_qword_value(index) {
2380 Ok(value) => value,
2381 Err(_) => {
2382 debug_assert!(false, "Invalid index: {}", index);
2383 0
2384 }
2385 }
2386 }
2387
2388 #[allow(clippy::missing_inline_in_public_items)]
2389 #[doc(hidden)]
2390 pub const fn try_get_declare_qword_value(&self, index: usize) -> Result<u64, IcedError> {
2391 Ok(match index {
2392 0 => {
2393 self.regs[0] as u64
2394 | ((self.regs[1] as u64) << 8)
2395 | ((self.regs[2] as u64) << 16)
2396 | ((self.regs[3] as u64) << 24)
2397 | ((self.immediate as u64) << 32)
2398 }
2399 1 => self.mem_displ,
2400 _ => return Err(IcedError::new("Invalid index")),
2401 })
2402 }
2403
2404 #[must_use]
2409 #[inline]
2410 pub const fn is_vsib(&self) -> bool {
2411 self.vsib().is_some()
2412 }
2413
2414 #[must_use]
2418 #[inline]
2419 pub const fn is_vsib32(&self) -> bool {
2420 if let Some(is_vsib64) = self.vsib() {
2421 !is_vsib64
2422 } else {
2423 false
2424 }
2425 }
2426
2427 #[must_use]
2431 #[inline]
2432 pub const fn is_vsib64(&self) -> bool {
2433 if let Some(is_vsib64) = self.vsib() {
2434 is_vsib64
2435 } else {
2436 false
2437 }
2438 }
2439
2440 #[must_use]
2448 #[allow(clippy::missing_inline_in_public_items)]
2449 #[allow(clippy::match_single_binding)]
2450 pub const fn vsib(&self) -> Option<bool> {
2451 #[cfg_attr(feature = "cargo-fmt", rustfmt::skip)]
2452 match self.code() {
2453 Code::VEX_Vpgatherdd_xmm_vm32x_xmm
2456 | Code::VEX_Vpgatherdd_ymm_vm32y_ymm
2457 | Code::VEX_Vpgatherdq_xmm_vm32x_xmm
2458 | Code::VEX_Vpgatherdq_ymm_vm32x_ymm
2459 | Code::EVEX_Vpgatherdd_xmm_k1_vm32x
2460 | Code::EVEX_Vpgatherdd_ymm_k1_vm32y
2461 | Code::EVEX_Vpgatherdd_zmm_k1_vm32z
2462 | Code::EVEX_Vpgatherdq_xmm_k1_vm32x
2463 | Code::EVEX_Vpgatherdq_ymm_k1_vm32x
2464 | Code::EVEX_Vpgatherdq_zmm_k1_vm32y
2465 | Code::VEX_Vgatherdps_xmm_vm32x_xmm
2466 | Code::VEX_Vgatherdps_ymm_vm32y_ymm
2467 | Code::VEX_Vgatherdpd_xmm_vm32x_xmm
2468 | Code::VEX_Vgatherdpd_ymm_vm32x_ymm
2469 | Code::EVEX_Vgatherdps_xmm_k1_vm32x
2470 | Code::EVEX_Vgatherdps_ymm_k1_vm32y
2471 | Code::EVEX_Vgatherdps_zmm_k1_vm32z
2472 | Code::EVEX_Vgatherdpd_xmm_k1_vm32x
2473 | Code::EVEX_Vgatherdpd_ymm_k1_vm32x
2474 | Code::EVEX_Vgatherdpd_zmm_k1_vm32y
2475 | Code::EVEX_Vpscatterdd_vm32x_k1_xmm
2476 | Code::EVEX_Vpscatterdd_vm32y_k1_ymm
2477 | Code::EVEX_Vpscatterdd_vm32z_k1_zmm
2478 | Code::EVEX_Vpscatterdq_vm32x_k1_xmm
2479 | Code::EVEX_Vpscatterdq_vm32x_k1_ymm
2480 | Code::EVEX_Vpscatterdq_vm32y_k1_zmm
2481 | Code::EVEX_Vscatterdps_vm32x_k1_xmm
2482 | Code::EVEX_Vscatterdps_vm32y_k1_ymm
2483 | Code::EVEX_Vscatterdps_vm32z_k1_zmm
2484 | Code::EVEX_Vscatterdpd_vm32x_k1_xmm
2485 | Code::EVEX_Vscatterdpd_vm32x_k1_ymm
2486 | Code::EVEX_Vscatterdpd_vm32y_k1_zmm
2487 | Code::EVEX_Vgatherpf0dps_vm32z_k1
2488 | Code::EVEX_Vgatherpf0dpd_vm32y_k1
2489 | Code::EVEX_Vgatherpf1dps_vm32z_k1
2490 | Code::EVEX_Vgatherpf1dpd_vm32y_k1
2491 | Code::EVEX_Vscatterpf0dps_vm32z_k1
2492 | Code::EVEX_Vscatterpf0dpd_vm32y_k1
2493 | Code::EVEX_Vscatterpf1dps_vm32z_k1
2494 | Code::EVEX_Vscatterpf1dpd_vm32y_k1
2495 | Code::MVEX_Vpgatherdd_zmm_k1_mvt
2496 | Code::MVEX_Vpgatherdq_zmm_k1_mvt
2497 | Code::MVEX_Vgatherdps_zmm_k1_mvt
2498 | Code::MVEX_Vgatherdpd_zmm_k1_mvt
2499 | Code::MVEX_Vpscatterdd_mvt_k1_zmm
2500 | Code::MVEX_Vpscatterdq_mvt_k1_zmm
2501 | Code::MVEX_Vscatterdps_mvt_k1_zmm
2502 | Code::MVEX_Vscatterdpd_mvt_k1_zmm
2503 | Code::MVEX_Undoc_zmm_k1_mvt_512_66_0F38_W0_B0
2504 | Code::MVEX_Undoc_zmm_k1_mvt_512_66_0F38_W0_B2
2505 | Code::MVEX_Undoc_zmm_k1_mvt_512_66_0F38_W0_C0
2506 | Code::MVEX_Vgatherpf0hintdps_mvt_k1
2507 | Code::MVEX_Vgatherpf0hintdpd_mvt_k1
2508 | Code::MVEX_Vgatherpf0dps_mvt_k1
2509 | Code::MVEX_Vgatherpf1dps_mvt_k1
2510 | Code::MVEX_Vscatterpf0hintdps_mvt_k1
2511 | Code::MVEX_Vscatterpf0hintdpd_mvt_k1
2512 | Code::MVEX_Vscatterpf0dps_mvt_k1
2513 | Code::MVEX_Vscatterpf1dps_mvt_k1
2514 => Some(false),
2515 Code::VEX_Vpgatherqd_xmm_vm64x_xmm
2520 | Code::VEX_Vpgatherqd_xmm_vm64y_xmm
2521 | Code::VEX_Vpgatherqq_xmm_vm64x_xmm
2522 | Code::VEX_Vpgatherqq_ymm_vm64y_ymm
2523 | Code::EVEX_Vpgatherqd_xmm_k1_vm64x
2524 | Code::EVEX_Vpgatherqd_xmm_k1_vm64y
2525 | Code::EVEX_Vpgatherqd_ymm_k1_vm64z
2526 | Code::EVEX_Vpgatherqq_xmm_k1_vm64x
2527 | Code::EVEX_Vpgatherqq_ymm_k1_vm64y
2528 | Code::EVEX_Vpgatherqq_zmm_k1_vm64z
2529 | Code::VEX_Vgatherqps_xmm_vm64x_xmm
2530 | Code::VEX_Vgatherqps_xmm_vm64y_xmm
2531 | Code::VEX_Vgatherqpd_xmm_vm64x_xmm
2532 | Code::VEX_Vgatherqpd_ymm_vm64y_ymm
2533 | Code::EVEX_Vgatherqps_xmm_k1_vm64x
2534 | Code::EVEX_Vgatherqps_xmm_k1_vm64y
2535 | Code::EVEX_Vgatherqps_ymm_k1_vm64z
2536 | Code::EVEX_Vgatherqpd_xmm_k1_vm64x
2537 | Code::EVEX_Vgatherqpd_ymm_k1_vm64y
2538 | Code::EVEX_Vgatherqpd_zmm_k1_vm64z
2539 | Code::EVEX_Vpscatterqd_vm64x_k1_xmm
2540 | Code::EVEX_Vpscatterqd_vm64y_k1_xmm
2541 | Code::EVEX_Vpscatterqd_vm64z_k1_ymm
2542 | Code::EVEX_Vpscatterqq_vm64x_k1_xmm
2543 | Code::EVEX_Vpscatterqq_vm64y_k1_ymm
2544 | Code::EVEX_Vpscatterqq_vm64z_k1_zmm
2545 | Code::EVEX_Vscatterqps_vm64x_k1_xmm
2546 | Code::EVEX_Vscatterqps_vm64y_k1_xmm
2547 | Code::EVEX_Vscatterqps_vm64z_k1_ymm
2548 | Code::EVEX_Vscatterqpd_vm64x_k1_xmm
2549 | Code::EVEX_Vscatterqpd_vm64y_k1_ymm
2550 | Code::EVEX_Vscatterqpd_vm64z_k1_zmm
2551 | Code::EVEX_Vgatherpf0qps_vm64z_k1
2552 | Code::EVEX_Vgatherpf0qpd_vm64z_k1
2553 | Code::EVEX_Vgatherpf1qps_vm64z_k1
2554 | Code::EVEX_Vgatherpf1qpd_vm64z_k1
2555 | Code::EVEX_Vscatterpf0qps_vm64z_k1
2556 | Code::EVEX_Vscatterpf0qpd_vm64z_k1
2557 | Code::EVEX_Vscatterpf1qps_vm64z_k1
2558 | Code::EVEX_Vscatterpf1qpd_vm64z_k1
2559 => Some(true),
2560 _ => None,
2563 }
2564 }
2565
2566 #[must_use]
2572 #[inline]
2573 pub const fn suppress_all_exceptions(&self) -> bool {
2574 (self.flags1 & InstrFlags1::SUPPRESS_ALL_EXCEPTIONS) != 0
2575 }
2576
2577 #[inline]
2587 pub fn set_suppress_all_exceptions(&mut self, new_value: bool) {
2588 if new_value {
2589 self.flags1 |= InstrFlags1::SUPPRESS_ALL_EXCEPTIONS;
2590 } else {
2591 self.flags1 &= !InstrFlags1::SUPPRESS_ALL_EXCEPTIONS;
2592 }
2593 }
2594
2595 #[must_use]
2597 #[inline]
2598 pub fn is_ip_rel_memory_operand(&self) -> bool {
2599 let base_reg = self.memory_base();
2600 base_reg == Register::RIP || base_reg == Register::EIP
2601 }
2602
2603 #[must_use]
2610 #[inline]
2611 pub fn ip_rel_memory_address(&self) -> u64 {
2612 if self.memory_base() == Register::RIP {
2613 self.memory_displacement64()
2614 } else {
2615 self.memory_displacement32() as u64
2616 }
2617 }
2618
2619 #[must_use]
2656 #[inline]
2657 pub fn virtual_address<F>(&self, operand: u32, element_index: usize, get_register_value: F) -> Option<u64>
2658 where
2659 F: FnMut(Register, usize, usize) -> Option<u64>,
2660 {
2661 self.try_virtual_address(operand, element_index, get_register_value)
2662 }
2663
2664 #[must_use]
2665 #[allow(clippy::missing_inline_in_public_items)]
2666 #[doc(hidden)]
2667 pub fn try_virtual_address<F>(&self, operand: u32, element_index: usize, mut get_register_value: F) -> Option<u64>
2668 where
2669 F: FnMut(Register, usize, usize) -> Option<u64>,
2670 {
2671 let op_kind = self.op_kind(operand);
2672 Some(match op_kind {
2673 OpKind::Register
2674 | OpKind::NearBranch16
2675 | OpKind::NearBranch32
2676 | OpKind::NearBranch64
2677 | OpKind::FarBranch16
2678 | OpKind::FarBranch32
2679 | OpKind::Immediate8
2680 | OpKind::Immediate8_2nd
2681 | OpKind::Immediate16
2682 | OpKind::Immediate32
2683 | OpKind::Immediate64
2684 | OpKind::Immediate8to16
2685 | OpKind::Immediate8to32
2686 | OpKind::Immediate8to64
2687 | OpKind::Immediate32to64 => 0,
2688
2689 OpKind::MemorySegSI => {
2690 get_register_value(self.memory_segment(), 0, 0)?.wrapping_add(get_register_value(Register::SI, 0, 0)? as u16 as u64)
2691 }
2692 OpKind::MemorySegESI => {
2693 get_register_value(self.memory_segment(), 0, 0)?.wrapping_add(get_register_value(Register::ESI, 0, 0)? as u32 as u64)
2694 }
2695 OpKind::MemorySegRSI => get_register_value(self.memory_segment(), 0, 0)?.wrapping_add(get_register_value(Register::RSI, 0, 0)?),
2696 OpKind::MemorySegDI => {
2697 get_register_value(self.memory_segment(), 0, 0)?.wrapping_add(get_register_value(Register::DI, 0, 0)? as u16 as u64)
2698 }
2699 OpKind::MemorySegEDI => {
2700 get_register_value(self.memory_segment(), 0, 0)?.wrapping_add(get_register_value(Register::EDI, 0, 0)? as u32 as u64)
2701 }
2702 OpKind::MemorySegRDI => get_register_value(self.memory_segment(), 0, 0)?.wrapping_add(get_register_value(Register::RDI, 0, 0)?),
2703 OpKind::MemoryESDI => get_register_value(Register::ES, 0, 0)?.wrapping_add(get_register_value(Register::DI, 0, 0)? as u16 as u64),
2704 OpKind::MemoryESEDI => get_register_value(Register::ES, 0, 0)?.wrapping_add(get_register_value(Register::EDI, 0, 0)? as u32 as u64),
2705 OpKind::MemoryESRDI => get_register_value(Register::ES, 0, 0)?.wrapping_add(get_register_value(Register::RDI, 0, 0)?),
2706 OpKind::Memory => {
2707 let base_reg = self.memory_base();
2708 let index_reg = self.memory_index();
2709 let addr_size = instruction_internal::get_address_size_in_bytes(base_reg, index_reg, self.memory_displ_size(), self.code_size());
2710 let mut offset = self.memory_displacement64();
2711 let offset_mask = match addr_size {
2712 8 => u64::MAX,
2713 4 => u32::MAX as u64,
2714 _ => {
2715 debug_assert_eq!(addr_size, 2);
2716 u16::MAX as u64
2717 }
2718 };
2719 match base_reg {
2720 Register::None | Register::EIP | Register::RIP => {}
2721 _ => offset = offset.wrapping_add(get_register_value(base_reg, 0, 0)?),
2722 }
2723 let code = self.code();
2724 if index_reg != Register::None && !code.ignores_index() && !code.is_tile_stride_index() {
2725 if let Some(is_vsib64) = self.vsib() {
2726 if is_vsib64 {
2727 offset = offset.wrapping_add(
2728 get_register_value(index_reg, element_index, 8)? << instruction_internal::internal_get_memory_index_scale(self),
2729 );
2730 } else {
2731 offset = offset.wrapping_add(
2732 (get_register_value(index_reg, element_index, 4)? as i32 as u64)
2733 << instruction_internal::internal_get_memory_index_scale(self),
2734 );
2735 }
2736 } else {
2737 offset =
2738 offset.wrapping_add(get_register_value(index_reg, 0, 0)? << instruction_internal::internal_get_memory_index_scale(self));
2739 }
2740 }
2741 #[cfg(feature = "mvex")]
2742 {
2743 const _: () = assert!(Code::MVEX_Vloadunpackhd_zmm_k1_mt as u32 + 1 == Code::MVEX_Vloadunpackhq_zmm_k1_mt as u32);
2744 const _: () = assert!(Code::MVEX_Vloadunpackhd_zmm_k1_mt as u32 + 2 == Code::MVEX_Vpackstorehd_mt_k1_zmm as u32);
2745 const _: () = assert!(Code::MVEX_Vloadunpackhd_zmm_k1_mt as u32 + 3 == Code::MVEX_Vpackstorehq_mt_k1_zmm as u32);
2746 const _: () = assert!(Code::MVEX_Vloadunpackhd_zmm_k1_mt as u32 + 4 == Code::MVEX_Vloadunpackhps_zmm_k1_mt as u32);
2747 const _: () = assert!(Code::MVEX_Vloadunpackhd_zmm_k1_mt as u32 + 5 == Code::MVEX_Vloadunpackhpd_zmm_k1_mt as u32);
2748 const _: () = assert!(Code::MVEX_Vloadunpackhd_zmm_k1_mt as u32 + 6 == Code::MVEX_Vpackstorehps_mt_k1_zmm as u32);
2749 const _: () = assert!(Code::MVEX_Vloadunpackhd_zmm_k1_mt as u32 + 7 == Code::MVEX_Vpackstorehpd_mt_k1_zmm as u32);
2750 if code >= Code::MVEX_Vloadunpackhd_zmm_k1_mt && code <= Code::MVEX_Vpackstorehpd_mt_k1_zmm {
2751 offset = offset.wrapping_sub(0x40);
2752 }
2753 }
2754 offset &= offset_mask;
2755 if !code.ignores_segment() {
2756 get_register_value(self.memory_segment(), 0, 0)?.wrapping_add(offset)
2757 } else {
2758 offset
2759 }
2760 }
2761 })
2762 }
2763}
2764
2765#[cfg(feature = "instr_info")]
2767#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
2768pub struct FpuStackIncrementInfo {
2769 increment: i32,
2770 conditional: bool,
2771 writes_top: bool,
2772}
2773
2774#[cfg(feature = "instr_info")]
2775impl FpuStackIncrementInfo {
2776 #[must_use]
2778 #[inline]
2779 pub const fn new(increment: i32, conditional: bool, writes_top: bool) -> Self {
2780 Self { increment, conditional, writes_top }
2781 }
2782
2783 #[must_use]
2792 #[inline]
2793 pub const fn increment(&self) -> i32 {
2794 self.increment
2795 }
2796
2797 #[must_use]
2799 #[inline]
2800 pub const fn conditional(&self) -> bool {
2801 self.conditional
2802 }
2803
2804 #[must_use]
2806 #[inline]
2807 pub const fn writes_top(&self) -> bool {
2808 self.writes_top
2809 }
2810}
2811
2812#[cfg(feature = "instr_info")]
2813impl Instruction {
2814 #[must_use]
2831 #[allow(clippy::missing_inline_in_public_items)]
2832 pub fn stack_pointer_increment(&self) -> i32 {
2833 #[cfg_attr(feature = "cargo-fmt", rustfmt::skip)]
2834 #[allow(clippy::match_single_binding)]
2835 match self.code() {
2836 Code::Pushad => -32,
2839 Code::Pushaw
2840 | Code::Call_m1664 => -16,
2841 Code::Push_r64
2842 | Code::Pushq_imm32
2843 | Code::Pushq_imm8
2844 | Code::Call_ptr1632
2845 | Code::Pushfq
2846 | Code::Call_rel32_64
2847 | Code::Call_rm64
2848 | Code::Call_m1632
2849 | Code::Push_rm64
2850 | Code::Pushq_FS
2851 | Code::Pushq_GS => -8,
2852 Code::Pushd_ES
2853 | Code::Pushd_CS
2854 | Code::Pushd_SS
2855 | Code::Pushd_DS
2856 | Code::Push_r32
2857 | Code::Pushd_imm32
2858 | Code::Pushd_imm8
2859 | Code::Call_ptr1616
2860 | Code::Pushfd
2861 | Code::Call_rel32_32
2862 | Code::Call_rm32
2863 | Code::Call_m1616
2864 | Code::Push_rm32
2865 | Code::Pushd_FS
2866 | Code::Pushd_GS => -4,
2867 Code::Pushw_ES
2868 | Code::Pushw_CS
2869 | Code::Pushw_SS
2870 | Code::Pushw_DS
2871 | Code::Push_r16
2872 | Code::Push_imm16
2873 | Code::Pushw_imm8
2874 | Code::Pushfw
2875 | Code::Call_rel16
2876 | Code::Call_rm16
2877 | Code::Push_rm16
2878 | Code::Pushw_FS
2879 | Code::Pushw_GS => -2,
2880 Code::Popw_ES
2881 | Code::Popw_CS
2882 | Code::Popw_SS
2883 | Code::Popw_DS
2884 | Code::Pop_r16
2885 | Code::Pop_rm16
2886 | Code::Popfw
2887 | Code::Retnw
2888 | Code::Popw_FS
2889 | Code::Popw_GS => 2,
2890 Code::Popd_ES
2891 | Code::Popd_SS
2892 | Code::Popd_DS
2893 | Code::Pop_r32
2894 | Code::Pop_rm32
2895 | Code::Popfd
2896 | Code::Retnd
2897 | Code::Retfw
2898 | Code::Popd_FS
2899 | Code::Popd_GS => 4,
2900 Code::Pop_r64
2901 | Code::Pop_rm64
2902 | Code::Popfq
2903 | Code::Retnq
2904 | Code::Retfd
2905 | Code::Popq_FS
2906 | Code::Popq_GS => 8,
2907 Code::Popaw
2908 | Code::Retfq => 16,
2909 Code::Uiret => 24,
2910 Code::Popad => 32,
2911 Code::Iretq => 40,
2912 Code::Eretu
2913 | Code::Erets => 48,
2914 Code::Enterw_imm16_imm8 => -(2 + (self.immediate8_2nd() as i32 & 0x1F) * 2 + self.immediate16() as i32),
2915 Code::Enterd_imm16_imm8 => -(4 + (self.immediate8_2nd() as i32 & 0x1F) * 4 + self.immediate16() as i32),
2916 Code::Enterq_imm16_imm8 => -(8 + (self.immediate8_2nd() as i32 & 0x1F) * 8 + self.immediate16() as i32),
2917 Code::Iretw => if self.code_size() == CodeSize::Code64 { 2 * 5 } else { 2 * 3 },
2918 Code::Iretd => if self.code_size() == CodeSize::Code64 { 4 * 5 } else { 4 * 3 },
2919 Code::Retnw_imm16 => 2 + self.immediate16() as i32,
2920 Code::Retnd_imm16
2921 | Code::Retfw_imm16 => 4 + self.immediate16() as i32,
2922 Code::Retnq_imm16
2923 | Code::Retfd_imm16 => 8 + self.immediate16() as i32,
2924 Code::Retfq_imm16 => 16 + self.immediate16() as i32,
2925 _ => 0,
2927 }
2928 }
2929
2930 #[must_use]
2950 #[allow(clippy::missing_inline_in_public_items)]
2951 pub fn fpu_stack_increment_info(&self) -> FpuStackIncrementInfo {
2952 #[cfg_attr(feature = "cargo-fmt", rustfmt::skip)]
2953 #[allow(clippy::match_single_binding)]
2954 match self.code() {
2955 Code::Fld_m32fp
2958 | Code::Fld_sti
2959 | Code::Fld1
2960 | Code::Fldl2t
2961 | Code::Fldl2e
2962 | Code::Fldpi
2963 | Code::Fldlg2
2964 | Code::Fldln2
2965 | Code::Fldz
2966 | Code::Fxtract
2967 | Code::Fdecstp
2968 | Code::Fild_m32int
2969 | Code::Fld_m80fp
2970 | Code::Fld_m64fp
2971 | Code::Fild_m16int
2972 | Code::Fbld_m80bcd
2973 | Code::Fild_m64int
2974 => FpuStackIncrementInfo { increment: -1, conditional: false, writes_top: true },
2975 Code::Fptan
2976 | Code::Fsincos
2977 => FpuStackIncrementInfo { increment: -1, conditional: true, writes_top: true },
2978 Code::Fldenv_m14byte
2979 | Code::Fldenv_m28byte
2980 | Code::Fninit
2981 | Code::Finit
2982 | Code::Frstor_m94byte
2983 | Code::Frstor_m108byte
2984 | Code::Fnsave_m94byte
2985 | Code::Fsave_m94byte
2986 | Code::Fnsave_m108byte
2987 | Code::Fsave_m108byte
2988 => FpuStackIncrementInfo { increment: 0, conditional: false, writes_top: true },
2989 Code::Fcomp_m32fp
2990 | Code::Fcomp_st0_sti
2991 | Code::Fstp_m32fp
2992 | Code::Fstpnce_sti
2993 | Code::Fyl2x
2994 | Code::Fpatan
2995 | Code::Fincstp
2996 | Code::Fyl2xp1
2997 | Code::Ficomp_m32int
2998 | Code::Fisttp_m32int
2999 | Code::Fistp_m32int
3000 | Code::Fstp_m80fp
3001 | Code::Fcomp_m64fp
3002 | Code::Fcomp_st0_sti_DCD8
3003 | Code::Fisttp_m64int
3004 | Code::Fstp_m64fp
3005 | Code::Fstp_sti
3006 | Code::Fucomp_st0_sti
3007 | Code::Ficomp_m16int
3008 | Code::Faddp_sti_st0
3009 | Code::Fmulp_sti_st0
3010 | Code::Fcomp_st0_sti_DED0
3011 | Code::Fsubrp_sti_st0
3012 | Code::Fsubp_sti_st0
3013 | Code::Fdivrp_sti_st0
3014 | Code::Fdivp_sti_st0
3015 | Code::Fisttp_m16int
3016 | Code::Fistp_m16int
3017 | Code::Fbstp_m80bcd
3018 | Code::Fistp_m64int
3019 | Code::Ffreep_sti
3020 | Code::Fstp_sti_DFD0
3021 | Code::Fstp_sti_DFD8
3022 | Code::Fucomip_st0_sti
3023 | Code::Fcomip_st0_sti
3024 | Code::Ftstp
3025 => FpuStackIncrementInfo { increment: 1, conditional: false, writes_top: true },
3026 Code::Fucompp
3027 | Code::Fcompp
3028 => FpuStackIncrementInfo { increment: 2, conditional: false, writes_top: true },
3029 _ => FpuStackIncrementInfo::default(),
3031 }
3032 }
3033
3034 #[must_use]
3049 #[inline]
3050 pub fn encoding(&self) -> EncodingKind {
3051 self.code().encoding()
3052 }
3053
3054 #[must_use]
3080 #[allow(clippy::missing_inline_in_public_items)]
3081 pub fn cpuid_features(&self) -> &'static [CpuidFeature] {
3082 self.code().cpuid_features()
3083 }
3084
3085 #[must_use]
3111 #[inline]
3112 pub fn flow_control(&self) -> FlowControl {
3113 self.code().flow_control()
3114 }
3115
3116 #[must_use]
3118 #[inline]
3119 pub fn is_privileged(&self) -> bool {
3120 self.code().is_privileged()
3121 }
3122
3123 #[must_use]
3148 #[inline]
3149 pub fn is_stack_instruction(&self) -> bool {
3150 self.code().is_stack_instruction()
3151 }
3152
3153 #[must_use]
3155 #[inline]
3156 pub fn is_save_restore_instruction(&self) -> bool {
3157 self.code().is_save_restore_instruction()
3158 }
3159
3160 #[must_use]
3162 #[inline]
3163 pub const fn is_string_instruction(&self) -> bool {
3164 self.code().is_string_instruction()
3165 }
3166
3167 #[must_use]
3168 fn rflags_info(&self) -> RflagsInfo {
3169 let flags1 = crate::info::info_table::TABLE[self.code() as usize].0;
3170 let implied_access = (flags1 >> InfoFlags1::IMPLIED_ACCESS_SHIFT) & InfoFlags1::IMPLIED_ACCESS_MASK;
3171 const _: () = assert!(ImpliedAccess::Shift_Ib_MASK1FMOD9 as u32 + 1 == ImpliedAccess::Shift_Ib_MASK1FMOD11 as u32);
3172 const _: () = assert!(ImpliedAccess::Shift_Ib_MASK1FMOD9 as u32 + 2 == ImpliedAccess::Shift_Ib_MASK1F as u32);
3173 const _: () = assert!(ImpliedAccess::Shift_Ib_MASK1FMOD9 as u32 + 3 == ImpliedAccess::Shift_Ib_MASK3F as u32);
3174 const _: () = assert!(ImpliedAccess::Shift_Ib_MASK1FMOD9 as u32 + 4 == ImpliedAccess::Clear_rflags as u32);
3175 let result = unsafe { mem::transmute(((flags1 >> InfoFlags1::RFLAGS_INFO_SHIFT) & InfoFlags1::RFLAGS_INFO_MASK) as u8) };
3177 let e = implied_access.wrapping_sub(ImpliedAccess::Shift_Ib_MASK1FMOD9 as u32);
3178 match e {
3179 0 | 1 => {
3180 #[allow(clippy::eq_op)]
3181 const _: () = assert!(ImpliedAccess::Shift_Ib_MASK1FMOD9 as u32 - ImpliedAccess::Shift_Ib_MASK1FMOD9 as u32 == 0);
3182 const _: () = assert!(ImpliedAccess::Shift_Ib_MASK1FMOD11 as u32 - ImpliedAccess::Shift_Ib_MASK1FMOD9 as u32 == 1);
3183 let m = if e == 0 { 9 } else { 17 };
3184 match (self.immediate8() & 0x1F) % m {
3185 0 => return RflagsInfo::None,
3186 1 => return RflagsInfo::R_c_W_co,
3187 _ => {}
3188 }
3189 }
3190 2 | 3 => {
3191 const _: () = assert!(ImpliedAccess::Shift_Ib_MASK1F as u32 - ImpliedAccess::Shift_Ib_MASK1FMOD9 as u32 == 2);
3192 const _: () = assert!(ImpliedAccess::Shift_Ib_MASK3F as u32 - ImpliedAccess::Shift_Ib_MASK1FMOD9 as u32 == 3);
3193 let mask = if e == 2 { 0x1F } else { 0x3F };
3194 match self.immediate8() & mask {
3195 0 => return RflagsInfo::None,
3196 1 => {
3197 if result == RflagsInfo::W_c_U_o {
3198 return RflagsInfo::W_co;
3199 } else if result == RflagsInfo::R_c_W_c_U_o {
3200 return RflagsInfo::R_c_W_co;
3201 } else {
3202 debug_assert_eq!(result, RflagsInfo::W_cpsz_U_ao);
3203 return RflagsInfo::W_copsz_U_a;
3204 }
3205 }
3206 _ => {}
3207 }
3208 }
3209 4 => {
3210 const _: () = assert!(ImpliedAccess::Clear_rflags as u32 - ImpliedAccess::Shift_Ib_MASK1FMOD9 as u32 == 4);
3211 if self.op0_register() == self.op1_register() && self.op0_kind() == OpKind::Register && self.op1_kind() == OpKind::Register {
3212 if self.mnemonic() == Mnemonic::Xor {
3213 return RflagsInfo::C_cos_S_pz_U_a;
3214 } else {
3215 return RflagsInfo::C_acos_S_pz;
3216 }
3217 }
3218 }
3219 _ => {}
3220 }
3221 result
3222 }
3223
3224 #[must_use]
3259 #[inline]
3260 pub fn rflags_read(&self) -> u32 {
3261 crate::info::rflags_table::FLAGS_READ[self.rflags_info() as usize] as u32
3262 }
3263
3264 #[must_use]
3299 #[inline]
3300 pub fn rflags_written(&self) -> u32 {
3301 crate::info::rflags_table::FLAGS_WRITTEN[self.rflags_info() as usize] as u32
3302 }
3303
3304 #[must_use]
3339 #[inline]
3340 pub fn rflags_cleared(&self) -> u32 {
3341 crate::info::rflags_table::FLAGS_CLEARED[self.rflags_info() as usize] as u32
3342 }
3343
3344 #[must_use]
3379 #[inline]
3380 pub fn rflags_set(&self) -> u32 {
3381 crate::info::rflags_table::FLAGS_SET[self.rflags_info() as usize] as u32
3382 }
3383
3384 #[must_use]
3419 #[inline]
3420 pub fn rflags_undefined(&self) -> u32 {
3421 crate::info::rflags_table::FLAGS_UNDEFINED[self.rflags_info() as usize] as u32
3422 }
3423
3424 #[must_use]
3457 #[inline]
3458 pub fn rflags_modified(&self) -> u32 {
3459 crate::info::rflags_table::FLAGS_MODIFIED[self.rflags_info() as usize] as u32
3460 }
3461
3462 #[must_use]
3464 #[inline]
3465 pub const fn is_jcc_short_or_near(&self) -> bool {
3466 self.code().is_jcc_short_or_near()
3467 }
3468
3469 #[must_use]
3471 #[inline]
3472 pub const fn is_jcc_near(&self) -> bool {
3473 self.code().is_jcc_near()
3474 }
3475
3476 #[must_use]
3478 #[inline]
3479 pub const fn is_jcc_short(&self) -> bool {
3480 self.code().is_jcc_short()
3481 }
3482
3483 #[must_use]
3485 #[inline]
3486 pub const fn is_jmp_short(&self) -> bool {
3487 self.code().is_jmp_short()
3488 }
3489
3490 #[must_use]
3492 #[inline]
3493 pub const fn is_jmp_near(&self) -> bool {
3494 self.code().is_jmp_near()
3495 }
3496
3497 #[must_use]
3499 #[inline]
3500 pub const fn is_jmp_short_or_near(&self) -> bool {
3501 self.code().is_jmp_short_or_near()
3502 }
3503
3504 #[must_use]
3506 #[inline]
3507 pub const fn is_jmp_far(&self) -> bool {
3508 self.code().is_jmp_far()
3509 }
3510
3511 #[must_use]
3513 #[inline]
3514 pub const fn is_call_near(&self) -> bool {
3515 self.code().is_call_near()
3516 }
3517
3518 #[must_use]
3520 #[inline]
3521 pub const fn is_call_far(&self) -> bool {
3522 self.code().is_call_far()
3523 }
3524
3525 #[must_use]
3527 #[inline]
3528 pub const fn is_jmp_near_indirect(&self) -> bool {
3529 self.code().is_jmp_near_indirect()
3530 }
3531
3532 #[must_use]
3534 #[inline]
3535 pub const fn is_jmp_far_indirect(&self) -> bool {
3536 self.code().is_jmp_far_indirect()
3537 }
3538
3539 #[must_use]
3541 #[inline]
3542 pub const fn is_call_near_indirect(&self) -> bool {
3543 self.code().is_call_near_indirect()
3544 }
3545
3546 #[must_use]
3548 #[inline]
3549 pub const fn is_call_far_indirect(&self) -> bool {
3550 self.code().is_call_far_indirect()
3551 }
3552
3553 #[must_use]
3555 #[inline]
3556 #[cfg(feature = "mvex")]
3557 pub const fn is_jkcc_short_or_near(&self) -> bool {
3558 self.code().is_jkcc_short_or_near()
3559 }
3560
3561 #[must_use]
3563 #[inline]
3564 #[cfg(feature = "mvex")]
3565 pub const fn is_jkcc_near(&self) -> bool {
3566 self.code().is_jkcc_near()
3567 }
3568
3569 #[must_use]
3571 #[inline]
3572 #[cfg(feature = "mvex")]
3573 pub const fn is_jkcc_short(&self) -> bool {
3574 self.code().is_jkcc_short()
3575 }
3576
3577 #[must_use]
3579 #[inline]
3580 pub const fn is_jcx_short(&self) -> bool {
3581 self.code().is_jcx_short()
3582 }
3583
3584 #[must_use]
3586 #[inline]
3587 pub const fn is_loopcc(&self) -> bool {
3588 self.code().is_loopcc()
3589 }
3590
3591 #[must_use]
3593 #[inline]
3594 pub const fn is_loop(&self) -> bool {
3595 self.code().is_loop()
3596 }
3597
3598 #[inline]
3618 pub fn negate_condition_code(&mut self) {
3619 self.set_code(self.code().negate_condition_code())
3620 }
3621
3622 #[inline]
3641 pub fn as_short_branch(&mut self) {
3642 self.set_code(self.code().as_short_branch())
3643 }
3644
3645 #[inline]
3664 pub fn as_near_branch(&mut self) {
3665 self.set_code(self.code().as_near_branch())
3666 }
3667
3668 #[must_use]
3701 #[inline]
3702 pub fn condition_code(&self) -> ConditionCode {
3703 self.code().condition_code()
3704 }
3705}
3706
3707#[cfg(all(feature = "encoder", feature = "op_code_info"))]
3708impl Instruction {
3709 #[must_use]
3713 #[inline]
3714 pub fn op_code(&self) -> &'static OpCodeInfo {
3715 self.code().op_code()
3716 }
3717}
3718
3719impl Eq for Instruction {}
3720
3721impl PartialEq<Instruction> for Instruction {
3722 #[must_use]
3723 #[allow(clippy::missing_inline_in_public_items)]
3724 fn eq(&self, other: &Self) -> bool {
3725 self.mem_displ == other.mem_displ
3726 && ((self.flags1 ^ other.flags1) & !InstrFlags1::EQUALS_IGNORE_MASK) == 0
3727 && self.immediate == other.immediate
3728 && self.code == other.code
3729 && self.mem_base_reg == other.mem_base_reg
3730 && self.mem_index_reg == other.mem_index_reg
3731 && self.regs == other.regs
3732 && self.op_kinds == other.op_kinds
3733 && self.scale == other.scale
3734 && self.displ_size == other.displ_size
3735 && self.pad == other.pad
3736 }
3737}
3738
3739impl Hash for Instruction {
3740 #[allow(clippy::missing_inline_in_public_items)]
3741 fn hash<H: Hasher>(&self, state: &mut H) {
3742 self.mem_displ.hash(state);
3743 (self.flags1 & !InstrFlags1::EQUALS_IGNORE_MASK).hash(state);
3744 self.immediate.hash(state);
3745 self.code.hash(state);
3746 self.mem_base_reg.hash(state);
3747 self.mem_index_reg.hash(state);
3748 self.regs.hash(state);
3749 self.op_kinds.hash(state);
3750 self.scale.hash(state);
3751 self.displ_size.hash(state);
3752 self.pad.hash(state);
3753 }
3754}
3755
3756#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
3757struct FmtFormatterOutput<'a, 'b> {
3758 f: &'a mut fmt::Formatter<'b>,
3759 result: fmt::Result,
3760}
3761#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
3762impl<'a, 'b> FmtFormatterOutput<'a, 'b> {
3763 fn new(f: &'a mut fmt::Formatter<'b>) -> Self {
3764 Self { f, result: Ok(()) }
3765 }
3766}
3767#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
3768impl FormatterOutput for FmtFormatterOutput<'_, '_> {
3769 fn write(&mut self, text: &str, _kind: FormatterTextKind) {
3770 if self.result.is_ok() {
3771 self.result = self.f.write_str(text);
3772 }
3773 }
3774}
3775
3776#[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm", feature = "fast_fmt"))]
3777impl fmt::Display for Instruction {
3778 #[allow(clippy::missing_inline_in_public_items)]
3779 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3780 #[cfg(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm"))]
3784 {
3785 #[cfg(feature = "masm")]
3786 let mut formatter = MasmFormatter::new();
3787
3788 #[cfg(all(not(feature = "masm"), feature = "nasm"))]
3789 let mut formatter = NasmFormatter::new();
3790
3791 #[cfg(all(not(feature = "masm"), not(feature = "nasm"), feature = "intel"))]
3792 let mut formatter = IntelFormatter::new();
3793
3794 #[cfg(all(not(feature = "masm"), not(feature = "nasm"), not(feature = "intel"), feature = "gas"))]
3795 let mut formatter = GasFormatter::new();
3796
3797 let mut output = FmtFormatterOutput::new(f);
3798 formatter.format(self, &mut output);
3799 output.result
3800 }
3801 #[cfg(not(any(feature = "gas", feature = "intel", feature = "masm", feature = "nasm")))]
3802 {
3803 let mut formatter = FastFormatter::new();
3804
3805 let mut output = alloc::string::String::new();
3806 formatter.format(self, &mut output);
3807 f.write_str(&output)
3808 }
3809 }
3810}
3811
3812struct OpKindIterator {
3813 count: u8,
3814 index: u8,
3815 op_kinds: [OpKind; IcedConstants::MAX_OP_COUNT],
3816}
3817
3818impl OpKindIterator {
3819 fn new(instruction: &Instruction) -> Self {
3820 const _: () = assert!(IcedConstants::MAX_OP_COUNT <= core::u8::MAX as usize);
3822 OpKindIterator {
3823 count: instruction.op_count() as u8,
3824 index: 0,
3825 op_kinds: [instruction.op0_kind(), instruction.op1_kind(), instruction.op2_kind(), instruction.op3_kind(), instruction.op4_kind()],
3826 }
3827 }
3828}
3829
3830impl Iterator for OpKindIterator {
3831 type Item = OpKind;
3832
3833 #[inline]
3834 fn next(&mut self) -> Option<Self::Item> {
3835 let index = self.index;
3836 if index < self.count {
3837 self.index = index + 1;
3838 Some(self.op_kinds[index as usize])
3839 } else {
3840 None
3841 }
3842 }
3843
3844 #[inline]
3845 fn size_hint(&self) -> (usize, Option<usize>) {
3846 let len = self.count as usize - self.index as usize;
3847 (len, Some(len))
3848 }
3849}
3850
3851impl ExactSizeIterator for OpKindIterator {}
3852impl FusedIterator for OpKindIterator {}
3853
3854#[cfg(feature = "serde")]
3858const _: () = {
3859 #[cfg(not(feature = "std"))]
3860 use alloc::string::String;
3861 use core::marker::PhantomData;
3862 use serde::de;
3863 use serde::ser::SerializeStruct;
3864 use serde::{Deserialize, Deserializer, Serialize, Serializer};
3865
3866 const NUM_FIELDS_READABLE: usize = 13;
3868 const NUM_FIELDS_BINARY: usize = 19;
3870
3871 #[inline]
3872 const fn is_human_readable(value: bool) -> bool {
3873 if cfg!(feature = "__internal_flip") {
3875 value ^ true
3876 } else {
3877 value
3878 }
3879 }
3880
3881 impl Serialize for Instruction {
3882 #[allow(clippy::missing_inline_in_public_items)]
3883 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
3884 where
3885 S: Serializer,
3886 {
3887 if is_human_readable(serializer.is_human_readable()) {
3888 let mut serde_state = serializer.serialize_struct("Instruction", NUM_FIELDS_READABLE)?;
3889 let mut fields = 0;
3890 macro_rules! serialize {
3891 ($field:ident) => {
3892 serde_state.serialize_field(stringify!($field), &self.$field)?;
3893 fields += 1;
3894 };
3895 }
3896 serialize!(next_rip);
3897 serialize!(mem_displ);
3898 serialize!(flags1);
3899 serialize!(immediate);
3900 serialize!(code);
3901 serialize!(mem_base_reg);
3902 serialize!(mem_index_reg);
3903 serialize!(regs);
3904 serialize!(op_kinds);
3905 serialize!(scale);
3906 serialize!(displ_size);
3907 serialize!(len);
3908 serialize!(pad);
3909 debug_assert_eq!(fields, NUM_FIELDS_READABLE);
3910 serde_state.end()
3911 } else {
3912 let mut serde_state = serializer.serialize_struct("Instruction", NUM_FIELDS_BINARY)?;
3913 let mut fields = 0;
3914 macro_rules! serialize {
3915 ($field:ident) => {
3916 serde_state.serialize_field(stringify!($field), &self.$field)?;
3917 fields += 1;
3918 };
3919 ($field:ident, $underlying_ty:ty) => {
3920 serde_state.serialize_field(stringify!($field), &(self.$field as $underlying_ty))?;
3921 fields += 1;
3922 };
3923 ($field:ident, $index:literal, $underlying_ty:ty) => {
3924 serde_state.serialize_field(concat!(stringify!($field), stringify!($index)), &(self.$field[$index] as $underlying_ty))?;
3925 fields += 1;
3926 };
3927 }
3928 serialize!(next_rip);
3929 serialize!(mem_displ);
3930 serialize!(flags1);
3931 serialize!(immediate);
3932 serialize!(code, CodeUnderlyingType);
3933 serialize!(mem_base_reg, RegisterUnderlyingType);
3934 serialize!(mem_index_reg, RegisterUnderlyingType);
3935 debug_assert_eq!(self.regs.len(), 4);
3936 serialize!(regs, 0, RegisterUnderlyingType);
3937 serialize!(regs, 1, RegisterUnderlyingType);
3938 serialize!(regs, 2, RegisterUnderlyingType);
3939 serialize!(regs, 3, RegisterUnderlyingType);
3940 debug_assert_eq!(self.op_kinds.len(), 4);
3941 serialize!(op_kinds, 0, OpKindUnderlyingType);
3942 serialize!(op_kinds, 1, OpKindUnderlyingType);
3943 serialize!(op_kinds, 2, OpKindUnderlyingType);
3944 serialize!(op_kinds, 3, OpKindUnderlyingType);
3945 serialize!(scale, InstrScaleUnderlyingType);
3946 serialize!(displ_size);
3947 serialize!(len);
3948 serialize!(pad);
3949 debug_assert_eq!(fields, NUM_FIELDS_BINARY);
3950 serde_state.end()
3951 }
3952 }
3953 }
3954
3955 macro_rules! mk_struct_field_visitor {
3956 () => {
3957 struct StructFieldVisitor;
3958 impl<'de> de::Visitor<'de> for StructFieldVisitor {
3959 type Value = StructField;
3960 #[inline]
3961 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
3962 formatter.write_str("field identifier")
3963 }
3964 #[inline]
3965 fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
3966 where
3967 E: de::Error,
3968 {
3969 if let Ok(v) = <usize as TryFrom<_>>::try_from(v) {
3970 if let Ok(value) = <StructField as TryFrom<_>>::try_from(v) {
3971 return Ok(value);
3972 }
3973 }
3974 Err(de::Error::invalid_value(de::Unexpected::Unsigned(v), &"Invalid Instruction field value"))
3975 }
3976 #[inline]
3977 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
3978 where
3979 E: de::Error,
3980 {
3981 StructFieldVisitor::deserialize_name(v.as_bytes())
3982 }
3983 #[inline]
3984 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
3985 where
3986 E: de::Error,
3987 {
3988 StructFieldVisitor::deserialize_name(v)
3989 }
3990 }
3991 impl StructFieldVisitor {
3992 #[inline]
3993 fn deserialize_name<E>(v: &[u8]) -> Result<StructField, E>
3994 where
3995 E: de::Error,
3996 {
3997 for (&name, value) in FIELDS.iter().zip(StructField::values()) {
3998 if name.as_bytes() == v {
3999 return Ok(value);
4000 }
4001 }
4002 Err(de::Error::unknown_field(&String::from_utf8_lossy(v), &["Instruction fields"][..]))
4003 }
4004 }
4005 impl<'de> Deserialize<'de> for StructField {
4006 #[inline]
4007 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
4008 where
4009 D: Deserializer<'de>,
4010 {
4011 deserializer.deserialize_identifier(StructFieldVisitor)
4012 }
4013 }
4014 };
4015 }
4016
4017 impl<'de> Deserialize<'de> for Instruction {
4018 #[inline]
4019 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
4020 where
4021 D: Deserializer<'de>,
4022 {
4023 if is_human_readable(deserializer.is_human_readable()) {
4024 #[allow(non_camel_case_types)]
4025 #[derive(Copy, Clone)]
4026 #[allow(dead_code)]
4027 enum StructField {
4028 next_rip,
4029 mem_displ,
4030 flags1,
4031 immediate,
4032 code,
4033 mem_base_reg,
4034 mem_index_reg,
4035 regs,
4036 op_kinds,
4037 scale,
4038 displ_size,
4039 len,
4040 pad,
4041 }
4042 const _: () = assert!(StructField::pad as usize + 1 == NUM_FIELDS_READABLE);
4043 const FIELDS: [&str; NUM_FIELDS_READABLE] = [
4044 "next_rip",
4045 "mem_displ",
4046 "flags1",
4047 "immediate",
4048 "code",
4049 "mem_base_reg",
4050 "mem_index_reg",
4051 "regs",
4052 "op_kinds",
4053 "scale",
4054 "displ_size",
4055 "len",
4056 "pad",
4057 ];
4058 impl StructField {
4059 #[inline]
4060 fn values() -> impl Iterator<Item = StructField> + DoubleEndedIterator + ExactSizeIterator + FusedIterator {
4061 (0..NUM_FIELDS_READABLE).map(|x| unsafe { mem::transmute::<u8, StructField>(x as u8) })
4063 }
4064 }
4065 impl TryFrom<usize> for StructField {
4066 type Error = &'static str;
4067 #[inline]
4068 fn try_from(value: usize) -> Result<Self, Self::Error> {
4069 if value < NUM_FIELDS_READABLE {
4070 Ok(unsafe { mem::transmute(value as u8) })
4072 } else {
4073 Err("Invalid struct field")
4074 }
4075 }
4076 }
4077
4078 mk_struct_field_visitor!();
4079
4080 struct Visitor<'de> {
4081 marker: PhantomData<Instruction>,
4082 lifetime: PhantomData<&'de ()>,
4083 }
4084 impl<'de> de::Visitor<'de> for Visitor<'de> {
4085 type Value = Instruction;
4086 #[inline]
4087 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
4088 formatter.write_str("struct Instruction")
4089 }
4090 #[allow(clippy::missing_inline_in_public_items)]
4091 #[allow(clippy::mixed_read_write_in_expression)]
4092 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
4093 where
4094 A: de::SeqAccess<'de>,
4095 {
4096 let mut fields = 0;
4097 macro_rules! next_element {
4098 ($field_name:ident : $field_ty:ty) => {{
4099 fields += 1;
4100 match seq.next_element::<$field_ty>()? {
4101 Some(value) => value,
4102 None => return Err(de::Error::invalid_length(fields, &"struct Instruction with all its fields")),
4103 }
4104 }};
4105 }
4106 let instruction = Instruction {
4107 next_rip: next_element!(next_rip: u64),
4108 mem_displ: next_element!(mem_displ: u64),
4109 flags1: next_element!(flags1: u32),
4110 immediate: next_element!(immediate: u32),
4111 code: next_element!(code: Code),
4112 mem_base_reg: next_element!(mem_base_reg: Register),
4113 mem_index_reg: next_element!(mem_index_reg: Register),
4114 regs: next_element!(regs: [Register; 4]),
4115 op_kinds: next_element!(op_kinds: [OpKind; 4]),
4116 scale: next_element!(scale: InstrScale),
4117 displ_size: next_element!(displ_size: u8),
4118 len: next_element!(len: u8),
4119 pad: next_element!(pad: u8),
4120 };
4121 debug_assert_eq!(fields, NUM_FIELDS_READABLE);
4122 Ok(instruction)
4123 }
4124 #[allow(clippy::missing_inline_in_public_items)]
4125 #[allow(clippy::mixed_read_write_in_expression)]
4126 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
4127 where
4128 A: de::MapAccess<'de>,
4129 {
4130 let mut next_rip: Option<u64> = None;
4131 let mut mem_displ: Option<u64> = None;
4132 let mut flags1: Option<u32> = None;
4133 let mut immediate: Option<u32> = None;
4134 let mut code: Option<Code> = None;
4135 let mut mem_base_reg: Option<Register> = None;
4136 let mut mem_index_reg: Option<Register> = None;
4137 let mut regs: Option<[Register; 4]> = None;
4138 let mut op_kinds: Option<[OpKind; 4]> = None;
4139 let mut scale: Option<InstrScale> = None;
4140 let mut displ_size: Option<u8> = None;
4141 let mut len: Option<u8> = None;
4142 let mut pad: Option<u8> = None;
4143 while let Some(field) = map.next_key::<StructField>()? {
4144 macro_rules! unpack {
4145 ($field:ident : $field_ty:ty) => {{
4146 if $field.is_some() {
4147 return Err(<A::Error as de::Error>::duplicate_field(stringify!($field)));
4148 }
4149 $field = Some(map.next_value::<$field_ty>()?);
4150 }};
4151 }
4152 match field {
4153 StructField::next_rip => unpack!(next_rip: u64),
4154 StructField::mem_displ => unpack!(mem_displ: u64),
4155 StructField::flags1 => unpack!(flags1: u32),
4156 StructField::immediate => unpack!(immediate: u32),
4157 StructField::code => unpack!(code: Code),
4158 StructField::mem_base_reg => unpack!(mem_base_reg: Register),
4159 StructField::mem_index_reg => unpack!(mem_index_reg: Register),
4160 StructField::regs => unpack!(regs: [Register; 4]),
4161 StructField::op_kinds => unpack!(op_kinds: [OpKind; 4]),
4162 StructField::scale => unpack!(scale: InstrScale),
4163 StructField::displ_size => unpack!(displ_size: u8),
4164 StructField::len => unpack!(len: u8),
4165 StructField::pad => unpack!(pad: u8),
4166 }
4167 }
4168 let mut fields = 0;
4169 macro_rules! unpack_field {
4170 ($field:ident) => {{
4171 fields += 1;
4172 match $field {
4173 Some(value) => value,
4174 None => return Err(<A::Error as de::Error>::missing_field(stringify!($field))),
4175 }
4176 }};
4177 }
4178 let instruction = Instruction {
4179 next_rip: unpack_field!(next_rip),
4180 mem_displ: unpack_field!(mem_displ),
4181 flags1: unpack_field!(flags1),
4182 immediate: unpack_field!(immediate),
4183 code: unpack_field!(code),
4184 mem_base_reg: unpack_field!(mem_base_reg),
4185 mem_index_reg: unpack_field!(mem_index_reg),
4186 regs: unpack_field!(regs),
4187 op_kinds: unpack_field!(op_kinds),
4188 scale: unpack_field!(scale),
4189 displ_size: unpack_field!(displ_size),
4190 len: unpack_field!(len),
4191 pad: unpack_field!(pad),
4192 };
4193 debug_assert_eq!(fields, NUM_FIELDS_READABLE);
4194 Ok(instruction)
4195 }
4196 }
4197 deserializer.deserialize_struct("Instruction", &FIELDS[..], Visitor { marker: PhantomData::<Instruction>, lifetime: PhantomData })
4198 } else {
4199 #[allow(non_camel_case_types)]
4200 #[derive(Copy, Clone)]
4201 #[allow(dead_code)]
4202 enum StructField {
4203 next_rip,
4204 mem_displ,
4205 flags1,
4206 immediate,
4207 code,
4208 mem_base_reg,
4209 mem_index_reg,
4210 regs0,
4211 regs1,
4212 regs2,
4213 regs3,
4214 op_kinds0,
4215 op_kinds1,
4216 op_kinds2,
4217 op_kinds3,
4218 scale,
4219 displ_size,
4220 len,
4221 pad,
4222 }
4223 const _: () = assert!(StructField::pad as usize + 1 == NUM_FIELDS_BINARY);
4224 const FIELDS: [&str; NUM_FIELDS_BINARY] = [
4225 "next_rip",
4226 "mem_displ",
4227 "flags1",
4228 "immediate",
4229 "code",
4230 "mem_base_reg",
4231 "mem_index_reg",
4232 "regs0",
4233 "regs1",
4234 "regs2",
4235 "regs3",
4236 "op_kinds0",
4237 "op_kinds1",
4238 "op_kinds2",
4239 "op_kinds3",
4240 "scale",
4241 "displ_size",
4242 "len",
4243 "pad",
4244 ];
4245 impl StructField {
4246 #[inline]
4247 fn values() -> impl Iterator<Item = StructField> + DoubleEndedIterator + ExactSizeIterator + FusedIterator {
4248 (0..NUM_FIELDS_BINARY).map(|x| unsafe { mem::transmute::<u8, StructField>(x as u8) })
4250 }
4251 }
4252 impl TryFrom<usize> for StructField {
4253 type Error = &'static str;
4254 #[inline]
4255 fn try_from(value: usize) -> Result<Self, Self::Error> {
4256 if value < NUM_FIELDS_BINARY {
4257 Ok(unsafe { mem::transmute(value as u8) })
4259 } else {
4260 Err("Invalid struct field")
4261 }
4262 }
4263 }
4264
4265 mk_struct_field_visitor!();
4266
4267 struct Visitor<'de> {
4268 marker: PhantomData<Instruction>,
4269 lifetime: PhantomData<&'de ()>,
4270 }
4271 impl<'de> de::Visitor<'de> for Visitor<'de> {
4272 type Value = Instruction;
4273 #[inline]
4274 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
4275 formatter.write_str("struct Instruction")
4276 }
4277 #[allow(clippy::missing_inline_in_public_items)]
4278 #[allow(clippy::mixed_read_write_in_expression)]
4279 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
4280 where
4281 A: de::SeqAccess<'de>,
4282 {
4283 let mut fields = 0;
4284 macro_rules! next_element {
4285 ($field_name:ident : $field_ty:ty) => {{
4286 fields += 1;
4287 match seq.next_element::<$field_ty>()? {
4288 Some(value) => value,
4289 None => return Err(de::Error::invalid_length(fields, &"struct Instruction with all its fields")),
4290 }
4291 }};
4292 ($field_name:ident : $field_ty:ty : $underlying_ty:ty) => {{
4293 fields += 1;
4294 let value = match seq.next_element::<$underlying_ty>()? {
4295 Some(value) => value,
4296 None => return Err(de::Error::invalid_length(fields, &"struct Instruction with all its fields")),
4297 };
4298 if let Ok(enum_value) = <$field_ty as TryFrom<usize>>::try_from(value as usize) {
4299 enum_value
4300 } else {
4301 return Err(<A::Error as de::Error>::invalid_value(
4302 de::Unexpected::Unsigned(value.into()),
4303 &"an enum variant in range",
4304 ));
4305 }
4306 }};
4307 }
4308 let instruction = Instruction {
4309 next_rip: next_element!(next_rip: u64),
4310 mem_displ: next_element!(mem_displ: u64),
4311 flags1: next_element!(flags1: u32),
4312 immediate: next_element!(immediate: u32),
4313 code: next_element!(code: Code: CodeUnderlyingType),
4314 mem_base_reg: next_element!(mem_base_reg: Register: RegisterUnderlyingType),
4315 mem_index_reg: next_element!(mem_index_reg: Register: RegisterUnderlyingType),
4316 regs: [
4317 next_element!(regs0: Register: RegisterUnderlyingType),
4318 next_element!(regs1: Register: RegisterUnderlyingType),
4319 next_element!(regs2: Register: RegisterUnderlyingType),
4320 next_element!(regs3: Register: RegisterUnderlyingType),
4321 ],
4322 op_kinds: [
4323 next_element!(op_kinds0: OpKind: OpKindUnderlyingType),
4324 next_element!(op_kinds1: OpKind: OpKindUnderlyingType),
4325 next_element!(op_kinds2: OpKind: OpKindUnderlyingType),
4326 next_element!(op_kinds3: OpKind: OpKindUnderlyingType),
4327 ],
4328 scale: next_element!(scale: InstrScale: InstrScaleUnderlyingType),
4329 displ_size: next_element!(displ_size: u8),
4330 len: next_element!(len: u8),
4331 pad: next_element!(pad: u8),
4332 };
4333 debug_assert_eq!(fields, NUM_FIELDS_BINARY);
4334 Ok(instruction)
4335 }
4336 #[allow(clippy::missing_inline_in_public_items)]
4337 #[allow(clippy::mixed_read_write_in_expression)]
4338 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
4339 where
4340 A: de::MapAccess<'de>,
4341 {
4342 let mut next_rip: Option<u64> = None;
4343 let mut mem_displ: Option<u64> = None;
4344 let mut flags1: Option<u32> = None;
4345 let mut immediate: Option<u32> = None;
4346 let mut code: Option<Code> = None;
4347 let mut mem_base_reg: Option<Register> = None;
4348 let mut mem_index_reg: Option<Register> = None;
4349 let mut regs0: Option<Register> = None;
4350 let mut regs1: Option<Register> = None;
4351 let mut regs2: Option<Register> = None;
4352 let mut regs3: Option<Register> = None;
4353 let mut op_kinds0: Option<OpKind> = None;
4354 let mut op_kinds1: Option<OpKind> = None;
4355 let mut op_kinds2: Option<OpKind> = None;
4356 let mut op_kinds3: Option<OpKind> = None;
4357 let mut scale: Option<InstrScale> = None;
4358 let mut displ_size: Option<u8> = None;
4359 let mut len: Option<u8> = None;
4360 let mut pad: Option<u8> = None;
4361 while let Some(field) = map.next_key::<StructField>()? {
4362 macro_rules! unpack {
4363 ($field:ident : $field_ty:ty) => {{
4364 if $field.is_some() {
4365 return Err(<A::Error as de::Error>::duplicate_field(stringify!($field)));
4366 }
4367 $field = Some(map.next_value::<$field_ty>()?);
4368 }};
4369 ($field:ident : $field_ty:ty : $underlying_ty:ty) => {{
4370 if $field.is_some() {
4371 return Err(<A::Error as de::Error>::duplicate_field(stringify!($field)));
4372 }
4373 let value = map.next_value::<$underlying_ty>()?;
4374 if let Ok(enum_value) = <$field_ty as TryFrom<usize>>::try_from(value as usize) {
4375 $field = Some(enum_value);
4376 } else {
4377 return Err(<A::Error as de::Error>::invalid_value(
4378 de::Unexpected::Unsigned(value.into()),
4379 &"an enum variant in range",
4380 ));
4381 }
4382 }};
4383 }
4384 match field {
4385 StructField::next_rip => unpack!(next_rip: u64),
4386 StructField::mem_displ => unpack!(mem_displ: u64),
4387 StructField::flags1 => unpack!(flags1: u32),
4388 StructField::immediate => unpack!(immediate: u32),
4389 StructField::code => unpack!(code: Code: CodeUnderlyingType),
4390 StructField::mem_base_reg => unpack!(mem_base_reg: Register: RegisterUnderlyingType),
4391 StructField::mem_index_reg => unpack!(mem_index_reg: Register: RegisterUnderlyingType),
4392 StructField::regs0 => unpack!(regs0: Register: RegisterUnderlyingType),
4393 StructField::regs1 => unpack!(regs1: Register: RegisterUnderlyingType),
4394 StructField::regs2 => unpack!(regs2: Register: RegisterUnderlyingType),
4395 StructField::regs3 => unpack!(regs3: Register: RegisterUnderlyingType),
4396 StructField::op_kinds0 => unpack!(op_kinds0: OpKind: OpKindUnderlyingType),
4397 StructField::op_kinds1 => unpack!(op_kinds1: OpKind: OpKindUnderlyingType),
4398 StructField::op_kinds2 => unpack!(op_kinds2: OpKind: OpKindUnderlyingType),
4399 StructField::op_kinds3 => unpack!(op_kinds3: OpKind: OpKindUnderlyingType),
4400 StructField::scale => unpack!(scale: InstrScale: InstrScaleUnderlyingType),
4401 StructField::displ_size => unpack!(displ_size: u8),
4402 StructField::len => unpack!(len: u8),
4403 StructField::pad => unpack!(pad: u8),
4404 }
4405 }
4406 let mut fields = 0;
4407 macro_rules! unpack_field {
4408 ($field:ident) => {{
4409 fields += 1;
4410 match $field {
4411 Some(value) => value,
4412 None => return Err(<A::Error as de::Error>::missing_field(stringify!($field))),
4413 }
4414 }};
4415 }
4416 let instruction = Instruction {
4417 next_rip: unpack_field!(next_rip),
4418 mem_displ: unpack_field!(mem_displ),
4419 flags1: unpack_field!(flags1),
4420 immediate: unpack_field!(immediate),
4421 code: unpack_field!(code),
4422 mem_base_reg: unpack_field!(mem_base_reg),
4423 mem_index_reg: unpack_field!(mem_index_reg),
4424 regs: [unpack_field!(regs0), unpack_field!(regs1), unpack_field!(regs2), unpack_field!(regs3)],
4425 op_kinds: [unpack_field!(op_kinds0), unpack_field!(op_kinds1), unpack_field!(op_kinds2), unpack_field!(op_kinds3)],
4426 scale: unpack_field!(scale),
4427 displ_size: unpack_field!(displ_size),
4428 len: unpack_field!(len),
4429 pad: unpack_field!(pad),
4430 };
4431 debug_assert_eq!(fields, NUM_FIELDS_BINARY);
4432 Ok(instruction)
4433 }
4434 }
4435 deserializer.deserialize_struct("Instruction", &FIELDS[..], Visitor { marker: PhantomData::<Instruction>, lifetime: PhantomData })
4436 }
4437 }
4438 }
4439};