1
//! Instruction operand sub-components (aka "parts"): definitions and printing.
2

            
3
use super::regs::{self};
4
use super::EmitState;
5
use crate::ir::condcodes::{FloatCC, IntCC};
6
use crate::ir::{MemFlags, Type};
7
use crate::isa::x64::inst::regs::pretty_print_reg;
8
use crate::isa::x64::inst::Inst;
9
use crate::machinst::*;
10
use regalloc2::VReg;
11
use smallvec::{smallvec, SmallVec};
12
use std::fmt;
13
use std::string::String;
14

            
15
pub use crate::isa::x64::lower::isle::generated_code::DivSignedness;
16

            
17
/// An extenstion trait for converting `Writable{Xmm,Gpr}` to `Writable<Reg>`.
18
pub trait ToWritableReg {
19
    /// Convert `Writable{Xmm,Gpr}` to `Writable<Reg>`.
20
    fn to_writable_reg(&self) -> Writable<Reg>;
21
}
22

            
23
/// An extension trait for converting `Writable<Reg>` to `Writable{Xmm,Gpr}`.
24
pub trait FromWritableReg: Sized {
25
    /// Convert `Writable<Reg>` to `Writable{Xmm,Gpr}`.
26
    fn from_writable_reg(w: Writable<Reg>) -> Option<Self>;
27
}
28

            
29
/// A macro for defining a newtype of `Reg` that enforces some invariant about
30
/// the wrapped `Reg` (such as that it is of a particular register class).
31
macro_rules! newtype_of_reg {
32
    (
33
        $newtype_reg:ident,
34
        $newtype_writable_reg:ident,
35
        $newtype_option_writable_reg:ident,
36
        reg_mem: ($($newtype_reg_mem:ident $(aligned:$aligned:ident)?),*),
37
        reg_mem_imm: ($($newtype_reg_mem_imm:ident $(aligned:$aligned_imm:ident)?),*),
38
        $newtype_imm8_reg:ident,
39
        |$check_reg:ident| $check:expr
40
    ) => {
41
        /// A newtype wrapper around `Reg`.
42
        #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
43
        pub struct $newtype_reg(Reg);
44

            
45
        impl PartialEq<Reg> for $newtype_reg {
46
            fn eq(&self, other: &Reg) -> bool {
47
                self.0 == *other
48
            }
49
        }
50

            
51
        impl From<$newtype_reg> for Reg {
52
            fn from(r: $newtype_reg) -> Self {
53
                r.0
54
            }
55
        }
56

            
57
        impl $newtype_reg {
58
            /// Create this newtype from the given register, or return `None` if the register
59
            /// is not a valid instance of this newtype.
60
            pub fn new($check_reg: Reg) -> Option<Self> {
61
                if $check {
62
                    Some(Self($check_reg))
63
                } else {
64
                    None
65
                }
66
            }
67

            
68
            /// Get this newtype's underlying `Reg`.
69
            pub fn to_reg(self) -> Reg {
70
                self.0
71
            }
72
        }
73

            
74
        // Convenience impl so that people working with this newtype can use it
75
        // "just like" a plain `Reg`.
76
        //
77
        // NB: We cannot implement `DerefMut` because that would let people do
78
        // nasty stuff like `*my_gpr.deref_mut() = some_xmm_reg`, breaking the
79
        // invariants that `Gpr` provides.
80
        impl std::ops::Deref for $newtype_reg {
81
            type Target = Reg;
82

            
83
            fn deref(&self) -> &Reg {
84
                &self.0
85
            }
86
        }
87

            
88
        /// Writable Gpr.
89
        pub type $newtype_writable_reg = Writable<$newtype_reg>;
90

            
91
        #[allow(dead_code)] // Used by some newtypes and not others.
92
        /// Optional writable Gpr.
93
        pub type $newtype_option_writable_reg = Option<Writable<$newtype_reg>>;
94

            
95
        impl ToWritableReg for $newtype_writable_reg {
96
            fn to_writable_reg(&self) -> Writable<Reg> {
97
                Writable::from_reg(self.to_reg().to_reg())
98
            }
99
        }
100

            
101
        impl FromWritableReg for $newtype_writable_reg {
102
            fn from_writable_reg(w: Writable<Reg>) -> Option<Self> {
103
                Some(Writable::from_reg($newtype_reg::new(w.to_reg())?))
104
            }
105
        }
106

            
107
        $(
108
            /// A newtype wrapper around `RegMem` for general-purpose registers.
109
            #[derive(Clone, Debug)]
110
            pub struct $newtype_reg_mem(RegMem);
111

            
112
            impl From<$newtype_reg_mem> for RegMem {
113
                fn from(rm: $newtype_reg_mem) -> Self {
114
                    rm.0
115
                }
116
            }
117

            
118
            impl From<$newtype_reg> for $newtype_reg_mem {
119
                fn from(r: $newtype_reg) -> Self {
120
                    $newtype_reg_mem(RegMem::reg(r.into()))
121
                }
122
            }
123

            
124
            impl $newtype_reg_mem {
125
                /// Construct a `RegMem` newtype from the given `RegMem`, or return
126
                /// `None` if the `RegMem` is not a valid instance of this `RegMem`
127
                /// newtype.
128
                pub fn new(rm: RegMem) -> Option<Self> {
129
                    match rm {
130
                        RegMem::Mem { addr } => {
131
                            let mut _allow = true;
132
                            $(
133
                                if $aligned {
134
                                    _allow = addr.aligned();
135
                                }
136
                            )?
137
                            if _allow {
138
                                Some(Self(RegMem::Mem { addr }))
139
                            } else {
140
                                None
141
                            }
142
                        }
143
                        RegMem::Reg { reg: $check_reg } if $check => Some(Self(rm)),
144
                        RegMem::Reg { reg: _ } => None,
145
                    }
146
                }
147

            
148
                /// Convert this newtype into its underlying `RegMem`.
149
                pub fn to_reg_mem(self) -> RegMem {
150
                    self.0
151
                }
152

            
153
                #[allow(dead_code)] // Used by some newtypes and not others.
154
                pub(crate) fn get_operands<F: Fn(VReg) -> VReg>(
155
                    &self,
156
                    collector: &mut OperandCollector<'_, F>,
157
                ) {
158
                    self.0.get_operands(collector);
159
                }
160
            }
161
            impl PrettyPrint for $newtype_reg_mem {
162
                fn pretty_print(&self, size: u8, allocs: &mut AllocationConsumer<'_>) -> String {
163
                    self.0.pretty_print(size, allocs)
164
                }
165
            }
166
        )*
167

            
168
        $(
169
            /// A newtype wrapper around `RegMemImm`.
170
            #[derive(Clone, Debug)]
171
            pub struct $newtype_reg_mem_imm(RegMemImm);
172

            
173
            impl From<$newtype_reg_mem_imm> for RegMemImm {
174
                fn from(rmi: $newtype_reg_mem_imm) -> RegMemImm {
175
                    rmi.0
176
                }
177
            }
178

            
179
            impl From<$newtype_reg> for $newtype_reg_mem_imm {
180
                fn from(r: $newtype_reg) -> Self {
181
                    $newtype_reg_mem_imm(RegMemImm::reg(r.into()))
182
                }
183
            }
184

            
185
            impl $newtype_reg_mem_imm {
186
                /// Construct this newtype from the given `RegMemImm`, or return
187
                /// `None` if the `RegMemImm` is not a valid instance of this
188
                /// newtype.
189
                pub fn new(rmi: RegMemImm) -> Option<Self> {
190
                    match rmi {
191
                        RegMemImm::Imm { .. } => Some(Self(rmi)),
192
                        RegMemImm::Mem { addr } => {
193
                            let mut _allow = true;
194
                            $(
195
                                if $aligned_imm {
196
                                    _allow = addr.aligned();
197
                                }
198
                            )?
199
                            if _allow {
200
                                Some(Self(RegMemImm::Mem { addr }))
201
                            } else {
202
                                None
203
                            }
204
                        }
205
                        RegMemImm::Reg { reg: $check_reg } if $check => Some(Self(rmi)),
206
                        RegMemImm::Reg { reg: _ } => None,
207
                    }
208
                }
209

            
210
                /// Convert this newtype into its underlying `RegMemImm`.
211
                #[allow(dead_code)] // Used by some newtypes and not others.
212
                pub fn to_reg_mem_imm(self) -> RegMemImm {
213
                    self.0
214
                }
215

            
216
                #[allow(dead_code)] // Used by some newtypes and not others.
217
                pub(crate) fn get_operands<F: Fn(VReg) -> VReg>(
218
                    &self,
219
                    collector: &mut OperandCollector<'_, F>,
220
                ) {
221
                    self.0.get_operands(collector);
222
                }
223
            }
224

            
225
            impl PrettyPrint for $newtype_reg_mem_imm {
226
                fn pretty_print(&self, size: u8, allocs: &mut AllocationConsumer<'_>) -> String {
227
                    self.0.pretty_print(size, allocs)
228
                }
229
            }
230
        )*
231

            
232
        /// A newtype wrapper around `Imm8Reg`.
233
        #[derive(Clone, Debug)]
234
        #[allow(dead_code)] // Used by some newtypes and not others.
235
        pub struct $newtype_imm8_reg(Imm8Reg);
236

            
237
        impl From<$newtype_reg> for $newtype_imm8_reg {
238
            fn from(r: $newtype_reg) -> Self {
239
                Self(Imm8Reg::Reg { reg: r.to_reg() })
240
            }
241
        }
242

            
243
        impl $newtype_imm8_reg {
244
            /// Construct this newtype from the given `Imm8Reg`, or return
245
            /// `None` if the `Imm8Reg` is not a valid instance of this newtype.
246
            #[allow(dead_code)] // Used by some newtypes and not others.
247
            pub fn new(imm8_reg: Imm8Reg) -> Option<Self> {
248
                match imm8_reg {
249
                    Imm8Reg::Imm8 { .. } => Some(Self(imm8_reg)),
250
                    Imm8Reg::Reg { reg: $check_reg } if $check => Some(Self(imm8_reg)),
251
                    Imm8Reg::Reg { reg: _ } => None,
252
                }
253
            }
254

            
255
            /// Convert this newtype into its underlying `Imm8Reg`.
256
            #[allow(dead_code)] // Used by some newtypes and not others.
257
            pub fn to_imm8_reg(self) -> Imm8Reg {
258
                self.0
259
            }
260
        }
261
    };
262
}
263

            
264
// Define a newtype of `Reg` for general-purpose registers.
265
newtype_of_reg!(
266
    Gpr,
267
    WritableGpr,
268
    OptionWritableGpr,
269
    reg_mem: (GprMem),
270
    reg_mem_imm: (GprMemImm),
271
    Imm8Gpr,
272
    |reg| reg.class() == RegClass::Int
273
);
274

            
275
// Define a newtype of `Reg` for XMM registers.
276
newtype_of_reg!(
277
    Xmm,
278
    WritableXmm,
279
    OptionWritableXmm,
280
    reg_mem: (XmmMem, XmmMemAligned aligned:true),
281
    reg_mem_imm: (XmmMemImm, XmmMemAlignedImm aligned:true),
282
    Imm8Xmm,
283
    |reg| reg.class() == RegClass::Float
284
);
285

            
286
// N.B.: `Amode` is defined in `inst.isle`. We add some convenience
287
// constructors here.
288

            
289
// Re-export the type from the ISLE generated code.
290
pub use crate::isa::x64::lower::isle::generated_code::Amode;
291

            
292
impl Amode {
293
    /// Create an immediate sign-extended and register addressing mode.
294
    pub fn imm_reg(simm32: u32, base: Reg) -> Self {
295
        debug_assert!(base.class() == RegClass::Int);
296
        Self::ImmReg {
297
            simm32,
298
            base,
299
            flags: MemFlags::trusted(),
300
        }
301
    }
302

            
303
    /// Create a sign-extended-32-to-64 with register and shift addressing mode.
304
    pub fn imm_reg_reg_shift(simm32: u32, base: Gpr, index: Gpr, shift: u8) -> Self {
305
        debug_assert!(base.class() == RegClass::Int);
306
        debug_assert!(index.class() == RegClass::Int);
307
        debug_assert!(shift <= 3);
308
        Self::ImmRegRegShift {
309
            simm32,
310
            base,
311
            index,
312
            shift,
313
            flags: MemFlags::trusted(),
314
        }
315
    }
316

            
317
    pub(crate) fn rip_relative(target: MachLabel) -> Self {
318
        Self::RipRelative { target }
319
    }
320

            
321
    pub(crate) fn with_flags(&self, flags: MemFlags) -> Self {
322
        match self {
323
            &Self::ImmReg { simm32, base, .. } => Self::ImmReg {
324
                simm32,
325
                base,
326
                flags,
327
            },
328
            &Self::ImmRegRegShift {
329
                simm32,
330
                base,
331
                index,
332
                shift,
333
                ..
334
            } => Self::ImmRegRegShift {
335
                simm32,
336
                base,
337
                index,
338
                shift,
339
                flags,
340
            },
341
            _ => panic!("Amode {:?} cannot take memflags", self),
342
        }
343
    }
344

            
345
    /// Add the registers mentioned by `self` to `collector`.
346
    pub(crate) fn get_operands<F: Fn(VReg) -> VReg>(
347
        &self,
348
        collector: &mut OperandCollector<'_, F>,
349
    ) {
350
        match self {
351
            Amode::ImmReg { base, .. } => {
352
                if *base != regs::rbp() && *base != regs::rsp() {
353
                    collector.reg_use(*base);
354
                }
355
            }
356
            Amode::ImmRegRegShift { base, index, .. } => {
357
                debug_assert_ne!(base.to_reg(), regs::rbp());
358
                debug_assert_ne!(base.to_reg(), regs::rsp());
359
                collector.reg_use(base.to_reg());
360
                debug_assert_ne!(index.to_reg(), regs::rbp());
361
                debug_assert_ne!(index.to_reg(), regs::rsp());
362
                collector.reg_use(index.to_reg());
363
            }
364
            Amode::RipRelative { .. } => {
365
                // RIP isn't involved in regalloc.
366
            }
367
        }
368
    }
369

            
370
    /// Same as `get_operands`, but add the registers in the "late" phase.
371
    pub(crate) fn get_operands_late<F: Fn(VReg) -> VReg>(
372
        &self,
373
        collector: &mut OperandCollector<'_, F>,
374
    ) {
375
        match self {
376
            Amode::ImmReg { base, .. } => {
377
                collector.reg_late_use(*base);
378
            }
379
            Amode::ImmRegRegShift { base, index, .. } => {
380
                collector.reg_late_use(base.to_reg());
381
                collector.reg_late_use(index.to_reg());
382
            }
383
            Amode::RipRelative { .. } => {
384
                // RIP isn't involved in regalloc.
385
            }
386
        }
387
    }
388

            
389
    pub(crate) fn get_flags(&self) -> MemFlags {
390
        match self {
391
            Amode::ImmReg { flags, .. } | Amode::ImmRegRegShift { flags, .. } => *flags,
392
            Amode::RipRelative { .. } => MemFlags::trusted(),
393
        }
394
    }
395

            
396
    pub(crate) fn can_trap(&self) -> bool {
397
        !self.get_flags().notrap()
398
    }
399

            
400
    pub(crate) fn with_allocs(&self, allocs: &mut AllocationConsumer<'_>) -> Self {
401
        // The order in which we consume allocs here must match the
402
        // order in which we produce operands in get_operands() above.
403
        match self {
404
            &Amode::ImmReg {
405
                simm32,
406
                base,
407
                flags,
408
            } => {
409
                let base = if base == regs::rsp() || base == regs::rbp() {
410
                    base
411
                } else {
412
                    allocs.next(base)
413
                };
414
                Amode::ImmReg {
415
                    simm32,
416
                    flags,
417
                    base,
418
                }
419
            }
420
            &Amode::ImmRegRegShift {
421
                simm32,
422
                base,
423
                index,
424
                shift,
425
                flags,
426
            } => Amode::ImmRegRegShift {
427
                simm32,
428
                shift,
429
                flags,
430
                base: Gpr::new(allocs.next(*base)).unwrap(),
431
                index: Gpr::new(allocs.next(*index)).unwrap(),
432
            },
433
            &Amode::RipRelative { target } => Amode::RipRelative { target },
434
        }
435
    }
436

            
437
    /// Offset the amode by a fixed offset.
438
    pub(crate) fn offset(&self, offset: u32) -> Self {
439
        let mut ret = self.clone();
440
        match &mut ret {
441
            &mut Amode::ImmReg { ref mut simm32, .. } => *simm32 += offset,
442
            &mut Amode::ImmRegRegShift { ref mut simm32, .. } => *simm32 += offset,
443
            _ => panic!("Cannot offset amode: {:?}", self),
444
        }
445
        ret
446
    }
447

            
448
    pub(crate) fn aligned(&self) -> bool {
449
        self.get_flags().aligned()
450
    }
451
}
452

            
453
impl PrettyPrint for Amode {
454
    fn pretty_print(&self, _size: u8, allocs: &mut AllocationConsumer<'_>) -> String {
455
        match self {
456
            Amode::ImmReg { simm32, base, .. } => {
457
                // Note: size is always 8; the address is 64 bits,
458
                // even if the addressed operand is smaller.
459
                format!("{}({})", *simm32 as i32, pretty_print_reg(*base, 8, allocs))
460
            }
461
            Amode::ImmRegRegShift {
462
                simm32,
463
                base,
464
                index,
465
                shift,
466
                ..
467
            } => format!(
468
                "{}({},{},{})",
469
                *simm32 as i32,
470
                pretty_print_reg(base.to_reg(), 8, allocs),
471
                pretty_print_reg(index.to_reg(), 8, allocs),
472
                1 << shift
473
            ),
474
            Amode::RipRelative { ref target } => format!("label{}(%rip)", target.get()),
475
        }
476
    }
477
}
478

            
479
/// A Memory Address. These denote a 64-bit value only.
480
/// Used for usual addressing modes as well as addressing modes used during compilation, when the
481
/// moving SP offset is not known.
482
#[derive(Clone, Debug)]
483
pub enum SyntheticAmode {
484
    /// A real amode.
485
    Real(Amode),
486

            
487
    /// A (virtual) offset to the "nominal SP" value, which will be recomputed as we push and pop
488
    /// within the function.
489
    NominalSPOffset {
490
        /// The nominal stack pointer value.
491
        simm32: u32,
492
    },
493

            
494
    /// A virtual offset to a constant that will be emitted in the constant section of the buffer.
495
    ConstantOffset(VCodeConstant),
496
}
497

            
498
impl SyntheticAmode {
499
    /// Create a real addressing mode.
500
    pub fn real(amode: Amode) -> Self {
501
        Self::Real(amode)
502
    }
503

            
504
    pub(crate) fn nominal_sp_offset(simm32: u32) -> Self {
505
        SyntheticAmode::NominalSPOffset { simm32 }
506
    }
507

            
508
    /// Add the registers mentioned by `self` to `collector`.
509
    pub(crate) fn get_operands<F: Fn(VReg) -> VReg>(
510
        &self,
511
        collector: &mut OperandCollector<'_, F>,
512
    ) {
513
        match self {
514
            SyntheticAmode::Real(addr) => addr.get_operands(collector),
515
            SyntheticAmode::NominalSPOffset { .. } => {
516
                // Nothing to do; the base is SP and isn't involved in regalloc.
517
            }
518
            SyntheticAmode::ConstantOffset(_) => {}
519
        }
520
    }
521

            
522
    /// Same as `get_operands`, but add the register in the "late" phase.
523
    pub(crate) fn get_operands_late<F: Fn(VReg) -> VReg>(
524
        &self,
525
        collector: &mut OperandCollector<'_, F>,
526
    ) {
527
        match self {
528
            SyntheticAmode::Real(addr) => addr.get_operands_late(collector),
529
            SyntheticAmode::NominalSPOffset { .. } => {
530
                // Nothing to do; the base is SP and isn't involved in regalloc.
531
            }
532
            SyntheticAmode::ConstantOffset(_) => {}
533
        }
534
    }
535

            
536
    pub(crate) fn finalize(&self, state: &mut EmitState, buffer: &MachBuffer<Inst>) -> Amode {
537
        match self {
538
            SyntheticAmode::Real(addr) => addr.clone(),
539
            SyntheticAmode::NominalSPOffset { simm32 } => {
540
                let off = *simm32 as i64 + state.virtual_sp_offset;
541
                // TODO will require a sequence of add etc.
542
                assert!(
543
                    off <= u32::max_value() as i64,
544
                    "amode finalize: add sequence NYI"
545
                );
546
                Amode::imm_reg(off as u32, regs::rsp())
547
            }
548
            SyntheticAmode::ConstantOffset(c) => {
549
                Amode::rip_relative(buffer.get_label_for_constant(*c))
550
            }
551
        }
552
    }
553

            
554
    pub(crate) fn with_allocs(&self, allocs: &mut AllocationConsumer<'_>) -> Self {
555
        match self {
556
            SyntheticAmode::Real(addr) => SyntheticAmode::Real(addr.with_allocs(allocs)),
557
            &SyntheticAmode::NominalSPOffset { .. } | &SyntheticAmode::ConstantOffset { .. } => {
558
                self.clone()
559
            }
560
        }
561
    }
562

            
563
    pub(crate) fn aligned(&self) -> bool {
564
        match self {
565
            SyntheticAmode::Real(addr) => addr.aligned(),
566
            SyntheticAmode::NominalSPOffset { .. } | SyntheticAmode::ConstantOffset { .. } => true,
567
        }
568
    }
569
}
570

            
571
impl Into<SyntheticAmode> for Amode {
572
    fn into(self) -> SyntheticAmode {
573
        SyntheticAmode::Real(self)
574
    }
575
}
576

            
577
impl Into<SyntheticAmode> for VCodeConstant {
578
    fn into(self) -> SyntheticAmode {
579
        SyntheticAmode::ConstantOffset(self)
580
    }
581
}
582

            
583
impl PrettyPrint for SyntheticAmode {
584
    fn pretty_print(&self, _size: u8, allocs: &mut AllocationConsumer<'_>) -> String {
585
        match self {
586
            // See note in `Amode` regarding constant size of `8`.
587
            SyntheticAmode::Real(addr) => addr.pretty_print(8, allocs),
588
            SyntheticAmode::NominalSPOffset { simm32 } => {
589
                format!("rsp({} + virtual offset)", *simm32 as i32)
590
            }
591
            SyntheticAmode::ConstantOffset(c) => format!("const({})", c.as_u32()),
592
        }
593
    }
594
}
595

            
596
/// An operand which is either an integer Register, a value in Memory or an Immediate.  This can
597
/// denote an 8, 16, 32 or 64 bit value.  For the Immediate form, in the 8- and 16-bit case, only
598
/// the lower 8 or 16 bits of `simm32` is relevant.  In the 64-bit case, the value denoted by
599
/// `simm32` is its sign-extension out to 64 bits.
600
#[derive(Clone, Debug)]
601
pub enum RegMemImm {
602
    /// A register operand.
603
    Reg {
604
        /// The underlying register.
605
        reg: Reg,
606
    },
607
    /// A memory operand.
608
    Mem {
609
        /// The memory address.
610
        addr: SyntheticAmode,
611
    },
612
    /// An immediate operand.
613
    Imm {
614
        /// The immediate value.
615
        simm32: u32,
616
    },
617
}
618

            
619
impl RegMemImm {
620
    /// Create a register operand.
621
    pub fn reg(reg: Reg) -> Self {
622
        debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float);
623
        Self::Reg { reg }
624
    }
