cranelift_assembler_x64_meta/dsl/
encoding.rs

1//! A DSL for describing x64 encodings.
2//!
3//! Intended use:
4//! - construct an encoding using an abbreviated helper, e.g., [`rex`]
5//! - then, configure the encoding using builder methods, e.g., [`Rex::w`]
6//!
7//! ```
8//! # use cranelift_assembler_x64_meta::dsl::rex;
9//! let enc = rex(0x25).w().id();
10//! assert_eq!(enc.to_string(), "REX.W + 0x25 id")
11//! ```
12//!
13//! This module references the Intel® 64 and IA-32 Architectures Software
14//! Development Manual, Volume 2: [link].
15//!
16//! [link]: https://software.intel.com/content/www/us/en/develop/articles/intel-sdm.html
17
18use super::{Operand, OperandKind};
19use core::fmt;
20
21/// An abbreviated constructor for REX-encoded instructions.
22#[must_use]
23pub fn rex(opcode: impl Into<Opcodes>) -> Rex {
24    Rex {
25        opcodes: opcode.into(),
26        w: WBit::W0,
27        modrm: None,
28        imm: Imm::None,
29        opcode_mod: None,
30    }
31}
32
33/// An abbreviated constructor for VEX-encoded instructions.
34#[must_use]
35pub fn vex(length: Length) -> Vex {
36    Vex {
37        length,
38        pp: None,
39        mmmmm: None,
40        w: WBit::WIG,
41        opcode: u8::MAX,
42        modrm: None,
43        imm: Imm::None,
44        is4: false,
45    }
46}
47
48/// An abbreviated constructor for EVEX-encoded instructions.
49#[must_use]
50pub fn evex(length: Length, tuple_type: TupleType) -> Evex {
51    Evex {
52        length,
53        pp: None,
54        mmm: None,
55        w: WBit::WIG,
56        opcode: u8::MAX,
57        modrm: None,
58        imm: Imm::None,
59        tuple_type,
60    }
61}
62
63/// Enumerate the ways x64 encodes instructions.
64pub enum Encoding {
65    Rex(Rex),
66    Vex(Vex),
67    Evex(Evex),
68}
69
70impl Encoding {
71    /// Check that the encoding is valid for the given operands; this can find
72    /// issues earlier, before generating any Rust code.
73    pub fn validate(&self, operands: &[Operand]) {
74        match self {
75            Encoding::Rex(rex) => rex.validate(operands),
76            Encoding::Vex(vex) => vex.validate(operands),
77            Encoding::Evex(evex) => evex.validate(operands),
78        }
79    }
80
81    /// Return the opcode for this encoding.
82    pub fn opcode(&self) -> u8 {
83        match self {
84            Encoding::Rex(rex) => rex.opcodes.opcode(),
85            Encoding::Vex(vex) => vex.opcode,
86            Encoding::Evex(evex) => evex.opcode,
87        }
88    }
89}
90
91impl fmt::Display for Encoding {
92    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
93        match self {
94            Encoding::Rex(rex) => write!(f, "{rex}"),
95            Encoding::Vex(vex) => write!(f, "{vex}"),
96            Encoding::Evex(evex) => write!(f, "{evex}"),
97        }
98    }
99}
100
101#[derive(Clone, Copy, PartialEq)]
102pub enum ModRmKind {
103    /// Models `/digit`.
104    ///
105    /// From the reference manual: "a digit between 0 and 7 indicates that the
106    /// ModR/M byte of the instruction uses only the r/m (register or memory)
107    /// operand. The reg field contains the digit that provides an extension to
108    /// the instruction's opcode."
109    Digit(u8),
110
111    /// Models `/r`.
112    ///
113    /// From the reference manual: "indicates that the ModR/M byte of the
114    /// instruction contains a register operand and an r/m operand."
115    Reg,
116}
117
118impl ModRmKind {
119    /// Return the digit extending the opcode, if available.
120    #[must_use]
121    pub fn digit(&self) -> Option<u8> {
122        match self {
123            Self::Digit(digit) => Some(*digit),
124            _ => None,
125        }
126    }
127
128    /// Return the digit extending the opcode.
129    ///
130    /// # Panics
131    ///
132    /// Panics if not extension was defined.
133    pub fn unwrap_digit(&self) -> u8 {
134        self.digit().expect("expected an extension digit")
135    }
136}
137
138impl fmt::Display for ModRmKind {
139    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
140        match self {
141            ModRmKind::Digit(digit) => write!(f, "/{digit}"),
142            ModRmKind::Reg => write!(f, "/r"),
143        }
144    }
145}
146
147/// The traditional x64 encoding.
148///
149/// We use the "REX" name here in a slightly unorthodox way: "REX" is the name
150/// for the optional _byte_ extending the number of available registers, e.g.,
151/// but we use it here to distinguish this from other encoding formats (e.g.,
152/// VEX, EVEX). The "REX" _byte_ is still optional in this encoding and only
153/// emitted when necessary.
154pub struct Rex {
155    /// The opcodes for this instruction.
156    ///
157    /// Multi-byte opcodes are handled by passing an array of opcodes (including
158    /// prefixes like `0x66` and escape bytes like `0x0f`) to the constructor.
159    /// E.g., `66 0F 54` (`ANDPD`) is expressed as follows:
160    ///
161    /// ```
162    /// # use cranelift_assembler_x64_meta::dsl::rex;
163    /// let enc = rex([0x66, 0x0f, 0x54]);
164    /// ```
165    pub opcodes: Opcodes,
166    /// Indicates setting the REX.W bit.
167    ///
168    /// From the reference manual: "Indicates the use of a REX prefix that
169    /// affects operand size or instruction semantics. The ordering of the REX
170    /// prefix and other optional/mandatory instruction prefixes are discussed
171    /// in chapter 2. Note that REX prefixes that promote legacy instructions to
172    /// 64-bit behavior are not listed explicitly in the opcode column."
173    pub w: WBit,
174    /// Indicates modifications to the ModR/M byte.
175    pub modrm: Option<ModRmKind>,
176    /// The number of bits used as an immediate operand to the instruction.
177    pub imm: Imm,
178    /// Used for `+rb`, `+rw`, `+rd`, and `+ro` instructions, which encode `reg`
179    /// bits in the opcode byte; if `Some`, this contains the expected bit width
180    /// of `reg`.
181    ///
182    /// From the reference manual: "[...] the lower 3 bits of the opcode byte is
183    /// used to encode the register operand without a modR/M byte. The
184    /// instruction lists the corresponding hexadecimal value of the opcode byte
185    /// with low 3 bits as 000b. In non-64-bit mode, a register code, from 0
186    /// through 7, is added to the hexadecimal value of the opcode byte. In
187    /// 64-bit mode, indicates the four bit field of REX.b and opcode[2:0] field
188    /// encodes the register operand of the instruction. “+ro” is applicable
189    /// only in 64-bit mode."
190    pub opcode_mod: Option<OpcodeMod>,
191}
192
193impl Rex {
194    /// Set the `REX.W` bit.
195    #[must_use]
196    pub fn w(self) -> Self {
197        Self {
198            w: WBit::W1,
199            ..self
200        }
201    }
202
203    /// Set the ModR/M byte to contain a register operand and an r/m operand;
204    /// equivalent to `/r` in the reference manual.
205    #[must_use]
206    pub fn r(self) -> Self {
207        Self {
208            modrm: Some(ModRmKind::Reg),
209            ..self
210        }
211    }
212
213    /// Set the digit extending the opcode; equivalent to `/<digit>` in the
214    /// reference manual.
215    ///
216    /// # Panics
217    ///
218    /// Panics if `extension` is too large.
219    #[must_use]
220    pub fn digit(self, extension: u8) -> Self {
221        assert!(extension <= 0b111, "must fit in 3 bits");
222        Self {
223            modrm: Some(ModRmKind::Digit(extension)),
224            ..self
225        }
226    }
227
228    /// Retrieve the digit extending the opcode, if available.
229    #[must_use]
230    pub fn unwrap_digit(&self) -> Option<u8> {
231        match self.modrm {
232            Some(ModRmKind::Digit(digit)) => Some(digit),
233            _ => None,
234        }
235    }
236
237    /// Append a byte-sized immediate operand (8-bit); equivalent to `ib` in the
238    /// reference manual.
239    ///
240    /// # Panics
241    ///
242    /// Panics if an immediate operand is already set.
243    #[must_use]
244    pub fn ib(self) -> Self {
245        assert_eq!(self.imm, Imm::None);
246        Self {
247            imm: Imm::ib,
248            ..self
249        }
250    }
251
252    /// Append a word-sized immediate operand (16-bit); equivalent to `iw` in
253    /// the reference manual.
254    ///
255    /// # Panics
256    ///
257    /// Panics if an immediate operand is already set.
258    #[must_use]
259    pub fn iw(self) -> Self {
260        assert_eq!(self.imm, Imm::None);
261        Self {
262            imm: Imm::iw,
263            ..self
264        }
265    }
266
267    /// Append a doubleword-sized immediate operand (32-bit); equivalent to `id`
268    /// in the reference manual.
269    ///
270    /// # Panics
271    ///
272    /// Panics if an immediate operand is already set.
273    #[must_use]
274    pub fn id(self) -> Self {
275        assert_eq!(self.imm, Imm::None);
276        Self {
277            imm: Imm::id,
278            ..self
279        }
280    }
281
282    /// Append a quadword-sized immediate operand (64-bit); equivalent to `io`
283    /// in the reference manual.
284    ///
285    /// # Panics
286    ///
287    /// Panics if an immediate operand is already set.
288    #[must_use]
289    pub fn io(self) -> Self {
290        assert_eq!(self.imm, Imm::None);
291        Self {
292            imm: Imm::io,
293            ..self
294        }
295    }
296
297    /// Modify the opcode byte with bits from an 8-bit `reg`; equivalent to
298    /// `+rb` in the reference manual.
299    #[must_use]
300    pub fn rb(self) -> Self {
301        Self {
302            opcode_mod: Some(OpcodeMod::rb),
303            ..self
304        }
305    }
306
307    /// Modify the opcode byte with bits from a 16-bit `reg`; equivalent to
308    /// `+rw` in the reference manual.
309    #[must_use]
310    pub fn rw(self) -> Self {
311        Self {
312            opcode_mod: Some(OpcodeMod::rw),
313            ..self
314        }
315    }
316
317    /// Modify the opcode byte with bits from a 32-bit `reg`; equivalent to
318    /// `+rd` in the reference manual.
319    #[must_use]
320    pub fn rd(self) -> Self {
321        Self {
322            opcode_mod: Some(OpcodeMod::rd),
323            ..self
324        }
325    }
326
327    /// Modify the opcode byte with bits from a 64-bit `reg`; equivalent to
328    /// `+ro` in the reference manual.
329    #[must_use]
330    pub fn ro(self) -> Self {
331        Self {
332            opcode_mod: Some(OpcodeMod::ro),
333            ..self
334        }
335    }
336
337    /// Check a subset of the rules for valid encodings outlined in chapter 2,
338    /// _Instruction Format_, of the Intel® 64 and IA-32 Architectures Software
339    /// Developer’s Manual, Volume 2A.
340    fn validate(&self, operands: &[Operand]) {
341        if let Some(OperandKind::Imm(op)) = operands
342            .iter()
343            .map(|o| o.location.kind())
344            .find(|k| matches!(k, OperandKind::Imm(_)))
345        {
346            assert_eq!(
347                op.bits(),
348                self.imm.bits(),
349                "for an immediate, the encoding width must match the declared operand width"
350            );
351        }
352
353        if let Some(opcode_mod) = &self.opcode_mod {
354            assert!(
355                self.opcodes.primary & 0b111 == 0,
356                "the lower three bits of the opcode byte should be 0"
357            );
358            assert!(
359                operands
360                    .iter()
361                    .all(|o| o.location.bits() == opcode_mod.bits().into()),
362                "the opcode modifier width must match the operand widths"
363            );
364        }
365
366        assert!(!matches!(self.w, WBit::WIG));
367    }
368}
369
370impl From<Rex> for Encoding {
371    fn from(rex: Rex) -> Encoding {
372        Encoding::Rex(rex)
373    }
374}
375
376impl fmt::Display for Rex {
377    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
378        if let Some(group1) = &self.opcodes.prefixes.group1 {
379            write!(f, "{group1} + ")?;
380        }
381        if let Some(group2) = &self.opcodes.prefixes.group2 {
382            write!(f, "{group2} + ")?;
383        }
384        if let Some(group3) = &self.opcodes.prefixes.group3 {
385            write!(f, "{group3} + ")?;
386        }
387        if let Some(group4) = &self.opcodes.prefixes.group4 {
388            write!(f, "{group4} + ")?;
389        }
390        if self.w.as_bool() {
391            write!(f, "REX.W + ")?;
392        }
393        if self.opcodes.escape {
394            write!(f, "0x0F + ")?;
395        }
396        write!(f, "{:#04X}", self.opcodes.primary)?;
397        if let Some(secondary) = self.opcodes.secondary {
398            write!(f, " {secondary:#04X}")?;
399        }
400        if let Some(modrm) = self.modrm {
401            write!(f, " {modrm}")?;
402        }
403        if let Some(opcode_mod) = &self.opcode_mod {
404            write!(f, " {opcode_mod}")?;
405        }
406        if self.imm != Imm::None {
407            write!(f, " {}", self.imm)?;
408        }
409        Ok(())
410    }
411}
412
413/// Describe an instruction's opcodes. From section 2.1.2 "Opcodes" in the
414/// reference manual:
415///
416/// > A primary opcode can be 1, 2, or 3 bytes in length. An additional 3-bit
417/// > opcode field is sometimes encoded in the ModR/M byte. Smaller fields can
418/// > be defined within the primary opcode. Such fields define the direction of
419/// > operation, size of displacements, register encoding, condition codes, or
420/// > sign extension. Encoding fields used by an opcode vary depending on the
421/// > class of operation.
422/// >
423/// > Two-byte opcode formats for general-purpose and SIMD instructions consist
424/// > of one of the following:
425/// > - An escape opcode byte `0FH` as the primary opcode and a second opcode
426/// >   byte.
427/// > - A mandatory prefix (`66H`, `F2H`, or `F3H`), an escape opcode byte, and
428/// >   a second opcode byte (same as previous bullet).
429/// >
430/// > For example, `CVTDQ2PD` consists of the following sequence: `F3 0F E6`.
431/// > The first byte is a mandatory prefix (it is not considered as a repeat
432/// > prefix).
433/// >
434/// > Three-byte opcode formats for general-purpose and SIMD instructions
435/// > consist of one of the following:
436/// > - An escape opcode byte `0FH` as the primary opcode, plus two additional
437/// >   opcode bytes.
438/// > - A mandatory prefix (`66H`, `F2H`, or `F3H`), an escape opcode byte, plus
439/// >   two additional opcode bytes (same as previous bullet).
440/// >
441/// > For example, `PHADDW` for XMM registers consists of the following
442/// > sequence: `66 0F 38 01`. The first byte is the mandatory prefix.
443pub struct Opcodes {
444    /// The prefix bytes for this instruction.
445    pub prefixes: Prefixes,
446    /// Indicates the use of an escape opcode byte, `0x0f`.
447    pub escape: bool,
448    /// The primary opcode.
449    pub primary: u8,
450    /// Some instructions (e.g., SIMD) may have a secondary opcode.
451    pub secondary: Option<u8>,
452}
453
454impl Opcodes {
455    /// Return the main opcode for this instruction.
456    ///
457    /// Note that [`Rex`]-encoded instructions have a complex opcode scheme (see
458    /// [`Opcodes`] documentation); the opcode one is usually looking for is the
459    /// last one. This returns the last opcode: the secondary opcode if one is
460    /// available and the primary otherwise.
461    fn opcode(&self) -> u8 {
462        if let Some(secondary) = self.secondary {
463            secondary
464        } else {
465            self.primary
466        }
467    }
468}
469
470impl From<u8> for Opcodes {
471    fn from(primary: u8) -> Opcodes {
472        Opcodes {
473            prefixes: Prefixes::default(),
474            escape: false,
475            primary,
476            secondary: None,
477        }
478    }
479}
480
481impl<const N: usize> From<[u8; N]> for Opcodes {
482    fn from(bytes: [u8; N]) -> Self {
483        let (prefixes, remaining) = Prefixes::parse(&bytes);
484        let (escape, primary, secondary) = match remaining {
485            [primary] => (false, *primary, None),
486            [0x0f, primary] => (true, *primary, None),
487            [0x0f, primary, secondary] => (true, *primary, Some(*secondary)),
488            _ => panic!(
489                "invalid opcodes after prefix; expected [opcode], [0x0f, opcode], or [0x0f, opcode, opcode], found {remaining:x?}"
490            ),
491        };
492        Self {
493            prefixes,
494            escape,
495            primary,
496            secondary,
497        }
498    }
499}
500
501/// The allowed prefixes for an instruction. From the reference manual (section
502/// 2.1.1):
503///
504/// > Instruction prefixes are divided into four groups, each with a set of
505/// > allowable prefix codes. For each instruction, it is only useful to include
506/// > up to one prefix code from each of the four groups (Groups 1, 2, 3, 4).
507/// > Groups 1 through 4 may be placed in any order relative to each other.
508#[derive(Default)]
509pub struct Prefixes {
510    pub group1: Option<Group1Prefix>,
511    pub group2: Option<Group2Prefix>,
512    pub group3: Option<Group3Prefix>,
513    pub group4: Option<Group4Prefix>,
514}
515
516impl Prefixes {
517    /// Parse a slice of `bytes` into a set of prefixes, returning both the
518    /// configured [`Prefixes`] as well as any remaining bytes.
519    fn parse(mut bytes: &[u8]) -> (Self, &[u8]) {
520        let mut prefixes = Self::default();
521        while !bytes.is_empty() && prefixes.try_assign(bytes[0]).is_ok() {
522            bytes = &bytes[1..];
523        }
524        (prefixes, bytes)
525    }
526
527    /// Attempt to parse a `byte` as a prefix and, if successful, assigns it to
528    /// the correct prefix group.
529    ///
530    /// # Panics
531    ///
532    /// This function panics if the prefix for a group is already set; this
533    /// disallows specifying multiple prefixes per group.
534    fn try_assign(&mut self, byte: u8) -> Result<(), ()> {
535        if let Ok(p) = Group1Prefix::try_from(byte) {
536            assert!(self.group1.is_none());
537            self.group1 = Some(p);
538            Ok(())
539        } else if let Ok(p) = Group2Prefix::try_from(byte) {
540            assert!(self.group2.is_none());
541            self.group2 = Some(p);
542            Ok(())
543        } else if let Ok(p) = Group3Prefix::try_from(byte) {
544            assert!(self.group3.is_none());
545            self.group3 = Some(p);
546            Ok(())
547        } else if let Ok(p) = Group4Prefix::try_from(byte) {
548            assert!(self.group4.is_none());
549            self.group4 = Some(p);
550            Ok(())
551        } else {
552            Err(())
553        }
554    }
555
556    /// Check if any prefix is present.
557    pub fn is_empty(&self) -> bool {
558        self.group1.is_none()
559            && self.group2.is_none()
560            && self.group3.is_none()
561            && self.group4.is_none()
562    }
563}
564
565pub enum Group1Prefix {
566    /// The LOCK prefix (`0xf0`). From the reference manual:
567    ///
568    /// > The LOCK prefix (F0H) forces an operation that ensures exclusive use
569    /// > of shared memory in a multiprocessor environment. See "LOCK—Assert
570    /// > LOCK# Signal Prefix" in Chapter 3, Instruction Set Reference, A-L, for
571    /// > a description of this prefix.
572    Lock,
573    /// A REPNE/REPNZ prefix (`0xf2`) or a BND prefix under certain conditions.
574    /// `REP*` prefixes apply only to string and input/output instructions but
575    /// can be used as mandatory prefixes in other kinds of instructions (e.g.,
576    /// SIMD) From the reference manual:
577    ///
578    /// > Repeat prefixes (F2H, F3H) cause an instruction to be repeated for
579    /// > each element of a string. Use these prefixes only with string and I/O
580    /// > instructions (MOVS, CMPS, SCAS, LODS, STOS, INS, and OUTS). Use of
581    /// > repeat prefixes and/or undefined opcodes with other Intel 64 or IA-32
582    /// > instructions is reserved; such use may cause unpredictable behavior.
583    /// >
584    /// > Some instructions may use F2H, F3H as a mandatory prefix to express
585    /// > distinct functionality.
586    REPNorBND,
587    /// A REPE/REPZ prefix (`0xf3`); `REP*` prefixes apply only to string and
588    /// input/output instructions but can be used as mandatory prefixes in other
589    /// kinds of instructions (e.g., SIMD). See `REPNorBND` for more details.
590    REP_,
591}
592
593impl TryFrom<u8> for Group1Prefix {
594    type Error = u8;
595    fn try_from(byte: u8) -> Result<Self, Self::Error> {
596        Ok(match byte {
597            0xF0 => Group1Prefix::Lock,
598            0xF2 => Group1Prefix::REPNorBND,
599            0xF3 => Group1Prefix::REP_,
600            byte => return Err(byte),
601        })
602    }
603}
604
605impl fmt::Display for Group1Prefix {
606    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
607        match self {
608            Group1Prefix::Lock => write!(f, "0xF0"),
609            Group1Prefix::REPNorBND => write!(f, "0xF2"),
610            Group1Prefix::REP_ => write!(f, "0xF3"),
611        }
612    }
613}
614
615/// Contains the segment override prefixes or a (deprecated) branch hint when
616/// used on a `Jcc` instruction. Note that using the segment override prefixes
617/// on a branch instruction is reserved. See section 2.1.1, "Instruction
618/// Prefixes," in the reference manual.
619pub enum Group2Prefix {
620    /// The CS segment override prefix (`0x2e`); also the "branch not taken"
621    /// hint.
622    CSorBNT,
623    /// The SS segment override prefix (`0x36`).
624    SS,
625    /// The DS segment override prefix (`0x3e`); also the "branch taken" hint.
626    DSorBT,
627    /// The ES segment override prefix (`0x26`).
628    ES,
629    /// The FS segment override prefix (`0x64`).
630    FS,
631    /// The GS segment override prefix (`0x65`).
632    GS,
633}
634
635impl TryFrom<u8> for Group2Prefix {
636    type Error = u8;
637    fn try_from(byte: u8) -> Result<Self, Self::Error> {
638        Ok(match byte {
639            0x2E => Group2Prefix::CSorBNT,
640            0x36 => Group2Prefix::SS,
641            0x3E => Group2Prefix::DSorBT,
642            0x26 => Group2Prefix::ES,
643            0x64 => Group2Prefix::FS,
644            0x65 => Group2Prefix::GS,
645            byte => return Err(byte),
646        })
647    }
648}
649
650impl fmt::Display for Group2Prefix {
651    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
652        match self {
653            Group2Prefix::CSorBNT => write!(f, "0x2E"),
654            Group2Prefix::SS => write!(f, "0x36"),
655            Group2Prefix::DSorBT => write!(f, "0x3E"),
656            Group2Prefix::ES => write!(f, "0x26"),
657            Group2Prefix::FS => write!(f, "0x64"),
658            Group2Prefix::GS => write!(f, "0x65"),
659        }
660    }
661}
662
663/// Contains the operand-size override prefix (`0x66`); also used as a SIMD
664/// prefix. From the reference manual:
665///
666/// > The operand-size override prefix allows a program to switch between 16-
667/// > and 32-bit operand sizes. Either size can be the default; use of the
668/// > prefix selects the non-default size. Some SSE2/SSE3/SSSE3/SSE4
669/// > instructions and instructions using a three-byte sequence of primary
670/// > opcode bytes may use 66H as a mandatory prefix to express distinct
671/// > functionality.
672pub enum Group3Prefix {
673    OperandSizeOverride,
674}
675
676impl TryFrom<u8> for Group3Prefix {
677    type Error = u8;
678    fn try_from(byte: u8) -> Result<Self, Self::Error> {
679        Ok(match byte {
680            0x66 => Group3Prefix::OperandSizeOverride,
681            byte => return Err(byte),
682        })
683    }
684}
685
686impl fmt::Display for Group3Prefix {
687    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
688        match self {
689            Group3Prefix::OperandSizeOverride => write!(f, "0x66"),
690        }
691    }
692}
693
694/// Contains the address-size override prefix (`0x67`). From the reference
695/// manual:
696///
697/// > The address-size override prefix (67H) allows programs to switch between
698/// > 16- and 32-bit addressing. Either size can be the default; the prefix
699/// > selects the non-default size.
700pub enum Group4Prefix {
701    AddressSizeOverride,
702}
703
704impl TryFrom<u8> for Group4Prefix {
705    type Error = u8;
706    fn try_from(byte: u8) -> Result<Self, Self::Error> {
707        Ok(match byte {
708            0x67 => Group4Prefix::AddressSizeOverride,
709            byte => return Err(byte),
710        })
711    }
712}
713
714impl fmt::Display for Group4Prefix {
715    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
716        match self {
717            Group4Prefix::AddressSizeOverride => write!(f, "0x67"),
718        }
719    }
720}
721
722/// Indicate the size of an immediate operand. From the reference manual:
723///
724/// > A 1-byte (ib), 2-byte (iw), 4-byte (id) or 8-byte (io) immediate operand
725/// > to the instruction that follows the opcode, ModR/M bytes or scale-indexing
726/// > bytes. The opcode determines if the operand is a signed value. All words,
727/// > doublewords, and quadwords are given with the low-order byte first.
728#[derive(Debug, PartialEq)]
729#[allow(non_camel_case_types, reason = "makes DSL definitions easier to read")]
730pub enum Imm {
731    None,
732    ib,
733    iw,
734    id,
735    io,
736}
737
738impl Imm {
739    fn bits(&self) -> u16 {
740        match self {
741            Self::None => 0,
742            Self::ib => 8,
743            Self::iw => 16,
744            Self::id => 32,
745            Self::io => 64,
746        }
747    }
748}
749
750impl fmt::Display for Imm {
751    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
752        match self {
753            Self::None => write!(f, ""),
754            Self::ib => write!(f, "ib"),
755            Self::iw => write!(f, "iw"),
756            Self::id => write!(f, "id"),
757            Self::io => write!(f, "io"),
758        }
759    }
760}
761
762/// Indicate the size of the `reg` used when modifying the lower three bits of
763/// the opcode byte; this corresponds to the `+rb`, `+rw`, `+rd`, and `+ro`
764/// modifiers in the reference manual.
765///
766/// ```
767/// # use cranelift_assembler_x64_meta::dsl::{rex};
768/// // The `bswap` instruction extends the opcode byte:
769/// let enc = rex([0x0F, 0xC8]).rd();
770/// assert_eq!(enc.to_string(), "0x0F + 0xC8 +rd");
771/// ```
772#[derive(Clone, Copy, Debug, PartialEq)]
773#[allow(non_camel_case_types, reason = "makes DSL definitions easier to read")]
774pub enum OpcodeMod {
775    rb,
776    rw,
777    rd,
778    ro,
779}
780
781impl OpcodeMod {
782    fn bits(&self) -> u8 {
783        match self {
784            Self::rb => 8,
785            Self::rw => 16,
786            Self::rd => 32,
787            Self::ro => 64,
788        }
789    }
790}
791
792impl fmt::Display for OpcodeMod {
793    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
794        match self {
795            Self::rb => write!(f, "+rb"),
796            Self::rw => write!(f, "+rw"),
797            Self::rd => write!(f, "+rd"),
798            Self::ro => write!(f, "+ro"),
799        }
800    }
801}
802
803/// Contains the legacy prefixes allowed for VEX-encoded instructions.
804///
805/// VEX encodes a subset of [`Group1Prefix`] and `0x66` (see [`Group3Prefix`])
806/// as part of the `pp` bit field.
807#[derive(Clone, Copy, PartialEq)]
808pub enum VexPrefix {
809    _66,
810    _F2,
811    _F3,
812}
813
814impl VexPrefix {
815    /// Encode the `pp` bits.
816    #[inline(always)]
817    pub(crate) fn bits(self) -> u8 {
818        match self {
819            Self::_66 => 0b01,
820            Self::_F3 => 0b10,
821            Self::_F2 => 0b11,
822        }
823    }
824}
825
826impl fmt::Display for VexPrefix {
827    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
828        match self {
829            Self::_66 => write!(f, "66"),
830            Self::_F3 => write!(f, "F3"),
831            Self::_F2 => write!(f, "F2"),
832        }
833    }
834}
835
836/// Contains the escape sequences allowed for VEX-encoded instructions.
837///
838/// VEX encodes these in the `mmmmmm` bit field.
839#[derive(Clone, Copy, PartialEq)]
840pub enum VexEscape {
841    _0F,
842    _0F3A,
843    _0F38,
844}
845
846impl VexEscape {
847    /// Encode the `m-mmmm` bits.
848    #[inline(always)]
849    pub(crate) fn bits(&self) -> u8 {
850        match self {
851            Self::_0F => 0b01,
852            Self::_0F38 => 0b10,
853            Self::_0F3A => 0b11,
854        }
855    }
856}
857
858impl fmt::Display for VexEscape {
859    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
860        match self {
861            Self::_0F => write!(f, "0F"),
862            Self::_0F3A => write!(f, "0F3A"),
863            Self::_0F38 => write!(f, "0F38"),
864        }
865    }
866}
867
868/// Contains vector length definitions.
869///
870/// VEX encodes these in the `L` bit field, a single bit with `128-bit = 0` and
871/// `256-bit = 1`. For convenience, we also include the `LIG` and `LZ` syntax,
872/// used by the reference manual, and always set these to `0`.
873///
874/// EVEX encodes this in the `L'L` bits, two bits that typically indicate the
875/// vector length for packed vector instructions but can also be used for
876/// rounding control for floating-point instructions with rounding semantics
877/// (see section 2.7.1 in the reference manual).
878pub enum Length {
879    /// 128-bit vector length.
880    L128,
881    /// 256-bit vector length.
882    L256,
883    /// 512-bit vector length; invalid for VEX instructions.
884    L512,
885    /// Force the length bits to `0`, but not necessarily for 128-bit operation.
886    /// From the reference manual: "The VEX.L must be encoded to be 0B, an #UD
887    /// occurs if VEX.L is not zero."
888    LZ,
889    /// The length bits are ignored (e.g., for floating point scalar
890    /// instructions). This assembler will emit `0`.
891    LIG,
892}
893
894impl Length {
895    /// Encode the `VEX.L` bit.
896    pub fn vex_bits(&self) -> u8 {
897        match self {
898            Self::L128 | Self::LIG | Self::LZ => 0b0,
899            Self::L256 => 0b1,
900            Self::L512 => unreachable!("VEX does not support 512-bit vector length"),
901        }
902    }
903
904    /// Encode the `EVEX.L'L` bits.
905    ///
906    /// See section 2.7.10, Vector Length Orthogonality, in the reference manual
907    pub fn evex_bits(&self) -> u8 {
908        match self {
909            Self::L128 | Self::LIG | Self::LZ => 0b00,
910            Self::L256 => 0b01,
911            Self::L512 => 0b10,
912        }
913    }
914}
915
916impl fmt::Display for Length {
917    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
918        match self {
919            Self::L128 => write!(f, "128"),
920            Self::L256 => write!(f, "256"),
921            Self::L512 => write!(f, "512"),
922            Self::LIG => write!(f, "LIG"),
923            Self::LZ => write!(f, "LZ"),
924        }
925    }
926}
927
928/// Model the `W` bit.
929pub enum WBit {
930    /// The `W` bit is ignored; equivalent to `.WIG` in the manual.
931    WIG,
932    /// The `W` bit is set to `0`; equivalent to `.W0` in the manual.
933    W0,
934    /// The `W` bit is set to `1`; equivalent to `.W1` in the manual.
935    W1,
936}
937
938impl WBit {
939    /// Return `true` if the `W` bit is ignored; this is useful to check in the
940    /// DSL for the default case.
941    fn is_ignored(&self) -> bool {
942        match self {
943            Self::WIG => true,
944            Self::W0 | Self::W1 => false,
945        }
946    }
947
948    /// Return `true` if the `W` bit is set (`W1`); otherwise, return `false`.
949    pub(crate) fn as_bool(&self) -> bool {
950        match self {
951            Self::W1 => true,
952            Self::W0 | Self::WIG => false,
953        }
954    }
955}
956
957impl fmt::Display for WBit {
958    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
959        match self {
960            Self::WIG => write!(f, "WIG"),
961            Self::W0 => write!(f, "W0"),
962            Self::W1 => write!(f, "W1"),
963        }
964    }
965}
966
967/// The VEX encoding, introduced for AVX instructions.
968///
969/// ```
970/// # use cranelift_assembler_x64_meta::dsl::{vex, Length::L128};
971/// // To encode a BLENDPD instruction in the manual: VEX.128.66.0F3A.WIG 0D /r ib
972/// let enc = vex(L128)._66()._0f3a().wig().op(0x0D).r().ib();
973/// assert_eq!(enc.to_string(), "VEX.128.66.0F3A.WIG 0x0D /r ib");
974/// ```
975pub struct Vex {
976    /// The length of the operand (e.g., 128-bit or 256-bit).
977    pub length: Length,
978    /// Any SIMD prefixes, but encoded in the `VEX.pp` bit field.
979    pub pp: Option<VexPrefix>,
980    /// Any leading map bytes, but encoded in the `VEX.mmmmm` bit field.
981    pub mmmmm: Option<VexEscape>,
982    /// The `W` bit.
983    pub w: WBit,
984    /// VEX-encoded instructions have a single-byte opcode. Other prefix-related
985    /// bytes (see [`Opcodes`]) are encoded in the VEX prefixes (see `pp`,
986    /// `mmmmmm`). From the reference manual: "One (and only one) opcode byte
987    /// follows the 2 or 3 byte VEX."
988    pub opcode: u8,
989    /// See [`Rex.modrm`](Rex.modrm).
990    pub modrm: Option<ModRmKind>,
991    /// See [`Rex.imm`](Rex.imm).
992    pub imm: Imm,
993    /// See [`Vex::is4`]
994    pub is4: bool,
995}
996
997impl Vex {
998    /// Set the `pp` field to use [`VexPrefix::_66`]; equivalent to `.66` in the
999    /// manual.
1000    pub fn _66(self) -> Self {
1001        assert!(self.pp.is_none());
1002        Self {
1003            pp: Some(VexPrefix::_66),
1004            ..self
1005        }
1006    }
1007
1008    /// Set the `pp` field to use [`VexPrefix::_F2`]; equivalent to `.F2` in the
1009    /// manual.
1010    pub fn _f2(self) -> Self {
1011        assert!(self.pp.is_none());
1012        Self {
1013            pp: Some(VexPrefix::_F2),
1014            ..self
1015        }
1016    }
1017
1018    /// Set the `pp` field to use [`VexPrefix::_F3`]; equivalent to `.F3` in the
1019    /// manual.
1020    pub fn _f3(self) -> Self {
1021        assert!(self.pp.is_none());
1022        Self {
1023            pp: Some(VexPrefix::_F3),
1024            ..self
1025        }
1026    }
1027
1028    /// Set the `mmmmmm` field to use [`VexEscape::_0F`]; equivalent to `.0F` in
1029    /// the manual.
1030    pub fn _0f(self) -> Self {
1031        assert!(self.mmmmm.is_none());
1032        Self {
1033            mmmmm: Some(VexEscape::_0F),
1034            ..self
1035        }
1036    }
1037
1038    /// Set the `mmmmmm` field to use [`VexEscape::_0F3A`]; equivalent to
1039    /// `.0F3A` in the manual.
1040    pub fn _0f3a(self) -> Self {
1041        assert!(self.mmmmm.is_none());
1042        Self {
1043            mmmmm: Some(VexEscape::_0F3A),
1044            ..self
1045        }
1046    }
1047
1048    /// Set the `mmmmmm` field to use [`VexEscape::_0F38`]; equivalent to
1049    /// `.0F38` in the manual.
1050    pub fn _0f38(self) -> Self {
1051        assert!(self.mmmmm.is_none());
1052        Self {
1053            mmmmm: Some(VexEscape::_0F38),
1054            ..self
1055        }
1056    }
1057
1058    /// Set the `W` bit to `0`; equivalent to `.W0` in the manual.
1059    pub fn w0(self) -> Self {
1060        assert!(self.w.is_ignored());
1061        Self {
1062            w: WBit::W0,
1063            ..self
1064        }
1065    }
1066
1067    /// Set the `W` bit to `1`; equivalent to `.W1` in the manual.
1068    pub fn w1(self) -> Self {
1069        assert!(self.w.is_ignored());
1070        Self {
1071            w: WBit::W1,
1072            ..self
1073        }
1074    }
1075
1076    /// Ignore the `W` bit; equivalent to `.WIG` in the manual.
1077    pub fn wig(self) -> Self {
1078        assert!(self.w.is_ignored());
1079        Self {
1080            w: WBit::WIG,
1081            ..self
1082        }
1083    }
1084
1085    /// Set the single opcode for this VEX-encoded instruction.
1086    pub fn op(self, opcode: u8) -> Self {
1087        assert_eq!(self.opcode, u8::MAX);
1088        Self { opcode, ..self }
1089    }
1090
1091    /// Set the ModR/M byte to contain a register operand; see [`Rex::r`].
1092    pub fn r(self) -> Self {
1093        assert!(self.modrm.is_none());
1094        Self {
1095            modrm: Some(ModRmKind::Reg),
1096            ..self
1097        }
1098    }
1099
1100    /// Append a byte-sized immediate operand (8-bit); equivalent to `ib` in the
1101    /// reference manual.
1102    ///
1103    /// # Panics
1104    ///
1105    /// Panics if an immediate operand is already set.
1106    #[must_use]
1107    pub fn ib(self) -> Self {
1108        assert_eq!(self.imm, Imm::None);
1109        Self {
1110            imm: Imm::ib,
1111            ..self
1112        }
1113    }
1114
1115    /// Append a word-sized immediate operand (16-bit); equivalent to `iw` in
1116    /// the reference manual.
1117    ///
1118    /// # Panics
1119    ///
1120    /// Panics if an immediate operand is already set.
1121    #[must_use]
1122    pub fn iw(self) -> Self {
1123        assert_eq!(self.imm, Imm::None);
1124        Self {
1125            imm: Imm::iw,
1126            ..self
1127        }
1128    }
1129
1130    /// Append a doubleword-sized immediate operand (32-bit); equivalent to `id`
1131    /// in the reference manual.
1132    ///
1133    /// # Panics
1134    ///
1135    /// Panics if an immediate operand is already set.
1136    #[must_use]
1137    pub fn id(self) -> Self {
1138        assert_eq!(self.imm, Imm::None);
1139        Self {
1140            imm: Imm::id,
1141            ..self
1142        }
1143    }
1144
1145    /// Append a quadword-sized immediate operand (64-bit); equivalent to `io`
1146    /// in the reference manual.
1147    ///
1148    /// # Panics
1149    ///
1150    /// Panics if an immediate operand is already set.
1151    #[must_use]
1152    pub fn io(self) -> Self {
1153        assert_eq!(self.imm, Imm::None);
1154        Self {
1155            imm: Imm::io,
1156            ..self
1157        }
1158    }
1159
1160    /// Set the digit extending the opcode; equivalent to `/<digit>` in the
1161    /// reference manual.
1162    ///
1163    /// # Panics
1164    ///
1165    /// Panics if `extension` is too large.
1166    #[must_use]
1167    pub fn digit(self, extension: u8) -> Self {
1168        assert!(extension <= 0b111, "must fit in 3 bits");
1169        Self {
1170            modrm: Some(ModRmKind::Digit(extension)),
1171            ..self
1172        }
1173    }
1174
1175    /// An 8-bit immediate byte is present containing a source register
1176    /// specifier in either imm8[7:4] (for 64-bit
1177    /// mode) or imm8[6:4] (for 32-bit mode), and instruction-specific payload
1178    /// in imm8[3:0].
1179    pub fn is4(self) -> Self {
1180        Self { is4: true, ..self }
1181    }
1182
1183    fn validate(&self, _operands: &[Operand]) {
1184        assert!(self.opcode != u8::MAX);
1185        assert!(self.mmmmm.is_some());
1186        assert!(!matches!(self.length, Length::L512));
1187    }
1188
1189    /// Retrieve the digit extending the opcode, if available.
1190    #[must_use]
1191    pub fn unwrap_digit(&self) -> Option<u8> {
1192        match self.modrm {
1193            Some(ModRmKind::Digit(digit)) => Some(digit),
1194            _ => None,
1195        }
1196    }
1197}
1198
1199impl From<Vex> for Encoding {
1200    fn from(vex: Vex) -> Encoding {
1201        Encoding::Vex(vex)
1202    }
1203}
1204
1205impl fmt::Display for Vex {
1206    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1207        write!(f, "VEX.{}", self.length)?;
1208        if let Some(pp) = self.pp {
1209            write!(f, ".{pp}")?;
1210        }
1211        if let Some(mmmmm) = self.mmmmm {
1212            write!(f, ".{mmmmm}")?;
1213        }
1214        write!(f, ".{} {:#04X}", self.w, self.opcode)?;
1215        if let Some(modrm) = self.modrm {
1216            write!(f, " {modrm}")?;
1217        }
1218        if self.imm != Imm::None {
1219            write!(f, " {}", self.imm)?;
1220        }
1221        Ok(())
1222    }
1223}
1224
1225pub struct Evex {
1226    /// The vector length of the operand (e.g., 128-bit, 256-bit, or 512-bit).
1227    pub length: Length,
1228    /// Any SIMD prefixes, but encoded in the `EVEX.pp` bit field (see similar:
1229    /// [`Vex::pp`]).
1230    pub pp: Option<VexPrefix>,
1231    /// The `mmm` bits.
1232    ///
1233    /// Bits `1:0` are identical to the lowest 2 bits of `VEX.mmmmm`; EVEX adds
1234    /// one more bit here. From the reference manual: "provides access to up to
1235    /// eight decoding maps. Currently, only the following decoding maps are
1236    /// supported: 1, 2, 3, 5, and 6. Map ids 1, 2, and 3 are denoted by 0F,
1237    /// 0F38, and 0F3A, respectively, in the instruction encoding descriptions."
1238    pub mmm: Option<VexEscape>,
1239    /// The `W` bit.
1240    pub w: WBit,
1241    /// EVEX-encoded instructions opcode byte"
1242    pub opcode: u8,
1243    /// See [`Rex.modrm`](Rex.modrm).
1244    pub modrm: Option<ModRmKind>,
1245    /// See [`Rex.imm`](Rex.imm).
1246    pub imm: Imm,
1247    /// The "Tuple Type" corresponding to scaling of the 8-bit displacement
1248    /// parameter for memory operands. See [`TupleType`] for more information.
1249    pub tuple_type: TupleType,
1250}
1251
1252impl Evex {
1253    /// Set the `pp` field to use [`VexPrefix::_66`]; equivalent to `.66` in the
1254    /// manual.
1255    pub fn _66(self) -> Self {
1256        assert!(self.pp.is_none());
1257        Self {
1258            pp: Some(VexPrefix::_66),
1259            ..self
1260        }
1261    }
1262
1263    /// Set the `pp` field to use [`VexPrefix::_F2`]; equivalent to `.F2` in the
1264    /// manual.
1265    pub fn _f2(self) -> Self {
1266        assert!(self.pp.is_none());
1267        Self {
1268            pp: Some(VexPrefix::_F2),
1269            ..self
1270        }
1271    }
1272
1273    /// Set the `pp` field to use [`VexPrefix::_F3`]; equivalent to `.F3` in the
1274    /// manual.
1275    pub fn _f3(self) -> Self {
1276        assert!(self.pp.is_none());
1277        Self {
1278            pp: Some(VexPrefix::_F3),
1279            ..self
1280        }
1281    }
1282
1283    /// Set the `mmmmmm` field to use [`VexEscape::_0F`]; equivalent to `.0F` in
1284    /// the manual.
1285    pub fn _0f(self) -> Self {
1286        assert!(self.mmm.is_none());
1287        Self {
1288            mmm: Some(VexEscape::_0F),
1289            ..self
1290        }
1291    }
1292
1293    /// Set the `mmmmmm` field to use [`VexEscape::_0F3A`]; equivalent to
1294    /// `.0F3A` in the manual.
1295    pub fn _0f3a(self) -> Self {
1296        assert!(self.mmm.is_none());
1297        Self {
1298            mmm: Some(VexEscape::_0F3A),
1299            ..self
1300        }
1301    }
1302
1303    /// Set the `mmmmmm` field to use [`VexEscape::_0F38`]; equivalent to
1304    /// `.0F38` in the manual.
1305    pub fn _0f38(self) -> Self {
1306        assert!(self.mmm.is_none());
1307        Self {
1308            mmm: Some(VexEscape::_0F38),
1309            ..self
1310        }
1311    }
1312
1313    /// Set the `W` bit to `0`; equivalent to `.W0` in the manual.
1314    pub fn w0(self) -> Self {
1315        assert!(self.w.is_ignored());
1316        Self {
1317            w: WBit::W0,
1318            ..self
1319        }
1320    }
1321
1322    /// Set the `W` bit to `1`; equivalent to `.W1` in the manual.
1323    pub fn w1(self) -> Self {
1324        assert!(self.w.is_ignored());
1325        Self {
1326            w: WBit::W1,
1327            ..self
1328        }
1329    }
1330
1331    /// Ignore the `W` bit; equivalent to `.WIG` in the manual.
1332    pub fn wig(self) -> Self {
1333        assert!(self.w.is_ignored());
1334        Self {
1335            w: WBit::WIG,
1336            ..self
1337        }
1338    }
1339
1340    /// Set the single opcode for this VEX-encoded instruction.
1341    pub fn op(self, opcode: u8) -> Self {
1342        assert_eq!(self.opcode, u8::MAX);
1343        Self { opcode, ..self }
1344    }
1345
1346    /// Set the ModR/M byte to contain a register operand; see [`Rex::r`].
1347    pub fn r(self) -> Self {
1348        assert!(self.modrm.is_none());
1349        Self {
1350            modrm: Some(ModRmKind::Reg),
1351            ..self
1352        }
1353    }
1354
1355    fn validate(&self, _operands: &[Operand]) {
1356        assert!(self.opcode != u8::MAX);
1357        assert!(self.mmm.is_some());
1358    }
1359
1360    /// Retrieve the digit extending the opcode, if available.
1361    #[must_use]
1362    pub fn unwrap_digit(&self) -> Option<u8> {
1363        match self.modrm {
1364            Some(ModRmKind::Digit(digit)) => Some(digit),
1365            _ => None,
1366        }
1367    }
1368
1369    /// Set the digit extending the opcode; equivalent to `/<digit>` in the
1370    /// reference manual.
1371    ///
1372    /// # Panics
1373    ///
1374    /// Panics if `extension` is too large.
1375    #[must_use]
1376    pub fn digit(self, extension: u8) -> Self {
1377        assert!(extension <= 0b111, "must fit in 3 bits");
1378        Self {
1379            modrm: Some(ModRmKind::Digit(extension)),
1380            ..self
1381        }
1382    }
1383
1384    /// Append a byte-sized immediate operand (8-bit); equivalent to `ib` in the
1385    /// reference manual.
1386    ///
1387    /// # Panics
1388    ///
1389    /// Panics if an immediate operand is already set.
1390    #[must_use]
1391    pub fn ib(self) -> Self {
1392        assert_eq!(self.imm, Imm::None);
1393        Self {
1394            imm: Imm::ib,
1395            ..self
1396        }
1397    }
1398}
1399
1400impl From<Evex> for Encoding {
1401    fn from(evex: Evex) -> Encoding {
1402        Encoding::Evex(evex)
1403    }
1404}
1405
1406impl fmt::Display for Evex {
1407    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1408        write!(f, "EVEX.{}", self.length)?;
1409        if let Some(pp) = self.pp {
1410            write!(f, ".{pp}")?;
1411        }
1412        if let Some(mmmmm) = self.mmm {
1413            write!(f, ".{mmmmm}")?;
1414        }
1415        write!(f, ".{} {:#04X}", self.w, self.opcode)?;
1416        if let Some(modrm) = self.modrm {
1417            write!(f, " {modrm}")?;
1418        }
1419        if self.imm != Imm::None {
1420            write!(f, " {}", self.imm)?;
1421        }
1422        Ok(())
1423    }
1424}
1425
1426/// Tuple Type definitions used in EVEX encodings.
1427///
1428/// This enumeration corresponds to table 2-34 and 2-35 in the Intel manual.
1429/// This is a property of all instruction formats listed in the encoding table
1430/// for each instruction.
1431#[expect(missing_docs, reason = "matching manual names")]
1432pub enum TupleType {
1433    Full,
1434    Half,
1435    FullMem,
1436    Tuple1Scalar,
1437    Tuple1Fixed,
1438    Tuple2,
1439    Tuple4,
1440    Tuple8,
1441    HalfMem,
1442    QuarterMem,
1443    EigthMem,
1444    Mem128,
1445    Movddup,
1446}