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