cranelift_codegen/isa/x64/inst/
args.rs

1//! Instruction operand sub-components (aka "parts"): definitions and printing.
2
3use super::regs::{self};
4use crate::ir::MemFlags;
5use crate::ir::condcodes::{FloatCC, IntCC};
6use crate::ir::types::*;
7use crate::isa::x64::inst::Inst;
8use crate::isa::x64::inst::regs::pretty_print_reg;
9use crate::machinst::*;
10use smallvec::{SmallVec, smallvec};
11use std::fmt;
12use std::string::String;
13
14/// An extension trait for converting `Writable{Xmm,Gpr}` to `Writable<Reg>`.
15pub 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}`.
21pub 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).
28macro_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.
298newtype_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.
308newtype_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.
321pub use crate::isa::x64::lower::isle::generated_code::Amode;
322
323impl 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
438impl 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)]
468pub 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
489impl 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
559impl From<Amode> for SyntheticAmode {
560    fn from(amode: Amode) -> SyntheticAmode {
561        SyntheticAmode::Real(amode)
562    }
563}
564
565impl From<VCodeConstant> for SyntheticAmode {
566    fn from(c: VCodeConstant) -> SyntheticAmode {
567        SyntheticAmode::ConstantOffset(c)
568    }
569}
570
571impl 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)]
592pub 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
610impl 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
644impl 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
653impl From<Reg> for RegMemImm {
654    fn from(reg: Reg) -> Self {
655        RegMemImm::Reg { reg }
656    }
657}
658
659impl 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)]
672pub 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
685impl 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
711impl From<Reg> for RegMem {
712    fn from(reg: Reg) -> RegMem {
713        RegMem::Reg { reg }
714    }
715}
716
717impl From<Writable<Reg>> for RegMem {
718    fn from(r: Writable<Reg>) -> Self {
719        RegMem::reg(r.to_reg())
720    }
721}
722
723impl 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.
734pub 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)]
742pub(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)]
769pub enum SseOpcode {
770    Blendvpd,
771    Blendvps,
772    Comiss,
773    Comisd,
774    Cmpps,
775    Cmppd,
776    Cmpss,
777    Cmpsd,
778    Insertps,
779    Movlhps,
780    Pabsb,
781    Pabsw,
782    Pabsd,
783    Packssdw,
784    Packsswb,
785    Packusdw,
786    Packuswb,
787    Palignr,
788    Pavgb,
789    Pavgw,
790    Pblendvb,
791    Pcmpeqb,
792    Pcmpeqw,
793    Pcmpeqd,
794    Pcmpeqq,
795    Pcmpgtb,
796    Pcmpgtw,
797    Pcmpgtd,
798    Pcmpgtq,
799    Pmaddubsw,
800    Pmaddwd,
801    Pshufb,
802    Pshufd,
803    Ptest,
804    Rcpss,
805    Roundps,
806    Roundpd,
807    Roundss,
808    Roundsd,
809    Rsqrtss,
810    Shufps,
811    Ucomiss,
812    Ucomisd,
813    Pshuflw,
814    Pshufhw,
815    Pblendw,
816}
817
818impl SseOpcode {
819    /// Which `InstructionSet` is the first supporting this opcode?
820    pub(crate) fn available_from(&self) -> InstructionSet {
821        use InstructionSet::*;
822        match self {
823            SseOpcode::Comiss
824            | SseOpcode::Cmpps
825            | SseOpcode::Cmpss
826            | SseOpcode::Movlhps
827            | SseOpcode::Rcpss
828            | SseOpcode::Rsqrtss
829            | SseOpcode::Shufps
830            | SseOpcode::Ucomiss => SSE,
831
832            SseOpcode::Cmppd
833            | SseOpcode::Cmpsd
834            | SseOpcode::Comisd
835            | SseOpcode::Packssdw
836            | SseOpcode::Packsswb
837            | SseOpcode::Packuswb
838            | SseOpcode::Pavgb
839            | SseOpcode::Pavgw
840            | SseOpcode::Pcmpeqb
841            | SseOpcode::Pcmpeqw
842            | SseOpcode::Pcmpeqd
843            | SseOpcode::Pcmpgtb
844            | SseOpcode::Pcmpgtw
845            | SseOpcode::Pcmpgtd
846            | SseOpcode::Pmaddwd
847            | SseOpcode::Pshufd
848            | SseOpcode::Ucomisd
849            | SseOpcode::Pshuflw
850            | SseOpcode::Pshufhw => SSE2,
851
852            SseOpcode::Pabsb
853            | SseOpcode::Pabsw
854            | SseOpcode::Pabsd
855            | SseOpcode::Palignr
856            | SseOpcode::Pshufb
857            | SseOpcode::Pmaddubsw => SSSE3,
858
859            SseOpcode::Blendvpd
860            | SseOpcode::Blendvps
861            | SseOpcode::Insertps
862            | SseOpcode::Packusdw
863            | SseOpcode::Pblendvb
864            | SseOpcode::Pcmpeqq
865            | SseOpcode::Ptest
866            | SseOpcode::Roundps
867            | SseOpcode::Roundpd
868            | SseOpcode::Roundss
869            | SseOpcode::Roundsd
870            | SseOpcode::Pblendw => SSE41,
871
872            SseOpcode::Pcmpgtq => SSE42,
873        }
874    }
875
876    /// Returns the src operand size for an instruction.
877    pub(crate) fn src_size(&self) -> u8 {
878        match self {
879            _ => 8,
880        }
881    }
882
883    /// Is `src2` with this opcode a scalar, as for lane insertions?
884    pub(crate) fn has_scalar_src2(self) -> bool {
885        false
886    }
887}
888
889impl fmt::Debug for SseOpcode {
890    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
891        let name = match self {
892            SseOpcode::Blendvpd => "blendvpd",
893            SseOpcode::Blendvps => "blendvps",
894            SseOpcode::Cmpps => "cmpps",
895            SseOpcode::Cmppd => "cmppd",
896            SseOpcode::Cmpss => "cmpss",
897            SseOpcode::Cmpsd => "cmpsd",
898            SseOpcode::Comiss => "comiss",
899            SseOpcode::Comisd => "comisd",
900            SseOpcode::Insertps => "insertps",
901            SseOpcode::Movlhps => "movlhps",
902            SseOpcode::Pabsb => "pabsb",
903            SseOpcode::Pabsw => "pabsw",
904            SseOpcode::Pabsd => "pabsd",
905            SseOpcode::Packssdw => "packssdw",
906            SseOpcode::Packsswb => "packsswb",
907            SseOpcode::Packusdw => "packusdw",
908            SseOpcode::Packuswb => "packuswb",
909            SseOpcode::Palignr => "palignr",
910            SseOpcode::Pavgb => "pavgb",
911            SseOpcode::Pavgw => "pavgw",
912            SseOpcode::Pblendvb => "pblendvb",
913            SseOpcode::Pcmpeqb => "pcmpeqb",
914            SseOpcode::Pcmpeqw => "pcmpeqw",
915            SseOpcode::Pcmpeqd => "pcmpeqd",
916            SseOpcode::Pcmpeqq => "pcmpeqq",
917            SseOpcode::Pcmpgtb => "pcmpgtb",
918            SseOpcode::Pcmpgtw => "pcmpgtw",
919            SseOpcode::Pcmpgtd => "pcmpgtd",
920            SseOpcode::Pcmpgtq => "pcmpgtq",
921            SseOpcode::Pmaddubsw => "pmaddubsw",
922            SseOpcode::Pmaddwd => "pmaddwd",
923            SseOpcode::Pshufb => "pshufb",
924            SseOpcode::Pshufd => "pshufd",
925            SseOpcode::Ptest => "ptest",
926            SseOpcode::Rcpss => "rcpss",
927            SseOpcode::Roundps => "roundps",
928            SseOpcode::Roundpd => "roundpd",
929            SseOpcode::Roundss => "roundss",
930            SseOpcode::Roundsd => "roundsd",
931            SseOpcode::Rsqrtss => "rsqrtss",
932            SseOpcode::Shufps => "shufps",
933            SseOpcode::Ucomiss => "ucomiss",
934            SseOpcode::Ucomisd => "ucomisd",
935            SseOpcode::Pshuflw => "pshuflw",
936            SseOpcode::Pshufhw => "pshufhw",
937            SseOpcode::Pblendw => "pblendw",
938        };
939        write!(fmt, "{name}")
940    }
941}
942
943impl fmt::Display for SseOpcode {
944    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
945        fmt::Debug::fmt(self, f)
946    }
947}
948
949pub use crate::isa::x64::lower::isle::generated_code::AvxOpcode;
950
951impl AvxOpcode {
952    /// Which `InstructionSet`s support the opcode?
953    pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> {
954        match self {
955            AvxOpcode::Vfmadd213ss
956            | AvxOpcode::Vfmadd213sd
957            | AvxOpcode::Vfmadd213ps
958            | AvxOpcode::Vfmadd213pd
959            | AvxOpcode::Vfmadd132ss
960            | AvxOpcode::Vfmadd132sd
961            | AvxOpcode::Vfmadd132ps
962            | AvxOpcode::Vfmadd132pd
963            | AvxOpcode::Vfnmadd213ss
964            | AvxOpcode::Vfnmadd213sd
965            | AvxOpcode::Vfnmadd213ps
966            | AvxOpcode::Vfnmadd213pd
967            | AvxOpcode::Vfnmadd132ss
968            | AvxOpcode::Vfnmadd132sd
969            | AvxOpcode::Vfnmadd132ps
970            | AvxOpcode::Vfnmadd132pd
971            | AvxOpcode::Vfmsub213ss
972            | AvxOpcode::Vfmsub213sd
973            | AvxOpcode::Vfmsub213ps
974            | AvxOpcode::Vfmsub213pd
975            | AvxOpcode::Vfmsub132ss
976            | AvxOpcode::Vfmsub132sd
977            | AvxOpcode::Vfmsub132ps
978            | AvxOpcode::Vfmsub132pd
979            | AvxOpcode::Vfnmsub213ss
980            | AvxOpcode::Vfnmsub213sd
981            | AvxOpcode::Vfnmsub213ps
982            | AvxOpcode::Vfnmsub213pd
983            | AvxOpcode::Vfnmsub132ss
984            | AvxOpcode::Vfnmsub132sd
985            | AvxOpcode::Vfnmsub132ps
986            | AvxOpcode::Vfnmsub132pd => smallvec![InstructionSet::FMA],
987            AvxOpcode::Vminps
988            | AvxOpcode::Vminpd
989            | AvxOpcode::Vmaxps
990            | AvxOpcode::Vmaxpd
991            | AvxOpcode::Vandnps
992            | AvxOpcode::Vandnpd
993            | AvxOpcode::Vpandn
994            | AvxOpcode::Vcmpps
995            | AvxOpcode::Vcmppd
996            | AvxOpcode::Vpsrlw
997            | AvxOpcode::Vpsrld
998            | AvxOpcode::Vpsrlq
999            | AvxOpcode::Vpaddb
1000            | AvxOpcode::Vpaddw
1001            | AvxOpcode::Vpaddd
1002            | AvxOpcode::Vpaddq
1003            | AvxOpcode::Vpaddsb
1004            | AvxOpcode::Vpaddsw
1005            | AvxOpcode::Vpaddusb
1006            | AvxOpcode::Vpaddusw
1007            | AvxOpcode::Vpsubb
1008            | AvxOpcode::Vpsubw
1009            | AvxOpcode::Vpsubd
1010            | AvxOpcode::Vpsubq
1011            | AvxOpcode::Vpsubsb
1012            | AvxOpcode::Vpsubsw
1013            | AvxOpcode::Vpsubusb
1014            | AvxOpcode::Vpsubusw
1015            | AvxOpcode::Vpavgb
1016            | AvxOpcode::Vpavgw
1017            | AvxOpcode::Vpand
1018            | AvxOpcode::Vandps
1019            | AvxOpcode::Vandpd
1020            | AvxOpcode::Vpor
1021            | AvxOpcode::Vorps
1022            | AvxOpcode::Vorpd
1023            | AvxOpcode::Vpxor
1024            | AvxOpcode::Vxorps
1025            | AvxOpcode::Vxorpd
1026            | AvxOpcode::Vpmullw
1027            | AvxOpcode::Vpmulld
1028            | AvxOpcode::Vpmulhw
1029            | AvxOpcode::Vpmulhd
1030            | AvxOpcode::Vpmulhrsw
1031            | AvxOpcode::Vpmulhuw
1032            | AvxOpcode::Vpmuldq
1033            | AvxOpcode::Vpmuludq
1034            | AvxOpcode::Vpunpckhwd
1035            | AvxOpcode::Vpunpcklwd
1036            | AvxOpcode::Vunpcklps
1037            | AvxOpcode::Vunpckhps
1038            | AvxOpcode::Vaddps
1039            | AvxOpcode::Vaddpd
1040            | AvxOpcode::Vsubps
1041            | AvxOpcode::Vsubpd
1042            | AvxOpcode::Vmulps
1043            | AvxOpcode::Vmulpd
1044            | AvxOpcode::Vdivps
1045            | AvxOpcode::Vdivpd
1046            | AvxOpcode::Vpcmpeqb
1047            | AvxOpcode::Vpcmpeqw
1048            | AvxOpcode::Vpcmpeqd
1049            | AvxOpcode::Vpcmpeqq
1050            | AvxOpcode::Vpcmpgtb
1051            | AvxOpcode::Vpcmpgtw
1052            | AvxOpcode::Vpcmpgtd
1053            | AvxOpcode::Vpcmpgtq
1054            | AvxOpcode::Vblendvps
1055            | AvxOpcode::Vblendvpd
1056            | AvxOpcode::Vpblendvb
1057            | AvxOpcode::Vmovlhps
1058            | AvxOpcode::Vpminsb
1059            | AvxOpcode::Vpminsw
1060            | AvxOpcode::Vpminsd
1061            | AvxOpcode::Vpminub
1062            | AvxOpcode::Vpminuw
1063            | AvxOpcode::Vpminud
1064            | AvxOpcode::Vpmaxsb
1065            | AvxOpcode::Vpmaxsw
1066            | AvxOpcode::Vpmaxsd
1067            | AvxOpcode::Vpmaxub
1068            | AvxOpcode::Vpmaxuw
1069            | AvxOpcode::Vpmaxud
1070            | AvxOpcode::Vpunpcklbw
1071            | AvxOpcode::Vpunpckhbw
1072            | AvxOpcode::Vpacksswb
1073            | AvxOpcode::Vpackssdw
1074            | AvxOpcode::Vpackuswb
1075            | AvxOpcode::Vpackusdw
1076            | AvxOpcode::Vpalignr
1077            | AvxOpcode::Vpmaddwd
1078            | AvxOpcode::Vpmaddubsw
1079            | AvxOpcode::Vinsertps
1080            | AvxOpcode::Vpshufb
1081            | AvxOpcode::Vshufps
1082            | AvxOpcode::Vpsllw
1083            | AvxOpcode::Vpslld
1084            | AvxOpcode::Vpsllq
1085            | AvxOpcode::Vpsraw
1086            | AvxOpcode::Vpsrad
1087            | AvxOpcode::Vpmovsxbw
1088            | AvxOpcode::Vpmovzxbw
1089            | AvxOpcode::Vpmovsxwd
1090            | AvxOpcode::Vpmovzxwd
1091            | AvxOpcode::Vpmovsxdq
1092            | AvxOpcode::Vpmovzxdq
1093            | AvxOpcode::Vaddss
1094            | AvxOpcode::Vaddsd
1095            | AvxOpcode::Vmulss
1096            | AvxOpcode::Vmulsd
1097            | AvxOpcode::Vsubss
1098            | AvxOpcode::Vsubsd
1099            | AvxOpcode::Vdivss
1100            | AvxOpcode::Vdivsd
1101            | AvxOpcode::Vpabsb
1102            | AvxOpcode::Vpabsw
1103            | AvxOpcode::Vpabsd
1104            | AvxOpcode::Vminss
1105            | AvxOpcode::Vminsd
1106            | AvxOpcode::Vmaxss
1107            | AvxOpcode::Vmaxsd
1108            | AvxOpcode::Vsqrtps
1109            | AvxOpcode::Vsqrtpd
1110            | AvxOpcode::Vroundpd
1111            | AvxOpcode::Vroundps
1112            | AvxOpcode::Vphaddw
1113            | AvxOpcode::Vphaddd
1114            | AvxOpcode::Vpunpckldq
1115            | AvxOpcode::Vpunpckhdq
1116            | AvxOpcode::Vpunpcklqdq
1117            | AvxOpcode::Vpunpckhqdq
1118            | AvxOpcode::Vpshuflw
1119            | AvxOpcode::Vpshufhw
1120            | AvxOpcode::Vpshufd
1121            | AvxOpcode::Vmovss
1122            | AvxOpcode::Vmovsd
1123            | AvxOpcode::Vmovups
1124            | AvxOpcode::Vmovupd
1125            | AvxOpcode::Vmovdqu
1126            | AvxOpcode::Vpextrb
1127            | AvxOpcode::Vpextrw
1128            | AvxOpcode::Vpextrd
1129            | AvxOpcode::Vpextrq
1130            | AvxOpcode::Vpblendw
1131            | AvxOpcode::Vbroadcastss
1132            | AvxOpcode::Vsqrtss
1133            | AvxOpcode::Vsqrtsd
1134            | AvxOpcode::Vroundss
1135            | AvxOpcode::Vroundsd
1136            | AvxOpcode::Vunpcklpd
1137            | AvxOpcode::Vptest
1138            | AvxOpcode::Vucomiss
1139            | AvxOpcode::Vucomisd => {
1140                smallvec![InstructionSet::AVX]
1141            }
1142
1143            AvxOpcode::Vpbroadcastb | AvxOpcode::Vpbroadcastw | AvxOpcode::Vpbroadcastd => {
1144                smallvec![InstructionSet::AVX2]
1145            }
1146        }
1147    }
1148
1149    /// Is the opcode known to be commutative?
1150    ///
1151    /// Note that this method is not exhaustive, and there may be commutative
1152    /// opcodes that we don't recognize as commutative.
1153    pub(crate) fn is_commutative(&self) -> bool {
1154        match *self {
1155            AvxOpcode::Vpaddb
1156            | AvxOpcode::Vpaddw
1157            | AvxOpcode::Vpaddd
1158            | AvxOpcode::Vpaddq
1159            | AvxOpcode::Vpaddsb
1160            | AvxOpcode::Vpaddsw
1161            | AvxOpcode::Vpaddusb
1162            | AvxOpcode::Vpaddusw
1163            | AvxOpcode::Vpand
1164            | AvxOpcode::Vandps
1165            | AvxOpcode::Vandpd
1166            | AvxOpcode::Vpor
1167            | AvxOpcode::Vorps
1168            | AvxOpcode::Vorpd
1169            | AvxOpcode::Vpxor
1170            | AvxOpcode::Vxorps
1171            | AvxOpcode::Vxorpd
1172            | AvxOpcode::Vpmuldq
1173            | AvxOpcode::Vpmuludq
1174            | AvxOpcode::Vaddps
1175            | AvxOpcode::Vaddpd
1176            | AvxOpcode::Vmulps
1177            | AvxOpcode::Vmulpd
1178            | AvxOpcode::Vpcmpeqb
1179            | AvxOpcode::Vpcmpeqw
1180            | AvxOpcode::Vpcmpeqd
1181            | AvxOpcode::Vpcmpeqq
1182            | AvxOpcode::Vaddss
1183            | AvxOpcode::Vaddsd
1184            | AvxOpcode::Vmulss
1185            | AvxOpcode::Vmulsd => true,
1186            _ => false,
1187        }
1188    }
1189}
1190
1191impl fmt::Display for AvxOpcode {
1192    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1193        format!("{self:?}").to_lowercase().fmt(f)
1194    }
1195}
1196
1197#[derive(Copy, Clone, PartialEq)]
1198#[allow(missing_docs)]
1199pub enum Avx512TupleType {
1200    Full,
1201    FullMem,
1202    Mem128,
1203}
1204
1205pub use crate::isa::x64::lower::isle::generated_code::Avx512Opcode;
1206
1207impl Avx512Opcode {
1208    /// Which `InstructionSet`s support the opcode?
1209    pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> {
1210        match self {
1211            Avx512Opcode::Vcvtudq2ps
1212            | Avx512Opcode::Vpabsq
1213            | Avx512Opcode::Vpsraq
1214            | Avx512Opcode::VpsraqImm => {
1215                smallvec![InstructionSet::AVX512F, InstructionSet::AVX512VL]
1216            }
1217            Avx512Opcode::Vpermi2b => {
1218                smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512VBMI]
1219            }
1220            Avx512Opcode::Vpmullq => smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512DQ],
1221            Avx512Opcode::Vpopcntb => {
1222                smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512BITALG]
1223            }
1224        }
1225    }
1226
1227    /// What is the "TupleType" of this opcode, which affects the scaling factor
1228    /// for 8-bit displacements when this instruction uses memory operands.
1229    ///
1230    /// This can be found in the encoding table for each instruction and is
1231    /// interpreted according to Table 2-34 and 2-35 in the Intel instruction
1232    /// manual.
1233    pub fn tuple_type(&self) -> Avx512TupleType {
1234        use Avx512Opcode::*;
1235        use Avx512TupleType::*;
1236
1237        match self {
1238            Vcvtudq2ps | Vpabsq | Vpmullq | VpsraqImm => Full,
1239            Vpermi2b | Vpopcntb => FullMem,
1240            Vpsraq => Mem128,
1241        }
1242    }
1243}
1244
1245impl fmt::Display for Avx512Opcode {
1246    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1247        let s = format!("{self:?}");
1248        f.write_str(&s.to_lowercase())
1249    }
1250}
1251
1252/// This defines the ways a value can be extended: either signed- or zero-extension, or none for
1253/// types that are not extended. Contrast with [ExtMode], which defines the widths from and to which
1254/// values can be extended.
1255#[allow(dead_code)]
1256#[derive(Clone, PartialEq)]
1257pub enum ExtKind {
1258    /// No extension.
1259    None,
1260    /// Sign-extend.
1261    SignExtend,
1262    /// Zero-extend.
1263    ZeroExtend,
1264}
1265
1266/// These indicate ways of extending (widening) a value, using the Intel
1267/// naming: B(yte) = u8, W(ord) = u16, L(ong)word = u32, Q(uad)word = u64
1268#[derive(Clone, PartialEq)]
1269pub enum ExtMode {
1270    /// Byte -> Longword.
1271    BL,
1272    /// Byte -> Quadword.
1273    BQ,
1274    /// Word -> Longword.
1275    WL,
1276    /// Word -> Quadword.
1277    WQ,
1278    /// Longword -> Quadword.
1279    LQ,
1280}
1281
1282impl ExtMode {
1283    /// Calculate the `ExtMode` from passed bit lengths of the from/to types.
1284    pub(crate) fn new(from_bits: u16, to_bits: u16) -> Option<ExtMode> {
1285        match (from_bits, to_bits) {
1286            (1, 8) | (1, 16) | (1, 32) | (8, 16) | (8, 32) => Some(ExtMode::BL),
1287            (1, 64) | (8, 64) => Some(ExtMode::BQ),
1288            (16, 32) => Some(ExtMode::WL),
1289            (16, 64) => Some(ExtMode::WQ),
1290            (32, 64) => Some(ExtMode::LQ),
1291            _ => None,
1292        }
1293    }
1294}
1295
1296impl fmt::Debug for ExtMode {
1297    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1298        let name = match self {
1299            ExtMode::BL => "bl",
1300            ExtMode::BQ => "bq",
1301            ExtMode::WL => "wl",
1302            ExtMode::WQ => "wq",
1303            ExtMode::LQ => "lq",
1304        };
1305        write!(fmt, "{name}")
1306    }
1307}
1308
1309impl fmt::Display for ExtMode {
1310    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1311        fmt::Debug::fmt(self, f)
1312    }
1313}
1314
1315/// These indicate condition code tests.  Not all are represented since not all are useful in
1316/// compiler-generated code.
1317#[derive(Copy, Clone, PartialEq, Eq)]
1318#[repr(u8)]
1319pub enum CC {
1320    ///  overflow
1321    O = 0,
1322    /// no overflow
1323    NO = 1,
1324
1325    /// < unsigned
1326    B = 2,
1327    /// >= unsigned
1328    NB = 3,
1329
1330    /// zero
1331    Z = 4,
1332    /// not-zero
1333    NZ = 5,
1334
1335    /// <= unsigned
1336    BE = 6,
1337    /// > unsigned
1338    NBE = 7,
1339
1340    /// negative
1341    S = 8,
1342    /// not-negative
1343    NS = 9,
1344
1345    /// < signed
1346    L = 12,
1347    /// >= signed
1348    NL = 13,
1349
1350    /// <= signed
1351    LE = 14,
1352    /// > signed
1353    NLE = 15,
1354
1355    /// parity
1356    P = 10,
1357
1358    /// not parity
1359    NP = 11,
1360}
1361
1362impl CC {
1363    pub(crate) fn from_intcc(intcc: IntCC) -> Self {
1364        match intcc {
1365            IntCC::Equal => CC::Z,
1366            IntCC::NotEqual => CC::NZ,
1367            IntCC::SignedGreaterThanOrEqual => CC::NL,
1368            IntCC::SignedGreaterThan => CC::NLE,
1369            IntCC::SignedLessThanOrEqual => CC::LE,
1370            IntCC::SignedLessThan => CC::L,
1371            IntCC::UnsignedGreaterThanOrEqual => CC::NB,
1372            IntCC::UnsignedGreaterThan => CC::NBE,
1373            IntCC::UnsignedLessThanOrEqual => CC::BE,
1374            IntCC::UnsignedLessThan => CC::B,
1375        }
1376    }
1377
1378    pub(crate) fn invert(&self) -> Self {
1379        match self {
1380            CC::O => CC::NO,
1381            CC::NO => CC::O,
1382
1383            CC::B => CC::NB,
1384            CC::NB => CC::B,
1385
1386            CC::Z => CC::NZ,
1387            CC::NZ => CC::Z,
1388
1389            CC::BE => CC::NBE,
1390            CC::NBE => CC::BE,
1391
1392            CC::S => CC::NS,
1393            CC::NS => CC::S,
1394
1395            CC::L => CC::NL,
1396            CC::NL => CC::L,
1397
1398            CC::LE => CC::NLE,
1399            CC::NLE => CC::LE,
1400
1401            CC::P => CC::NP,
1402            CC::NP => CC::P,
1403        }
1404    }
1405
1406    pub(crate) fn get_enc(self) -> u8 {
1407        self as u8
1408    }
1409}
1410
1411impl fmt::Debug for CC {
1412    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1413        let name = match self {
1414            CC::O => "o",
1415            CC::NO => "no",
1416            CC::B => "b",
1417            CC::NB => "nb",
1418            CC::Z => "z",
1419            CC::NZ => "nz",
1420            CC::BE => "be",
1421            CC::NBE => "nbe",
1422            CC::S => "s",
1423            CC::NS => "ns",
1424            CC::L => "l",
1425            CC::NL => "nl",
1426            CC::LE => "le",
1427            CC::NLE => "nle",
1428            CC::P => "p",
1429            CC::NP => "np",
1430        };
1431        write!(fmt, "{name}")
1432    }
1433}
1434
1435impl fmt::Display for CC {
1436    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1437        fmt::Debug::fmt(self, f)
1438    }
1439}
1440
1441/// Encode the ways that floats can be compared. This is used in float comparisons such as `cmpps`,
1442/// e.g.; it is distinguished from other float comparisons (e.g. `ucomiss`) in that those use EFLAGS
1443/// whereas [FcmpImm] is used as an immediate.
1444#[derive(Clone, Copy)]
1445pub enum FcmpImm {
1446    /// Equal comparison.
1447    Equal = 0x00,
1448    /// Less than comparison.
1449    LessThan = 0x01,
1450    /// Less than or equal comparison.
1451    LessThanOrEqual = 0x02,
1452    /// Unordered.
1453    Unordered = 0x03,
1454    /// Not equal comparison.
1455    NotEqual = 0x04,
1456    /// Unordered of greater than or equal comparison.
1457    UnorderedOrGreaterThanOrEqual = 0x05,
1458    /// Unordered or greater than comparison.
1459    UnorderedOrGreaterThan = 0x06,
1460    /// Ordered.
1461    Ordered = 0x07,
1462}
1463
1464impl FcmpImm {
1465    pub(crate) fn encode(self) -> u8 {
1466        self as u8
1467    }
1468}
1469
1470impl From<FloatCC> for FcmpImm {
1471    fn from(cond: FloatCC) -> Self {
1472        match cond {
1473            FloatCC::Equal => FcmpImm::Equal,
1474            FloatCC::LessThan => FcmpImm::LessThan,
1475            FloatCC::LessThanOrEqual => FcmpImm::LessThanOrEqual,
1476            FloatCC::Unordered => FcmpImm::Unordered,
1477            FloatCC::NotEqual => FcmpImm::NotEqual,
1478            FloatCC::UnorderedOrGreaterThanOrEqual => FcmpImm::UnorderedOrGreaterThanOrEqual,
1479            FloatCC::UnorderedOrGreaterThan => FcmpImm::UnorderedOrGreaterThan,
1480            FloatCC::Ordered => FcmpImm::Ordered,
1481            _ => panic!("unable to create comparison predicate for {cond}"),
1482        }
1483    }
1484}
1485
1486/// Encode the rounding modes used as part of the Rounding Control field.
1487/// Note, these rounding immediates only consider the rounding control field
1488/// (i.e. the rounding mode) which only take up the first two bits when encoded.
1489/// However the rounding immediate which this field helps make up, also includes
1490/// bits 3 and 4 which define the rounding select and precision mask respectively.
1491/// These two bits are not defined here and are implicitly set to zero when encoded.
1492#[derive(Clone, Copy)]
1493pub enum RoundImm {
1494    /// Round to nearest mode.
1495    RoundNearest = 0x00,
1496    /// Round down mode.
1497    RoundDown = 0x01,
1498    /// Round up mode.
1499    RoundUp = 0x02,
1500    /// Round to zero mode.
1501    RoundZero = 0x03,
1502}
1503
1504impl RoundImm {
1505    pub(crate) fn encode(self) -> u8 {
1506        self as u8
1507    }
1508}
1509
1510/// An operand's size in bits.
1511#[derive(Clone, Copy, PartialEq)]
1512pub enum OperandSize {
1513    /// 8-bit.
1514    Size8,
1515    /// 16-bit.
1516    Size16,
1517    /// 32-bit.
1518    Size32,
1519    /// 64-bit.
1520    Size64,
1521}
1522
1523impl OperandSize {
1524    pub(crate) fn from_bytes(num_bytes: u32) -> Self {
1525        match num_bytes {
1526            1 => OperandSize::Size8,
1527            2 => OperandSize::Size16,
1528            4 => OperandSize::Size32,
1529            8 => OperandSize::Size64,
1530            _ => unreachable!("Invalid OperandSize: {}", num_bytes),
1531        }
1532    }
1533
1534    // Computes the OperandSize for a given type.
1535    // For vectors, the OperandSize of the lanes is returned.
1536    pub(crate) fn from_ty(ty: Type) -> Self {
1537        Self::from_bytes(ty.lane_type().bytes())
1538    }
1539
1540    // Check that the value of self is one of the allowed sizes.
1541    pub(crate) fn is_one_of(&self, sizes: &[Self]) -> bool {
1542        sizes.iter().any(|val| *self == *val)
1543    }
1544
1545    pub(crate) fn to_bytes(&self) -> u8 {
1546        match self {
1547            Self::Size8 => 1,
1548            Self::Size16 => 2,
1549            Self::Size32 => 4,
1550            Self::Size64 => 8,
1551        }
1552    }
1553
1554    pub(crate) fn to_bits(&self) -> u8 {
1555        self.to_bytes() * 8
1556    }
1557
1558    pub(crate) fn to_type(&self) -> Type {
1559        match self {
1560            Self::Size8 => I8,
1561            Self::Size16 => I16,
1562            Self::Size32 => I32,
1563            Self::Size64 => I64,
1564        }
1565    }
1566}
1567
1568/// An x64 memory fence kind.
1569#[derive(Clone)]
1570#[allow(dead_code)]
1571pub enum FenceKind {
1572    /// `mfence` instruction ("Memory Fence")
1573    MFence,
1574    /// `lfence` instruction ("Load Fence")
1575    LFence,
1576    /// `sfence` instruction ("Store Fence")
1577    SFence,
1578}