625

            
626
    /// Create a memory operand.
627
    pub fn mem(addr: impl Into<SyntheticAmode>) -> Self {
628
        Self::Mem { addr: addr.into() }
629
    }
630

            
631
    /// Create an immediate operand.
632
    pub fn imm(simm32: u32) -> Self {
633
        Self::Imm { simm32 }
634
    }
635

            
636
    /// Asserts that in register mode, the reg class is the one that's expected.
637
    pub(crate) fn assert_regclass_is(&self, expected_reg_class: RegClass) {
638
        if let Self::Reg { reg } = self {
639
            debug_assert_eq!(reg.class(), expected_reg_class);
640
        }
641
    }
642

            
643
    /// Add the regs mentioned by `self` to `collector`.
644
    pub(crate) fn get_operands<F: Fn(VReg) -> VReg>(
645
        &self,
646
        collector: &mut OperandCollector<'_, F>,
647
    ) {
648
        match self {
649
            Self::Reg { reg } => collector.reg_use(*reg),
650
            Self::Mem { addr } => addr.get_operands(collector),
651
            Self::Imm { .. } => {}
652
        }
653
    }
654

            
655
    pub(crate) fn with_allocs(&self, allocs: &mut AllocationConsumer<'_>) -> Self {
656
        match self {
657
            Self::Reg { reg } => Self::Reg {
658
                reg: allocs.next(*reg),
659
            },
660
            Self::Mem { addr } => Self::Mem {
661
                addr: addr.with_allocs(allocs),
662
            },
663
            Self::Imm { .. } => self.clone(),
664
        }
665
    }
