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] 23 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] 35 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] 50 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. 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 91 impl 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)] 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] 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 138 impl 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. 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] 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 370 impl From<Rex> for Encoding { 371 fn from(rex: Rex) -> Encoding { 372 Encoding::Rex(rex) 373 } 374 } 375 376 impl 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. 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. 461 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 { 471 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 { 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)] 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. 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 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; 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 { 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. 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; 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 { 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. 672 pub enum Group3Prefix { 673 OperandSizeOverride, 674 } 675 676 impl 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 686 impl 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. 700 pub enum Group4Prefix { 701 AddressSizeOverride, 702 } 703 704 impl 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 714 impl 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")] 730 pub enum Imm { 731 None, 732 ib, 733 iw, 734 id, 735 io, 736 } 737 738 impl 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 750 impl 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")] 774 pub enum OpcodeMod { 775 rb, 776 rw, 777 rd, 778 ro, 779 } 780 781 impl 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 792 impl 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)] 808 pub enum VexPrefix { 809 _66, 810 _F2, 811 _F3, 812 } 813 814 impl 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 826 impl 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)] 840 pub enum VexEscape { 841 _0F, 842 _0F3A, 843 _0F38, 844 } 845 846 impl 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 858 impl 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). 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. 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 916 impl 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. 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. 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 957 impl 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 /// ``` 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. 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 1199 impl From<Vex> for Encoding { 1200 fn from(vex: Vex) -> Encoding { 1201 Encoding::Vex(vex) 1202 } 1203 } 1204 1205 impl 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 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. 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 1400 impl From<Evex> for Encoding { 1401 fn from(evex: Evex) -> Encoding { 1402 Encoding::Evex(evex) 1403 } 1404 } 1405 1406 impl 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")] 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