1 //! Instruction operand sub-components (aka "parts"): definitions and printing. 2 3 use super::regs::{self}; 4 use crate::ir::MemFlags; 5 use crate::ir::condcodes::{FloatCC, IntCC}; 6 use crate::ir::types::*; 7 use crate::isa::x64::inst::Inst; 8 use crate::isa::x64::inst::regs::pretty_print_reg; 9 use crate::machinst::*; 10 use smallvec::{SmallVec, smallvec}; 11 use std::fmt; 12 use std::string::String; 13 14 /// An extension trait for converting `Writable{Xmm,Gpr}` to `Writable<Reg>`. 15 pub trait ToWritableReg { 16 /// Convert `Writable{Xmm,Gpr}` to `Writable<Reg>`. 17 fn to_writable_reg(&self) -> Writable<Reg>; 18 } 19 20 /// An extension trait for converting `Writable<Reg>` to `Writable{Xmm,Gpr}`. 21 pub trait FromWritableReg: Sized { 22 /// Convert `Writable<Reg>` to `Writable{Xmm,Gpr}`. 23 fn from_writable_reg(w: Writable<Reg>) -> Option<Self>; 24 } 25 26 /// A macro for defining a newtype of `Reg` that enforces some invariant about 27 /// the wrapped `Reg` (such as that it is of a particular register class). 28 macro_rules! newtype_of_reg { 29 ( 30 $newtype_reg:ident, 31 $newtype_writable_reg:ident, 32 $newtype_option_writable_reg:ident, 33 reg_mem: ($($newtype_reg_mem:ident $(aligned:$aligned:ident)?),*), 34 reg_mem_imm: ($($newtype_reg_mem_imm:ident $(aligned:$aligned_imm:ident)?),*), 35 |$check_reg:ident| $check:expr 36 ) => { 37 /// A newtype wrapper around `Reg`. 38 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 39 pub struct $newtype_reg(Reg); 40 41 impl PartialEq<Reg> for $newtype_reg { 42 fn eq(&self, other: &Reg) -> bool { 43 self.0 == *other 44 } 45 } 46 47 impl From<$newtype_reg> for Reg { 48 fn from(r: $newtype_reg) -> Self { 49 r.0 50 } 51 } 52 53 impl $newtype_reg { 54 /// Create this newtype from the given register, or return `None` if the register 55 /// is not a valid instance of this newtype. 56 pub fn new($check_reg: Reg) -> Option<Self> { 57 if $check { 58 Some(Self($check_reg)) 59 } else { 60 None 61 } 62 } 63 64 /// Like `Self::new(r).unwrap()` but with a better panic message on 65 /// failure. 66 pub fn unwrap_new($check_reg: Reg) -> Self { 67 if $check { 68 Self($check_reg) 69 } else { 70 panic!( 71 "cannot construct {} from register {:?} with register class {:?}", 72 stringify!($newtype_reg), 73 $check_reg, 74 $check_reg.class(), 75 ) 76 } 77 } 78 79 /// Get this newtype's underlying `Reg`. 80 pub fn to_reg(self) -> Reg { 81 self.0 82 } 83 } 84 85 // Convenience impl so that people working with this newtype can use it 86 // "just like" a plain `Reg`. 87 // 88 // NB: We cannot implement `DerefMut` because that would let people do 89 // nasty stuff like `*my_gpr.deref_mut() = some_xmm_reg`, breaking the 90 // invariants that `Gpr` provides. 91 impl std::ops::Deref for $newtype_reg { 92 type Target = Reg; 93 94 fn deref(&self) -> &Reg { 95 &self.0 96 } 97 } 98 99 /// If you know what you're doing, you can explicitly mutably borrow the 100 /// underlying `Reg`. Don't make it point to the wrong type of register 101 /// please. 102 impl AsMut<Reg> for $newtype_reg { 103 fn as_mut(&mut self) -> &mut Reg { 104 &mut self.0 105 } 106 } 107 108 /// Writable Gpr. 109 pub type $newtype_writable_reg = Writable<$newtype_reg>; 110 111 #[allow(dead_code)] // Used by some newtypes and not others. 112 /// Optional writable Gpr. 113 pub type $newtype_option_writable_reg = Option<Writable<$newtype_reg>>; 114 115 impl ToWritableReg for $newtype_writable_reg { 116 fn to_writable_reg(&self) -> Writable<Reg> { 117 Writable::from_reg(self.to_reg().to_reg()) 118 } 119 } 120 121 impl FromWritableReg for $newtype_writable_reg { 122 fn from_writable_reg(w: Writable<Reg>) -> Option<Self> { 123 Some(Writable::from_reg($newtype_reg::new(w.to_reg())?)) 124 } 125 } 126 127 $( 128 /// A newtype wrapper around `RegMem` for general-purpose registers. 129 #[derive(Clone, Debug)] 130 pub struct $newtype_reg_mem(RegMem); 131 132 impl From<$newtype_reg_mem> for RegMem { 133 fn from(rm: $newtype_reg_mem) -> Self { 134 rm.0 135 } 136 } 137 impl<'a> From<&'a $newtype_reg_mem> for &'a RegMem { 138 fn from(rm: &'a $newtype_reg_mem) -> &'a RegMem { 139 &rm.0 140 } 141 } 142 143 impl From<$newtype_reg> for $newtype_reg_mem { 144 fn from(r: $newtype_reg) -> Self { 145 $newtype_reg_mem(RegMem::reg(r.into())) 146 } 147 } 148 149 impl $newtype_reg_mem { 150 /// Construct a `RegMem` newtype from the given `RegMem`, or return 151 /// `None` if the `RegMem` is not a valid instance of this `RegMem` 152 /// newtype. 153 pub fn new(rm: RegMem) -> Option<Self> { 154 match rm { 155 RegMem::Mem { addr } => { 156 let mut _allow = true; 157 $( 158 if $aligned { 159 _allow = addr.aligned(); 160 } 161 )? 162 if _allow { 163 Some(Self(RegMem::Mem { addr })) 164 } else { 165 None 166 } 167 } 168 RegMem::Reg { reg } => Some($newtype_reg::new(reg)?.into()), 169 } 170 } 171 172 /// Like `Self::new(rm).unwrap()` but with better panic messages 173 /// in case of failure. 174 pub fn unwrap_new(rm: RegMem) -> Self { 175 match rm { 176 RegMem::Mem { addr } => { 177 $( 178 if $aligned && !addr.aligned() { 179 panic!( 180 "cannot create {} from an unaligned memory address: {addr:?}", 181 stringify!($newtype_reg_mem), 182 ); 183 } 184 )? 185 Self(RegMem::Mem { addr }) 186 } 187 RegMem::Reg { reg } => $newtype_reg::unwrap_new(reg).into(), 188 } 189 } 190 191 /// Convert this newtype into its underlying `RegMem`. 192 pub fn to_reg_mem(self) -> RegMem { 193 self.0 194 } 195 196 #[allow(dead_code)] // Used by some newtypes and not others. 197 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { 198 self.0.get_operands(collector); 199 } 200 } 201 impl PrettyPrint for $newtype_reg_mem { 202 fn pretty_print(&self, size: u8) -> String { 203 self.0.pretty_print(size) 204 } 205 } 206 )* 207 208 $( 209 /// A newtype wrapper around `RegMemImm`. 210 #[derive(Clone, Debug)] 211 pub struct $newtype_reg_mem_imm(RegMemImm); 212 213 impl From<$newtype_reg_mem_imm> for RegMemImm { 214 fn from(rmi: $newtype_reg_mem_imm) -> RegMemImm { 215 rmi.0 216 } 217 } 218 impl<'a> From<&'a $newtype_reg_mem_imm> for &'a RegMemImm { 219 fn from(rmi: &'a $newtype_reg_mem_imm) -> &'a RegMemImm { 220 &rmi.0 221 } 222 } 223 224 impl From<$newtype_reg> for $newtype_reg_mem_imm { 225 fn from(r: $newtype_reg) -> Self { 226 $newtype_reg_mem_imm(RegMemImm::reg(r.into())) 227 } 228 } 229 230 impl $newtype_reg_mem_imm { 231 /// Construct this newtype from the given `RegMemImm`, or return 232 /// `None` if the `RegMemImm` is not a valid instance of this 233 /// newtype. 234 pub fn new(rmi: RegMemImm) -> Option<Self> { 235 match rmi { 236 RegMemImm::Imm { .. } => Some(Self(rmi)), 237 RegMemImm::Mem { addr } => { 238 let mut _allow = true; 239 $( 240 if $aligned_imm { 241 _allow = addr.aligned(); 242 } 243 )? 244 if _allow { 245 Some(Self(RegMemImm::Mem { addr })) 246 } else { 247 None 248 } 249 } 250 RegMemImm::Reg { reg } => Some($newtype_reg::new(reg)?.into()), 251 } 252 } 253 254 /// Like `Self::new(rmi).unwrap()` but with better panic 255 /// messages in case of failure. 256 pub fn unwrap_new(rmi: RegMemImm) -> Self { 257 match rmi { 258 RegMemImm::Imm { .. } => Self(rmi), 259 RegMemImm::Mem { addr } => { 260 $( 261 if $aligned_imm && !addr.aligned() { 262 panic!( 263 "cannot construct {} from unaligned memory address: {:?}", 264 stringify!($newtype_reg_mem_imm), 265 addr, 266 ); 267 } 268 )? 269 Self(RegMemImm::Mem { addr }) 270 271 } 272 RegMemImm::Reg { reg } => $newtype_reg::unwrap_new(reg).into(), 273 } 274 } 275 276 /// Convert this newtype into its underlying `RegMemImm`. 277 #[allow(dead_code)] // Used by some newtypes and not others. 278 pub fn to_reg_mem_imm(self) -> RegMemImm { 279 self.0 280 } 281 282 #[allow(dead_code)] // Used by some newtypes and not others. 283 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { 284 self.0.get_operands(collector); 285 } 286 } 287 288 impl PrettyPrint for $newtype_reg_mem_imm { 289 fn pretty_print(&self, size: u8) -> String { 290 self.0.pretty_print(size) 291 } 292 } 293 )* 294 }; 295 } 296 297 // Define a newtype of `Reg` for general-purpose registers. 298 newtype_of_reg!( 299 Gpr, 300 WritableGpr, 301 OptionWritableGpr, 302 reg_mem: (GprMem), 303 reg_mem_imm: (GprMemImm), 304 |reg| reg.class() == RegClass::Int 305 ); 306 307 #[expect(missing_docs, reason = "self-describing fields")] 308 impl Gpr { 309 pub const RAX: Gpr = Gpr(regs::rax()); 310 pub const RBX: Gpr = Gpr(regs::rbx()); 311 pub const RCX: Gpr = Gpr(regs::rcx()); 312 pub const RDX: Gpr = Gpr(regs::rdx()); 313 pub const RSI: Gpr = Gpr(regs::rsi()); 314 pub const RDI: Gpr = Gpr(regs::rdi()); 315 pub const RSP: Gpr = Gpr(regs::rsp()); 316 pub const RBP: Gpr = Gpr(regs::rbp()); 317 pub const R8: Gpr = Gpr(regs::r8()); 318 pub const R9: Gpr = Gpr(regs::r9()); 319 pub const R10: Gpr = Gpr(regs::r10()); 320 pub const R11: Gpr = Gpr(regs::r11()); 321 pub const R12: Gpr = Gpr(regs::r12()); 322 pub const R13: Gpr = Gpr(regs::r13()); 323 pub const R14: Gpr = Gpr(regs::r14()); 324 pub const R15: Gpr = Gpr(regs::r15()); 325 } 326 327 // Define a newtype of `Reg` for XMM registers. 328 newtype_of_reg!( 329 Xmm, 330 WritableXmm, 331 OptionWritableXmm, 332 reg_mem: (XmmMem, XmmMemAligned aligned:true), 333 reg_mem_imm: (XmmMemImm, XmmMemAlignedImm aligned:true), 334 |reg| reg.class() == RegClass::Float 335 ); 336 337 // N.B.: `Amode` is defined in `inst.isle`. We add some convenience 338 // constructors here. 339 340 // Re-export the type from the ISLE generated code. 341 pub use crate::isa::x64::lower::isle::generated_code::Amode; 342 343 impl Amode { 344 /// Create an immediate sign-extended and register addressing mode. 345 pub fn imm_reg(simm32: i32, base: Reg) -> Self { 346 debug_assert!(base.class() == RegClass::Int); 347 Self::ImmReg { 348 simm32, 349 base, 350 flags: MemFlags::trusted(), 351 } 352 } 353 354 /// Create a sign-extended-32-to-64 with register and shift addressing mode. 355 pub fn imm_reg_reg_shift(simm32: i32, base: Gpr, index: Gpr, shift: u8) -> Self { 356 debug_assert!(base.class() == RegClass::Int); 357 debug_assert!(index.class() == RegClass::Int); 358 debug_assert!(shift <= 3); 359 Self::ImmRegRegShift { 360 simm32, 361 base, 362 index, 363 shift, 364 flags: MemFlags::trusted(), 365 } 366 } 367 368 pub(crate) fn rip_relative(target: MachLabel) -> Self { 369 Self::RipRelative { target } 370 } 371 372 /// Set the specified [MemFlags] to the [Amode]. 373 pub fn with_flags(&self, flags: MemFlags) -> Self { 374 match self { 375 &Self::ImmReg { simm32, base, .. } => Self::ImmReg { 376 simm32, 377 base, 378 flags, 379 }, 380 &Self::ImmRegRegShift { 381 simm32, 382 base, 383 index, 384 shift, 385 .. 386 } => Self::ImmRegRegShift { 387 simm32, 388 base, 389 index, 390 shift, 391 flags, 392 }, 393 _ => panic!("Amode {self:?} cannot take memflags"), 394 } 395 } 396 397 /// Add the registers mentioned by `self` to `collector`. 398 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { 399 match self { 400 Amode::ImmReg { base, .. } => { 401 if *base != regs::rbp() && *base != regs::rsp() { 402 collector.reg_use(base); 403 } 404 } 405 Amode::ImmRegRegShift { base, index, .. } => { 406 debug_assert_ne!(base.to_reg(), regs::rbp()); 407 debug_assert_ne!(base.to_reg(), regs::rsp()); 408 collector.reg_use(base); 409 debug_assert_ne!(index.to_reg(), regs::rbp()); 410 debug_assert_ne!(index.to_reg(), regs::rsp()); 411 collector.reg_use(index); 412 } 413 Amode::RipRelative { .. } => { 414 // RIP isn't involved in regalloc. 415 } 416 } 417 } 418 419 /// Same as `get_operands`, but add the registers in the "late" phase. 420 pub(crate) fn get_operands_late(&mut self, collector: &mut impl OperandVisitor) { 421 match self { 422 Amode::ImmReg { base, .. } => { 423 collector.reg_late_use(base); 424 } 425 Amode::ImmRegRegShift { base, index, .. } => { 426 collector.reg_late_use(base); 427 collector.reg_late_use(index); 428 } 429 Amode::RipRelative { .. } => { 430 // RIP isn't involved in regalloc. 431 } 432 } 433 } 434 435 pub(crate) fn get_flags(&self) -> MemFlags { 436 match self { 437 Amode::ImmReg { flags, .. } | Amode::ImmRegRegShift { flags, .. } => *flags, 438 Amode::RipRelative { .. } => MemFlags::trusted(), 439 } 440 } 441 442 /// Offset the amode by a fixed offset. 443 pub(crate) fn offset(&self, offset: i32) -> Self { 444 let mut ret = self.clone(); 445 match &mut ret { 446 &mut Amode::ImmReg { ref mut simm32, .. } => *simm32 += offset, 447 &mut Amode::ImmRegRegShift { ref mut simm32, .. } => *simm32 += offset, 448 _ => panic!("Cannot offset amode: {self:?}"), 449 } 450 ret 451 } 452 453 pub(crate) fn aligned(&self) -> bool { 454 self.get_flags().aligned() 455 } 456 } 457 458 impl PrettyPrint for Amode { 459 fn pretty_print(&self, _size: u8) -> String { 460 match self { 461 Amode::ImmReg { simm32, base, .. } => { 462 // Note: size is always 8; the address is 64 bits, 463 // even if the addressed operand is smaller. 464 format!("{}({})", *simm32, pretty_print_reg(*base, 8)) 465 } 466 Amode::ImmRegRegShift { 467 simm32, 468 base, 469 index, 470 shift, 471 .. 472 } => format!( 473 "{}({},{},{})", 474 *simm32, 475 pretty_print_reg(base.to_reg(), 8), 476 pretty_print_reg(index.to_reg(), 8), 477 1 << shift 478 ), 479 Amode::RipRelative { target } => format!("label{}(%rip)", target.as_u32()), 480 } 481 } 482 } 483 484 /// A Memory Address. These denote a 64-bit value only. 485 /// Used for usual addressing modes as well as addressing modes used during compilation, when the 486 /// moving SP offset is not known. 487 #[derive(Clone, Debug)] 488 pub enum SyntheticAmode { 489 /// A real amode. 490 Real(Amode), 491 492 /// A (virtual) offset into the incoming argument area. 493 IncomingArg { 494 /// The downward offset from the start of the incoming argument area. 495 offset: u32, 496 }, 497 498 /// A (virtual) offset to the slot area of the function frame, which lies just above the 499 /// outgoing arguments. 500 SlotOffset { 501 /// The offset into the slot area. 502 simm32: i32, 503 }, 504 505 /// A virtual offset to a constant that will be emitted in the constant section of the buffer. 506 ConstantOffset(VCodeConstant), 507 } 508 509 impl SyntheticAmode { 510 /// Create a real addressing mode. 511 pub fn real(amode: Amode) -> Self { 512 Self::Real(amode) 513 } 514 515 pub(crate) fn slot_offset(simm32: i32) -> Self { 516 SyntheticAmode::SlotOffset { simm32 } 517 } 518 519 /// Add the registers mentioned by `self` to `collector`. 520 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { 521 match self { 522 SyntheticAmode::Real(addr) => addr.get_operands(collector), 523 SyntheticAmode::IncomingArg { .. } => { 524 // Nothing to do; the base is known and isn't involved in regalloc. 525 } 526 SyntheticAmode::SlotOffset { .. } => { 527 // Nothing to do; the base is SP and isn't involved in regalloc. 528 } 529 SyntheticAmode::ConstantOffset(_) => {} 530 } 531 } 532 533 /// Same as `get_operands`, but add the register in the "late" phase. 534 pub(crate) fn get_operands_late(&mut self, collector: &mut impl OperandVisitor) { 535 match self { 536 SyntheticAmode::Real(addr) => addr.get_operands_late(collector), 537 SyntheticAmode::IncomingArg { .. } => { 538 // Nothing to do; the base is known and isn't involved in regalloc. 539 } 540 SyntheticAmode::SlotOffset { .. } => { 541 // Nothing to do; the base is SP and isn't involved in regalloc. 542 } 543 SyntheticAmode::ConstantOffset(_) => {} 544 } 545 } 546 547 pub(crate) fn finalize(&self, frame: &FrameLayout, buffer: &mut MachBuffer<Inst>) -> Amode { 548 match self { 549 SyntheticAmode::Real(addr) => addr.clone(), 550 SyntheticAmode::IncomingArg { offset } => { 551 // NOTE: this could be made relative to RSP by adding additional 552 // offsets from the frame_layout. 553 let args_max_fp_offset = frame.tail_args_size + frame.setup_area_size; 554 Amode::imm_reg( 555 i32::try_from(args_max_fp_offset - offset).unwrap(), 556 regs::rbp(), 557 ) 558 } 559 SyntheticAmode::SlotOffset { simm32 } => { 560 let off = *simm32 as i64 + i64::from(frame.outgoing_args_size); 561 Amode::imm_reg(off.try_into().expect("invalid sp offset"), regs::rsp()) 562 } 563 SyntheticAmode::ConstantOffset(c) => { 564 Amode::rip_relative(buffer.get_label_for_constant(*c)) 565 } 566 } 567 } 568 569 pub(crate) fn aligned(&self) -> bool { 570 match self { 571 SyntheticAmode::Real(addr) => addr.aligned(), 572 &SyntheticAmode::IncomingArg { .. } 573 | SyntheticAmode::SlotOffset { .. } 574 | SyntheticAmode::ConstantOffset { .. } => true, 575 } 576 } 577 } 578 579 impl From<Amode> for SyntheticAmode { 580 fn from(amode: Amode) -> SyntheticAmode { 581 SyntheticAmode::Real(amode) 582 } 583 } 584 585 impl From<VCodeConstant> for SyntheticAmode { 586 fn from(c: VCodeConstant) -> SyntheticAmode { 587 SyntheticAmode::ConstantOffset(c) 588 } 589 } 590 591 impl PrettyPrint for SyntheticAmode { 592 fn pretty_print(&self, _size: u8) -> String { 593 match self { 594 // See note in `Amode` regarding constant size of `8`. 595 SyntheticAmode::Real(addr) => addr.pretty_print(8), 596 &SyntheticAmode::IncomingArg { offset } => { 597 format!("rbp(stack args max - {offset})") 598 } 599 SyntheticAmode::SlotOffset { simm32 } => { 600 format!("rsp({} + virtual offset)", *simm32) 601 } 602 SyntheticAmode::ConstantOffset(c) => format!("const({})", c.as_u32()), 603 } 604 } 605 } 606 607 /// An operand which is either an integer Register, a value in Memory or an Immediate. This can 608 /// denote an 8, 16, 32 or 64 bit value. For the Immediate form, in the 8- and 16-bit case, only 609 /// the lower 8 or 16 bits of `simm32` is relevant. In the 64-bit case, the value denoted by 610 /// `simm32` is its sign-extension out to 64 bits. 611 #[derive(Clone, Debug)] 612 pub enum RegMemImm { 613 /// A register operand. 614 Reg { 615 /// The underlying register. 616 reg: Reg, 617 }, 618 /// A memory operand. 619 Mem { 620 /// The memory address. 621 addr: SyntheticAmode, 622 }, 623 /// An immediate operand. 624 Imm { 625 /// The immediate value. 626 simm32: u32, 627 }, 628 } 629 630 impl RegMemImm { 631 /// Create a register operand. 632 pub fn reg(reg: Reg) -> Self { 633 debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float); 634 Self::Reg { reg } 635 } 636 637 /// Create a memory operand. 638 pub fn mem(addr: impl Into<SyntheticAmode>) -> Self { 639 Self::Mem { addr: addr.into() } 640 } 641 642 /// Create an immediate operand. 643 pub fn imm(simm32: u32) -> Self { 644 Self::Imm { simm32 } 645 } 646 647 /// Add the regs mentioned by `self` to `collector`. 648 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { 649 match self { 650 Self::Reg { reg } => collector.reg_use(reg), 651 Self::Mem { addr } => addr.get_operands(collector), 652 Self::Imm { .. } => {} 653 } 654 } 655 } 656 657 impl From<RegMem> for RegMemImm { 658 fn from(rm: RegMem) -> RegMemImm { 659 match rm { 660 RegMem::Reg { reg } => RegMemImm::Reg { reg }, 661 RegMem::Mem { addr } => RegMemImm::Mem { addr }, 662 } 663 } 664 } 665 666 impl From<Reg> for RegMemImm { 667 fn from(reg: Reg) -> Self { 668 RegMemImm::Reg { reg } 669 } 670 } 671 672 impl PrettyPrint for RegMemImm { 673 fn pretty_print(&self, size: u8) -> String { 674 match self { 675 Self::Reg { reg } => pretty_print_reg(*reg, size), 676 Self::Mem { addr } => addr.pretty_print(size), 677 Self::Imm { simm32 } => format!("${}", *simm32 as i32), 678 } 679 } 680 } 681 682 /// An operand which is either an integer Register or a value in Memory. This can denote an 8, 16, 683 /// 32, 64, or 128 bit value. 684 #[derive(Clone, Debug)] 685 pub enum RegMem { 686 /// A register operand. 687 Reg { 688 /// The underlying register. 689 reg: Reg, 690 }, 691 /// A memory operand. 692 Mem { 693 /// The memory address. 694 addr: SyntheticAmode, 695 }, 696 } 697 698 impl RegMem { 699 /// Create a register operand. 700 pub fn reg(reg: Reg) -> Self { 701 debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float); 702 Self::Reg { reg } 703 } 704 705 /// Create a memory operand. 706 pub fn mem(addr: impl Into<SyntheticAmode>) -> Self { 707 Self::Mem { addr: addr.into() } 708 } 709 /// Asserts that in register mode, the reg class is the one that's expected. 710 pub(crate) fn assert_regclass_is(&self, expected_reg_class: RegClass) { 711 if let Self::Reg { reg } = self { 712 debug_assert_eq!(reg.class(), expected_reg_class); 713 } 714 } 715 /// Add the regs mentioned by `self` to `collector`. 716 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { 717 match self { 718 RegMem::Reg { reg } => collector.reg_use(reg), 719 RegMem::Mem { addr, .. } => addr.get_operands(collector), 720 } 721 } 722 } 723 724 impl From<Reg> for RegMem { 725 fn from(reg: Reg) -> RegMem { 726 RegMem::Reg { reg } 727 } 728 } 729 730 impl From<Writable<Reg>> for RegMem { 731 fn from(r: Writable<Reg>) -> Self { 732 RegMem::reg(r.to_reg()) 733 } 734 } 735 736 impl PrettyPrint for RegMem { 737 fn pretty_print(&self, size: u8) -> String { 738 match self { 739 RegMem::Reg { reg } => pretty_print_reg(*reg, size), 740 RegMem::Mem { addr, .. } => addr.pretty_print(size), 741 } 742 } 743 } 744 745 #[derive(Debug)] 746 pub(crate) enum InstructionSet { 747 SSE, 748 SSE2, 749 CMPXCHG16b, 750 SSE3, 751 SSSE3, 752 SSE41, 753 SSE42, 754 Popcnt, 755 Lzcnt, 756 BMI1, 757 #[allow(dead_code)] // never constructed (yet). 758 BMI2, 759 FMA, 760 AVX, 761 AVX2, 762 AVX512BITALG, 763 AVX512DQ, 764 AVX512F, 765 AVX512VBMI, 766 AVX512VL, 767 } 768 769 /// Some SSE operations requiring 2 operands r/m and r. 770 #[derive(Clone, Copy, PartialEq)] 771 #[allow(dead_code)] // some variants here aren't used just yet 772 #[allow(missing_docs)] 773 pub enum SseOpcode { 774 Blendvpd, 775 Blendvps, 776 Insertps, 777 Pabsb, 778 Pabsw, 779 Pabsd, 780 Packssdw, 781 Packsswb, 782 Packusdw, 783 Packuswb, 784 Palignr, 785 Pavgb, 786 Pavgw, 787 Pblendvb, 788 Pcmpeqb, 789 Pcmpeqw, 790 Pcmpeqd, 791 Pcmpeqq, 792 Pcmpgtb, 793 Pcmpgtw, 794 Pcmpgtd, 795 Pcmpgtq, 796 Pmaddubsw, 797 Pmaddwd, 798 Pshufb, 799 Pshufd, 800 Ptest, 801 Rcpss, 802 Roundps, 803 Roundpd, 804 Roundss, 805 Roundsd, 806 Rsqrtss, 807 Shufps, 808 Pshuflw, 809 Pshufhw, 810 Pblendw, 811 } 812 813 impl SseOpcode { 814 /// Which `InstructionSet` is the first supporting this opcode? 815 pub(crate) fn available_from(&self) -> InstructionSet { 816 use InstructionSet::*; 817 match self { 818 SseOpcode::Rcpss | SseOpcode::Rsqrtss | SseOpcode::Shufps => SSE, 819 820 SseOpcode::Packssdw 821 | SseOpcode::Packsswb 822 | SseOpcode::Packuswb 823 | SseOpcode::Pavgb 824 | SseOpcode::Pavgw 825 | SseOpcode::Pcmpeqb 826 | SseOpcode::Pcmpeqw 827 | SseOpcode::Pcmpeqd 828 | SseOpcode::Pcmpgtb 829 | SseOpcode::Pcmpgtw 830 | SseOpcode::Pcmpgtd 831 | SseOpcode::Pmaddwd 832 | SseOpcode::Pshufd 833 | SseOpcode::Pshuflw 834 | SseOpcode::Pshufhw => SSE2, 835 836 SseOpcode::Pabsb 837 | SseOpcode::Pabsw 838 | SseOpcode::Pabsd 839 | SseOpcode::Palignr 840 | SseOpcode::Pshufb 841 | SseOpcode::Pmaddubsw => SSSE3, 842 843 SseOpcode::Blendvpd 844 | SseOpcode::Blendvps 845 | SseOpcode::Insertps 846 | SseOpcode::Packusdw 847 | SseOpcode::Pblendvb 848 | SseOpcode::Pcmpeqq 849 | SseOpcode::Ptest 850 | SseOpcode::Roundps 851 | SseOpcode::Roundpd 852 | SseOpcode::Roundss 853 | SseOpcode::Roundsd 854 | SseOpcode::Pblendw => SSE41, 855 856 SseOpcode::Pcmpgtq => SSE42, 857 } 858 } 859 860 /// Returns the src operand size for an instruction. 861 pub(crate) fn src_size(&self) -> u8 { 862 match self { 863 _ => 8, 864 } 865 } 866 867 /// Is `src2` with this opcode a scalar, as for lane insertions? 868 pub(crate) fn has_scalar_src2(self) -> bool { 869 false 870 } 871 } 872 873 impl fmt::Debug for SseOpcode { 874 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 875 let name = match self { 876 SseOpcode::Blendvpd => "blendvpd", 877 SseOpcode::Blendvps => "blendvps", 878 SseOpcode::Insertps => "insertps", 879 SseOpcode::Pabsb => "pabsb", 880 SseOpcode::Pabsw => "pabsw", 881 SseOpcode::Pabsd => "pabsd", 882 SseOpcode::Packssdw => "packssdw", 883 SseOpcode::Packsswb => "packsswb", 884 SseOpcode::Packusdw => "packusdw", 885 SseOpcode::Packuswb => "packuswb", 886 SseOpcode::Palignr => "palignr", 887 SseOpcode::Pavgb => "pavgb", 888 SseOpcode::Pavgw => "pavgw", 889 SseOpcode::Pblendvb => "pblendvb", 890 SseOpcode::Pcmpeqb => "pcmpeqb", 891 SseOpcode::Pcmpeqw => "pcmpeqw", 892 SseOpcode::Pcmpeqd => "pcmpeqd", 893 SseOpcode::Pcmpeqq => "pcmpeqq", 894 SseOpcode::Pcmpgtb => "pcmpgtb", 895 SseOpcode::Pcmpgtw => "pcmpgtw", 896 SseOpcode::Pcmpgtd => "pcmpgtd", 897 SseOpcode::Pcmpgtq => "pcmpgtq", 898 SseOpcode::Pmaddubsw => "pmaddubsw", 899 SseOpcode::Pmaddwd => "pmaddwd", 900 SseOpcode::Pshufb => "pshufb", 901 SseOpcode::Pshufd => "pshufd", 902 SseOpcode::Ptest => "ptest", 903 SseOpcode::Rcpss => "rcpss", 904 SseOpcode::Roundps => "roundps", 905 SseOpcode::Roundpd => "roundpd", 906 SseOpcode::Roundss => "roundss", 907 SseOpcode::Roundsd => "roundsd", 908 SseOpcode::Rsqrtss => "rsqrtss", 909 SseOpcode::Shufps => "shufps", 910 SseOpcode::Pshuflw => "pshuflw", 911 SseOpcode::Pshufhw => "pshufhw", 912 SseOpcode::Pblendw => "pblendw", 913 }; 914 write!(fmt, "{name}") 915 } 916 } 917 918 impl fmt::Display for SseOpcode { 919 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 920 fmt::Debug::fmt(self, f) 921 } 922 } 923 924 pub use crate::isa::x64::lower::isle::generated_code::AvxOpcode; 925 926 impl AvxOpcode { 927 /// Which `InstructionSet`s support the opcode? 928 pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> { 929 match self { 930 AvxOpcode::Vpacksswb 931 | AvxOpcode::Vpackssdw 932 | AvxOpcode::Vpackuswb 933 | AvxOpcode::Vpackusdw 934 | AvxOpcode::Vpalignr 935 | AvxOpcode::Vpmaddwd 936 | AvxOpcode::Vpmaddubsw 937 | AvxOpcode::Vinsertps 938 | AvxOpcode::Vpshufb 939 | AvxOpcode::Vshufps 940 | AvxOpcode::Vphaddw 941 | AvxOpcode::Vphaddd 942 | AvxOpcode::Vmovss 943 | AvxOpcode::Vmovsd 944 | AvxOpcode::Vmovups 945 | AvxOpcode::Vmovupd 946 | AvxOpcode::Vmovdqu 947 | AvxOpcode::Vpblendw 948 | AvxOpcode::Vptest => { 949 smallvec![InstructionSet::AVX] 950 } 951 } 952 } 953 954 /// Is the opcode known to be commutative? 955 /// 956 /// Note that this method is not exhaustive, and there may be commutative 957 /// opcodes that we don't recognize as commutative. 958 pub(crate) fn is_commutative(&self) -> bool { 959 false 960 } 961 } 962 963 impl fmt::Display for AvxOpcode { 964 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 965 format!("{self:?}").to_lowercase().fmt(f) 966 } 967 } 968 969 #[derive(Copy, Clone, PartialEq)] 970 #[allow(missing_docs)] 971 pub enum Avx512TupleType { 972 Full, 973 FullMem, 974 Mem128, 975 } 976 977 pub use crate::isa::x64::lower::isle::generated_code::Avx512Opcode; 978 979 impl Avx512Opcode { 980 /// Which `InstructionSet`s support the opcode? 981 pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> { 982 match self { 983 Avx512Opcode::Vcvtudq2ps 984 | Avx512Opcode::Vpabsq 985 | Avx512Opcode::Vpsraq 986 | Avx512Opcode::VpsraqImm => { 987 smallvec![InstructionSet::AVX512F, InstructionSet::AVX512VL] 988 } 989 Avx512Opcode::Vpermi2b => { 990 smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512VBMI] 991 } 992 Avx512Opcode::Vpmullq => smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512DQ], 993 Avx512Opcode::Vpopcntb => { 994 smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512BITALG] 995 } 996 } 997 } 998 999 /// What is the "TupleType" of this opcode, which affects the scaling factor 1000 /// for 8-bit displacements when this instruction uses memory operands. 1001 /// 1002 /// This can be found in the encoding table for each instruction and is 1003 /// interpreted according to Table 2-34 and 2-35 in the Intel instruction 1004 /// manual. 1005 pub fn tuple_type(&self) -> Avx512TupleType { 1006 use Avx512Opcode::*; 1007 use Avx512TupleType::*; 1008 1009 match self { 1010 Vcvtudq2ps | Vpabsq | Vpmullq | VpsraqImm => Full, 1011 Vpermi2b | Vpopcntb => FullMem, 1012 Vpsraq => Mem128, 1013 } 1014 } 1015 } 1016 1017 impl fmt::Display for Avx512Opcode { 1018 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1019 let s = format!("{self:?}"); 1020 f.write_str(&s.to_lowercase()) 1021 } 1022 } 1023 1024 /// This defines the ways a value can be extended: either signed- or zero-extension, or none for 1025 /// types that are not extended. Contrast with [ExtMode], which defines the widths from and to which 1026 /// values can be extended. 1027 #[allow(dead_code)] 1028 #[derive(Clone, PartialEq)] 1029 pub enum ExtKind { 1030 /// No extension. 1031 None, 1032 /// Sign-extend. 1033 SignExtend, 1034 /// Zero-extend. 1035 ZeroExtend, 1036 } 1037 1038 /// These indicate ways of extending (widening) a value, using the Intel 1039 /// naming: B(yte) = u8, W(ord) = u16, L(ong)word = u32, Q(uad)word = u64 1040 #[derive(Clone, PartialEq)] 1041 pub enum ExtMode { 1042 /// Byte -> Longword. 1043 BL, 1044 /// Byte -> Quadword. 1045 BQ, 1046 /// Word -> Longword. 1047 WL, 1048 /// Word -> Quadword. 1049 WQ, 1050 /// Longword -> Quadword. 1051 LQ, 1052 } 1053 1054 impl ExtMode { 1055 /// Calculate the `ExtMode` from passed bit lengths of the from/to types. 1056 pub(crate) fn new(from_bits: u16, to_bits: u16) -> Option<ExtMode> { 1057 match (from_bits, to_bits) { 1058 (1, 8) | (1, 16) | (1, 32) | (8, 16) | (8, 32) => Some(ExtMode::BL), 1059 (1, 64) | (8, 64) => Some(ExtMode::BQ), 1060 (16, 32) => Some(ExtMode::WL), 1061 (16, 64) => Some(ExtMode::WQ), 1062 (32, 64) => Some(ExtMode::LQ), 1063 _ => None, 1064 } 1065 } 1066 } 1067 1068 impl fmt::Debug for ExtMode { 1069 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 1070 let name = match self { 1071 ExtMode::BL => "bl", 1072 ExtMode::BQ => "bq", 1073 ExtMode::WL => "wl", 1074 ExtMode::WQ => "wq", 1075 ExtMode::LQ => "lq", 1076 }; 1077 write!(fmt, "{name}") 1078 } 1079 } 1080 1081 impl fmt::Display for ExtMode { 1082 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1083 fmt::Debug::fmt(self, f) 1084 } 1085 } 1086 1087 /// These indicate condition code tests. Not all are represented since not all are useful in 1088 /// compiler-generated code. 1089 #[derive(Copy, Clone, PartialEq, Eq)] 1090 #[repr(u8)] 1091 pub enum CC { 1092 /// overflow 1093 O = 0, 1094 /// no overflow 1095 NO = 1, 1096 1097 /// < unsigned 1098 B = 2, 1099 /// >= unsigned 1100 NB = 3, 1101 1102 /// zero 1103 Z = 4, 1104 /// not-zero 1105 NZ = 5, 1106 1107 /// <= unsigned 1108 BE = 6, 1109 /// > unsigned 1110 NBE = 7, 1111 1112 /// negative 1113 S = 8, 1114 /// not-negative 1115 NS = 9, 1116 1117 /// < signed 1118 L = 12, 1119 /// >= signed 1120 NL = 13, 1121 1122 /// <= signed 1123 LE = 14, 1124 /// > signed 1125 NLE = 15, 1126 1127 /// parity 1128 P = 10, 1129 1130 /// not parity 1131 NP = 11, 1132 } 1133 1134 impl CC { 1135 pub(crate) fn from_intcc(intcc: IntCC) -> Self { 1136 match intcc { 1137 IntCC::Equal => CC::Z, 1138 IntCC::NotEqual => CC::NZ, 1139 IntCC::SignedGreaterThanOrEqual => CC::NL, 1140 IntCC::SignedGreaterThan => CC::NLE, 1141 IntCC::SignedLessThanOrEqual => CC::LE, 1142 IntCC::SignedLessThan => CC::L, 1143 IntCC::UnsignedGreaterThanOrEqual => CC::NB, 1144 IntCC::UnsignedGreaterThan => CC::NBE, 1145 IntCC::UnsignedLessThanOrEqual => CC::BE, 1146 IntCC::UnsignedLessThan => CC::B, 1147 } 1148 } 1149 1150 pub(crate) fn invert(&self) -> Self { 1151 match self { 1152 CC::O => CC::NO, 1153 CC::NO => CC::O, 1154 1155 CC::B => CC::NB, 1156 CC::NB => CC::B, 1157 1158 CC::Z => CC::NZ, 1159 CC::NZ => CC::Z, 1160 1161 CC::BE => CC::NBE, 1162 CC::NBE => CC::BE, 1163 1164 CC::S => CC::NS, 1165 CC::NS => CC::S, 1166 1167 CC::L => CC::NL, 1168 CC::NL => CC::L, 1169 1170 CC::LE => CC::NLE, 1171 CC::NLE => CC::LE, 1172 1173 CC::P => CC::NP, 1174 CC::NP => CC::P, 1175 } 1176 } 1177 1178 pub(crate) fn get_enc(self) -> u8 { 1179 self as u8 1180 } 1181 } 1182 1183 impl fmt::Debug for CC { 1184 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 1185 let name = match self { 1186 CC::O => "o", 1187 CC::NO => "no", 1188 CC::B => "b", 1189 CC::NB => "nb", 1190 CC::Z => "z", 1191 CC::NZ => "nz", 1192 CC::BE => "be", 1193 CC::NBE => "nbe", 1194 CC::S => "s", 1195 CC::NS => "ns", 1196 CC::L => "l", 1197 CC::NL => "nl", 1198 CC::LE => "le", 1199 CC::NLE => "nle", 1200 CC::P => "p", 1201 CC::NP => "np", 1202 }; 1203 write!(fmt, "{name}") 1204 } 1205 } 1206 1207 impl fmt::Display for CC { 1208 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1209 fmt::Debug::fmt(self, f) 1210 } 1211 } 1212 1213 /// Encode the ways that floats can be compared. This is used in float comparisons such as `cmpps`, 1214 /// e.g.; it is distinguished from other float comparisons (e.g. `ucomiss`) in that those use EFLAGS 1215 /// whereas [FcmpImm] is used as an immediate. 1216 #[derive(Clone, Copy)] 1217 pub enum FcmpImm { 1218 /// Equal comparison. 1219 Equal = 0x00, 1220 /// Less than comparison. 1221 LessThan = 0x01, 1222 /// Less than or equal comparison. 1223 LessThanOrEqual = 0x02, 1224 /// Unordered. 1225 Unordered = 0x03, 1226 /// Not equal comparison. 1227 NotEqual = 0x04, 1228 /// Unordered of greater than or equal comparison. 1229 UnorderedOrGreaterThanOrEqual = 0x05, 1230 /// Unordered or greater than comparison. 1231 UnorderedOrGreaterThan = 0x06, 1232 /// Ordered. 1233 Ordered = 0x07, 1234 } 1235 1236 impl FcmpImm { 1237 pub(crate) fn encode(self) -> u8 { 1238 self as u8 1239 } 1240 } 1241 1242 impl From<FloatCC> for FcmpImm { 1243 fn from(cond: FloatCC) -> Self { 1244 match cond { 1245 FloatCC::Equal => FcmpImm::Equal, 1246 FloatCC::LessThan => FcmpImm::LessThan, 1247 FloatCC::LessThanOrEqual => FcmpImm::LessThanOrEqual, 1248 FloatCC::Unordered => FcmpImm::Unordered, 1249 FloatCC::NotEqual => FcmpImm::NotEqual, 1250 FloatCC::UnorderedOrGreaterThanOrEqual => FcmpImm::UnorderedOrGreaterThanOrEqual, 1251 FloatCC::UnorderedOrGreaterThan => FcmpImm::UnorderedOrGreaterThan, 1252 FloatCC::Ordered => FcmpImm::Ordered, 1253 _ => panic!("unable to create comparison predicate for {cond}"), 1254 } 1255 } 1256 } 1257 1258 /// Encode the rounding modes used as part of the Rounding Control field. 1259 /// Note, these rounding immediates only consider the rounding control field 1260 /// (i.e. the rounding mode) which only take up the first two bits when encoded. 1261 /// However the rounding immediate which this field helps make up, also includes 1262 /// bits 3 and 4 which define the rounding select and precision mask respectively. 1263 /// These two bits are not defined here and are implicitly set to zero when encoded. 1264 #[derive(Clone, Copy)] 1265 pub enum RoundImm { 1266 /// Round to nearest mode. 1267 RoundNearest = 0x00, 1268 /// Round down mode. 1269 RoundDown = 0x01, 1270 /// Round up mode. 1271 RoundUp = 0x02, 1272 /// Round to zero mode. 1273 RoundZero = 0x03, 1274 } 1275 1276 impl RoundImm { 1277 pub(crate) fn encode(self) -> u8 { 1278 self as u8 1279 } 1280 } 1281 1282 /// An operand's size in bits. 1283 #[derive(Clone, Copy, PartialEq)] 1284 pub enum OperandSize { 1285 /// 8-bit. 1286 Size8, 1287 /// 16-bit. 1288 Size16, 1289 /// 32-bit. 1290 Size32, 1291 /// 64-bit. 1292 Size64, 1293 } 1294 1295 impl OperandSize { 1296 pub(crate) fn from_bytes(num_bytes: u32) -> Self { 1297 match num_bytes { 1298 1 => OperandSize::Size8, 1299 2 => OperandSize::Size16, 1300 4 => OperandSize::Size32, 1301 8 => OperandSize::Size64, 1302 _ => unreachable!("Invalid OperandSize: {}", num_bytes), 1303 } 1304 } 1305 1306 // Computes the OperandSize for a given type. 1307 // For vectors, the OperandSize of the lanes is returned. 1308 pub(crate) fn from_ty(ty: Type) -> Self { 1309 Self::from_bytes(ty.lane_type().bytes()) 1310 } 1311 1312 // Check that the value of self is one of the allowed sizes. 1313 pub(crate) fn is_one_of(&self, sizes: &[Self]) -> bool { 1314 sizes.iter().any(|val| *self == *val) 1315 } 1316 1317 pub(crate) fn to_bytes(&self) -> u8 { 1318 match self { 1319 Self::Size8 => 1, 1320 Self::Size16 => 2, 1321 Self::Size32 => 4, 1322 Self::Size64 => 8, 1323 } 1324 } 1325 1326 pub(crate) fn to_bits(&self) -> u8 { 1327 self.to_bytes() * 8 1328 } 1329 1330 pub(crate) fn to_type(&self) -> Type { 1331 match self { 1332 Self::Size8 => I8, 1333 Self::Size16 => I16, 1334 Self::Size32 => I32, 1335 Self::Size64 => I64, 1336 } 1337 } 1338 } 1339