666
}
667

            
668
impl From<RegMem> for RegMemImm {
669
    fn from(rm: RegMem) -> RegMemImm {
670
        match rm {
671
            RegMem::Reg { reg } => RegMemImm::Reg { reg },
672
            RegMem::Mem { addr } => RegMemImm::Mem { addr },
673
        }
674
    }
675
}
676

            
677
impl PrettyPrint for RegMemImm {
678
    fn pretty_print(&self, size: u8, allocs: &mut AllocationConsumer<'_>) -> String {
679
        match self {
680
            Self::Reg { reg } => pretty_print_reg(*reg, size, allocs),
681
            Self::Mem { addr } => addr.pretty_print(size, allocs),
682
            Self::Imm { simm32 } => format!("${}", *simm32 as i32),
683
        }
684
    }
685
}
686

            
687
/// An operand which is either an 8-bit integer immediate or a register.
688
#[derive(Clone, Debug)]
689
pub enum Imm8Reg {
690
    /// 8-bit immediate operand.
691
    Imm8 {
692
        /// The 8-bit immediate value.
693
        imm: u8,
694
    },
695
    /// A register operand.
696
    Reg {
697
        /// The underlying register.
698
        reg: Reg,
699
    },
700
}
701

            
702
impl From<u8> for Imm8Reg {
703
    fn from(imm: u8) -> Self {
704
        Self::Imm8 { imm }
705
    }
706
}
707

            
708
impl From<Reg> for Imm8Reg {
709
    fn from(reg: Reg) -> Self {
710
        Self::Reg { reg }
711
    }
712
}
713

            
714
/// An operand which is either an integer Register or a value in Memory.  This can denote an 8, 16,
715
/// 32, 64, or 128 bit value.
716
#[derive(Clone, Debug)]
717
pub enum RegMem {
718
    /// A register operand.
719
    Reg {
720
        /// The underlying register.
721
        reg: Reg,
722
    },
723
    /// A memory operand.
724
    Mem {
725
        /// The memory address.
726
        addr: SyntheticAmode,
727
    },
728
}
729

            
730
impl RegMem {
731
    /// Create a register operand.
732
    pub fn reg(reg: Reg) -> Self {
733
        debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float);
734
        Self::Reg { reg }
735
    }
736

            
737
    /// Create a memory operand.
738
    pub fn mem(addr: impl Into<SyntheticAmode>) -> Self {
739
        Self::Mem { addr: addr.into() }
740
    }
741
    /// Asserts that in register mode, the reg class is the one that's expected.
742
    pub(crate) fn assert_regclass_is(&self, expected_reg_class: RegClass) {
743
        if let Self::Reg { reg } = self {
744
            debug_assert_eq!(reg.class(), expected_reg_class);
745
        }
746
    }
747
    /// Add the regs mentioned by `self` to `collector`.
748
    pub(crate) fn get_operands<F: Fn(VReg) -> VReg>(
749
        &self,
750
        collector: &mut OperandCollector<'_, F>,
751
    ) {
752
        match self {
753
            RegMem::Reg { reg } => collector.reg_use(*reg),
754
            RegMem::Mem { addr, .. } => addr.get_operands(collector),
755
        }
756
    }
757

            
758
    pub(crate) fn with_allocs(&self, allocs: &mut AllocationConsumer<'_>) -> Self {
759
        match self {
760
            RegMem::Reg { reg } => RegMem::Reg {
761
                reg: allocs.next(*reg),
762
            },
763
            RegMem::Mem { addr } => RegMem::Mem {
764
                addr: addr.with_allocs(allocs),
765
            },
766
        }
767
    }
