Skip to main content

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