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