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 #[expect(missing_docs, reason = "self-describing fields")]
308 impl Gpr {
309     pub const RAX: Gpr = Gpr(regs::rax());
310     pub const RBX: Gpr = Gpr(regs::rbx());
311     pub const RCX: Gpr = Gpr(regs::rcx());
312     pub const RDX: Gpr = Gpr(regs::rdx());
313     pub const RSI: Gpr = Gpr(regs::rsi());
314     pub const RDI: Gpr = Gpr(regs::rdi());
315     pub const RSP: Gpr = Gpr(regs::rsp());
316     pub const RBP: Gpr = Gpr(regs::rbp());
317     pub const R8: Gpr = Gpr(regs::r8());
318     pub const R9: Gpr = Gpr(regs::r9());
319     pub const R10: Gpr = Gpr(regs::r10());
320     pub const R11: Gpr = Gpr(regs::r11());
321     pub const R12: Gpr = Gpr(regs::r12());
322     pub const R13: Gpr = Gpr(regs::r13());
323     pub const R14: Gpr = Gpr(regs::r14());
324     pub const R15: Gpr = Gpr(regs::r15());
325 }
326 
327 // Define a newtype of `Reg` for XMM registers.
328 newtype_of_reg!(
329     Xmm,
330     WritableXmm,
331     OptionWritableXmm,
332     reg_mem: (XmmMem, XmmMemAligned aligned:true),
333     reg_mem_imm: (XmmMemImm, XmmMemAlignedImm aligned:true),
334     |reg| reg.class() == RegClass::Float
335 );
336 
337 // N.B.: `Amode` is defined in `inst.isle`. We add some convenience
338 // constructors here.
339 
340 // Re-export the type from the ISLE generated code.
341 pub use crate::isa::x64::lower::isle::generated_code::Amode;
342 
343 impl Amode {
344     /// Create an immediate sign-extended and register addressing mode.
345     pub fn imm_reg(simm32: i32, base: Reg) -> Self {
346         debug_assert!(base.class() == RegClass::Int);
347         Self::ImmReg {
348             simm32,
349             base,
350             flags: MemFlags::trusted(),
351         }
352     }
353 
354     /// Create a sign-extended-32-to-64 with register and shift addressing mode.
355     pub fn imm_reg_reg_shift(simm32: i32, base: Gpr, index: Gpr, shift: u8) -> Self {
356         debug_assert!(base.class() == RegClass::Int);
357         debug_assert!(index.class() == RegClass::Int);
358         debug_assert!(shift <= 3);
359         Self::ImmRegRegShift {
360             simm32,
361             base,
362             index,
363             shift,
364             flags: MemFlags::trusted(),
365         }
366     }
367 
368     pub(crate) fn rip_relative(target: MachLabel) -> Self {
369         Self::RipRelative { target }
370     }
371 
372     /// Set the specified [MemFlags] to the [Amode].
373     pub fn with_flags(&self, flags: MemFlags) -> Self {
374         match self {
375             &Self::ImmReg { simm32, base, .. } => Self::ImmReg {
376                 simm32,
377                 base,
378                 flags,
379             },
380             &Self::ImmRegRegShift {
381                 simm32,
382                 base,
383                 index,
384                 shift,
385                 ..
386             } => Self::ImmRegRegShift {
387                 simm32,
388                 base,
389                 index,
390                 shift,
391                 flags,
392             },
393             _ => panic!("Amode {self:?} cannot take memflags"),
394         }
395     }
396 
397     /// Add the registers mentioned by `self` to `collector`.
398     pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
399         match self {
400             Amode::ImmReg { base, .. } => {
401                 if *base != regs::rbp() && *base != regs::rsp() {
402                     collector.reg_use(base);
403                 }
404             }
405             Amode::ImmRegRegShift { base, index, .. } => {
406                 debug_assert_ne!(base.to_reg(), regs::rbp());
407                 debug_assert_ne!(base.to_reg(), regs::rsp());
408                 collector.reg_use(base);
409                 debug_assert_ne!(index.to_reg(), regs::rbp());
410                 debug_assert_ne!(index.to_reg(), regs::rsp());
411                 collector.reg_use(index);
412             }
413             Amode::RipRelative { .. } => {
414                 // RIP isn't involved in regalloc.
415             }
416         }
417     }
418 
419     /// Same as `get_operands`, but add the registers in the "late" phase.
420     pub(crate) fn get_operands_late(&mut self, collector: &mut impl OperandVisitor) {
421         match self {
422             Amode::ImmReg { base, .. } => {
423                 collector.reg_late_use(base);
424             }
425             Amode::ImmRegRegShift { base, index, .. } => {
426                 collector.reg_late_use(base);
427                 collector.reg_late_use(index);
428             }
429             Amode::RipRelative { .. } => {
430                 // RIP isn't involved in regalloc.
431             }
432         }
433     }
434 
435     pub(crate) fn get_flags(&self) -> MemFlags {
436         match self {
437             Amode::ImmReg { flags, .. } | Amode::ImmRegRegShift { flags, .. } => *flags,
438             Amode::RipRelative { .. } => MemFlags::trusted(),
439         }
440     }
441 
442     /// Offset the amode by a fixed offset.
443     pub(crate) fn offset(&self, offset: i32) -> Self {
444         let mut ret = self.clone();
445         match &mut ret {
446             &mut Amode::ImmReg { ref mut simm32, .. } => *simm32 += offset,
447             &mut Amode::ImmRegRegShift { ref mut simm32, .. } => *simm32 += offset,
448             _ => panic!("Cannot offset amode: {self:?}"),
449         }
450         ret
451     }
452 
453     pub(crate) fn aligned(&self) -> bool {
454         self.get_flags().aligned()
455     }
456 }
457 
458 impl PrettyPrint for Amode {
459     fn pretty_print(&self, _size: u8) -> String {
460         match self {
461             Amode::ImmReg { simm32, base, .. } => {
462                 // Note: size is always 8; the address is 64 bits,
463                 // even if the addressed operand is smaller.
464                 format!("{}({})", *simm32, pretty_print_reg(*base, 8))
465             }
466             Amode::ImmRegRegShift {
467                 simm32,
468                 base,
469                 index,
470                 shift,
471                 ..
472             } => format!(
473                 "{}({},{},{})",
474                 *simm32,
475                 pretty_print_reg(base.to_reg(), 8),
476                 pretty_print_reg(index.to_reg(), 8),
477                 1 << shift
478             ),
479             Amode::RipRelative { target } => format!("label{}(%rip)", target.as_u32()),
480         }
481     }
482 }
483 
484 /// A Memory Address. These denote a 64-bit value only.
485 /// Used for usual addressing modes as well as addressing modes used during compilation, when the
486 /// moving SP offset is not known.
487 #[derive(Clone, Debug)]
488 pub enum SyntheticAmode {
489     /// A real amode.
490     Real(Amode),
491 
492     /// A (virtual) offset into the incoming argument area.
493     IncomingArg {
494         /// The downward offset from the start of the incoming argument area.
495         offset: u32,
496     },
497 
498     /// A (virtual) offset to the slot area of the function frame, which lies just above the
499     /// outgoing arguments.
500     SlotOffset {
501         /// The offset into the slot area.
502         simm32: i32,
503     },
504 
505     /// A virtual offset to a constant that will be emitted in the constant section of the buffer.
506     ConstantOffset(VCodeConstant),
507 }
508 
509 impl SyntheticAmode {
510     /// Create a real addressing mode.
511     pub fn real(amode: Amode) -> Self {
512         Self::Real(amode)
513     }
514 
515     pub(crate) fn slot_offset(simm32: i32) -> Self {
516         SyntheticAmode::SlotOffset { simm32 }
517     }
518 
519     /// Add the registers mentioned by `self` to `collector`.
520     pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
521         match self {
522             SyntheticAmode::Real(addr) => addr.get_operands(collector),
523             SyntheticAmode::IncomingArg { .. } => {
524                 // Nothing to do; the base is known and isn't involved in regalloc.
525             }
526             SyntheticAmode::SlotOffset { .. } => {
527                 // Nothing to do; the base is SP and isn't involved in regalloc.
528             }
529             SyntheticAmode::ConstantOffset(_) => {}
530         }
531     }
532 
533     /// Same as `get_operands`, but add the register in the "late" phase.
534     pub(crate) fn get_operands_late(&mut self, collector: &mut impl OperandVisitor) {
535         match self {
536             SyntheticAmode::Real(addr) => addr.get_operands_late(collector),
537             SyntheticAmode::IncomingArg { .. } => {
538                 // Nothing to do; the base is known and isn't involved in regalloc.
539             }
540             SyntheticAmode::SlotOffset { .. } => {
541                 // Nothing to do; the base is SP and isn't involved in regalloc.
542             }
543             SyntheticAmode::ConstantOffset(_) => {}
544         }
545     }
546 
547     pub(crate) fn finalize(&self, frame: &FrameLayout, buffer: &mut MachBuffer<Inst>) -> Amode {
548         match self {
549             SyntheticAmode::Real(addr) => addr.clone(),
550             SyntheticAmode::IncomingArg { offset } => {
551                 // NOTE: this could be made relative to RSP by adding additional
552                 // offsets from the frame_layout.
553                 let args_max_fp_offset = frame.tail_args_size + frame.setup_area_size;
554                 Amode::imm_reg(
555                     i32::try_from(args_max_fp_offset - offset).unwrap(),
556                     regs::rbp(),
557                 )
558             }
559             SyntheticAmode::SlotOffset { simm32 } => {
560                 let off = *simm32 as i64 + i64::from(frame.outgoing_args_size);
561                 Amode::imm_reg(off.try_into().expect("invalid sp offset"), regs::rsp())
562             }
563             SyntheticAmode::ConstantOffset(c) => {
564                 Amode::rip_relative(buffer.get_label_for_constant(*c))
565             }
566         }
567     }
568 
569     pub(crate) fn aligned(&self) -> bool {
570         match self {
571             SyntheticAmode::Real(addr) => addr.aligned(),
572             &SyntheticAmode::IncomingArg { .. }
573             | SyntheticAmode::SlotOffset { .. }
574             | SyntheticAmode::ConstantOffset { .. } => true,
575         }
576     }
577 }
578 
579 impl From<Amode> for SyntheticAmode {
580     fn from(amode: Amode) -> SyntheticAmode {
581         SyntheticAmode::Real(amode)
582     }
583 }
584 
585 impl From<VCodeConstant> for SyntheticAmode {
586     fn from(c: VCodeConstant) -> SyntheticAmode {
587         SyntheticAmode::ConstantOffset(c)
588     }
589 }
590 
591 impl PrettyPrint for SyntheticAmode {
592     fn pretty_print(&self, _size: u8) -> String {
593         match self {
594             // See note in `Amode` regarding constant size of `8`.
595             SyntheticAmode::Real(addr) => addr.pretty_print(8),
596             &SyntheticAmode::IncomingArg { offset } => {
597                 format!("rbp(stack args max - {offset})")
598             }
599             SyntheticAmode::SlotOffset { simm32 } => {
600                 format!("rsp({} + virtual offset)", *simm32)
601             }
602             SyntheticAmode::ConstantOffset(c) => format!("const({})", c.as_u32()),
603         }
604     }
605 }
606 
607 /// An operand which is either an integer Register, a value in Memory or an Immediate.  This can
608 /// denote an 8, 16, 32 or 64 bit value.  For the Immediate form, in the 8- and 16-bit case, only
609 /// the lower 8 or 16 bits of `simm32` is relevant.  In the 64-bit case, the value denoted by
610 /// `simm32` is its sign-extension out to 64 bits.
611 #[derive(Clone, Debug)]
612 pub enum RegMemImm {
613     /// A register operand.
614     Reg {
615         /// The underlying register.
616         reg: Reg,
617     },
618     /// A memory operand.
619     Mem {
620         /// The memory address.
621         addr: SyntheticAmode,
622     },
623     /// An immediate operand.
624     Imm {
625         /// The immediate value.
626         simm32: u32,
627     },
628 }
629 
630 impl RegMemImm {
631     /// Create a register operand.
632     pub fn reg(reg: Reg) -> Self {
633         debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float);
634         Self::Reg { reg }
635     }
636 
637     /// Create a memory operand.
638     pub fn mem(addr: impl Into<SyntheticAmode>) -> Self {
639         Self::Mem { addr: addr.into() }
640     }
641 
642     /// Create an immediate operand.
643     pub fn imm(simm32: u32) -> Self {
644         Self::Imm { simm32 }
645     }
646 
647     /// Add the regs mentioned by `self` to `collector`.
648     pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
649         match self {
650             Self::Reg { reg } => collector.reg_use(reg),
651             Self::Mem { addr } => addr.get_operands(collector),
652             Self::Imm { .. } => {}
653         }
654     }
655 }
656 
657 impl From<RegMem> for RegMemImm {
658     fn from(rm: RegMem) -> RegMemImm {
659         match rm {
660             RegMem::Reg { reg } => RegMemImm::Reg { reg },
661             RegMem::Mem { addr } => RegMemImm::Mem { addr },
662         }
663     }
664 }
665 
666 impl From<Reg> for RegMemImm {
667     fn from(reg: Reg) -> Self {
668         RegMemImm::Reg { reg }
669     }
670 }
671 
672 impl PrettyPrint for RegMemImm {
673     fn pretty_print(&self, size: u8) -> String {
674         match self {
675             Self::Reg { reg } => pretty_print_reg(*reg, size),
676             Self::Mem { addr } => addr.pretty_print(size),
677             Self::Imm { simm32 } => format!("${}", *simm32 as i32),
678         }
679     }
680 }
681 
682 /// An operand which is either an integer Register or a value in Memory.  This can denote an 8, 16,
683 /// 32, 64, or 128 bit value.
684 #[derive(Clone, Debug)]
685 pub enum RegMem {
686     /// A register operand.
687     Reg {
688         /// The underlying register.
689         reg: Reg,
690     },
691     /// A memory operand.
692     Mem {
693         /// The memory address.
694         addr: SyntheticAmode,
695     },
696 }
697 
698 impl RegMem {
699     /// Create a register operand.
700     pub fn reg(reg: Reg) -> Self {
701         debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float);
702         Self::Reg { reg }
703     }
704 
705     /// Create a memory operand.
706     pub fn mem(addr: impl Into<SyntheticAmode>) -> Self {
707         Self::Mem { addr: addr.into() }
708     }
709     /// Asserts that in register mode, the reg class is the one that's expected.
710     pub(crate) fn assert_regclass_is(&self, expected_reg_class: RegClass) {
711         if let Self::Reg { reg } = self {
712             debug_assert_eq!(reg.class(), expected_reg_class);
713         }
714     }
715     /// Add the regs mentioned by `self` to `collector`.
716     pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
717         match self {
718             RegMem::Reg { reg } => collector.reg_use(reg),
719             RegMem::Mem { addr, .. } => addr.get_operands(collector),
720         }
721     }
722 }
723 
724 impl From<Reg> for RegMem {
725     fn from(reg: Reg) -> RegMem {
726         RegMem::Reg { reg }
727     }
728 }
729 
730 impl From<Writable<Reg>> for RegMem {
731     fn from(r: Writable<Reg>) -> Self {
732         RegMem::reg(r.to_reg())
733     }
734 }
735 
736 impl PrettyPrint for RegMem {
737     fn pretty_print(&self, size: u8) -> String {
738         match self {
739             RegMem::Reg { reg } => pretty_print_reg(*reg, size),
740             RegMem::Mem { addr, .. } => addr.pretty_print(size),
741         }
742     }
743 }
744 
745 #[derive(Debug)]
746 pub(crate) enum InstructionSet {
747     SSE,
748     SSE2,
749     CMPXCHG16b,
750     SSE3,
751     SSSE3,
752     SSE41,
753     SSE42,
754     Popcnt,
755     Lzcnt,
756     BMI1,
757     #[allow(dead_code)] // never constructed (yet).
758     BMI2,
759     FMA,
760     AVX,
761     AVX2,
762     AVX512BITALG,
763     AVX512DQ,
764     AVX512F,
765     AVX512VBMI,
766     AVX512VL,
767 }
768 
769 /// Some SSE operations requiring 2 operands r/m and r.
770 #[derive(Clone, Copy, PartialEq)]
771 #[allow(dead_code)] // some variants here aren't used just yet
772 #[allow(missing_docs)]
773 pub enum SseOpcode {
774     Blendvpd,
775     Blendvps,
776     Insertps,
777     Pabsb,
778     Pabsw,
779     Pabsd,
780     Packssdw,
781     Packsswb,
782     Packusdw,
783     Packuswb,
784     Palignr,
785     Pavgb,
786     Pavgw,
787     Pblendvb,
788     Pcmpeqb,
789     Pcmpeqw,
790     Pcmpeqd,
791     Pcmpeqq,
792     Pcmpgtb,
793     Pcmpgtw,
794     Pcmpgtd,
795     Pcmpgtq,
796     Pmaddubsw,
797     Pmaddwd,
798     Pshufb,
799     Pshufd,
800     Ptest,
801     Rcpss,
802     Roundps,
803     Roundpd,
804     Roundss,
805     Roundsd,
806     Rsqrtss,
807     Shufps,
808     Pshuflw,
809     Pshufhw,
810     Pblendw,
811 }
812 
813 impl SseOpcode {
814     /// Which `InstructionSet` is the first supporting this opcode?
815     pub(crate) fn available_from(&self) -> InstructionSet {
816         use InstructionSet::*;
817         match self {
818             SseOpcode::Rcpss | SseOpcode::Rsqrtss | SseOpcode::Shufps => SSE,
819 
820             SseOpcode::Packssdw
821             | SseOpcode::Packsswb
822             | SseOpcode::Packuswb
823             | SseOpcode::Pavgb
824             | SseOpcode::Pavgw
825             | SseOpcode::Pcmpeqb
826             | SseOpcode::Pcmpeqw
827             | SseOpcode::Pcmpeqd
828             | SseOpcode::Pcmpgtb
829             | SseOpcode::Pcmpgtw
830             | SseOpcode::Pcmpgtd
831             | SseOpcode::Pmaddwd
832             | SseOpcode::Pshufd
833             | SseOpcode::Pshuflw
834             | SseOpcode::Pshufhw => SSE2,
835 
836             SseOpcode::Pabsb
837             | SseOpcode::Pabsw
838             | SseOpcode::Pabsd
839             | SseOpcode::Palignr
840             | SseOpcode::Pshufb
841             | SseOpcode::Pmaddubsw => SSSE3,
842 
843             SseOpcode::Blendvpd
844             | SseOpcode::Blendvps
845             | SseOpcode::Insertps
846             | SseOpcode::Packusdw
847             | SseOpcode::Pblendvb
848             | SseOpcode::Pcmpeqq
849             | SseOpcode::Ptest
850             | SseOpcode::Roundps
851             | SseOpcode::Roundpd
852             | SseOpcode::Roundss
853             | SseOpcode::Roundsd
854             | SseOpcode::Pblendw => SSE41,
855 
856             SseOpcode::Pcmpgtq => SSE42,
857         }
858     }
859 
860     /// Returns the src operand size for an instruction.
861     pub(crate) fn src_size(&self) -> u8 {
862         match self {
863             _ => 8,
864         }
865     }
866 
867     /// Is `src2` with this opcode a scalar, as for lane insertions?
868     pub(crate) fn has_scalar_src2(self) -> bool {
869         false
870     }
871 }
872 
873 impl fmt::Debug for SseOpcode {
874     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
875         let name = match self {
876             SseOpcode::Blendvpd => "blendvpd",
877             SseOpcode::Blendvps => "blendvps",
878             SseOpcode::Insertps => "insertps",
879             SseOpcode::Pabsb => "pabsb",
880             SseOpcode::Pabsw => "pabsw",
881             SseOpcode::Pabsd => "pabsd",
882             SseOpcode::Packssdw => "packssdw",
883             SseOpcode::Packsswb => "packsswb",
884             SseOpcode::Packusdw => "packusdw",
885             SseOpcode::Packuswb => "packuswb",
886             SseOpcode::Palignr => "palignr",
887             SseOpcode::Pavgb => "pavgb",
888             SseOpcode::Pavgw => "pavgw",
889             SseOpcode::Pblendvb => "pblendvb",
890             SseOpcode::Pcmpeqb => "pcmpeqb",
891             SseOpcode::Pcmpeqw => "pcmpeqw",
892             SseOpcode::Pcmpeqd => "pcmpeqd",
893             SseOpcode::Pcmpeqq => "pcmpeqq",
894             SseOpcode::Pcmpgtb => "pcmpgtb",
895             SseOpcode::Pcmpgtw => "pcmpgtw",
896             SseOpcode::Pcmpgtd => "pcmpgtd",
897             SseOpcode::Pcmpgtq => "pcmpgtq",
898             SseOpcode::Pmaddubsw => "pmaddubsw",
899             SseOpcode::Pmaddwd => "pmaddwd",
900             SseOpcode::Pshufb => "pshufb",
901             SseOpcode::Pshufd => "pshufd",
902             SseOpcode::Ptest => "ptest",
903             SseOpcode::Rcpss => "rcpss",
904             SseOpcode::Roundps => "roundps",
905             SseOpcode::Roundpd => "roundpd",
906             SseOpcode::Roundss => "roundss",
907             SseOpcode::Roundsd => "roundsd",
908             SseOpcode::Rsqrtss => "rsqrtss",
909             SseOpcode::Shufps => "shufps",
910             SseOpcode::Pshuflw => "pshuflw",
911             SseOpcode::Pshufhw => "pshufhw",
912             SseOpcode::Pblendw => "pblendw",
913         };
914         write!(fmt, "{name}")
915     }
916 }
917 
918 impl fmt::Display for SseOpcode {
919     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
920         fmt::Debug::fmt(self, f)
921     }
922 }
923 
924 pub use crate::isa::x64::lower::isle::generated_code::AvxOpcode;
925 
926 impl AvxOpcode {
927     /// Which `InstructionSet`s support the opcode?
928     pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> {
929         match self {
930             AvxOpcode::Vpacksswb
931             | AvxOpcode::Vpackssdw
932             | AvxOpcode::Vpackuswb
933             | AvxOpcode::Vpackusdw
934             | AvxOpcode::Vpalignr
935             | AvxOpcode::Vpmaddwd
936             | AvxOpcode::Vpmaddubsw
937             | AvxOpcode::Vinsertps
938             | AvxOpcode::Vpshufb
939             | AvxOpcode::Vshufps
940             | AvxOpcode::Vphaddw
941             | AvxOpcode::Vphaddd
942             | AvxOpcode::Vmovss
943             | AvxOpcode::Vmovsd
944             | AvxOpcode::Vmovups
945             | AvxOpcode::Vmovupd
946             | AvxOpcode::Vmovdqu
947             | AvxOpcode::Vpblendw
948             | AvxOpcode::Vptest => {
949                 smallvec![InstructionSet::AVX]
950             }
951         }
952     }
953 
954     /// Is the opcode known to be commutative?
955     ///
956     /// Note that this method is not exhaustive, and there may be commutative
957     /// opcodes that we don't recognize as commutative.
958     pub(crate) fn is_commutative(&self) -> bool {
959         false
960     }
961 }
962 
963 impl fmt::Display for AvxOpcode {
964     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
965         format!("{self:?}").to_lowercase().fmt(f)
966     }
967 }
968 
969 #[derive(Copy, Clone, PartialEq)]
970 #[allow(missing_docs)]
971 pub enum Avx512TupleType {
972     Full,
973     FullMem,
974     Mem128,
975 }
976 
977 pub use crate::isa::x64::lower::isle::generated_code::Avx512Opcode;
978 
979 impl Avx512Opcode {
980     /// Which `InstructionSet`s support the opcode?
981     pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> {
982         match self {
983             Avx512Opcode::Vcvtudq2ps
984             | Avx512Opcode::Vpabsq
985             | Avx512Opcode::Vpsraq
986             | Avx512Opcode::VpsraqImm => {
987                 smallvec![InstructionSet::AVX512F, InstructionSet::AVX512VL]
988             }
989             Avx512Opcode::Vpermi2b => {
990                 smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512VBMI]
991             }
992             Avx512Opcode::Vpmullq => smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512DQ],
993             Avx512Opcode::Vpopcntb => {
994                 smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512BITALG]
995             }
996         }
997     }
998 
999     /// What is the "TupleType" of this opcode, which affects the scaling factor
1000     /// for 8-bit displacements when this instruction uses memory operands.
1001     ///
1002     /// This can be found in the encoding table for each instruction and is
1003     /// interpreted according to Table 2-34 and 2-35 in the Intel instruction
1004     /// manual.
1005     pub fn tuple_type(&self) -> Avx512TupleType {
1006         use Avx512Opcode::*;
1007         use Avx512TupleType::*;
1008 
1009         match self {
1010             Vcvtudq2ps | Vpabsq | Vpmullq | VpsraqImm => Full,
1011             Vpermi2b | Vpopcntb => FullMem,
1012             Vpsraq => Mem128,
1013         }
1014     }
1015 }
1016 
1017 impl fmt::Display for Avx512Opcode {
1018     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1019         let s = format!("{self:?}");
1020         f.write_str(&s.to_lowercase())
1021     }
1022 }
1023 
1024 /// This defines the ways a value can be extended: either signed- or zero-extension, or none for
1025 /// types that are not extended. Contrast with [ExtMode], which defines the widths from and to which
1026 /// values can be extended.
1027 #[allow(dead_code)]
1028 #[derive(Clone, PartialEq)]
1029 pub enum ExtKind {
1030     /// No extension.
1031     None,
1032     /// Sign-extend.
1033     SignExtend,
1034     /// Zero-extend.
1035     ZeroExtend,
1036 }
1037 
1038 /// These indicate ways of extending (widening) a value, using the Intel
1039 /// naming: B(yte) = u8, W(ord) = u16, L(ong)word = u32, Q(uad)word = u64
1040 #[derive(Clone, PartialEq)]
1041 pub enum ExtMode {
1042     /// Byte -> Longword.
1043     BL,
1044     /// Byte -> Quadword.
1045     BQ,
1046     /// Word -> Longword.
1047     WL,
1048     /// Word -> Quadword.
1049     WQ,
1050     /// Longword -> Quadword.
1051     LQ,
1052 }
1053 
1054 impl ExtMode {
1055     /// Calculate the `ExtMode` from passed bit lengths of the from/to types.
1056     pub(crate) fn new(from_bits: u16, to_bits: u16) -> Option<ExtMode> {
1057         match (from_bits, to_bits) {
1058             (1, 8) | (1, 16) | (1, 32) | (8, 16) | (8, 32) => Some(ExtMode::BL),
1059             (1, 64) | (8, 64) => Some(ExtMode::BQ),
1060             (16, 32) => Some(ExtMode::WL),
1061             (16, 64) => Some(ExtMode::WQ),
1062             (32, 64) => Some(ExtMode::LQ),
1063             _ => None,
1064         }
1065     }
1066 }
1067 
1068 impl fmt::Debug for ExtMode {
1069     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1070         let name = match self {
1071             ExtMode::BL => "bl",
1072             ExtMode::BQ => "bq",
1073             ExtMode::WL => "wl",
1074             ExtMode::WQ => "wq",
1075             ExtMode::LQ => "lq",
1076         };
1077         write!(fmt, "{name}")
1078     }
1079 }
1080 
1081 impl fmt::Display for ExtMode {
1082     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1083         fmt::Debug::fmt(self, f)
1084     }
1085 }
1086 
1087 /// These indicate condition code tests.  Not all are represented since not all are useful in
1088 /// compiler-generated code.
1089 #[derive(Copy, Clone, PartialEq, Eq)]
1090 #[repr(u8)]
1091 pub enum CC {
1092     ///  overflow
1093     O = 0,
1094     /// no overflow
1095     NO = 1,
1096 
1097     /// < unsigned
1098     B = 2,
1099     /// >= unsigned
1100     NB = 3,
1101 
1102     /// zero
1103     Z = 4,
1104     /// not-zero
1105     NZ = 5,
1106 
1107     /// <= unsigned
1108     BE = 6,
1109     /// > unsigned
1110     NBE = 7,
1111 
1112     /// negative
1113     S = 8,
1114     /// not-negative
1115     NS = 9,
1116 
1117     /// < signed
1118     L = 12,
1119     /// >= signed
1120     NL = 13,
1121 
1122     /// <= signed
1123     LE = 14,
1124     /// > signed
1125     NLE = 15,
1126 
1127     /// parity
1128     P = 10,
1129 
1130     /// not parity
1131     NP = 11,
1132 }
1133 
1134 impl CC {
1135     pub(crate) fn from_intcc(intcc: IntCC) -> Self {
1136         match intcc {
1137             IntCC::Equal => CC::Z,
1138             IntCC::NotEqual => CC::NZ,
1139             IntCC::SignedGreaterThanOrEqual => CC::NL,
1140             IntCC::SignedGreaterThan => CC::NLE,
1141             IntCC::SignedLessThanOrEqual => CC::LE,
1142             IntCC::SignedLessThan => CC::L,
1143             IntCC::UnsignedGreaterThanOrEqual => CC::NB,
1144             IntCC::UnsignedGreaterThan => CC::NBE,
1145             IntCC::UnsignedLessThanOrEqual => CC::BE,
1146             IntCC::UnsignedLessThan => CC::B,
1147         }
1148     }
1149 
1150     pub(crate) fn invert(&self) -> Self {
1151         match self {
1152             CC::O => CC::NO,
1153             CC::NO => CC::O,
1154 
1155             CC::B => CC::NB,
1156             CC::NB => CC::B,
1157 
1158             CC::Z => CC::NZ,
1159             CC::NZ => CC::Z,
1160 
1161             CC::BE => CC::NBE,
1162             CC::NBE => CC::BE,
1163 
1164             CC::S => CC::NS,
1165             CC::NS => CC::S,
1166 
1167             CC::L => CC::NL,
1168             CC::NL => CC::L,
1169 
1170             CC::LE => CC::NLE,
1171             CC::NLE => CC::LE,
1172 
1173             CC::P => CC::NP,
1174             CC::NP => CC::P,
1175         }
1176     }
1177 
1178     pub(crate) fn get_enc(self) -> u8 {
1179         self as u8
1180     }
1181 }
1182 
1183 impl fmt::Debug for CC {
1184     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1185         let name = match self {
1186             CC::O => "o",
1187             CC::NO => "no",
1188             CC::B => "b",
1189             CC::NB => "nb",
1190             CC::Z => "z",
1191             CC::NZ => "nz",
1192             CC::BE => "be",
1193             CC::NBE => "nbe",
1194             CC::S => "s",
1195             CC::NS => "ns",
1196             CC::L => "l",
1197             CC::NL => "nl",
1198             CC::LE => "le",
1199             CC::NLE => "nle",
1200             CC::P => "p",
1201             CC::NP => "np",
1202         };
1203         write!(fmt, "{name}")
1204     }
1205 }
1206 
1207 impl fmt::Display for CC {
1208     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1209         fmt::Debug::fmt(self, f)
1210     }
1211 }
1212 
1213 /// Encode the ways that floats can be compared. This is used in float comparisons such as `cmpps`,
1214 /// e.g.; it is distinguished from other float comparisons (e.g. `ucomiss`) in that those use EFLAGS
1215 /// whereas [FcmpImm] is used as an immediate.
1216 #[derive(Clone, Copy)]
1217 pub enum FcmpImm {
1218     /// Equal comparison.
1219     Equal = 0x00,
1220     /// Less than comparison.
1221     LessThan = 0x01,
1222     /// Less than or equal comparison.
1223     LessThanOrEqual = 0x02,
1224     /// Unordered.
1225     Unordered = 0x03,
1226     /// Not equal comparison.
1227     NotEqual = 0x04,
1228     /// Unordered of greater than or equal comparison.
1229     UnorderedOrGreaterThanOrEqual = 0x05,
1230     /// Unordered or greater than comparison.
1231     UnorderedOrGreaterThan = 0x06,
1232     /// Ordered.
1233     Ordered = 0x07,
1234 }
1235 
1236 impl FcmpImm {
1237     pub(crate) fn encode(self) -> u8 {
1238         self as u8
1239     }
1240 }
1241 
1242 impl From<FloatCC> for FcmpImm {
1243     fn from(cond: FloatCC) -> Self {
1244         match cond {
1245             FloatCC::Equal => FcmpImm::Equal,
1246             FloatCC::LessThan => FcmpImm::LessThan,
1247             FloatCC::LessThanOrEqual => FcmpImm::LessThanOrEqual,
1248             FloatCC::Unordered => FcmpImm::Unordered,
1249             FloatCC::NotEqual => FcmpImm::NotEqual,
1250             FloatCC::UnorderedOrGreaterThanOrEqual => FcmpImm::UnorderedOrGreaterThanOrEqual,
1251             FloatCC::UnorderedOrGreaterThan => FcmpImm::UnorderedOrGreaterThan,
1252             FloatCC::Ordered => FcmpImm::Ordered,
1253             _ => panic!("unable to create comparison predicate for {cond}"),
1254         }
1255     }
1256 }
1257 
1258 /// Encode the rounding modes used as part of the Rounding Control field.
1259 /// Note, these rounding immediates only consider the rounding control field
1260 /// (i.e. the rounding mode) which only take up the first two bits when encoded.
1261 /// However the rounding immediate which this field helps make up, also includes
1262 /// bits 3 and 4 which define the rounding select and precision mask respectively.
1263 /// These two bits are not defined here and are implicitly set to zero when encoded.
1264 #[derive(Clone, Copy)]
1265 pub enum RoundImm {
1266     /// Round to nearest mode.
1267     RoundNearest = 0x00,
1268     /// Round down mode.
1269     RoundDown = 0x01,
1270     /// Round up mode.
1271     RoundUp = 0x02,
1272     /// Round to zero mode.
1273     RoundZero = 0x03,
1274 }
1275 
1276 impl RoundImm {
1277     pub(crate) fn encode(self) -> u8 {
1278         self as u8
1279     }
1280 }
1281 
1282 /// An operand's size in bits.
1283 #[derive(Clone, Copy, PartialEq)]
1284 pub enum OperandSize {
1285     /// 8-bit.
1286     Size8,
1287     /// 16-bit.
1288     Size16,
1289     /// 32-bit.
1290     Size32,
1291     /// 64-bit.
1292     Size64,
1293 }
1294 
1295 impl OperandSize {
1296     pub(crate) fn from_bytes(num_bytes: u32) -> Self {
1297         match num_bytes {
1298             1 => OperandSize::Size8,
1299             2 => OperandSize::Size16,
1300             4 => OperandSize::Size32,
1301             8 => OperandSize::Size64,
1302             _ => unreachable!("Invalid OperandSize: {}", num_bytes),
1303         }
1304     }
1305 
1306     // Computes the OperandSize for a given type.
1307     // For vectors, the OperandSize of the lanes is returned.
1308     pub(crate) fn from_ty(ty: Type) -> Self {
1309         Self::from_bytes(ty.lane_type().bytes())
1310     }
1311 
1312     // Check that the value of self is one of the allowed sizes.
1313     pub(crate) fn is_one_of(&self, sizes: &[Self]) -> bool {
1314         sizes.iter().any(|val| *self == *val)
1315     }
1316 
1317     pub(crate) fn to_bytes(&self) -> u8 {
1318         match self {
1319             Self::Size8 => 1,
1320             Self::Size16 => 2,
1321             Self::Size32 => 4,
1322             Self::Size64 => 8,
1323         }
1324     }
1325 
1326     pub(crate) fn to_bits(&self) -> u8 {
1327         self.to_bytes() * 8
1328     }
1329 
1330     pub(crate) fn to_type(&self) -> Type {
1331         match self {
1332             Self::Size8 => I8,
1333             Self::Size16 => I16,
1334             Self::Size32 => I32,
1335             Self::Size64 => I64,
1336         }
1337     }
1338 }
1339