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 
18 use super::{Operand, OperandKind};
19 use core::fmt;
20 
21 /// An abbreviated constructor for REX-encoded instructions.
22 #[must_use]
rex(opcode: impl Into<Opcodes>) -> Rex23 pub 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]
vex(length: Length) -> Vex35 pub 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]
evex(length: Length, tuple_type: TupleType) -> Evex50 pub 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.
64 pub enum Encoding {
65     Rex(Rex),
66     Vex(Vex),
67     Evex(Evex),
68 }
69 
70 impl Encoding {
71     /// Check that the encoding is valid for the given operands; this can find
72     /// issues earlier, before generating any Rust code.
validate(&self, operands: &[Operand])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.
opcode(&self) -> u882     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 
91 impl fmt::Display for Encoding {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result92     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)]
102 pub 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 
118 impl ModRmKind {
119     /// Return the digit extending the opcode, if available.
120     #[must_use]
digit(&self) -> Option<u8>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.
unwrap_digit(&self) -> u8133     pub fn unwrap_digit(&self) -> u8 {
134         self.digit().expect("expected an extension digit")
135     }
136 }
137 
138 impl fmt::Display for ModRmKind {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result139     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.
154 pub 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]`
188     /// field encodes the register operand of the instruction. “+ro” is
189     /// applicable only in 64-bit mode."
190     pub opcode_mod: Option<OpcodeMod>,
191 }
192 
193 impl Rex {
194     /// Set the `REX.W` bit.
195     #[must_use]
w(self) -> Self196     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]
r(self) -> Self206     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]
digit(self, extension: u8) -> Self220     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]
unwrap_digit(&self) -> Option<u8>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]
ib(self) -> Self244     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]
iw(self) -> Self259     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]
id(self) -> Self274     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]
io(self) -> Self289     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]
rb(self) -> Self300     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]
rw(self) -> Self310     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]
rd(self) -> Self320     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]
ro(self) -> Self330     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.
validate(&self, operands: &[Operand])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 
370 impl From<Rex> for Encoding {
from(rex: Rex) -> Encoding371     fn from(rex: Rex) -> Encoding {
372         Encoding::Rex(rex)
373     }
374 }
375 
376 impl fmt::Display for Rex {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result377     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.
443 pub 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 
454 impl 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.
opcode(&self) -> u8461     fn opcode(&self) -> u8 {
462         if let Some(secondary) = self.secondary {
463             secondary
464         } else {
465             self.primary
466         }
467     }
468 }
469 
470 impl From<u8> for Opcodes {
from(primary: u8) -> Opcodes471     fn from(primary: u8) -> Opcodes {
472         Opcodes {
473             prefixes: Prefixes::default(),
474             escape: false,
475             primary,
476             secondary: None,
477         }
478     }
479 }
480 
481 impl<const N: usize> From<[u8; N]> for Opcodes {
from(bytes: [u8; N]) -> Self482     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)]
509 pub struct Prefixes {
510     pub group1: Option<Group1Prefix>,
511     pub group2: Option<Group2Prefix>,
512     pub group3: Option<Group3Prefix>,
513     pub group4: Option<Group4Prefix>,
514 }
515 
516 impl Prefixes {
517     /// Parse a slice of `bytes` into a set of prefixes, returning both the
518     /// configured [`Prefixes`] as well as any remaining bytes.
parse(mut bytes: &[u8]) -> (Self, &[u8])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.
try_assign(&mut self, byte: u8) -> Result<(), ()>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.
is_empty(&self) -> bool557     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 
565 pub 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 
593 impl TryFrom<u8> for Group1Prefix {
594     type Error = u8;
try_from(byte: u8) -> Result<Self, Self::Error>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 
605 impl fmt::Display for Group1Prefix {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result606     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.
619 pub 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 
635 impl TryFrom<u8> for Group2Prefix {
636     type Error = u8;
try_from(byte: u8) -> Result<Self, Self::Error>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 
650 impl fmt::Display for Group2Prefix {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result651     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.
672 pub enum Group3Prefix {
673     OperandSizeOverride,
674 }
675 
676 impl TryFrom<u8> for Group3Prefix {
677     type Error = u8;
try_from(byte: u8) -> Result<Self, Self::Error>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 
686 impl fmt::Display for Group3Prefix {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result687     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.
700 pub enum Group4Prefix {
701     AddressSizeOverride,
702 }
703 
704 impl TryFrom<u8> for Group4Prefix {
705     type Error = u8;
try_from(byte: u8) -> Result<Self, Self::Error>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 
714 impl fmt::Display for Group4Prefix {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result715     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")]
730 pub enum Imm {
731     None,
732     ib,
733     iw,
734     id,
735     io,
736 }
737 
738 impl Imm {
bits(&self) -> u16739     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 
750 impl fmt::Display for Imm {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result751     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")]
774 pub enum OpcodeMod {
775     rb,
776     rw,
777     rd,
778     ro,
779 }
780 
781 impl OpcodeMod {
bits(&self) -> u8782     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 
792 impl fmt::Display for OpcodeMod {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result793     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)]
808 pub enum VexPrefix {
809     _66,
810     _F2,
811     _F3,
812 }
813 
814 impl VexPrefix {
815     /// Encode the `pp` bits.
816     #[inline(always)]
bits(self) -> u8817     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 
826 impl fmt::Display for VexPrefix {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result827     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)]
840 pub enum VexEscape {
841     _0F,
842     _0F3A,
843     _0F38,
844 }
845 
846 impl VexEscape {
847     /// Encode the `m-mmmm` bits.
848     #[inline(always)]
bits(&self) -> u8849     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 
858 impl fmt::Display for VexEscape {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result859     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).
878 pub 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 
894 impl Length {
895     /// Encode the `VEX.L` bit.
vex_bits(&self) -> u8896     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
evex_bits(&self) -> u8907     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 
916 impl fmt::Display for Length {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result917     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.
929 pub 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 
938 impl WBit {
939     /// Return `true` if the `W` bit is ignored; this is useful to check in the
940     /// DSL for the default case.
is_ignored(&self) -> bool941     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`.
as_bool(&self) -> bool949     pub(crate) fn as_bool(&self) -> bool {
950         match self {
951             Self::W1 => true,
952             Self::W0 | Self::WIG => false,
953         }
954     }
955 }
956 
957 impl fmt::Display for WBit {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result958     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 /// ```
975 pub 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 
997 impl Vex {
998     /// Set the `pp` field to use [`VexPrefix::_66`]; equivalent to `.66` in the
999     /// manual.
_66(self) -> Self1000     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.
_f2(self) -> Self1010     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.
_f3(self) -> Self1020     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.
_0f(self) -> Self1030     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.
_0f3a(self) -> Self1040     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.
_0f38(self) -> Self1050     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.
w0(self) -> Self1059     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.
w1(self) -> Self1068     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.
wig(self) -> Self1077     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.
op(self, opcode: u8) -> Self1086     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`].
r(self) -> Self1092     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]
ib(self) -> Self1107     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]
iw(self) -> Self1122     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]
id(self) -> Self1137     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]
io(self) -> Self1152     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]
digit(self, extension: u8) -> Self1167     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]`.
is4(self) -> Self1179     pub fn is4(self) -> Self {
1180         Self { is4: true, ..self }
1181     }
1182 
validate(&self, _operands: &[Operand])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]
unwrap_digit(&self) -> Option<u8>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 
1199 impl From<Vex> for Encoding {
from(vex: Vex) -> Encoding1200     fn from(vex: Vex) -> Encoding {
1201         Encoding::Vex(vex)
1202     }
1203 }
1204 
1205 impl fmt::Display for Vex {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1206     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 
1225 pub 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 
1252 impl Evex {
1253     /// Set the `pp` field to use [`VexPrefix::_66`]; equivalent to `.66` in the
1254     /// manual.
_66(self) -> Self1255     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.
_f2(self) -> Self1265     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.
_f3(self) -> Self1275     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.
_0f(self) -> Self1285     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.
_0f3a(self) -> Self1295     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.
_0f38(self) -> Self1305     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.
w0(self) -> Self1314     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.
w1(self) -> Self1323     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.
wig(self) -> Self1332     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.
op(self, opcode: u8) -> Self1341     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`].
r(self) -> Self1347     pub fn r(self) -> Self {
1348         assert!(self.modrm.is_none());
1349         Self {
1350             modrm: Some(ModRmKind::Reg),
1351             ..self
1352         }
1353     }
1354 
validate(&self, _operands: &[Operand])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]
unwrap_digit(&self) -> Option<u8>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]
digit(self, extension: u8) -> Self1376     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]
ib(self) -> Self1391     pub fn ib(self) -> Self {
1392         assert_eq!(self.imm, Imm::None);
1393         Self {
1394             imm: Imm::ib,
1395             ..self
1396         }
1397     }
1398 }
1399 
1400 impl From<Evex> for Encoding {
from(evex: Evex) -> Encoding1401     fn from(evex: Evex) -> Encoding {
1402         Encoding::Evex(evex)
1403     }
1404 }
1405 
1406 impl fmt::Display for Evex {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result1407     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")]
1432 pub 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 }
1447