1 //! Instruction operand sub-components (aka "parts"): definitions and printing.
2 
3 use super::regs::{self};
4 use crate::ir::MemFlags;
5 use crate::ir::condcodes::{FloatCC, IntCC};
6 use crate::ir::types::*;
7 use crate::isa::x64::inst::Inst;
8 use crate::isa::x64::inst::regs::pretty_print_reg;
9 use crate::machinst::*;
10 use smallvec::{SmallVec, smallvec};
11 use std::fmt;
12 use std::string::String;
13 
14 /// An extension trait for converting `Writable{Xmm,Gpr}` to `Writable<Reg>`.
15 pub trait ToWritableReg {
16     /// Convert `Writable{Xmm,Gpr}` to `Writable<Reg>`.
17     fn to_writable_reg(&self) -> Writable<Reg>;
18 }
19 
20 /// An extension trait for converting `Writable<Reg>` to `Writable{Xmm,Gpr}`.
21 pub trait FromWritableReg: Sized {
22     /// Convert `Writable<Reg>` to `Writable{Xmm,Gpr}`.
23     fn from_writable_reg(w: Writable<Reg>) -> Option<Self>;
24 }
25 
26 /// A macro for defining a newtype of `Reg` that enforces some invariant about
27 /// the wrapped `Reg` (such as that it is of a particular register class).
28 macro_rules! newtype_of_reg {
29     (
30         $newtype_reg:ident,
31         $newtype_writable_reg:ident,
32         $newtype_option_writable_reg:ident,
33         reg_mem: ($($newtype_reg_mem:ident $(aligned:$aligned:ident)?),*),
34         reg_mem_imm: ($($newtype_reg_mem_imm:ident $(aligned:$aligned_imm:ident)?),*),
35         |$check_reg:ident| $check:expr
36     ) => {
37         /// A newtype wrapper around `Reg`.
38         #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
39         pub struct $newtype_reg(Reg);
40 
41         impl PartialEq<Reg> for $newtype_reg {
42             fn eq(&self, other: &Reg) -> bool {
43                 self.0 == *other
44             }
45         }
46 
47         impl From<$newtype_reg> for Reg {
48             fn from(r: $newtype_reg) -> Self {
49                 r.0
50             }
51         }
52 
53         impl $newtype_reg {
54             /// Create this newtype from the given register, or return `None` if the register
55             /// is not a valid instance of this newtype.
56             pub fn new($check_reg: Reg) -> Option<Self> {
57                 if $check {
58                     Some(Self($check_reg))
59                 } else {
60                     None
61                 }
62             }
63 
64             /// Like `Self::new(r).unwrap()` but with a better panic message on
65             /// failure.
66             pub fn unwrap_new($check_reg: Reg) -> Self {
67                 if $check {
68                     Self($check_reg)
69                 } else {
70                     panic!(
71                         "cannot construct {} from register {:?} with register class {:?}",
72                         stringify!($newtype_reg),
73                         $check_reg,
74                         $check_reg.class(),
75                     )
76                 }
77             }
78 
79             /// Get this newtype's underlying `Reg`.
80             pub fn to_reg(self) -> Reg {
81                 self.0
82             }
83         }
84 
85         // Convenience impl so that people working with this newtype can use it
86         // "just like" a plain `Reg`.
87         //
88         // NB: We cannot implement `DerefMut` because that would let people do
89         // nasty stuff like `*my_gpr.deref_mut() = some_xmm_reg`, breaking the
90         // invariants that `Gpr` provides.
91         impl std::ops::Deref for $newtype_reg {
92             type Target = Reg;
93 
94             fn deref(&self) -> &Reg {
95                 &self.0
96             }
97         }
98 
99         /// If you know what you're doing, you can explicitly mutably borrow the
100         /// underlying `Reg`. Don't make it point to the wrong type of register
101         /// please.
102         impl AsMut<Reg> for $newtype_reg {
103             fn as_mut(&mut self) -> &mut Reg {
104                 &mut self.0
105             }
106         }
107 
108         /// Writable Gpr.
109         pub type $newtype_writable_reg = Writable<$newtype_reg>;
110 
111         #[allow(dead_code)] // Used by some newtypes and not others.
112         /// Optional writable Gpr.
113         pub type $newtype_option_writable_reg = Option<Writable<$newtype_reg>>;
114 
115         impl ToWritableReg for $newtype_writable_reg {
116             fn to_writable_reg(&self) -> Writable<Reg> {
117                 Writable::from_reg(self.to_reg().to_reg())
118             }
119         }
120 
121         impl FromWritableReg for $newtype_writable_reg {
122             fn from_writable_reg(w: Writable<Reg>) -> Option<Self> {
123                 Some(Writable::from_reg($newtype_reg::new(w.to_reg())?))
124             }
125         }
126 
127         $(
128             /// A newtype wrapper around `RegMem` for general-purpose registers.
129             #[derive(Clone, Debug)]
130             pub struct $newtype_reg_mem(RegMem);
131 
132             impl From<$newtype_reg_mem> for RegMem {
133                 fn from(rm: $newtype_reg_mem) -> Self {
134                     rm.0
135                 }
136             }
137             impl<'a> From<&'a $newtype_reg_mem> for &'a RegMem {
138                 fn from(rm: &'a $newtype_reg_mem) -> &'a RegMem {
139                     &rm.0
140                 }
141             }
142 
143             impl From<$newtype_reg> for $newtype_reg_mem {
144                 fn from(r: $newtype_reg) -> Self {
145                     $newtype_reg_mem(RegMem::reg(r.into()))
146                 }
147             }
148 
149             impl $newtype_reg_mem {
150                 /// Construct a `RegMem` newtype from the given `RegMem`, or return
151                 /// `None` if the `RegMem` is not a valid instance of this `RegMem`
152                 /// newtype.
153                 pub fn new(rm: RegMem) -> Option<Self> {
154                     match rm {
155                         RegMem::Mem { addr } => {
156                             let mut _allow = true;
157                             $(
158                                 if $aligned {
159                                     _allow = addr.aligned();
160                                 }
161                             )?
162                             if _allow {
163                                 Some(Self(RegMem::Mem { addr }))
164                             } else {
165                                 None
166                             }
167                         }
168                         RegMem::Reg { reg } => Some($newtype_reg::new(reg)?.into()),
169                     }
170                 }
171 
172                 /// Like `Self::new(rm).unwrap()` but with better panic messages
173                 /// in case of failure.
174                 pub fn unwrap_new(rm: RegMem) -> Self {
175                     match rm {
176                         RegMem::Mem { addr } => {
177                             $(
178                                 if $aligned && !addr.aligned() {
179                                     panic!(
180                                         "cannot create {} from an unaligned memory address: {addr:?}",
181                                         stringify!($newtype_reg_mem),
182                                     );
183                                 }
184                             )?
185                             Self(RegMem::Mem { addr })
186                         }
187                         RegMem::Reg { reg } => $newtype_reg::unwrap_new(reg).into(),
188                     }
189                 }
190 
191                 /// Convert this newtype into its underlying `RegMem`.
192                 pub fn to_reg_mem(self) -> RegMem {
193                     self.0
194                 }
195 
196                 #[allow(dead_code)] // Used by some newtypes and not others.
197                 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
198                     self.0.get_operands(collector);
199                 }
200             }
201             impl PrettyPrint for $newtype_reg_mem {
202                 fn pretty_print(&self, size: u8) -> String {
203                     self.0.pretty_print(size)
204                 }
205             }
206         )*
207 
208         $(
209             /// A newtype wrapper around `RegMemImm`.
210             #[derive(Clone, Debug)]
211             pub struct $newtype_reg_mem_imm(RegMemImm);
212 
213             impl From<$newtype_reg_mem_imm> for RegMemImm {
214                 fn from(rmi: $newtype_reg_mem_imm) -> RegMemImm {
215                     rmi.0
216                 }
217             }
218             impl<'a> From<&'a $newtype_reg_mem_imm> for &'a RegMemImm {
219                 fn from(rmi: &'a $newtype_reg_mem_imm) -> &'a RegMemImm {
220                     &rmi.0
221                 }
222             }
223 
224             impl From<$newtype_reg> for $newtype_reg_mem_imm {
225                 fn from(r: $newtype_reg) -> Self {
226                     $newtype_reg_mem_imm(RegMemImm::reg(r.into()))
227                 }
228             }
229 
230             impl $newtype_reg_mem_imm {
231                 /// Construct this newtype from the given `RegMemImm`, or return
232                 /// `None` if the `RegMemImm` is not a valid instance of this
233                 /// newtype.
234                 pub fn new(rmi: RegMemImm) -> Option<Self> {
235                     match rmi {
236                         RegMemImm::Imm { .. } => Some(Self(rmi)),
237                         RegMemImm::Mem { addr } => {
238                             let mut _allow = true;
239                             $(
240                                 if $aligned_imm {
241                                     _allow = addr.aligned();
242                                 }
243                             )?
244                             if _allow {
245                                 Some(Self(RegMemImm::Mem { addr }))
246                             } else {
247                                 None
248                             }
249                         }
250                         RegMemImm::Reg { reg } => Some($newtype_reg::new(reg)?.into()),
251                     }
252                 }
253 
254                 /// Like `Self::new(rmi).unwrap()` but with better panic
255                 /// messages in case of failure.
256                 pub fn unwrap_new(rmi: RegMemImm) -> Self {
257                     match rmi {
258                         RegMemImm::Imm { .. } => Self(rmi),
259                         RegMemImm::Mem { addr } => {
260                             $(
261                                 if $aligned_imm && !addr.aligned() {
262                                     panic!(
263                                         "cannot construct {} from unaligned memory address: {:?}",
264                                         stringify!($newtype_reg_mem_imm),
265                                         addr,
266                                     );
267                                 }
268                             )?
269                             Self(RegMemImm::Mem { addr })
270 
271                         }
272                         RegMemImm::Reg { reg } => $newtype_reg::unwrap_new(reg).into(),
273                     }
274                 }
275 
276                 /// Convert this newtype into its underlying `RegMemImm`.
277                 #[allow(dead_code)] // Used by some newtypes and not others.
278                 pub fn to_reg_mem_imm(self) -> RegMemImm {
279                     self.0
280                 }
281 
282                 #[allow(dead_code)] // Used by some newtypes and not others.
283                 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
284                     self.0.get_operands(collector);
285                 }
286             }
287 
288             impl PrettyPrint for $newtype_reg_mem_imm {
289                 fn pretty_print(&self, size: u8) -> String {
290                     self.0.pretty_print(size)
291                 }
292             }
293         )*
294     };
295 }
296 
297 // Define a newtype of `Reg` for general-purpose registers.
298 newtype_of_reg!(
299     Gpr,
300     WritableGpr,
301     OptionWritableGpr,
302     reg_mem: (GprMem),
303     reg_mem_imm: (GprMemImm),
304     |reg| reg.class() == RegClass::Int
305 );
306 
307 // Define a newtype of `Reg` for XMM registers.
308 newtype_of_reg!(
309     Xmm,
310     WritableXmm,
311     OptionWritableXmm,
312     reg_mem: (XmmMem, XmmMemAligned aligned:true),
313     reg_mem_imm: (XmmMemImm, XmmMemAlignedImm aligned:true),
314     |reg| reg.class() == RegClass::Float
315 );
316 
317 // N.B.: `Amode` is defined in `inst.isle`. We add some convenience
318 // constructors here.
319 
320 // Re-export the type from the ISLE generated code.
321 pub use crate::isa::x64::lower::isle::generated_code::Amode;
322 
323 impl Amode {
324     /// Create an immediate sign-extended and register addressing mode.
325     pub fn imm_reg(simm32: i32, base: Reg) -> Self {
326         debug_assert!(base.class() == RegClass::Int);
327         Self::ImmReg {
328             simm32,
329             base,
330             flags: MemFlags::trusted(),
331         }
332     }
333 
334     /// Create a sign-extended-32-to-64 with register and shift addressing mode.
335     pub fn imm_reg_reg_shift(simm32: i32, base: Gpr, index: Gpr, shift: u8) -> Self {
336         debug_assert!(base.class() == RegClass::Int);
337         debug_assert!(index.class() == RegClass::Int);
338         debug_assert!(shift <= 3);
339         Self::ImmRegRegShift {
340             simm32,
341             base,
342             index,
343             shift,
344             flags: MemFlags::trusted(),
345         }
346     }
347 
348     pub(crate) fn rip_relative(target: MachLabel) -> Self {
349         Self::RipRelative { target }
350     }
351 
352     /// Set the specified [MemFlags] to the [Amode].
353     pub fn with_flags(&self, flags: MemFlags) -> Self {
354         match self {
355             &Self::ImmReg { simm32, base, .. } => Self::ImmReg {
356                 simm32,
357                 base,
358                 flags,
359             },
360             &Self::ImmRegRegShift {
361                 simm32,
362                 base,
363                 index,
364                 shift,
365                 ..
366             } => Self::ImmRegRegShift {
367                 simm32,
368                 base,
369                 index,
370                 shift,
371                 flags,
372             },
373             _ => panic!("Amode {self:?} cannot take memflags"),
374         }
375     }
376 
377     /// Add the registers mentioned by `self` to `collector`.
378     pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
379         match self {
380             Amode::ImmReg { base, .. } => {
381                 if *base != regs::rbp() && *base != regs::rsp() {
382                     collector.reg_use(base);
383                 }
384             }
385             Amode::ImmRegRegShift { base, index, .. } => {
386                 debug_assert_ne!(base.to_reg(), regs::rbp());
387                 debug_assert_ne!(base.to_reg(), regs::rsp());
388                 collector.reg_use(base);
389                 debug_assert_ne!(index.to_reg(), regs::rbp());
390                 debug_assert_ne!(index.to_reg(), regs::rsp());
391                 collector.reg_use(index);
392             }
393             Amode::RipRelative { .. } => {
394                 // RIP isn't involved in regalloc.
395             }
396         }
397     }
398 
399     /// Same as `get_operands`, but add the registers in the "late" phase.
400     pub(crate) fn get_operands_late(&mut self, collector: &mut impl OperandVisitor) {
401         match self {
402             Amode::ImmReg { base, .. } => {
403                 collector.reg_late_use(base);
404             }
405             Amode::ImmRegRegShift { base, index, .. } => {
406                 collector.reg_late_use(base);
407                 collector.reg_late_use(index);
408             }
409             Amode::RipRelative { .. } => {
410                 // RIP isn't involved in regalloc.
411             }
412         }
413     }
414 
415     pub(crate) fn get_flags(&self) -> MemFlags {
416         match self {
417             Amode::ImmReg { flags, .. } | Amode::ImmRegRegShift { flags, .. } => *flags,
418             Amode::RipRelative { .. } => MemFlags::trusted(),
419         }
420     }
421 
422     /// Offset the amode by a fixed offset.
423     pub(crate) fn offset(&self, offset: i32) -> Self {
424         let mut ret = self.clone();
425         match &mut ret {
426             &mut Amode::ImmReg { ref mut simm32, .. } => *simm32 += offset,
427             &mut Amode::ImmRegRegShift { ref mut simm32, .. } => *simm32 += offset,
428             _ => panic!("Cannot offset amode: {self:?}"),
429         }
430         ret
431     }
432 
433     pub(crate) fn aligned(&self) -> bool {
434         self.get_flags().aligned()
435     }
436 }
437 
438 impl PrettyPrint for Amode {
439     fn pretty_print(&self, _size: u8) -> String {
440         match self {
441             Amode::ImmReg { simm32, base, .. } => {
442                 // Note: size is always 8; the address is 64 bits,
443                 // even if the addressed operand is smaller.
444                 format!("{}({})", *simm32, pretty_print_reg(*base, 8))
445             }
446             Amode::ImmRegRegShift {
447                 simm32,
448                 base,
449                 index,
450                 shift,
451                 ..
452             } => format!(
453                 "{}({},{},{})",
454                 *simm32,
455                 pretty_print_reg(base.to_reg(), 8),
456                 pretty_print_reg(index.to_reg(), 8),
457                 1 << shift
458             ),
459             Amode::RipRelative { target } => format!("label{}(%rip)", target.as_u32()),
460         }
461     }
462 }
463 
464 /// A Memory Address. These denote a 64-bit value only.
465 /// Used for usual addressing modes as well as addressing modes used during compilation, when the
466 /// moving SP offset is not known.
467 #[derive(Clone, Debug)]
468 pub enum SyntheticAmode {
469     /// A real amode.
470     Real(Amode),
471 
472     /// A (virtual) offset into the incoming argument area.
473     IncomingArg {
474         /// The downward offset from the start of the incoming argument area.
475         offset: u32,
476     },
477 
478     /// A (virtual) offset to the slot area of the function frame, which lies just above the
479     /// outgoing arguments.
480     SlotOffset {
481         /// The offset into the slot area.
482         simm32: i32,
483     },
484 
485     /// A virtual offset to a constant that will be emitted in the constant section of the buffer.
486     ConstantOffset(VCodeConstant),
487 }
488 
489 impl SyntheticAmode {
490     /// Create a real addressing mode.
491     pub fn real(amode: Amode) -> Self {
492         Self::Real(amode)
493     }
494 
495     pub(crate) fn slot_offset(simm32: i32) -> Self {
496         SyntheticAmode::SlotOffset { simm32 }
497     }
498 
499     /// Add the registers mentioned by `self` to `collector`.
500     pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
501         match self {
502             SyntheticAmode::Real(addr) => addr.get_operands(collector),
503             SyntheticAmode::IncomingArg { .. } => {
504                 // Nothing to do; the base is known and isn't involved in regalloc.
505             }
506             SyntheticAmode::SlotOffset { .. } => {
507                 // Nothing to do; the base is SP and isn't involved in regalloc.
508             }
509             SyntheticAmode::ConstantOffset(_) => {}
510         }
511     }
512 
513     /// Same as `get_operands`, but add the register in the "late" phase.
514     pub(crate) fn get_operands_late(&mut self, collector: &mut impl OperandVisitor) {
515         match self {
516             SyntheticAmode::Real(addr) => addr.get_operands_late(collector),
517             SyntheticAmode::IncomingArg { .. } => {
518                 // Nothing to do; the base is known and isn't involved in regalloc.
519             }
520             SyntheticAmode::SlotOffset { .. } => {
521                 // Nothing to do; the base is SP and isn't involved in regalloc.
522             }
523             SyntheticAmode::ConstantOffset(_) => {}
524         }
525     }
526 
527     pub(crate) fn finalize(&self, frame: &FrameLayout, buffer: &mut MachBuffer<Inst>) -> Amode {
528         match self {
529             SyntheticAmode::Real(addr) => addr.clone(),
530             SyntheticAmode::IncomingArg { offset } => {
531                 // NOTE: this could be made relative to RSP by adding additional
532                 // offsets from the frame_layout.
533                 let args_max_fp_offset = frame.tail_args_size + frame.setup_area_size;
534                 Amode::imm_reg(
535                     i32::try_from(args_max_fp_offset - offset).unwrap(),
536                     regs::rbp(),
537                 )
538             }
539             SyntheticAmode::SlotOffset { simm32 } => {
540                 let off = *simm32 as i64 + i64::from(frame.outgoing_args_size);
541                 Amode::imm_reg(off.try_into().expect("invalid sp offset"), regs::rsp())
542             }
543             SyntheticAmode::ConstantOffset(c) => {
544                 Amode::rip_relative(buffer.get_label_for_constant(*c))
545             }
546         }
547     }
548 
549     pub(crate) fn aligned(&self) -> bool {
550         match self {
551             SyntheticAmode::Real(addr) => addr.aligned(),
552             &SyntheticAmode::IncomingArg { .. }
553             | SyntheticAmode::SlotOffset { .. }
554             | SyntheticAmode::ConstantOffset { .. } => true,
555         }
556     }
557 }
558 
559 impl From<Amode> for SyntheticAmode {
560     fn from(amode: Amode) -> SyntheticAmode {
561         SyntheticAmode::Real(amode)
562     }
563 }
564 
565 impl From<VCodeConstant> for SyntheticAmode {
566     fn from(c: VCodeConstant) -> SyntheticAmode {
567         SyntheticAmode::ConstantOffset(c)
568     }
569 }
570 
571 impl PrettyPrint for SyntheticAmode {
572     fn pretty_print(&self, _size: u8) -> String {
573         match self {
574             // See note in `Amode` regarding constant size of `8`.
575             SyntheticAmode::Real(addr) => addr.pretty_print(8),
576             &SyntheticAmode::IncomingArg { offset } => {
577                 format!("rbp(stack args max - {offset})")
578             }
579             SyntheticAmode::SlotOffset { simm32 } => {
580                 format!("rsp({} + virtual offset)", *simm32)
581             }
582             SyntheticAmode::ConstantOffset(c) => format!("const({})", c.as_u32()),
583         }
584     }
585 }
586 
587 /// An operand which is either an integer Register, a value in Memory or an Immediate.  This can
588 /// denote an 8, 16, 32 or 64 bit value.  For the Immediate form, in the 8- and 16-bit case, only
589 /// the lower 8 or 16 bits of `simm32` is relevant.  In the 64-bit case, the value denoted by
590 /// `simm32` is its sign-extension out to 64 bits.
591 #[derive(Clone, Debug)]
592 pub enum RegMemImm {
593     /// A register operand.
594     Reg {
595         /// The underlying register.
596         reg: Reg,
597     },
598     /// A memory operand.
599     Mem {
600         /// The memory address.
601         addr: SyntheticAmode,
602     },
603     /// An immediate operand.
604     Imm {
605         /// The immediate value.
606         simm32: u32,
607     },
608 }
609 
610 impl RegMemImm {
611     /// Create a register operand.
612     pub fn reg(reg: Reg) -> Self {
613         debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float);
614         Self::Reg { reg }
615     }
616 
617     /// Create a memory operand.
618     pub fn mem(addr: impl Into<SyntheticAmode>) -> Self {
619         Self::Mem { addr: addr.into() }
620     }
621 
622     /// Create an immediate operand.
623     pub fn imm(simm32: u32) -> Self {
624         Self::Imm { simm32 }
625     }
626 
627     /// Asserts that in register mode, the reg class is the one that's expected.
628     pub(crate) fn assert_regclass_is(&self, expected_reg_class: RegClass) {
629         if let Self::Reg { reg } = self {
630             debug_assert_eq!(reg.class(), expected_reg_class);
631         }
632     }
633 
634     /// Add the regs mentioned by `self` to `collector`.
635     pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
636         match self {
637             Self::Reg { reg } => collector.reg_use(reg),
638             Self::Mem { addr } => addr.get_operands(collector),
639             Self::Imm { .. } => {}
640         }
641     }
642 }
643 
644 impl From<RegMem> for RegMemImm {
645     fn from(rm: RegMem) -> RegMemImm {
646         match rm {
647             RegMem::Reg { reg } => RegMemImm::Reg { reg },
648             RegMem::Mem { addr } => RegMemImm::Mem { addr },
649         }
650     }
651 }
652 
653 impl From<Reg> for RegMemImm {
654     fn from(reg: Reg) -> Self {
655         RegMemImm::Reg { reg }
656     }
657 }
658 
659 impl PrettyPrint for RegMemImm {
660     fn pretty_print(&self, size: u8) -> String {
661         match self {
662             Self::Reg { reg } => pretty_print_reg(*reg, size),
663             Self::Mem { addr } => addr.pretty_print(size),
664             Self::Imm { simm32 } => format!("${}", *simm32 as i32),
665         }
666     }
667 }
668 
669 /// An operand which is either an integer Register or a value in Memory.  This can denote an 8, 16,
670 /// 32, 64, or 128 bit value.
671 #[derive(Clone, Debug)]
672 pub enum RegMem {
673     /// A register operand.
674     Reg {
675         /// The underlying register.
676         reg: Reg,
677     },
678     /// A memory operand.
679     Mem {
680         /// The memory address.
681         addr: SyntheticAmode,
682     },
683 }
684 
685 impl RegMem {
686     /// Create a register operand.
687     pub fn reg(reg: Reg) -> Self {
688         debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float);
689         Self::Reg { reg }
690     }
691 
692     /// Create a memory operand.
693     pub fn mem(addr: impl Into<SyntheticAmode>) -> Self {
694         Self::Mem { addr: addr.into() }
695     }
696     /// Asserts that in register mode, the reg class is the one that's expected.
697     pub(crate) fn assert_regclass_is(&self, expected_reg_class: RegClass) {
698         if let Self::Reg { reg } = self {
699             debug_assert_eq!(reg.class(), expected_reg_class);
700         }
701     }
702     /// Add the regs mentioned by `self` to `collector`.
703     pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
704         match self {
705             RegMem::Reg { reg } => collector.reg_use(reg),
706             RegMem::Mem { addr, .. } => addr.get_operands(collector),
707         }
708     }
709 }
710 
711 impl From<Reg> for RegMem {
712     fn from(reg: Reg) -> RegMem {
713         RegMem::Reg { reg }
714     }
715 }
716 
717 impl From<Writable<Reg>> for RegMem {
718     fn from(r: Writable<Reg>) -> Self {
719         RegMem::reg(r.to_reg())
720     }
721 }
722 
723 impl PrettyPrint for RegMem {
724     fn pretty_print(&self, size: u8) -> String {
725         match self {
726             RegMem::Reg { reg } => pretty_print_reg(*reg, size),
727             RegMem::Mem { addr, .. } => addr.pretty_print(size),
728         }
729     }
730 }
731 
732 #[derive(Clone, Copy, PartialEq)]
733 /// Comparison operations.
734 pub enum CmpOpcode {
735     /// CMP instruction: compute `a - b` and set flags from result.
736     Cmp,
737     /// TEST instruction: compute `a & b` and set flags from result.
738     Test,
739 }
740 
741 #[derive(Debug)]
742 pub(crate) enum InstructionSet {
743     SSE,
744     SSE2,
745     CMPXCHG16b,
746     SSE3,
747     SSSE3,
748     SSE41,
749     SSE42,
750     Popcnt,
751     Lzcnt,
752     BMI1,
753     #[allow(dead_code)] // never constructed (yet).
754     BMI2,
755     FMA,
756     AVX,
757     AVX2,
758     AVX512BITALG,
759     AVX512DQ,
760     AVX512F,
761     AVX512VBMI,
762     AVX512VL,
763 }
764 
765 /// Some SSE operations requiring 2 operands r/m and r.
766 #[derive(Clone, Copy, PartialEq)]
767 #[allow(dead_code)] // some variants here aren't used just yet
768 #[allow(missing_docs)]
769 pub enum SseOpcode {
770     Blendvpd,
771     Blendvps,
772     Insertps,
773     Pabsb,
774     Pabsw,
775     Pabsd,
776     Packssdw,
777     Packsswb,
778     Packusdw,
779     Packuswb,
780     Palignr,
781     Pavgb,
782     Pavgw,
783     Pblendvb,
784     Pcmpeqb,
785     Pcmpeqw,
786     Pcmpeqd,
787     Pcmpeqq,
788     Pcmpgtb,
789     Pcmpgtw,
790     Pcmpgtd,
791     Pcmpgtq,
792     Pmaddubsw,
793     Pmaddwd,
794     Pshufb,
795     Pshufd,
796     Ptest,
797     Rcpss,
798     Roundps,
799     Roundpd,
800     Roundss,
801     Roundsd,
802     Rsqrtss,
803     Shufps,
804     Pshuflw,
805     Pshufhw,
806     Pblendw,
807 }
808 
809 impl SseOpcode {
810     /// Which `InstructionSet` is the first supporting this opcode?
811     pub(crate) fn available_from(&self) -> InstructionSet {
812         use InstructionSet::*;
813         match self {
814             SseOpcode::Rcpss | SseOpcode::Rsqrtss | SseOpcode::Shufps => SSE,
815 
816             SseOpcode::Packssdw
817             | SseOpcode::Packsswb
818             | SseOpcode::Packuswb
819             | SseOpcode::Pavgb
820             | SseOpcode::Pavgw
821             | SseOpcode::Pcmpeqb
822             | SseOpcode::Pcmpeqw
823             | SseOpcode::Pcmpeqd
824             | SseOpcode::Pcmpgtb
825             | SseOpcode::Pcmpgtw
826             | SseOpcode::Pcmpgtd
827             | SseOpcode::Pmaddwd
828             | SseOpcode::Pshufd
829             | SseOpcode::Pshuflw
830             | SseOpcode::Pshufhw => SSE2,
831 
832             SseOpcode::Pabsb
833             | SseOpcode::Pabsw
834             | SseOpcode::Pabsd
835             | SseOpcode::Palignr
836             | SseOpcode::Pshufb
837             | SseOpcode::Pmaddubsw => SSSE3,
838 
839             SseOpcode::Blendvpd
840             | SseOpcode::Blendvps
841             | SseOpcode::Insertps
842             | SseOpcode::Packusdw
843             | SseOpcode::Pblendvb
844             | SseOpcode::Pcmpeqq
845             | SseOpcode::Ptest
846             | SseOpcode::Roundps
847             | SseOpcode::Roundpd
848             | SseOpcode::Roundss
849             | SseOpcode::Roundsd
850             | SseOpcode::Pblendw => SSE41,
851 
852             SseOpcode::Pcmpgtq => SSE42,
853         }
854     }
855 
856     /// Returns the src operand size for an instruction.
857     pub(crate) fn src_size(&self) -> u8 {
858         match self {
859             _ => 8,
860         }
861     }
862 
863     /// Is `src2` with this opcode a scalar, as for lane insertions?
864     pub(crate) fn has_scalar_src2(self) -> bool {
865         false
866     }
867 }
868 
869 impl fmt::Debug for SseOpcode {
870     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
871         let name = match self {
872             SseOpcode::Blendvpd => "blendvpd",
873             SseOpcode::Blendvps => "blendvps",
874             SseOpcode::Insertps => "insertps",
875             SseOpcode::Pabsb => "pabsb",
876             SseOpcode::Pabsw => "pabsw",
877             SseOpcode::Pabsd => "pabsd",
878             SseOpcode::Packssdw => "packssdw",
879             SseOpcode::Packsswb => "packsswb",
880             SseOpcode::Packusdw => "packusdw",
881             SseOpcode::Packuswb => "packuswb",
882             SseOpcode::Palignr => "palignr",
883             SseOpcode::Pavgb => "pavgb",
884             SseOpcode::Pavgw => "pavgw",
885             SseOpcode::Pblendvb => "pblendvb",
886             SseOpcode::Pcmpeqb => "pcmpeqb",
887             SseOpcode::Pcmpeqw => "pcmpeqw",
888             SseOpcode::Pcmpeqd => "pcmpeqd",
889             SseOpcode::Pcmpeqq => "pcmpeqq",
890             SseOpcode::Pcmpgtb => "pcmpgtb",
891             SseOpcode::Pcmpgtw => "pcmpgtw",
892             SseOpcode::Pcmpgtd => "pcmpgtd",
893             SseOpcode::Pcmpgtq => "pcmpgtq",
894             SseOpcode::Pmaddubsw => "pmaddubsw",
895             SseOpcode::Pmaddwd => "pmaddwd",
896             SseOpcode::Pshufb => "pshufb",
897             SseOpcode::Pshufd => "pshufd",
898             SseOpcode::Ptest => "ptest",
899             SseOpcode::Rcpss => "rcpss",
900             SseOpcode::Roundps => "roundps",
901             SseOpcode::Roundpd => "roundpd",
902             SseOpcode::Roundss => "roundss",
903             SseOpcode::Roundsd => "roundsd",
904             SseOpcode::Rsqrtss => "rsqrtss",
905             SseOpcode::Shufps => "shufps",
906             SseOpcode::Pshuflw => "pshuflw",
907             SseOpcode::Pshufhw => "pshufhw",
908             SseOpcode::Pblendw => "pblendw",
909         };
910         write!(fmt, "{name}")
911     }
912 }
913 
914 impl fmt::Display for SseOpcode {
915     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
916         fmt::Debug::fmt(self, f)
917     }
918 }
919 
920 pub use crate::isa::x64::lower::isle::generated_code::AvxOpcode;
921 
922 impl AvxOpcode {
923     /// Which `InstructionSet`s support the opcode?
924     pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> {
925         match self {
926             AvxOpcode::Vfmadd213ss
927             | AvxOpcode::Vfmadd213sd
928             | AvxOpcode::Vfmadd213ps
929             | AvxOpcode::Vfmadd213pd
930             | AvxOpcode::Vfmadd132ss
931             | AvxOpcode::Vfmadd132sd
932             | AvxOpcode::Vfmadd132ps
933             | AvxOpcode::Vfmadd132pd
934             | AvxOpcode::Vfnmadd213ss
935             | AvxOpcode::Vfnmadd213sd
936             | AvxOpcode::Vfnmadd213ps
937             | AvxOpcode::Vfnmadd213pd
938             | AvxOpcode::Vfnmadd132ss
939             | AvxOpcode::Vfnmadd132sd
940             | AvxOpcode::Vfnmadd132ps
941             | AvxOpcode::Vfnmadd132pd
942             | AvxOpcode::Vfmsub213ss
943             | AvxOpcode::Vfmsub213sd
944             | AvxOpcode::Vfmsub213ps
945             | AvxOpcode::Vfmsub213pd
946             | AvxOpcode::Vfmsub132ss
947             | AvxOpcode::Vfmsub132sd
948             | AvxOpcode::Vfmsub132ps
949             | AvxOpcode::Vfmsub132pd
950             | AvxOpcode::Vfnmsub213ss
951             | AvxOpcode::Vfnmsub213sd
952             | AvxOpcode::Vfnmsub213ps
953             | AvxOpcode::Vfnmsub213pd
954             | AvxOpcode::Vfnmsub132ss
955             | AvxOpcode::Vfnmsub132sd
956             | AvxOpcode::Vfnmsub132ps
957             | AvxOpcode::Vfnmsub132pd => smallvec![InstructionSet::FMA],
958             AvxOpcode::Vminps
959             | AvxOpcode::Vminpd
960             | AvxOpcode::Vmaxps
961             | AvxOpcode::Vmaxpd
962             | AvxOpcode::Vandnps
963             | AvxOpcode::Vandnpd
964             | AvxOpcode::Vpandn
965             | AvxOpcode::Vcmpps
966             | AvxOpcode::Vcmppd
967             | AvxOpcode::Vpsrlw
968             | AvxOpcode::Vpsrld
969             | AvxOpcode::Vpsrlq
970             | AvxOpcode::Vpaddb
971             | AvxOpcode::Vpaddw
972             | AvxOpcode::Vpaddd
973             | AvxOpcode::Vpaddq
974             | AvxOpcode::Vpaddsb
975             | AvxOpcode::Vpaddsw
976             | AvxOpcode::Vpaddusb
977             | AvxOpcode::Vpaddusw
978             | AvxOpcode::Vpsubb
979             | AvxOpcode::Vpsubw
980             | AvxOpcode::Vpsubd
981             | AvxOpcode::Vpsubq
982             | AvxOpcode::Vpsubsb
983             | AvxOpcode::Vpsubsw
984             | AvxOpcode::Vpsubusb
985             | AvxOpcode::Vpsubusw
986             | AvxOpcode::Vpavgb
987             | AvxOpcode::Vpavgw
988             | AvxOpcode::Vpand
989             | AvxOpcode::Vandps
990             | AvxOpcode::Vandpd
991             | AvxOpcode::Vpor
992             | AvxOpcode::Vorps
993             | AvxOpcode::Vorpd
994             | AvxOpcode::Vpxor
995             | AvxOpcode::Vxorps
996             | AvxOpcode::Vxorpd
997             | AvxOpcode::Vpmullw
998             | AvxOpcode::Vpmulld
999             | AvxOpcode::Vpmulhw
1000             | AvxOpcode::Vpmulhd
1001             | AvxOpcode::Vpmulhrsw
1002             | AvxOpcode::Vpmulhuw
1003             | AvxOpcode::Vpmuldq
1004             | AvxOpcode::Vpmuludq
1005             | AvxOpcode::Vpunpckhwd
1006             | AvxOpcode::Vpunpcklwd
1007             | AvxOpcode::Vunpcklps
1008             | AvxOpcode::Vunpckhps
1009             | AvxOpcode::Vaddps
1010             | AvxOpcode::Vaddpd
1011             | AvxOpcode::Vsubps
1012             | AvxOpcode::Vsubpd
1013             | AvxOpcode::Vmulps
1014             | AvxOpcode::Vmulpd
1015             | AvxOpcode::Vdivps
1016             | AvxOpcode::Vdivpd
1017             | AvxOpcode::Vpcmpeqb
1018             | AvxOpcode::Vpcmpeqw
1019             | AvxOpcode::Vpcmpeqd
1020             | AvxOpcode::Vpcmpeqq
1021             | AvxOpcode::Vpcmpgtb
1022             | AvxOpcode::Vpcmpgtw
1023             | AvxOpcode::Vpcmpgtd
1024             | AvxOpcode::Vpcmpgtq
1025             | AvxOpcode::Vpminsb
1026             | AvxOpcode::Vpminsw
1027             | AvxOpcode::Vpminsd
1028             | AvxOpcode::Vpminub
1029             | AvxOpcode::Vpminuw
1030             | AvxOpcode::Vpminud
1031             | AvxOpcode::Vpmaxsb
1032             | AvxOpcode::Vpmaxsw
1033             | AvxOpcode::Vpmaxsd
1034             | AvxOpcode::Vpmaxub
1035             | AvxOpcode::Vpmaxuw
1036             | AvxOpcode::Vpmaxud
1037             | AvxOpcode::Vpunpcklbw
1038             | AvxOpcode::Vpunpckhbw
1039             | AvxOpcode::Vpacksswb
1040             | AvxOpcode::Vpackssdw
1041             | AvxOpcode::Vpackuswb
1042             | AvxOpcode::Vpackusdw
1043             | AvxOpcode::Vpalignr
1044             | AvxOpcode::Vpmaddwd
1045             | AvxOpcode::Vpmaddubsw
1046             | AvxOpcode::Vinsertps
1047             | AvxOpcode::Vpshufb
1048             | AvxOpcode::Vshufps
1049             | AvxOpcode::Vpsllw
1050             | AvxOpcode::Vpslld
1051             | AvxOpcode::Vpsllq
1052             | AvxOpcode::Vpsraw
1053             | AvxOpcode::Vpsrad
1054             | AvxOpcode::Vpmovsxbw
1055             | AvxOpcode::Vpmovzxbw
1056             | AvxOpcode::Vpmovsxwd
1057             | AvxOpcode::Vpmovzxwd
1058             | AvxOpcode::Vpmovsxdq
1059             | AvxOpcode::Vpmovzxdq
1060             | AvxOpcode::Vaddss
1061             | AvxOpcode::Vaddsd
1062             | AvxOpcode::Vmulss
1063             | AvxOpcode::Vmulsd
1064             | AvxOpcode::Vsubss
1065             | AvxOpcode::Vsubsd
1066             | AvxOpcode::Vdivss
1067             | AvxOpcode::Vdivsd
1068             | AvxOpcode::Vpabsb
1069             | AvxOpcode::Vpabsw
1070             | AvxOpcode::Vpabsd
1071             | AvxOpcode::Vminss
1072             | AvxOpcode::Vminsd
1073             | AvxOpcode::Vmaxss
1074             | AvxOpcode::Vmaxsd
1075             | AvxOpcode::Vsqrtps
1076             | AvxOpcode::Vsqrtpd
1077             | AvxOpcode::Vphaddw
1078             | AvxOpcode::Vphaddd
1079             | AvxOpcode::Vpunpckldq
1080             | AvxOpcode::Vpunpckhdq
1081             | AvxOpcode::Vpunpcklqdq
1082             | AvxOpcode::Vpunpckhqdq
1083             | AvxOpcode::Vmovss
1084             | AvxOpcode::Vmovsd
1085             | AvxOpcode::Vmovups
1086             | AvxOpcode::Vmovupd
1087             | AvxOpcode::Vmovdqu
1088             | AvxOpcode::Vpextrb
1089             | AvxOpcode::Vpextrw
1090             | AvxOpcode::Vpextrd
1091             | AvxOpcode::Vpextrq
1092             | AvxOpcode::Vpblendw
1093             | AvxOpcode::Vbroadcastss
1094             | AvxOpcode::Vsqrtss
1095             | AvxOpcode::Vsqrtsd
1096             | AvxOpcode::Vunpcklpd
1097             | AvxOpcode::Vptest
1098             | AvxOpcode::Vucomiss
1099             | AvxOpcode::Vucomisd => {
1100                 smallvec![InstructionSet::AVX]
1101             }
1102 
1103             AvxOpcode::Vpbroadcastb | AvxOpcode::Vpbroadcastw | AvxOpcode::Vpbroadcastd => {
1104                 smallvec![InstructionSet::AVX2]
1105             }
1106         }
1107     }
1108 
1109     /// Is the opcode known to be commutative?
1110     ///
1111     /// Note that this method is not exhaustive, and there may be commutative
1112     /// opcodes that we don't recognize as commutative.
1113     pub(crate) fn is_commutative(&self) -> bool {
1114         match *self {
1115             AvxOpcode::Vpaddb
1116             | AvxOpcode::Vpaddw
1117             | AvxOpcode::Vpaddd
1118             | AvxOpcode::Vpaddq
1119             | AvxOpcode::Vpaddsb
1120             | AvxOpcode::Vpaddsw
1121             | AvxOpcode::Vpaddusb
1122             | AvxOpcode::Vpaddusw
1123             | AvxOpcode::Vpand
1124             | AvxOpcode::Vandps
1125             | AvxOpcode::Vandpd
1126             | AvxOpcode::Vpor
1127             | AvxOpcode::Vorps
1128             | AvxOpcode::Vorpd
1129             | AvxOpcode::Vpxor
1130             | AvxOpcode::Vxorps
1131             | AvxOpcode::Vxorpd
1132             | AvxOpcode::Vpmuldq
1133             | AvxOpcode::Vpmuludq
1134             | AvxOpcode::Vaddps
1135             | AvxOpcode::Vaddpd
1136             | AvxOpcode::Vmulps
1137             | AvxOpcode::Vmulpd
1138             | AvxOpcode::Vpcmpeqb
1139             | AvxOpcode::Vpcmpeqw
1140             | AvxOpcode::Vpcmpeqd
1141             | AvxOpcode::Vpcmpeqq
1142             | AvxOpcode::Vaddss
1143             | AvxOpcode::Vaddsd
1144             | AvxOpcode::Vmulss
1145             | AvxOpcode::Vmulsd => true,
1146             _ => false,
1147         }
1148     }
1149 }
1150 
1151 impl fmt::Display for AvxOpcode {
1152     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1153         format!("{self:?}").to_lowercase().fmt(f)
1154     }
1155 }
1156 
1157 #[derive(Copy, Clone, PartialEq)]
1158 #[allow(missing_docs)]
1159 pub enum Avx512TupleType {
1160     Full,
1161     FullMem,
1162     Mem128,
1163 }
1164 
1165 pub use crate::isa::x64::lower::isle::generated_code::Avx512Opcode;
1166 
1167 impl Avx512Opcode {
1168     /// Which `InstructionSet`s support the opcode?
1169     pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> {
1170         match self {
1171             Avx512Opcode::Vcvtudq2ps
1172             | Avx512Opcode::Vpabsq
1173             | Avx512Opcode::Vpsraq
1174             | Avx512Opcode::VpsraqImm => {
1175                 smallvec![InstructionSet::AVX512F, InstructionSet::AVX512VL]
1176             }
1177             Avx512Opcode::Vpermi2b => {
1178                 smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512VBMI]
1179             }
1180             Avx512Opcode::Vpmullq => smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512DQ],
1181             Avx512Opcode::Vpopcntb => {
1182                 smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512BITALG]
1183             }
1184         }
1185     }
1186 
1187     /// What is the "TupleType" of this opcode, which affects the scaling factor
1188     /// for 8-bit displacements when this instruction uses memory operands.
1189     ///
1190     /// This can be found in the encoding table for each instruction and is
1191     /// interpreted according to Table 2-34 and 2-35 in the Intel instruction
1192     /// manual.
1193     pub fn tuple_type(&self) -> Avx512TupleType {
1194         use Avx512Opcode::*;
1195         use Avx512TupleType::*;
1196 
1197         match self {
1198             Vcvtudq2ps | Vpabsq | Vpmullq | VpsraqImm => Full,
1199             Vpermi2b | Vpopcntb => FullMem,
1200             Vpsraq => Mem128,
1201         }
1202     }
1203 }
1204 
1205 impl fmt::Display for Avx512Opcode {
1206     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1207         let s = format!("{self:?}");
1208         f.write_str(&s.to_lowercase())
1209     }
1210 }
1211 
1212 /// This defines the ways a value can be extended: either signed- or zero-extension, or none for
1213 /// types that are not extended. Contrast with [ExtMode], which defines the widths from and to which
1214 /// values can be extended.
1215 #[allow(dead_code)]
1216 #[derive(Clone, PartialEq)]
1217 pub enum ExtKind {
1218     /// No extension.
1219     None,
1220     /// Sign-extend.
1221     SignExtend,
1222     /// Zero-extend.
1223     ZeroExtend,
1224 }
1225 
1226 /// These indicate ways of extending (widening) a value, using the Intel
1227 /// naming: B(yte) = u8, W(ord) = u16, L(ong)word = u32, Q(uad)word = u64
1228 #[derive(Clone, PartialEq)]
1229 pub enum ExtMode {
1230     /// Byte -> Longword.
1231     BL,
1232     /// Byte -> Quadword.
1233     BQ,
1234     /// Word -> Longword.
1235     WL,
1236     /// Word -> Quadword.
1237     WQ,
1238     /// Longword -> Quadword.
1239     LQ,
1240 }
1241 
1242 impl ExtMode {
1243     /// Calculate the `ExtMode` from passed bit lengths of the from/to types.
1244     pub(crate) fn new(from_bits: u16, to_bits: u16) -> Option<ExtMode> {
1245         match (from_bits, to_bits) {
1246             (1, 8) | (1, 16) | (1, 32) | (8, 16) | (8, 32) => Some(ExtMode::BL),
1247             (1, 64) | (8, 64) => Some(ExtMode::BQ),
1248             (16, 32) => Some(ExtMode::WL),
1249             (16, 64) => Some(ExtMode::WQ),
1250             (32, 64) => Some(ExtMode::LQ),
1251             _ => None,
1252         }
1253     }
1254 }
1255 
1256 impl fmt::Debug for ExtMode {
1257     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1258         let name = match self {
1259             ExtMode::BL => "bl",
1260             ExtMode::BQ => "bq",
1261             ExtMode::WL => "wl",
1262             ExtMode::WQ => "wq",
1263             ExtMode::LQ => "lq",
1264         };
1265         write!(fmt, "{name}")
1266     }
1267 }
1268 
1269 impl fmt::Display for ExtMode {
1270     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1271         fmt::Debug::fmt(self, f)
1272     }
1273 }
1274 
1275 /// These indicate condition code tests.  Not all are represented since not all are useful in
1276 /// compiler-generated code.
1277 #[derive(Copy, Clone, PartialEq, Eq)]
1278 #[repr(u8)]
1279 pub enum CC {
1280     ///  overflow
1281     O = 0,
1282     /// no overflow
1283     NO = 1,
1284 
1285     /// < unsigned
1286     B = 2,
1287     /// >= unsigned
1288     NB = 3,
1289 
1290     /// zero
1291     Z = 4,
1292     /// not-zero
1293     NZ = 5,
1294 
1295     /// <= unsigned
1296     BE = 6,
1297     /// > unsigned
1298     NBE = 7,
1299 
1300     /// negative
1301     S = 8,
1302     /// not-negative
1303     NS = 9,
1304 
1305     /// < signed
1306     L = 12,
1307     /// >= signed
1308     NL = 13,
1309 
1310     /// <= signed
1311     LE = 14,
1312     /// > signed
1313     NLE = 15,
1314 
1315     /// parity
1316     P = 10,
1317 
1318     /// not parity
1319     NP = 11,
1320 }
1321 
1322 impl CC {
1323     pub(crate) fn from_intcc(intcc: IntCC) -> Self {
1324         match intcc {
1325             IntCC::Equal => CC::Z,
1326             IntCC::NotEqual => CC::NZ,
1327             IntCC::SignedGreaterThanOrEqual => CC::NL,
1328             IntCC::SignedGreaterThan => CC::NLE,
1329             IntCC::SignedLessThanOrEqual => CC::LE,
1330             IntCC::SignedLessThan => CC::L,
1331             IntCC::UnsignedGreaterThanOrEqual => CC::NB,
1332             IntCC::UnsignedGreaterThan => CC::NBE,
1333             IntCC::UnsignedLessThanOrEqual => CC::BE,
1334             IntCC::UnsignedLessThan => CC::B,
1335         }
1336     }
1337 
1338     pub(crate) fn invert(&self) -> Self {
1339         match self {
1340             CC::O => CC::NO,
1341             CC::NO => CC::O,
1342 
1343             CC::B => CC::NB,
1344             CC::NB => CC::B,
1345 
1346             CC::Z => CC::NZ,
1347             CC::NZ => CC::Z,
1348 
1349             CC::BE => CC::NBE,
1350             CC::NBE => CC::BE,
1351 
1352             CC::S => CC::NS,
1353             CC::NS => CC::S,
1354 
1355             CC::L => CC::NL,
1356             CC::NL => CC::L,
1357 
1358             CC::LE => CC::NLE,
1359             CC::NLE => CC::LE,
1360 
1361             CC::P => CC::NP,
1362             CC::NP => CC::P,
1363         }
1364     }
1365 
1366     pub(crate) fn get_enc(self) -> u8 {
1367         self as u8
1368     }
1369 }
1370 
1371 impl fmt::Debug for CC {
1372     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1373         let name = match self {
1374             CC::O => "o",
1375             CC::NO => "no",
1376             CC::B => "b",
1377             CC::NB => "nb",
1378             CC::Z => "z",
1379             CC::NZ => "nz",
1380             CC::BE => "be",
1381             CC::NBE => "nbe",
1382             CC::S => "s",
1383             CC::NS => "ns",
1384             CC::L => "l",
1385             CC::NL => "nl",
1386             CC::LE => "le",
1387             CC::NLE => "nle",
1388             CC::P => "p",
1389             CC::NP => "np",
1390         };
1391         write!(fmt, "{name}")
1392     }
1393 }
1394 
1395 impl fmt::Display for CC {
1396     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1397         fmt::Debug::fmt(self, f)
1398     }
1399 }
1400 
1401 /// Encode the ways that floats can be compared. This is used in float comparisons such as `cmpps`,
1402 /// e.g.; it is distinguished from other float comparisons (e.g. `ucomiss`) in that those use EFLAGS
1403 /// whereas [FcmpImm] is used as an immediate.
1404 #[derive(Clone, Copy)]
1405 pub enum FcmpImm {
1406     /// Equal comparison.
1407     Equal = 0x00,
1408     /// Less than comparison.
1409     LessThan = 0x01,
1410     /// Less than or equal comparison.
1411     LessThanOrEqual = 0x02,
1412     /// Unordered.
1413     Unordered = 0x03,
1414     /// Not equal comparison.
1415     NotEqual = 0x04,
1416     /// Unordered of greater than or equal comparison.
1417     UnorderedOrGreaterThanOrEqual = 0x05,
1418     /// Unordered or greater than comparison.
1419     UnorderedOrGreaterThan = 0x06,
1420     /// Ordered.
1421     Ordered = 0x07,
1422 }
1423 
1424 impl FcmpImm {
1425     pub(crate) fn encode(self) -> u8 {
1426         self as u8
1427     }
1428 }
1429 
1430 impl From<FloatCC> for FcmpImm {
1431     fn from(cond: FloatCC) -> Self {
1432         match cond {
1433             FloatCC::Equal => FcmpImm::Equal,
1434             FloatCC::LessThan => FcmpImm::LessThan,
1435             FloatCC::LessThanOrEqual => FcmpImm::LessThanOrEqual,
1436             FloatCC::Unordered => FcmpImm::Unordered,
1437             FloatCC::NotEqual => FcmpImm::NotEqual,
1438             FloatCC::UnorderedOrGreaterThanOrEqual => FcmpImm::UnorderedOrGreaterThanOrEqual,
1439             FloatCC::UnorderedOrGreaterThan => FcmpImm::UnorderedOrGreaterThan,
1440             FloatCC::Ordered => FcmpImm::Ordered,
1441             _ => panic!("unable to create comparison predicate for {cond}"),
1442         }
1443     }
1444 }
1445 
1446 /// Encode the rounding modes used as part of the Rounding Control field.
1447 /// Note, these rounding immediates only consider the rounding control field
1448 /// (i.e. the rounding mode) which only take up the first two bits when encoded.
1449 /// However the rounding immediate which this field helps make up, also includes
1450 /// bits 3 and 4 which define the rounding select and precision mask respectively.
1451 /// These two bits are not defined here and are implicitly set to zero when encoded.
1452 #[derive(Clone, Copy)]
1453 pub enum RoundImm {
1454     /// Round to nearest mode.
1455     RoundNearest = 0x00,
1456     /// Round down mode.
1457     RoundDown = 0x01,
1458     /// Round up mode.
1459     RoundUp = 0x02,
1460     /// Round to zero mode.
1461     RoundZero = 0x03,
1462 }
1463 
1464 impl RoundImm {
1465     pub(crate) fn encode(self) -> u8 {
1466         self as u8
1467     }
1468 }
1469 
1470 /// An operand's size in bits.
1471 #[derive(Clone, Copy, PartialEq)]
1472 pub enum OperandSize {
1473     /// 8-bit.
1474     Size8,
1475     /// 16-bit.
1476     Size16,
1477     /// 32-bit.
1478     Size32,
1479     /// 64-bit.
1480     Size64,
1481 }
1482 
1483 impl OperandSize {
1484     pub(crate) fn from_bytes(num_bytes: u32) -> Self {
1485         match num_bytes {
1486             1 => OperandSize::Size8,
1487             2 => OperandSize::Size16,
1488             4 => OperandSize::Size32,
1489             8 => OperandSize::Size64,
1490             _ => unreachable!("Invalid OperandSize: {}", num_bytes),
1491         }
1492     }
1493 
1494     // Computes the OperandSize for a given type.
1495     // For vectors, the OperandSize of the lanes is returned.
1496     pub(crate) fn from_ty(ty: Type) -> Self {
1497         Self::from_bytes(ty.lane_type().bytes())
1498     }
1499 
1500     // Check that the value of self is one of the allowed sizes.
1501     pub(crate) fn is_one_of(&self, sizes: &[Self]) -> bool {
1502         sizes.iter().any(|val| *self == *val)
1503     }
1504 
1505     pub(crate) fn to_bytes(&self) -> u8 {
1506         match self {
1507             Self::Size8 => 1,
1508             Self::Size16 => 2,
1509             Self::Size32 => 4,
1510             Self::Size64 => 8,
1511         }
1512     }
1513 
1514     pub(crate) fn to_bits(&self) -> u8 {
1515         self.to_bytes() * 8
1516     }
1517 
1518     pub(crate) fn to_type(&self) -> Type {
1519         match self {
1520             Self::Size8 => I8,
1521             Self::Size16 => I16,
1522             Self::Size32 => I32,
1523             Self::Size64 => I64,
1524         }
1525     }
1526 }
1527