768
}
769

            
770
impl From<Reg> for RegMem {
771
    fn from(reg: Reg) -> RegMem {
772
        RegMem::Reg { reg }
773
    }
774
}
775

            
776
impl From<Writable<Reg>> for RegMem {
777
    fn from(r: Writable<Reg>) -> Self {
778
        RegMem::reg(r.to_reg())
779
    }
780
}
781

            
782
impl PrettyPrint for RegMem {
783
    fn pretty_print(&self, size: u8, allocs: &mut AllocationConsumer<'_>) -> String {
784
        match self {
785
            RegMem::Reg { reg } => pretty_print_reg(*reg, size, allocs),
786
            RegMem::Mem { addr, .. } => addr.pretty_print(size, allocs),
787
        }
788
    }
789
}
790

            
791
/// Some basic ALU operations.
792
#[derive(Copy, Clone, PartialEq)]
793
pub enum AluRmiROpcode {
794
    /// Add operation.
795
    Add,
796
    /// Add with carry.
797
    Adc,
798
    /// Integer subtraction.
799
    Sub,
800
    /// Integer subtraction with borrow.
801
    Sbb,
802
    /// Bitwise AND operation.
803
    And,
804
    /// Bitwise inclusive OR.
805
    Or,
806
    /// Bitwise exclusive OR.
807
    Xor,
808
    /// The signless, non-extending (N x N -> N, for N in {32,64}) variant.
809
    Mul,
810
}
811

            
812
impl fmt::Debug for AluRmiROpcode {
813
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
814
        let name = match self {
815
            AluRmiROpcode::Add => "add",
816
            AluRmiROpcode::Adc => "adc",
817
            AluRmiROpcode::Sub => "sub",
818
            AluRmiROpcode::Sbb => "sbb",
819
            AluRmiROpcode::And => "and",
820
            AluRmiROpcode::Or => "or",
821
            AluRmiROpcode::Xor => "xor",
822
            AluRmiROpcode::Mul => "imul",
823
        };
824
        write!(fmt, "{}", name)
825
    }
826
}
827

            
828
impl fmt::Display for AluRmiROpcode {
829
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
830
        fmt::Debug::fmt(self, f)
831
    }
832
}
833

            
834
/// ALU operations that don't accept intermediates.
835
#[derive(Copy, Clone, PartialEq)]
836
pub enum AluRmROpcode {
837
    /// And with negated second operand.
838
    Andn,
839
}
840

            
841
impl AluRmROpcode {
842
    pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> {
843
        match self {
844
            AluRmROpcode::Andn => smallvec![InstructionSet::BMI1],
845
        }
846
    }
847
}
848

            
849
impl fmt::Debug for AluRmROpcode {
850
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
851
        let name = match self {
852
            AluRmROpcode::Andn => "andn",
853
        };
854
        write!(fmt, "{}", name)
855
    }
856
}
857

            
858
impl fmt::Display for AluRmROpcode {
859
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
860
        fmt::Debug::fmt(self, f)
861
    }
862
}
863

            
864
#[derive(Clone, PartialEq)]
865
/// Unary operations requiring register or memory and register operands.
866
pub enum UnaryRmROpcode {
867
    /// Bit-scan reverse.
868
    Bsr,
869
    /// Bit-scan forward.
870
    Bsf,
871
    /// Counts leading zeroes (Leading Zero CouNT).
872
    Lzcnt,
873
    /// Counts trailing zeroes (Trailing Zero CouNT).
874
    Tzcnt,
875
    /// Counts the number of ones (POPulation CouNT).
876
    Popcnt,
877
}
878

            
879
impl UnaryRmROpcode {
880
    pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> {
881
        match self {
882
            UnaryRmROpcode::Bsr | UnaryRmROpcode::Bsf => smallvec![],
883
            UnaryRmROpcode::Lzcnt => smallvec![InstructionSet::Lzcnt],
884
            UnaryRmROpcode::Tzcnt => smallvec![InstructionSet::BMI1],
885
            UnaryRmROpcode::Popcnt => smallvec![InstructionSet::Popcnt],
886
        }
887
    }
888
}
889

            
890
impl fmt::Debug for UnaryRmROpcode {
891
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
892
        match self {
893
            UnaryRmROpcode::Bsr => write!(fmt, "bsr"),
894
            UnaryRmROpcode::Bsf => write!(fmt, "bsf"),
895
            UnaryRmROpcode::Lzcnt => write!(fmt, "lzcnt"),
896
            UnaryRmROpcode::Tzcnt => write!(fmt, "tzcnt"),
897
            UnaryRmROpcode::Popcnt => write!(fmt, "popcnt"),
898
        }
899
    }
900
}
901

            
902
impl fmt::Display for UnaryRmROpcode {
903
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
904
        fmt::Debug::fmt(self, f)
905
    }
