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