906
}
907

            
908
#[derive(Clone, Copy, PartialEq)]
909
/// Comparison operations.
910
pub enum CmpOpcode {
911
    /// CMP instruction: compute `a - b` and set flags from result.
912
    Cmp,
913
    /// TEST instruction: compute `a & b` and set flags from result.
914
    Test,
915
}
916

            
917
#[derive(Debug)]
918
pub(crate) enum InstructionSet {
919
    SSE,
920
    SSE2,
921
    SSSE3,
922
    SSE41,
923
    SSE42,
924
    Popcnt,
925
    Lzcnt,
926
    BMI1,
927
    #[allow(dead_code)] // never constructed (yet).
928
    BMI2,
929
    FMA,
930
    AVX,
931
    AVX2,
932
    AVX512BITALG,
933
    AVX512DQ,
934
    AVX512F,
935
    AVX512VBMI,
936
    AVX512VL,
937
}
938

            
939
/// Some SSE operations requiring 2 operands r/m and r.
940
#[derive(Clone, Copy, PartialEq)]
941
#[allow(dead_code)] // some variants here aren't used just yet
942
#[allow(missing_docs)]
943
pub enum SseOpcode {
944
    Addps,
945
    Addpd,
946
    Addss,
947
    Addsd,
948
    Andps,
949
    Andpd,
950
    Andnps,
951
    Andnpd,
952
    Blendvpd,
953
    Blendvps,
954
    Comiss,
955
    Comisd,
956
    Cmpps,
957
    Cmppd,
958
    Cmpss,
959
    Cmpsd,
960
    Cvtdq2ps,
961
    Cvtdq2pd,
962
    Cvtpd2ps,
963
    Cvtps2pd,
964
    Cvtsd2ss,
965
    Cvtsd2si,
966
    Cvtsi2ss,
967
    Cvtsi2sd,
968
    Cvtss2si,
969
    Cvtss2sd,
970
    Cvttpd2dq,
971
    Cvttps2dq,
972
    Cvttss2si,
973
    Cvttsd2si,
974
    Divps,
975
    Divpd,
976
    Divss,
977
    Divsd,
978
    Insertps,
979
    Maxps,
980
    Maxpd,
981
    Maxss,
982
    Maxsd,
983
    Minps,
984
    Minpd,
985
    Minss,
986
    Minsd,
987
    Movaps,
988
    Movapd,
989
    Movd,
990
    Movdqa,
991
    Movdqu,
992
    Movlhps,
993
    Movmskps,
994
    Movmskpd,
995
    Movq,
996
    Movss,
997
    Movsd,
998
    Movups,
999
    Movupd,
    Mulps,
    Mulpd,
    Mulss,
    Mulsd,
    Orps,
    Orpd,
    Pabsb,
    Pabsw,
    Pabsd,
    Packssdw,
    Packsswb,
    Packusdw,
    Packuswb,
    Paddb,
    Paddd,
    Paddq,
    Paddw,
    Paddsb,
    Paddsw,
    Paddusb,
    Paddusw,
    Palignr,
    Pand,
    Pandn,
    Pavgb,
    Pavgw,
    Pblendvb,
    Pcmpeqb,
    Pcmpeqw,
    Pcmpeqd,
    Pcmpeqq,
    Pcmpgtb,
    Pcmpgtw,
    Pcmpgtd,
    Pcmpgtq,
    Pextrb,
    Pextrw,
    Pextrd,
    Pextrq,
    Pinsrb,
    Pinsrw,
    Pinsrd,
    Pmaddubsw,
    Pmaddwd,
    Pmaxsb,
    Pmaxsw,
    Pmaxsd,
    Pmaxub,
    Pmaxuw,
    Pmaxud,
    Pminsb,
    Pminsw,
    Pminsd,
    Pminub,
    Pminuw,
    Pminud,
    Pmovmskb,
    Pmovsxbd,
    Pmovsxbw,
    Pmovsxbq,
    Pmovsxwd,
    Pmovsxwq,
    Pmovsxdq,
    Pmovzxbd,
    Pmovzxbw,
    Pmovzxbq,
    Pmovzxwd,
    Pmovzxwq,
    Pmovzxdq,
    Pmuldq,
    Pmulhw,
    Pmulhuw,
    Pmulhrsw,
    Pmulld,
    Pmullw,
    Pmuludq,
    Por,
    Pshufb,
    Pshufd,
    Psllw,
    Pslld,
    Psllq,
    Psraw,
    Psrad,
    Psrlw,
    Psrld,
    Psrlq,
    Psubb,
    Psubd,
    Psubq,
    Psubw,
    Psubsb,
    Psubsw,
    Psubusb,
    Psubusw,
    Ptest,
    Punpckhbw,
    Punpckhwd,
    Punpcklbw,
    Punpcklwd,
    Pxor,
    Rcpss,
    Roundps,
    Roundpd,
    Roundss,
    Roundsd,
    Rsqrtss,
    Shufps,
    Sqrtps,
    Sqrtpd,
    Sqrtss,
    Sqrtsd,
    Subps,
    Subpd,
    Subss,
    Subsd,
    Ucomiss,
    Ucomisd,
    Unpcklps,
    Xorps,
    Xorpd,
    Phaddw,
    Phaddd,
    Punpckhdq,
    Punpckldq,
    Punpckhqdq,
    Punpcklqdq,
    Pshuflw,
    Pshufhw,
    Pblendw,
    Movddup,
}
impl SseOpcode {
    /// Which `InstructionSet` is the first supporting this opcode?
    pub(crate) fn available_from(&self) -> InstructionSet {
        use InstructionSet::*;
        match self {
            SseOpcode::Addps
            | SseOpcode::Addss
            | SseOpcode::Andps
            | SseOpcode::Andnps
            | SseOpcode::Comiss
            | SseOpcode::Cmpps
            | SseOpcode::Cmpss
            | SseOpcode::Cvtsi2ss
            | SseOpcode::Cvtss2si
            | SseOpcode::Cvttss2si
            | SseOpcode::Divps
            | SseOpcode::Divss
            | SseOpcode::Maxps
            | SseOpcode::Maxss
            | SseOpcode::Minps
            | SseOpcode::Minss
            | SseOpcode::Movaps
            | SseOpcode::Movlhps
            | SseOpcode::Movmskps
            | SseOpcode::Movss
            | SseOpcode::Movups
            | SseOpcode::Mulps
            | SseOpcode::Mulss
            | SseOpcode::Orps
            | SseOpcode::Rcpss
            | SseOpcode::Rsqrtss
            | SseOpcode::Shufps
            | SseOpcode::Sqrtps
            | SseOpcode::Sqrtss
            | SseOpcode::Subps
            | SseOpcode::Subss
            | SseOpcode::Ucomiss
            | SseOpcode::Unpcklps
            | SseOpcode::Xorps => SSE,
            SseOpcode::Addpd
            | SseOpcode::Addsd
            | SseOpcode::Andpd
            | SseOpcode::Andnpd
            | SseOpcode::Cmppd
            | SseOpcode::Cmpsd
            | SseOpcode::Comisd
            | SseOpcode::Cvtdq2ps
            | SseOpcode::Cvtdq2pd
            | SseOpcode::Cvtpd2ps
            | SseOpcode::Cvtps2pd
            | SseOpcode::Cvtsd2ss
            | SseOpcode::Cvtsd2si
            | SseOpcode::Cvtsi2sd
            | SseOpcode::Cvtss2sd
            | SseOpcode::Cvttpd2dq
            | SseOpcode::Cvttps2dq
            | SseOpcode::Cvttsd2si
            | SseOpcode::Divpd
            | SseOpcode::Divsd
            | SseOpcode::Maxpd
            | SseOpcode::Maxsd
            | SseOpcode::Minpd
            | SseOpcode::Minsd
            | SseOpcode::Movapd
            | SseOpcode::Movd
            | SseOpcode::Movmskpd
            | SseOpcode::Movq
            | SseOpcode::Movsd
            | SseOpcode::Movupd
            | SseOpcode::Movdqa
            | SseOpcode::Movdqu
            | SseOpcode::Mulpd
            | SseOpcode::Mulsd
            | SseOpcode::Orpd
            | SseOpcode::Packssdw
            | SseOpcode::Packsswb
            | SseOpcode::Packuswb
            | SseOpcode::Paddb
            | SseOpcode::Paddd
            | SseOpcode::Paddq
            | SseOpcode::Paddw
            | SseOpcode::Paddsb
            | SseOpcode::Paddsw
            | SseOpcode::Paddusb
            | SseOpcode::Paddusw
            | SseOpcode::Pand
            | SseOpcode::Pandn
            | SseOpcode::Pavgb
            | SseOpcode::Pavgw
            | SseOpcode::Pcmpeqb
            | SseOpcode::Pcmpeqw
            | SseOpcode::Pcmpeqd
            | SseOpcode::Pcmpgtb
            | SseOpcode::Pcmpgtw
            | SseOpcode::Pcmpgtd
            | SseOpcode::Pextrw
            | SseOpcode::Pinsrw
            | SseOpcode::Pmaddubsw
            | SseOpcode::Pmaddwd
            | SseOpcode::Pmaxsw
            | SseOpcode::Pmaxub
            | SseOpcode::Pminsw
            | SseOpcode::Pminub
            | SseOpcode::Pmovmskb
            | SseOpcode::Pmulhw
            | SseOpcode::Pmulhuw
            | SseOpcode::Pmullw
            | SseOpcode::Pmuludq
            | SseOpcode::Por
            | SseOpcode::Pshufd
            | SseOpcode::Psllw
            | SseOpcode::Pslld
            | SseOpcode::Psllq
            | SseOpcode::Psraw
            | SseOpcode::Psrad
            | SseOpcode::Psrlw
            | SseOpcode::Psrld
            | SseOpcode::Psrlq
            | SseOpcode::Psubb
            | SseOpcode::Psubd
            | SseOpcode::Psubq
            | SseOpcode::Psubw
            | SseOpcode::Psubsb
            | SseOpcode::Psubsw
            | SseOpcode::Psubusb
            | SseOpcode::Psubusw
            | SseOpcode::Punpckhbw
            | SseOpcode::Punpckhwd
            | SseOpcode::Punpcklbw
            | SseOpcode::Punpcklwd
            | SseOpcode::Pxor
            | SseOpcode::Sqrtpd
            | SseOpcode::Sqrtsd
            | SseOpcode::Subpd
            | SseOpcode::Subsd
            | SseOpcode::Ucomisd
            | SseOpcode::Xorpd
            | SseOpcode::Punpckldq
            | SseOpcode::Punpckhdq
            | SseOpcode::Punpcklqdq
            | SseOpcode::Punpckhqdq
            | SseOpcode::Pshuflw
            | SseOpcode::Pshufhw => SSE2,
            SseOpcode::Pabsb
            | SseOpcode::Pabsw
            | SseOpcode::Pabsd
            | SseOpcode::Palignr
            | SseOpcode::Pmulhrsw
            | SseOpcode::Pshufb
            | SseOpcode::Phaddw
            | SseOpcode::Phaddd
            | SseOpcode::Movddup => SSSE3,
            SseOpcode::Blendvpd
            | SseOpcode::Blendvps
            | SseOpcode::Insertps
            | SseOpcode::Packusdw
            | SseOpcode::Pblendvb
            | SseOpcode::Pcmpeqq
            | SseOpcode::Pextrb
            | SseOpcode::Pextrd
            | SseOpcode::Pextrq
            | SseOpcode::Pinsrb
            | SseOpcode::Pinsrd
            | SseOpcode::Pmaxsb
            | SseOpcode::Pmaxsd
            | SseOpcode::Pmaxuw
            | SseOpcode::Pmaxud
            | SseOpcode::Pminsb
            | SseOpcode::Pminsd
            | SseOpcode::Pminuw
            | SseOpcode::Pminud
            | SseOpcode::Pmovsxbd
            | SseOpcode::Pmovsxbw
            | SseOpcode::Pmovsxbq
            | SseOpcode::Pmovsxwd
            | SseOpcode::Pmovsxwq
            | SseOpcode::Pmovsxdq
            | SseOpcode::Pmovzxbd
            | SseOpcode::Pmovzxbw
            | SseOpcode::Pmovzxbq
            | SseOpcode::Pmovzxwd
            | SseOpcode::Pmovzxwq
            | SseOpcode::Pmovzxdq
            | SseOpcode::Pmuldq
            | SseOpcode::Pmulld
            | SseOpcode::Ptest
            | SseOpcode::Roundps
            | SseOpcode::Roundpd
            | SseOpcode::Roundss
            | SseOpcode::Roundsd
            | SseOpcode::Pblendw => SSE41,
            SseOpcode::Pcmpgtq => SSE42,
        }
    }
    /// Returns the src operand size for an instruction.
    pub(crate) fn src_size(&self) -> u8 {
        match self {
            SseOpcode::Movd => 4,
            _ => 8,
        }
    }
}
impl fmt::Debug for SseOpcode {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let name = match self {
            SseOpcode::Addps => "addps",
            SseOpcode::Addpd => "addpd",
            SseOpcode::Addss => "addss",
            SseOpcode::Addsd => "addsd",
            SseOpcode::Andpd => "andpd",
            SseOpcode::Andps => "andps",
            SseOpcode::Andnps => "andnps",
            SseOpcode::Andnpd => "andnpd",
            SseOpcode::Blendvpd => "blendvpd",
            SseOpcode::Blendvps => "blendvps",
            SseOpcode::Cmpps => "cmpps",
            SseOpcode::Cmppd => "cmppd",
            SseOpcode::Cmpss => "cmpss",
            SseOpcode::Cmpsd => "cmpsd",
            SseOpcode::Comiss => "comiss",
            SseOpcode::Comisd => "comisd",
            SseOpcode::Cvtdq2ps => "cvtdq2ps",
            SseOpcode::Cvtdq2pd => "cvtdq2pd",
            SseOpcode::Cvtpd2ps => "cvtpd2ps",
            SseOpcode::Cvtps2pd => "cvtps2pd",
            SseOpcode::Cvtsd2ss => "cvtsd2ss",
            SseOpcode::Cvtsd2si => "cvtsd2si",
            SseOpcode::Cvtsi2ss => "cvtsi2ss",
            SseOpcode::Cvtsi2sd => "cvtsi2sd",
            SseOpcode::Cvtss2si => "cvtss2si",
            SseOpcode::Cvtss2sd => "cvtss2sd",
            SseOpcode::Cvttpd2dq => "cvttpd2dq",
            SseOpcode::Cvttps2dq => "cvttps2dq",
            SseOpcode::Cvttss2si => "cvttss2si",
            SseOpcode::Cvttsd2si => "cvttsd2si",
            SseOpcode::Divps => "divps",
            SseOpcode::Divpd => "divpd",
            SseOpcode::Divss => "divss",
            SseOpcode::Divsd => "divsd",
            SseOpcode::Insertps => "insertps",
            SseOpcode::Maxps => "maxps",
            SseOpcode::Maxpd => "maxpd",
            SseOpcode::Maxss => "maxss",
            SseOpcode::Maxsd => "maxsd",
            SseOpcode::Minps => "minps",
            SseOpcode::Minpd => "minpd",
            SseOpcode::Minss => "minss",
            SseOpcode::Minsd => "minsd",
            SseOpcode::Movaps => "movaps",
            SseOpcode::Movapd => "movapd",
            SseOpcode::Movd => "movd",
            SseOpcode::Movdqa => "movdqa",
            SseOpcode::Movdqu => "movdqu",
            SseOpcode::Movlhps => "movlhps",
            SseOpcode::Movmskps => "movmskps",
            SseOpcode::Movmskpd => "movmskpd",
            SseOpcode::Movq => "movq",
            SseOpcode::Movss => "movss",
            SseOpcode::Movsd => "movsd",
            SseOpcode::Movups => "movups",
            SseOpcode::Movupd => "movupd",
            SseOpcode::Mulps => "mulps",
            SseOpcode::Mulpd => "mulpd",
            SseOpcode::Mulss => "mulss",
            SseOpcode::Mulsd => "mulsd",
            SseOpcode::Orpd => "orpd",
            SseOpcode::Orps => "orps",
            SseOpcode::Pabsb => "pabsb",
            SseOpcode::Pabsw => "pabsw",
            SseOpcode::Pabsd => "pabsd",
            SseOpcode::Packssdw => "packssdw",
            SseOpcode::Packsswb => "packsswb",
            SseOpcode::Packusdw => "packusdw",
            SseOpcode::Packuswb => "packuswb",
            SseOpcode::Paddb => "paddb",
            SseOpcode::Paddd => "paddd",
            SseOpcode::Paddq => "paddq",
            SseOpcode::Paddw => "paddw",
            SseOpcode::Paddsb => "paddsb",
            SseOpcode::Paddsw => "paddsw",
            SseOpcode::Paddusb => "paddusb",
            SseOpcode::Paddusw => "paddusw",
            SseOpcode::Palignr => "palignr",
            SseOpcode::Pand => "pand",
            SseOpcode::Pandn => "pandn",
            SseOpcode::Pavgb => "pavgb",
            SseOpcode::Pavgw => "pavgw",
            SseOpcode::Pblendvb => "pblendvb",
            SseOpcode::Pcmpeqb => "pcmpeqb",
            SseOpcode::Pcmpeqw => "pcmpeqw",
            SseOpcode::Pcmpeqd => "pcmpeqd",
            SseOpcode::Pcmpeqq => "pcmpeqq",
            SseOpcode::Pcmpgtb => "pcmpgtb",
            SseOpcode::Pcmpgtw => "pcmpgtw",
            SseOpcode::Pcmpgtd => "pcmpgtd",
            SseOpcode::Pcmpgtq => "pcmpgtq",
            SseOpcode::Pextrb => "pextrb",
            SseOpcode::Pextrw => "pextrw",
            SseOpcode::Pextrd => "pextrd",
            SseOpcode::Pextrq => "pextrq",
            SseOpcode::Pinsrb => "pinsrb",
            SseOpcode::Pinsrw => "pinsrw",
            SseOpcode::Pinsrd => "pinsrd",
            SseOpcode::Pmaddubsw => "pmaddubsw",
            SseOpcode::Pmaddwd => "pmaddwd",
            SseOpcode::Pmaxsb => "pmaxsb",
            SseOpcode::Pmaxsw => "pmaxsw",
            SseOpcode::Pmaxsd => "pmaxsd",
            SseOpcode::Pmaxub => "pmaxub",
            SseOpcode::Pmaxuw => "pmaxuw",
            SseOpcode::Pmaxud => "pmaxud",
            SseOpcode::Pminsb => "pminsb",
            SseOpcode::Pminsw => "pminsw",
            SseOpcode::Pminsd => "pminsd",
            SseOpcode::Pminub => "pminub",
            SseOpcode::Pminuw => "pminuw",
            SseOpcode::Pminud => "pminud",
            SseOpcode::Pmovmskb => "pmovmskb",
            SseOpcode::Pmovsxbd => "pmovsxbd",
            SseOpcode::Pmovsxbw => "pmovsxbw",
            SseOpcode::Pmovsxbq => "pmovsxbq",
            SseOpcode::Pmovsxwd => "pmovsxwd",
            SseOpcode::Pmovsxwq => "pmovsxwq",
            SseOpcode::Pmovsxdq => "pmovsxdq",
            SseOpcode::Pmovzxbd => "pmovzxbd",
            SseOpcode::Pmovzxbw => "pmovzxbw",
            SseOpcode::Pmovzxbq => "pmovzxbq",
            SseOpcode::Pmovzxwd => "pmovzxwd",
            SseOpcode::Pmovzxwq => "pmovzxwq",
            SseOpcode::Pmovzxdq => "pmovzxdq",
            SseOpcode::Pmuldq => "pmuldq",
            SseOpcode::Pmulhw => "pmulhw",
            SseOpcode::Pmulhuw => "pmulhuw",
            SseOpcode::Pmulhrsw => "pmulhrsw",
            SseOpcode::Pmulld => "pmulld",
            SseOpcode::Pmullw => "pmullw",
            SseOpcode::Pmuludq => "pmuludq",
            SseOpcode::Por => "por",
            SseOpcode::Pshufb => "pshufb",
            SseOpcode::Pshufd => "pshufd",
            SseOpcode::Psllw => "psllw",
            SseOpcode::Pslld => "pslld",
            SseOpcode::Psllq => "psllq",
            SseOpcode::Psraw => "psraw",
            SseOpcode::Psrad => "psrad",
            SseOpcode::Psrlw => "psrlw",
            SseOpcode::Psrld => "psrld",
            SseOpcode::Psrlq => "psrlq",
            SseOpcode::Psubb => "psubb",
            SseOpcode::Psubd => "psubd",
            SseOpcode::Psubq => "psubq",
            SseOpcode::Psubw => "psubw",
            SseOpcode::Psubsb => "psubsb",
            SseOpcode::Psubsw => "psubsw",
            SseOpcode::Psubusb => "psubusb",
            SseOpcode::Psubusw => "psubusw",
            SseOpcode::Ptest => "ptest",
            SseOpcode::Punpckhbw => "punpckhbw",
            SseOpcode::Punpckhwd => "punpckhwd",
            SseOpcode::Punpcklbw => "punpcklbw",
            SseOpcode::Punpcklwd => "punpcklwd",
            SseOpcode::Pxor => "pxor",
            SseOpcode::Rcpss => "rcpss",
            SseOpcode::Roundps => "roundps",
            SseOpcode::Roundpd => "roundpd",
            SseOpcode::Roundss => "roundss",
            SseOpcode::Roundsd => "roundsd",
            SseOpcode::Rsqrtss => "rsqrtss",
            SseOpcode::Shufps => "shufps",
            SseOpcode::Sqrtps => "sqrtps",
            SseOpcode::Sqrtpd => "sqrtpd",
            SseOpcode::Sqrtss => "sqrtss",
            SseOpcode::Sqrtsd => "sqrtsd",
            SseOpcode::Subps => "subps",
            SseOpcode::Subpd => "subpd",
            SseOpcode::Subss => "subss",
            SseOpcode::Subsd => "subsd",
            SseOpcode::Ucomiss => "ucomiss",
            SseOpcode::Ucomisd => "ucomisd",
            SseOpcode::Unpcklps => "unpcklps",
            SseOpcode::Xorps => "xorps",
            SseOpcode::Xorpd => "xorpd",
            SseOpcode::Phaddw => "phaddw",
            SseOpcode::Phaddd => "phaddd",
            SseOpcode::Punpckldq => "punpckldq",
            SseOpcode::Punpckhdq => "punpckhdq",
            SseOpcode::Punpcklqdq => "punpcklqdq",
            SseOpcode::Punpckhqdq => "punpckhqdq",
            SseOpcode::Pshuflw => "pshuflw",
            SseOpcode::Pshufhw => "pshufhw",
            SseOpcode::Pblendw => "pblendw",
            SseOpcode::Movddup => "movddup",
        };
        write!(fmt, "{}", name)
    }
}
impl fmt::Display for SseOpcode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self, f)
    }
}
pub use crate::isa::x64::lower::isle::generated_code::AvxOpcode;
impl AvxOpcode {
    /// Which `InstructionSet`s support the opcode?
    pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> {
        match self {
            AvxOpcode::Vfmadd213ss
            | AvxOpcode::Vfmadd213sd
            | AvxOpcode::Vfmadd213ps
            | AvxOpcode::Vfmadd213pd
            | AvxOpcode::Vfmadd132ss
            | AvxOpcode::Vfmadd132sd
            | AvxOpcode::Vfmadd132ps
            | AvxOpcode::Vfmadd132pd
            | AvxOpcode::Vfnmadd213ss
            | AvxOpcode::Vfnmadd213sd
            | AvxOpcode::Vfnmadd213ps
            | AvxOpcode::Vfnmadd213pd
            | AvxOpcode::Vfnmadd132ss
            | AvxOpcode::Vfnmadd132sd
            | AvxOpcode::Vfnmadd132ps
            | AvxOpcode::Vfnmadd132pd => smallvec![InstructionSet::FMA],
            AvxOpcode::Vminps
            | AvxOpcode::Vminpd
            | AvxOpcode::Vmaxps
            | AvxOpcode::Vmaxpd
            | AvxOpcode::Vandnps
            | AvxOpcode::Vandnpd
            | AvxOpcode::Vpandn
            | AvxOpcode::Vcmpps
            | AvxOpcode::Vcmppd
            | AvxOpcode::Vpsrlw
            | AvxOpcode::Vpsrld
            | AvxOpcode::Vpsrlq
            | AvxOpcode::Vpaddb
            | AvxOpcode::Vpaddw
            | AvxOpcode::Vpaddd
            | AvxOpcode::Vpaddq
            | AvxOpcode::Vpaddsb
            | AvxOpcode::Vpaddsw
            | AvxOpcode::Vpaddusb
            | AvxOpcode::Vpaddusw
            | AvxOpcode::Vpsubb
            | AvxOpcode::Vpsubw
            | AvxOpcode::Vpsubd
            | AvxOpcode::Vpsubq
            | AvxOpcode::Vpsubsb
            | AvxOpcode::Vpsubsw
            | AvxOpcode::Vpsubusb
            | AvxOpcode::Vpsubusw
            | AvxOpcode::Vpavgb
            | AvxOpcode::Vpavgw
            | AvxOpcode::Vpand
            | AvxOpcode::Vandps
            | AvxOpcode::Vandpd
            | AvxOpcode::Vpor
            | AvxOpcode::Vorps
            | AvxOpcode::Vorpd
            | AvxOpcode::Vpxor
            | AvxOpcode::Vxorps
            | AvxOpcode::Vxorpd
            | AvxOpcode::Vpmullw
            | AvxOpcode::Vpmulld
            | AvxOpcode::Vpmulhw
            | AvxOpcode::Vpmulhd
            | AvxOpcode::Vpmulhrsw
            | AvxOpcode::Vpmulhuw
            | AvxOpcode::Vpmuldq
            | AvxOpcode::Vpmuludq
            | AvxOpcode::Vpunpckhwd
            | AvxOpcode::Vpunpcklwd
            | AvxOpcode::Vunpcklps
            | AvxOpcode::Vaddps
            | AvxOpcode::Vaddpd
            | AvxOpcode::Vsubps
            | AvxOpcode::Vsubpd
            | AvxOpcode::Vmulps
            | AvxOpcode::Vmulpd
            | AvxOpcode::Vdivps
            | AvxOpcode::Vdivpd
            | AvxOpcode::Vpcmpeqb
            | AvxOpcode::Vpcmpeqw
            | AvxOpcode::Vpcmpeqd
            | AvxOpcode::Vpcmpeqq
            | AvxOpcode::Vpcmpgtb
            | AvxOpcode::Vpcmpgtw
            | AvxOpcode::Vpcmpgtd
            | AvxOpcode::Vpcmpgtq
            | AvxOpcode::Vblendvps
            | AvxOpcode::Vblendvpd
            | AvxOpcode::Vpblendvb
            | AvxOpcode::Vmovlhps
            | AvxOpcode::Vpminsb
            | AvxOpcode::Vpminsw
            | AvxOpcode::Vpminsd
            | AvxOpcode::Vpminub
            | AvxOpcode::Vpminuw
            | AvxOpcode::Vpminud
            | AvxOpcode::Vpmaxsb
            | AvxOpcode::Vpmaxsw
            | AvxOpcode::Vpmaxsd
            | AvxOpcode::Vpmaxub
            | AvxOpcode::Vpmaxuw
            | AvxOpcode::Vpmaxud
            | AvxOpcode::Vpunpcklbw
            | AvxOpcode::Vpunpckhbw
            | AvxOpcode::Vpacksswb
            | AvxOpcode::Vpackssdw
            | AvxOpcode::Vpackuswb
            | AvxOpcode::Vpackusdw
            | AvxOpcode::Vpalignr
            | AvxOpcode::Vpinsrb
            | AvxOpcode::Vpinsrw
            | AvxOpcode::Vpinsrd
            | AvxOpcode::Vpinsrq
            | AvxOpcode::Vpmaddwd
            | AvxOpcode::Vpmaddubsw
            | AvxOpcode::Vinsertps
            | AvxOpcode::Vpshufb
            | AvxOpcode::Vshufps
            | AvxOpcode::Vpsllw
            | AvxOpcode::Vpslld
            | AvxOpcode::Vpsllq
            | AvxOpcode::Vpsraw
            | AvxOpcode::Vpsrad
            | AvxOpcode::Vpmovsxbw
            | AvxOpcode::Vpmovzxbw
            | AvxOpcode::Vpmovsxwd
            | AvxOpcode::Vpmovzxwd
            | AvxOpcode::Vpmovsxdq
            | AvxOpcode::Vpmovzxdq
            | AvxOpcode::Vaddss
            | AvxOpcode::Vaddsd
            | AvxOpcode::Vmulss
            | AvxOpcode::Vmulsd
            | AvxOpcode::Vsubss
            | AvxOpcode::Vsubsd
            | AvxOpcode::Vdivss
            | AvxOpcode::Vdivsd
            | AvxOpcode::Vpabsb
            | AvxOpcode::Vpabsw
            | AvxOpcode::Vpabsd
            | AvxOpcode::Vminss
            | AvxOpcode::Vminsd
            | AvxOpcode::Vmaxss
            | AvxOpcode::Vmaxsd
            | AvxOpcode::Vsqrtps
            | AvxOpcode::Vsqrtpd
            | AvxOpcode::Vroundpd
            | AvxOpcode::Vroundps
            | AvxOpcode::Vcvtdq2pd
            | AvxOpcode::Vcvtdq2ps
            | AvxOpcode::Vcvtpd2ps
            | AvxOpcode::Vcvtps2pd
            | AvxOpcode::Vcvttpd2dq
            | AvxOpcode::Vcvttps2dq
            | AvxOpcode::Vphaddw
            | AvxOpcode::Vphaddd
            | AvxOpcode::Vpunpckldq
            | AvxOpcode::Vpunpckhdq
            | AvxOpcode::Vpunpcklqdq
            | AvxOpcode::Vpunpckhqdq
            | AvxOpcode::Vpshuflw
            | AvxOpcode::Vpshufhw
            | AvxOpcode::Vpshufd
            | AvxOpcode::Vmovss
            | AvxOpcode::Vmovsd
            | AvxOpcode::Vmovups
            | AvxOpcode::Vmovupd
            | AvxOpcode::Vmovdqu
            | AvxOpcode::Vpextrb
            | AvxOpcode::Vpextrw
            | AvxOpcode::Vpextrd
            | AvxOpcode::Vpextrq
            | AvxOpcode::Vpblendw
            | AvxOpcode::Vmovddup
            | AvxOpcode::Vbroadcastss
            | AvxOpcode::Vmovd
            | AvxOpcode::Vmovq
            | AvxOpcode::Vmovmskps
            | AvxOpcode::Vmovmskpd
            | AvxOpcode::Vpmovmskb
            | AvxOpcode::Vcvtsi2ss
            | AvxOpcode::Vcvtsi2sd
            | AvxOpcode::Vcvtss2sd
            | AvxOpcode::Vcvtsd2ss
            | AvxOpcode::Vsqrtss
            | AvxOpcode::Vsqrtsd
            | AvxOpcode::Vroundss
            | AvxOpcode::Vroundsd => {
                smallvec![InstructionSet::AVX]
            }
            AvxOpcode::Vpbroadcastb | AvxOpcode::Vpbroadcastw | AvxOpcode::Vpbroadcastd => {
                smallvec![InstructionSet::AVX2]
            }
        }
    }
}
impl fmt::Display for AvxOpcode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format!("{self:?}").to_lowercase().fmt(f)
    }
}
#[derive(Clone, PartialEq)]
#[allow(missing_docs)]
pub enum Avx512Opcode {
    Vcvtudq2ps,
    Vpabsq,
    Vpermi2b,
    Vpmullq,
    Vpopcntb,
}
impl Avx512Opcode {
    /// Which `InstructionSet`s support the opcode?
    pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> {
        match self {
            Avx512Opcode::Vcvtudq2ps => {
                smallvec![InstructionSet::AVX512F, InstructionSet::AVX512VL]
            }
            Avx512Opcode::Vpabsq => smallvec![InstructionSet::AVX512F, InstructionSet::AVX512VL],
            Avx512Opcode::Vpermi2b => {
                smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512VBMI]
            }
            Avx512Opcode::Vpmullq => smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512DQ],
            Avx512Opcode::Vpopcntb => {
                smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512BITALG]
            }
        }
    }
}
impl fmt::Debug for Avx512Opcode {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let name = match self {
            Avx512Opcode::Vcvtudq2ps => "vcvtudq2ps",
            Avx512Opcode::Vpabsq => "vpabsq",
            Avx512Opcode::Vpermi2b => "vpermi2b",
            Avx512Opcode::Vpmullq => "vpmullq",
            Avx512Opcode::Vpopcntb => "vpopcntb",
        };
        write!(fmt, "{}", name)
    }
}
impl fmt::Display for Avx512Opcode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self, f)
    }
}
/// This defines the ways a value can be extended: either signed- or zero-extension, or none for
/// types that are not extended. Contrast with [ExtMode], which defines the widths from and to which
/// values can be extended.
#[allow(dead_code)]
#[derive(Clone, PartialEq)]
pub enum ExtKind {
    /// No extension.
    None,
    /// Sign-extend.
    SignExtend,
    /// Zero-extend.
    ZeroExtend,
}
/// These indicate ways of extending (widening) a value, using the Intel
/// naming: B(yte) = u8, W(ord) = u16, L(ong)word = u32, Q(uad)word = u64
#[derive(Clone, PartialEq)]
pub enum ExtMode {
    /// Byte -> Longword.
    BL,
    /// Byte -> Quadword.
    BQ,
    /// Word -> Longword.
    WL,
    /// Word -> Quadword.
    WQ,
    /// Longword -> Quadword.
    LQ,
}
impl ExtMode {
    /// Calculate the `ExtMode` from passed bit lengths of the from/to types.
    pub(crate) fn new(from_bits: u16, to_bits: u16) -> Option<ExtMode> {
        match (from_bits, to_bits) {
            (1, 8) | (1, 16) | (1, 32) | (8, 16) | (8, 32) => Some(ExtMode::BL),
            (1, 64) | (8, 64) => Some(ExtMode::BQ),
            (16, 32) => Some(ExtMode::WL),
            (16, 64) => Some(ExtMode::WQ),
            (32, 64) => Some(ExtMode::LQ),
            _ => None,
        }
    }
    /// Return the source register size in bytes.
    pub(crate) fn src_size(&self) -> u8 {
        match self {
            ExtMode::BL | ExtMode::BQ => 1,
            ExtMode::WL | ExtMode::WQ => 2,
            ExtMode::LQ => 4,
        }
    }
    /// Return the destination register size in bytes.
    pub(crate) fn dst_size(&self) -> u8 {
        match self {
            ExtMode::BL | ExtMode::WL => 4,
            ExtMode::BQ | ExtMode::WQ | ExtMode::LQ => 8,
        }
    }
}
impl fmt::Debug for ExtMode {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let name = match self {
            ExtMode::BL => "bl",
            ExtMode::BQ => "bq",
            ExtMode::WL => "wl",
            ExtMode::WQ => "wq",
            ExtMode::LQ => "lq",
        };
        write!(fmt, "{}", name)
    }
}
impl fmt::Display for ExtMode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self, f)
    }
}
/// These indicate the form of a scalar shift/rotate: left, signed right, unsigned right.
#[derive(Clone, Copy)]
pub enum ShiftKind {
    /// Left shift.
    ShiftLeft,
    /// Inserts zeros in the most significant bits.
    ShiftRightLogical,
    /// Replicates the sign bit in the most significant bits.
    ShiftRightArithmetic,
    /// Left rotation.
    RotateLeft,
    /// Right rotation.
    RotateRight,
}
impl fmt::Debug for ShiftKind {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let name = match self {
            ShiftKind::ShiftLeft => "shl",
            ShiftKind::ShiftRightLogical => "shr",
            ShiftKind::ShiftRightArithmetic => "sar",
            ShiftKind::RotateLeft => "rol",
            ShiftKind::RotateRight => "ror",
        };
        write!(fmt, "{}", name)
    }
}
impl fmt::Display for ShiftKind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self, f)
    }
}
/// These indicate condition code tests.  Not all are represented since not all are useful in
/// compiler-generated code.
#[derive(Copy, Clone)]
#[repr(u8)]
pub enum CC {
    ///  overflow
    O = 0,
    /// no overflow
    NO = 1,
    /// < unsigned
    B = 2,
    /// >= unsigned
    NB = 3,
    /// zero
    Z = 4,
    /// not-zero
    NZ = 5,
    /// <= unsigned
    BE = 6,
    /// > unsigned
    NBE = 7,
    /// negative
    S = 8,
    /// not-negative
    NS = 9,
    /// < signed
    L = 12,
    /// >= signed
    NL = 13,
    /// <= signed
    LE = 14,
    /// > signed
    NLE = 15,
    /// parity
    P = 10,
    /// not parity
    NP = 11,
}
impl CC {
    pub(crate) fn from_intcc(intcc: IntCC) -> Self {
        match intcc {
            IntCC::Equal => CC::Z,
            IntCC::NotEqual => CC::NZ,
            IntCC::SignedGreaterThanOrEqual => CC::NL,
            IntCC::SignedGreaterThan => CC::NLE,
            IntCC::SignedLessThanOrEqual => CC::LE,
            IntCC::SignedLessThan => CC::L,
            IntCC::UnsignedGreaterThanOrEqual => CC::NB,
            IntCC::UnsignedGreaterThan => CC::NBE,
            IntCC::UnsignedLessThanOrEqual => CC::BE,
            IntCC::UnsignedLessThan => CC::B,
        }
    }
    pub(crate) fn invert(&self) -> Self {
        match self {
            CC::O => CC::NO,
            CC::NO => CC::O,
            CC::B => CC::NB,
            CC::NB => CC::B,
            CC::Z => CC::NZ,
            CC::NZ => CC::Z,
            CC::BE => CC::NBE,
            CC::NBE => CC::BE,
            CC::S => CC::NS,
            CC::NS => CC::S,
            CC::L => CC::NL,
            CC::NL => CC::L,
            CC::LE => CC::NLE,
            CC::NLE => CC::LE,
            CC::P => CC::NP,
            CC::NP => CC::P,
        }
    }
    pub(crate) fn get_enc(self) -> u8 {
        self as u8
    }
}
impl fmt::Debug for CC {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let name = match self {
            CC::O => "o",
            CC::NO => "no",
            CC::B => "b",
            CC::NB => "nb",
            CC::Z => "z",
            CC::NZ => "nz",
            CC::BE => "be",
            CC::NBE => "nbe",
            CC::S => "s",
            CC::NS => "ns",
            CC::L => "l",
            CC::NL => "nl",
            CC::LE => "le",
            CC::NLE => "nle",
            CC::P => "p",
            CC::NP => "np",
        };
        write!(fmt, "{}", name)
    }
}
impl fmt::Display for CC {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self, f)
    }
}
/// Encode the ways that floats can be compared. This is used in float comparisons such as `cmpps`,
/// e.g.; it is distinguished from other float comparisons (e.g. `ucomiss`) in that those use EFLAGS
/// whereas [FcmpImm] is used as an immediate.
#[derive(Clone, Copy)]
pub enum FcmpImm {
    /// Equal comparison.
    Equal = 0x00,
    /// Less than comparison.
    LessThan = 0x01,
    /// Less than or equal comparison.
    LessThanOrEqual = 0x02,
    /// Unordered.
    Unordered = 0x03,
    /// Not equal comparison.
    NotEqual = 0x04,
    /// Unordered of greater than or equal comparison.
    UnorderedOrGreaterThanOrEqual = 0x05,
    /// Unordered or greater than comparison.
    UnorderedOrGreaterThan = 0x06,
    /// Ordered.
    Ordered = 0x07,
}
impl FcmpImm {
    pub(crate) fn encode(self) -> u8 {
        self as u8
    }
}
impl From<FloatCC> for FcmpImm {
    fn from(cond: FloatCC) -> Self {
        match cond {
            FloatCC::Equal => FcmpImm::Equal,
            FloatCC::LessThan => FcmpImm::LessThan,
            FloatCC::LessThanOrEqual => FcmpImm::LessThanOrEqual,
            FloatCC::Unordered => FcmpImm::Unordered,
            FloatCC::NotEqual => FcmpImm::NotEqual,
            FloatCC::UnorderedOrGreaterThanOrEqual => FcmpImm::UnorderedOrGreaterThanOrEqual,
            FloatCC::UnorderedOrGreaterThan => FcmpImm::UnorderedOrGreaterThan,
            FloatCC::Ordered => FcmpImm::Ordered,
            _ => panic!("unable to create comparison predicate for {}", cond),
        }
    }
}
/// Encode the rounding modes used as part of the Rounding Control field.
/// Note, these rounding immediates only consider the rounding control field
/// (i.e. the rounding mode) which only take up the first two bits when encoded.
/// However the rounding immediate which this field helps make up, also includes
/// bits 3 and 4 which define the rounding select and precision mask respectively.
/// These two bits are not defined here and are implictly set to zero when encoded.
#[derive(Clone, Copy)]
pub enum RoundImm {
    /// Round to nearest mode.
    RoundNearest = 0x00,
    /// Round down mode.
    RoundDown = 0x01,
    /// Round up mode.
    RoundUp = 0x02,
    /// Round to zero mode.
    RoundZero = 0x03,
}
impl RoundImm {
    pub(crate) fn encode(self) -> u8 {
        self as u8
    }
}
/// An operand's size in bits.
#[derive(Clone, Copy, PartialEq)]
pub enum OperandSize {
    /// 8-bit.
    Size8,
    /// 16-bit.
    Size16,
    /// 32-bit.
    Size32,
    /// 64-bit.
    Size64,
}
impl OperandSize {
    pub(crate) fn from_bytes(num_bytes: u32) -> Self {
        match num_bytes {
            1 => OperandSize::Size8,
            2 => OperandSize::Size16,
            4 => OperandSize::Size32,
            8 => OperandSize::Size64,
            _ => unreachable!("Invalid OperandSize: {}", num_bytes),
        }
    }
    // Computes the OperandSize for a given type.
    // For vectors, the OperandSize of the lanes is returned.
    pub(crate) fn from_ty(ty: Type) -> Self {
        Self::from_bytes(ty.lane_type().bytes())
    }
    // Check that the value of self is one of the allowed sizes.
    pub(crate) fn is_one_of(&self, sizes: &[Self]) -> bool {
        sizes.iter().any(|val| *self == *val)
    }
    pub(crate) fn to_bytes(&self) -> u8 {
        match self {
            Self::Size8 => 1,
            Self::Size16 => 2,
            Self::Size32 => 4,
            Self::Size64 => 8,
        }
    }
    pub(crate) fn to_bits(&self) -> u8 {
        self.to_bytes() * 8
    }
}
/// An x64 memory fence kind.
#[derive(Clone)]
#[allow(dead_code)]
pub enum FenceKind {
    /// `mfence` instruction ("Memory Fence")
    MFence,
    /// `lfence` instruction ("Load Fence")
    LFence,
    /// `sfence` instruction ("Store Fence")
    SFence,
}