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 std::fmt; 11 use std::string::String; 12 13 /// An extension trait for converting `Writable{Xmm,Gpr}` to `Writable<Reg>`. 14 pub trait ToWritableReg { 15 /// Convert `Writable{Xmm,Gpr}` to `Writable<Reg>`. 16 fn to_writable_reg(&self) -> Writable<Reg>; 17 } 18 19 /// An extension trait for converting `Writable<Reg>` to `Writable{Xmm,Gpr}`. 20 pub trait FromWritableReg: Sized { 21 /// Convert `Writable<Reg>` to `Writable{Xmm,Gpr}`. 22 fn from_writable_reg(w: Writable<Reg>) -> Option<Self>; 23 } 24 25 /// A macro for defining a newtype of `Reg` that enforces some invariant about 26 /// the wrapped `Reg` (such as that it is of a particular register class). 27 macro_rules! newtype_of_reg { 28 ( 29 $newtype_reg:ident, 30 $newtype_writable_reg:ident, 31 $newtype_option_writable_reg:ident, 32 reg_mem: ($($newtype_reg_mem:ident $(aligned:$aligned:ident)?),*), 33 reg_mem_imm: ($($newtype_reg_mem_imm:ident $(aligned:$aligned_imm:ident)?),*), 34 |$check_reg:ident| $check:expr 35 ) => { 36 /// A newtype wrapper around `Reg`. 37 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 38 pub struct $newtype_reg(Reg); 39 40 impl PartialEq<Reg> for $newtype_reg { 41 fn eq(&self, other: &Reg) -> bool { 42 self.0 == *other 43 } 44 } 45 46 impl From<$newtype_reg> for Reg { 47 fn from(r: $newtype_reg) -> Self { 48 r.0 49 } 50 } 51 52 impl $newtype_reg { 53 /// Create this newtype from the given register, or return `None` if the register 54 /// is not a valid instance of this newtype. 55 pub fn new($check_reg: Reg) -> Option<Self> { 56 if $check { 57 Some(Self($check_reg)) 58 } else { 59 None 60 } 61 } 62 63 /// Like `Self::new(r).unwrap()` but with a better panic message on 64 /// failure. 65 pub fn unwrap_new($check_reg: Reg) -> Self { 66 if $check { 67 Self($check_reg) 68 } else { 69 panic!( 70 "cannot construct {} from register {:?} with register class {:?}", 71 stringify!($newtype_reg), 72 $check_reg, 73 $check_reg.class(), 74 ) 75 } 76 } 77 78 /// Get this newtype's underlying `Reg`. 79 pub fn to_reg(self) -> Reg { 80 self.0 81 } 82 } 83 84 // Convenience impl so that people working with this newtype can use it 85 // "just like" a plain `Reg`. 86 // 87 // NB: We cannot implement `DerefMut` because that would let people do 88 // nasty stuff like `*my_gpr.deref_mut() = some_xmm_reg`, breaking the 89 // invariants that `Gpr` provides. 90 impl std::ops::Deref for $newtype_reg { 91 type Target = Reg; 92 93 fn deref(&self) -> &Reg { 94 &self.0 95 } 96 } 97 98 /// If you know what you're doing, you can explicitly mutably borrow the 99 /// underlying `Reg`. Don't make it point to the wrong type of register 100 /// please. 101 impl AsMut<Reg> for $newtype_reg { 102 fn as_mut(&mut self) -> &mut Reg { 103 &mut self.0 104 } 105 } 106 107 /// Writable Gpr. 108 pub type $newtype_writable_reg = Writable<$newtype_reg>; 109 110 #[allow(dead_code, reason = "Used by some newtypes and not others")] 111 /// Optional writable Gpr. 112 pub type $newtype_option_writable_reg = Option<Writable<$newtype_reg>>; 113 114 impl ToWritableReg for $newtype_writable_reg { 115 fn to_writable_reg(&self) -> Writable<Reg> { 116 Writable::from_reg(self.to_reg().to_reg()) 117 } 118 } 119 120 impl FromWritableReg for $newtype_writable_reg { 121 fn from_writable_reg(w: Writable<Reg>) -> Option<Self> { 122 Some(Writable::from_reg($newtype_reg::new(w.to_reg())?)) 123 } 124 } 125 126 $( 127 /// A newtype wrapper around `RegMem` for general-purpose registers. 128 #[derive(Clone, Debug)] 129 pub struct $newtype_reg_mem(RegMem); 130 131 impl From<$newtype_reg_mem> for RegMem { 132 fn from(rm: $newtype_reg_mem) -> Self { 133 rm.0 134 } 135 } 136 impl<'a> From<&'a $newtype_reg_mem> for &'a RegMem { 137 fn from(rm: &'a $newtype_reg_mem) -> &'a RegMem { 138 &rm.0 139 } 140 } 141 142 impl From<$newtype_reg> for $newtype_reg_mem { 143 fn from(r: $newtype_reg) -> Self { 144 $newtype_reg_mem(RegMem::reg(r.into())) 145 } 146 } 147 148 impl $newtype_reg_mem { 149 /// Construct a `RegMem` newtype from the given `RegMem`, or return 150 /// `None` if the `RegMem` is not a valid instance of this `RegMem` 151 /// newtype. 152 pub fn new(rm: RegMem) -> Option<Self> { 153 match rm { 154 RegMem::Mem { addr } => { 155 let mut _allow = true; 156 $( 157 if $aligned { 158 _allow = addr.aligned(); 159 } 160 )? 161 if _allow { 162 Some(Self(RegMem::Mem { addr })) 163 } else { 164 None 165 } 166 } 167 RegMem::Reg { reg } => Some($newtype_reg::new(reg)?.into()), 168 } 169 } 170 171 /// Like `Self::new(rm).unwrap()` but with better panic messages 172 /// in case of failure. 173 pub fn unwrap_new(rm: RegMem) -> Self { 174 match rm { 175 RegMem::Mem { addr } => { 176 $( 177 if $aligned && !addr.aligned() { 178 panic!( 179 "cannot create {} from an unaligned memory address: {addr:?}", 180 stringify!($newtype_reg_mem), 181 ); 182 } 183 )? 184 Self(RegMem::Mem { addr }) 185 } 186 RegMem::Reg { reg } => $newtype_reg::unwrap_new(reg).into(), 187 } 188 } 189 190 /// Convert this newtype into its underlying `RegMem`. 191 pub fn to_reg_mem(self) -> RegMem { 192 self.0 193 } 194 195 #[allow(dead_code, reason = "Used by some newtypes and not others")] 196 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { 197 self.0.get_operands(collector); 198 } 199 } 200 impl PrettyPrint for $newtype_reg_mem { 201 fn pretty_print(&self, size: u8) -> String { 202 self.0.pretty_print(size) 203 } 204 } 205 )* 206 207 $( 208 /// A newtype wrapper around `RegMemImm`. 209 #[derive(Clone, Debug)] 210 pub struct $newtype_reg_mem_imm(RegMemImm); 211 212 impl From<$newtype_reg_mem_imm> for RegMemImm { 213 fn from(rmi: $newtype_reg_mem_imm) -> RegMemImm { 214 rmi.0 215 } 216 } 217 impl<'a> From<&'a $newtype_reg_mem_imm> for &'a RegMemImm { 218 fn from(rmi: &'a $newtype_reg_mem_imm) -> &'a RegMemImm { 219 &rmi.0 220 } 221 } 222 223 impl From<$newtype_reg> for $newtype_reg_mem_imm { 224 fn from(r: $newtype_reg) -> Self { 225 $newtype_reg_mem_imm(RegMemImm::reg(r.into())) 226 } 227 } 228 229 impl $newtype_reg_mem_imm { 230 /// Construct this newtype from the given `RegMemImm`, or return 231 /// `None` if the `RegMemImm` is not a valid instance of this 232 /// newtype. 233 pub fn new(rmi: RegMemImm) -> Option<Self> { 234 match rmi { 235 RegMemImm::Imm { .. } => Some(Self(rmi)), 236 RegMemImm::Mem { addr } => { 237 let mut _allow = true; 238 $( 239 if $aligned_imm { 240 _allow = addr.aligned(); 241 } 242 )? 243 if _allow { 244 Some(Self(RegMemImm::Mem { addr })) 245 } else { 246 None 247 } 248 } 249 RegMemImm::Reg { reg } => Some($newtype_reg::new(reg)?.into()), 250 } 251 } 252 253 /// Like `Self::new(rmi).unwrap()` but with better panic 254 /// messages in case of failure. 255 pub fn unwrap_new(rmi: RegMemImm) -> Self { 256 match rmi { 257 RegMemImm::Imm { .. } => Self(rmi), 258 RegMemImm::Mem { addr } => { 259 $( 260 if $aligned_imm && !addr.aligned() { 261 panic!( 262 "cannot construct {} from unaligned memory address: {:?}", 263 stringify!($newtype_reg_mem_imm), 264 addr, 265 ); 266 } 267 )? 268 Self(RegMemImm::Mem { addr }) 269 270 } 271 RegMemImm::Reg { reg } => $newtype_reg::unwrap_new(reg).into(), 272 } 273 } 274 275 /// Convert this newtype into its underlying `RegMemImm`. 276 #[allow(dead_code, reason = "Used by some newtypes and not others")] 277 pub fn to_reg_mem_imm(self) -> RegMemImm { 278 self.0 279 } 280 281 #[allow(dead_code, reason = "Used by some newtypes and not others")] 282 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { 283 self.0.get_operands(collector); 284 } 285 } 286 287 impl PrettyPrint for $newtype_reg_mem_imm { 288 fn pretty_print(&self, size: u8) -> String { 289 self.0.pretty_print(size) 290 } 291 } 292 )* 293 }; 294 } 295 296 // Define a newtype of `Reg` for general-purpose registers. 297 newtype_of_reg!( 298 Gpr, 299 WritableGpr, 300 OptionWritableGpr, 301 reg_mem: (GprMem), 302 reg_mem_imm: (GprMemImm), 303 |reg| reg.class() == RegClass::Int 304 ); 305 306 #[expect(missing_docs, reason = "self-describing fields")] 307 impl Gpr { 308 pub const RAX: Gpr = Gpr(regs::rax()); 309 pub const RBX: Gpr = Gpr(regs::rbx()); 310 pub const RCX: Gpr = Gpr(regs::rcx()); 311 pub const RDX: Gpr = Gpr(regs::rdx()); 312 pub const RSI: Gpr = Gpr(regs::rsi()); 313 pub const RDI: Gpr = Gpr(regs::rdi()); 314 pub const RSP: Gpr = Gpr(regs::rsp()); 315 pub const RBP: Gpr = Gpr(regs::rbp()); 316 pub const R8: Gpr = Gpr(regs::r8()); 317 pub const R9: Gpr = Gpr(regs::r9()); 318 pub const R10: Gpr = Gpr(regs::r10()); 319 pub const R11: Gpr = Gpr(regs::r11()); 320 pub const R12: Gpr = Gpr(regs::r12()); 321 pub const R13: Gpr = Gpr(regs::r13()); 322 pub const R14: Gpr = Gpr(regs::r14()); 323 pub const R15: Gpr = Gpr(regs::r15()); 324 } 325 326 // Define a newtype of `Reg` for XMM registers. 327 newtype_of_reg!( 328 Xmm, 329 WritableXmm, 330 OptionWritableXmm, 331 reg_mem: (XmmMem, XmmMemAligned aligned:true), 332 reg_mem_imm: (XmmMemImm, XmmMemAlignedImm aligned:true), 333 |reg| reg.class() == RegClass::Float 334 ); 335 336 // N.B.: `Amode` is defined in `inst.isle`. We add some convenience 337 // constructors here. 338 339 // Re-export the type from the ISLE generated code. 340 pub use crate::isa::x64::lower::isle::generated_code::Amode; 341 342 impl Amode { 343 /// Create an immediate sign-extended and register addressing mode. 344 pub fn imm_reg(simm32: i32, base: Reg) -> Self { 345 debug_assert!(base.class() == RegClass::Int); 346 Self::ImmReg { 347 simm32, 348 base, 349 flags: MemFlags::trusted(), 350 } 351 } 352 353 /// Create a sign-extended-32-to-64 with register and shift addressing mode. 354 pub fn imm_reg_reg_shift(simm32: i32, base: Gpr, index: Gpr, shift: u8) -> Self { 355 debug_assert!(base.class() == RegClass::Int); 356 debug_assert!(index.class() == RegClass::Int); 357 debug_assert!(shift <= 3); 358 Self::ImmRegRegShift { 359 simm32, 360 base, 361 index, 362 shift, 363 flags: MemFlags::trusted(), 364 } 365 } 366 367 pub(crate) fn rip_relative(target: MachLabel) -> Self { 368 Self::RipRelative { target } 369 } 370 371 /// Set the specified [MemFlags] to the [Amode]. 372 pub fn with_flags(&self, flags: MemFlags) -> Self { 373 match self { 374 &Self::ImmReg { simm32, base, .. } => Self::ImmReg { 375 simm32, 376 base, 377 flags, 378 }, 379 &Self::ImmRegRegShift { 380 simm32, 381 base, 382 index, 383 shift, 384 .. 385 } => Self::ImmRegRegShift { 386 simm32, 387 base, 388 index, 389 shift, 390 flags, 391 }, 392 _ => panic!("Amode {self:?} cannot take memflags"), 393 } 394 } 395 396 /// Add the registers mentioned by `self` to `collector`. 397 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { 398 match self { 399 Amode::ImmReg { base, .. } => { 400 if *base != regs::rbp() && *base != regs::rsp() { 401 collector.reg_use(base); 402 } 403 } 404 Amode::ImmRegRegShift { base, index, .. } => { 405 debug_assert_ne!(base.to_reg(), regs::rbp()); 406 debug_assert_ne!(base.to_reg(), regs::rsp()); 407 collector.reg_use(base); 408 debug_assert_ne!(index.to_reg(), regs::rbp()); 409 debug_assert_ne!(index.to_reg(), regs::rsp()); 410 collector.reg_use(index); 411 } 412 Amode::RipRelative { .. } => { 413 // RIP isn't involved in regalloc. 414 } 415 } 416 } 417 418 /// Same as `get_operands`, but add the registers in the "late" phase. 419 pub(crate) fn get_operands_late(&mut self, collector: &mut impl OperandVisitor) { 420 match self { 421 Amode::ImmReg { base, .. } => { 422 collector.reg_late_use(base); 423 } 424 Amode::ImmRegRegShift { base, index, .. } => { 425 collector.reg_late_use(base); 426 collector.reg_late_use(index); 427 } 428 Amode::RipRelative { .. } => { 429 // RIP isn't involved in regalloc. 430 } 431 } 432 } 433 434 pub(crate) fn get_flags(&self) -> MemFlags { 435 match self { 436 Amode::ImmReg { flags, .. } | Amode::ImmRegRegShift { flags, .. } => *flags, 437 Amode::RipRelative { .. } => MemFlags::trusted(), 438 } 439 } 440 441 /// Offset the amode by a fixed offset. 442 pub(crate) fn offset(&self, offset: i32) -> Self { 443 let mut ret = self.clone(); 444 match &mut ret { 445 &mut Amode::ImmReg { ref mut simm32, .. } => *simm32 += offset, 446 &mut Amode::ImmRegRegShift { ref mut simm32, .. } => *simm32 += offset, 447 _ => panic!("Cannot offset amode: {self:?}"), 448 } 449 ret 450 } 451 452 pub(crate) fn aligned(&self) -> bool { 453 self.get_flags().aligned() 454 } 455 } 456 457 impl PrettyPrint for Amode { 458 fn pretty_print(&self, _size: u8) -> String { 459 match self { 460 Amode::ImmReg { simm32, base, .. } => { 461 // Note: size is always 8; the address is 64 bits, 462 // even if the addressed operand is smaller. 463 format!("{}({})", *simm32, pretty_print_reg(*base, 8)) 464 } 465 Amode::ImmRegRegShift { 466 simm32, 467 base, 468 index, 469 shift, 470 .. 471 } => format!( 472 "{}({},{},{})", 473 *simm32, 474 pretty_print_reg(base.to_reg(), 8), 475 pretty_print_reg(index.to_reg(), 8), 476 1 << shift 477 ), 478 Amode::RipRelative { target } => format!("label{}(%rip)", target.as_u32()), 479 } 480 } 481 } 482 483 /// A Memory Address. These denote a 64-bit value only. 484 /// Used for usual addressing modes as well as addressing modes used during compilation, when the 485 /// moving SP offset is not known. 486 #[derive(Clone, Debug)] 487 pub enum SyntheticAmode { 488 /// A real amode. 489 Real(Amode), 490 491 /// A (virtual) offset into the incoming argument area. 492 IncomingArg { 493 /// The downward offset from the start of the incoming argument area. 494 offset: u32, 495 }, 496 497 /// A (virtual) offset to the slot area of the function frame, which lies just above the 498 /// outgoing arguments. 499 SlotOffset { 500 /// The offset into the slot area. 501 simm32: i32, 502 }, 503 504 /// A virtual offset to a constant that will be emitted in the constant section of the buffer. 505 ConstantOffset(VCodeConstant), 506 } 507 508 impl SyntheticAmode { 509 /// Create a real addressing mode. 510 pub fn real(amode: Amode) -> Self { 511 Self::Real(amode) 512 } 513 514 pub(crate) fn slot_offset(simm32: i32) -> Self { 515 SyntheticAmode::SlotOffset { simm32 } 516 } 517 518 /// Add the registers mentioned by `self` to `collector`. 519 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { 520 match self { 521 SyntheticAmode::Real(addr) => addr.get_operands(collector), 522 SyntheticAmode::IncomingArg { .. } => { 523 // Nothing to do; the base is known and isn't involved in regalloc. 524 } 525 SyntheticAmode::SlotOffset { .. } => { 526 // Nothing to do; the base is SP and isn't involved in regalloc. 527 } 528 SyntheticAmode::ConstantOffset(_) => {} 529 } 530 } 531 532 /// Same as `get_operands`, but add the register in the "late" phase. 533 pub(crate) fn get_operands_late(&mut self, collector: &mut impl OperandVisitor) { 534 match self { 535 SyntheticAmode::Real(addr) => addr.get_operands_late(collector), 536 SyntheticAmode::IncomingArg { .. } => { 537 // Nothing to do; the base is known and isn't involved in regalloc. 538 } 539 SyntheticAmode::SlotOffset { .. } => { 540 // Nothing to do; the base is SP and isn't involved in regalloc. 541 } 542 SyntheticAmode::ConstantOffset(_) => {} 543 } 544 } 545 546 pub(crate) fn finalize(&self, frame: &FrameLayout, buffer: &mut MachBuffer<Inst>) -> Amode { 547 match self { 548 SyntheticAmode::Real(addr) => addr.clone(), 549 SyntheticAmode::IncomingArg { offset } => { 550 // NOTE: this could be made relative to RSP by adding additional 551 // offsets from the frame_layout. 552 let args_max_fp_offset = frame.tail_args_size + frame.setup_area_size; 553 Amode::imm_reg( 554 i32::try_from(args_max_fp_offset - offset).unwrap(), 555 regs::rbp(), 556 ) 557 } 558 SyntheticAmode::SlotOffset { simm32 } => { 559 let off = *simm32 as i64 + i64::from(frame.outgoing_args_size); 560 Amode::imm_reg(off.try_into().expect("invalid sp offset"), regs::rsp()) 561 } 562 SyntheticAmode::ConstantOffset(c) => { 563 Amode::rip_relative(buffer.get_label_for_constant(*c)) 564 } 565 } 566 } 567 568 pub(crate) fn aligned(&self) -> bool { 569 match self { 570 SyntheticAmode::Real(addr) => addr.aligned(), 571 &SyntheticAmode::IncomingArg { .. } 572 | SyntheticAmode::SlotOffset { .. } 573 | SyntheticAmode::ConstantOffset { .. } => true, 574 } 575 } 576 577 /// Offset the synthetic amode by a fixed offset. 578 pub(crate) fn offset(&self, offset: i32) -> Self { 579 let mut ret = self.clone(); 580 match &mut ret { 581 SyntheticAmode::Real(amode) => *amode = amode.offset(offset), 582 SyntheticAmode::SlotOffset { simm32 } => *simm32 += offset, 583 // `amode_offset` is used only in i128.load/store which 584 // takes a synthetic amode from `to_amode`; `to_amode` can 585 // only produce Real or SlotOffset amodes, never 586 // IncomingArg or ConstantOffset. 587 _ => panic!("Cannot offset SyntheticAmode: {self:?}"), 588 } 589 ret 590 } 591 } 592 593 impl From<Amode> for SyntheticAmode { 594 fn from(amode: Amode) -> SyntheticAmode { 595 SyntheticAmode::Real(amode) 596 } 597 } 598 599 impl From<VCodeConstant> for SyntheticAmode { 600 fn from(c: VCodeConstant) -> SyntheticAmode { 601 SyntheticAmode::ConstantOffset(c) 602 } 603 } 604 605 impl PrettyPrint for SyntheticAmode { 606 fn pretty_print(&self, _size: u8) -> String { 607 match self { 608 // See note in `Amode` regarding constant size of `8`. 609 SyntheticAmode::Real(addr) => addr.pretty_print(8), 610 &SyntheticAmode::IncomingArg { offset } => { 611 format!("rbp(stack args max - {offset})") 612 } 613 SyntheticAmode::SlotOffset { simm32 } => { 614 format!("rsp({} + virtual offset)", *simm32) 615 } 616 SyntheticAmode::ConstantOffset(c) => format!("const({})", c.as_u32()), 617 } 618 } 619 } 620 621 /// An operand which is either an integer Register, a value in Memory or an Immediate. This can 622 /// denote an 8, 16, 32 or 64 bit value. For the Immediate form, in the 8- and 16-bit case, only 623 /// the lower 8 or 16 bits of `simm32` is relevant. In the 64-bit case, the value denoted by 624 /// `simm32` is its sign-extension out to 64 bits. 625 #[derive(Clone, Debug)] 626 pub enum RegMemImm { 627 /// A register operand. 628 Reg { 629 /// The underlying register. 630 reg: Reg, 631 }, 632 /// A memory operand. 633 Mem { 634 /// The memory address. 635 addr: SyntheticAmode, 636 }, 637 /// An immediate operand. 638 Imm { 639 /// The immediate value. 640 simm32: u32, 641 }, 642 } 643 644 impl RegMemImm { 645 /// Create a register operand. 646 pub fn reg(reg: Reg) -> Self { 647 debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float); 648 Self::Reg { reg } 649 } 650 651 /// Create a memory operand. 652 pub fn mem(addr: impl Into<SyntheticAmode>) -> Self { 653 Self::Mem { addr: addr.into() } 654 } 655 656 /// Create an immediate operand. 657 pub fn imm(simm32: u32) -> Self { 658 Self::Imm { simm32 } 659 } 660 661 /// Add the regs mentioned by `self` to `collector`. 662 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { 663 match self { 664 Self::Reg { reg } => collector.reg_use(reg), 665 Self::Mem { addr } => addr.get_operands(collector), 666 Self::Imm { .. } => {} 667 } 668 } 669 } 670 671 impl From<RegMem> for RegMemImm { 672 fn from(rm: RegMem) -> RegMemImm { 673 match rm { 674 RegMem::Reg { reg } => RegMemImm::Reg { reg }, 675 RegMem::Mem { addr } => RegMemImm::Mem { addr }, 676 } 677 } 678 } 679 680 impl From<Reg> for RegMemImm { 681 fn from(reg: Reg) -> Self { 682 RegMemImm::Reg { reg } 683 } 684 } 685 686 impl PrettyPrint for RegMemImm { 687 fn pretty_print(&self, size: u8) -> String { 688 match self { 689 Self::Reg { reg } => pretty_print_reg(*reg, size), 690 Self::Mem { addr } => addr.pretty_print(size), 691 Self::Imm { simm32 } => format!("${}", *simm32 as i32), 692 } 693 } 694 } 695 696 /// An operand which is either an integer Register or a value in Memory. This can denote an 8, 16, 697 /// 32, 64, or 128 bit value. 698 #[derive(Clone, Debug)] 699 pub enum RegMem { 700 /// A register operand. 701 Reg { 702 /// The underlying register. 703 reg: Reg, 704 }, 705 /// A memory operand. 706 Mem { 707 /// The memory address. 708 addr: SyntheticAmode, 709 }, 710 } 711 712 impl RegMem { 713 /// Create a register operand. 714 pub fn reg(reg: Reg) -> Self { 715 debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float); 716 Self::Reg { reg } 717 } 718 719 /// Create a memory operand. 720 pub fn mem(addr: impl Into<SyntheticAmode>) -> Self { 721 Self::Mem { addr: addr.into() } 722 } 723 /// Asserts that in register mode, the reg class is the one that's expected. 724 pub(crate) fn assert_regclass_is(&self, expected_reg_class: RegClass) { 725 if let Self::Reg { reg } = self { 726 debug_assert_eq!(reg.class(), expected_reg_class); 727 } 728 } 729 /// Add the regs mentioned by `self` to `collector`. 730 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { 731 match self { 732 RegMem::Reg { reg } => collector.reg_use(reg), 733 RegMem::Mem { addr, .. } => addr.get_operands(collector), 734 } 735 } 736 } 737 738 impl From<Reg> for RegMem { 739 fn from(reg: Reg) -> RegMem { 740 RegMem::Reg { reg } 741 } 742 } 743 744 impl From<Writable<Reg>> for RegMem { 745 fn from(r: Writable<Reg>) -> Self { 746 RegMem::reg(r.to_reg()) 747 } 748 } 749 750 impl PrettyPrint for RegMem { 751 fn pretty_print(&self, size: u8) -> String { 752 match self { 753 RegMem::Reg { reg } => pretty_print_reg(*reg, size), 754 RegMem::Mem { addr, .. } => addr.pretty_print(size), 755 } 756 } 757 } 758 759 /// This defines the ways a value can be extended: either signed- or zero-extension, or none for 760 /// types that are not extended. Contrast with [ExtMode], which defines the widths from and to which 761 /// values can be extended. 762 #[derive(Clone, PartialEq)] 763 pub enum ExtKind { 764 /// No extension. 765 None, 766 /// Sign-extend. 767 SignExtend, 768 /// Zero-extend. 769 ZeroExtend, 770 } 771 772 /// These indicate ways of extending (widening) a value, using the Intel 773 /// naming: B(yte) = u8, W(ord) = u16, L(ong)word = u32, Q(uad)word = u64 774 #[derive(Clone, PartialEq)] 775 pub enum ExtMode { 776 /// Byte -> Longword. 777 BL, 778 /// Byte -> Quadword. 779 BQ, 780 /// Word -> Longword. 781 WL, 782 /// Word -> Quadword. 783 WQ, 784 /// Longword -> Quadword. 785 LQ, 786 } 787 788 impl ExtMode { 789 /// Calculate the `ExtMode` from passed bit lengths of the from/to types. 790 pub(crate) fn new(from_bits: u16, to_bits: u16) -> Option<ExtMode> { 791 match (from_bits, to_bits) { 792 (1, 8) | (1, 16) | (1, 32) | (8, 16) | (8, 32) => Some(ExtMode::BL), 793 (1, 64) | (8, 64) => Some(ExtMode::BQ), 794 (16, 32) => Some(ExtMode::WL), 795 (16, 64) => Some(ExtMode::WQ), 796 (32, 64) => Some(ExtMode::LQ), 797 _ => None, 798 } 799 } 800 } 801 802 impl fmt::Debug for ExtMode { 803 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 804 let name = match self { 805 ExtMode::BL => "bl", 806 ExtMode::BQ => "bq", 807 ExtMode::WL => "wl", 808 ExtMode::WQ => "wq", 809 ExtMode::LQ => "lq", 810 }; 811 write!(fmt, "{name}") 812 } 813 } 814 815 impl fmt::Display for ExtMode { 816 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 817 fmt::Debug::fmt(self, f) 818 } 819 } 820 821 /// These indicate condition code tests. Not all are represented since not all are useful in 822 /// compiler-generated code. 823 #[derive(Copy, Clone, PartialEq, Eq)] 824 #[repr(u8)] 825 pub enum CC { 826 /// overflow 827 O = 0, 828 /// no overflow 829 NO = 1, 830 831 /// < unsigned 832 B = 2, 833 /// >= unsigned 834 NB = 3, 835 836 /// zero 837 Z = 4, 838 /// not-zero 839 NZ = 5, 840 841 /// <= unsigned 842 BE = 6, 843 /// > unsigned 844 NBE = 7, 845 846 /// negative 847 S = 8, 848 /// not-negative 849 NS = 9, 850 851 /// < signed 852 L = 12, 853 /// >= signed 854 NL = 13, 855 856 /// <= signed 857 LE = 14, 858 /// > signed 859 NLE = 15, 860 861 /// parity 862 P = 10, 863 864 /// not parity 865 NP = 11, 866 } 867 868 impl CC { 869 pub(crate) fn from_intcc(intcc: IntCC) -> Self { 870 match intcc { 871 IntCC::Equal => CC::Z, 872 IntCC::NotEqual => CC::NZ, 873 IntCC::SignedGreaterThanOrEqual => CC::NL, 874 IntCC::SignedGreaterThan => CC::NLE, 875 IntCC::SignedLessThanOrEqual => CC::LE, 876 IntCC::SignedLessThan => CC::L, 877 IntCC::UnsignedGreaterThanOrEqual => CC::NB, 878 IntCC::UnsignedGreaterThan => CC::NBE, 879 IntCC::UnsignedLessThanOrEqual => CC::BE, 880 IntCC::UnsignedLessThan => CC::B, 881 } 882 } 883 884 pub(crate) fn invert(&self) -> Self { 885 match self { 886 CC::O => CC::NO, 887 CC::NO => CC::O, 888 889 CC::B => CC::NB, 890 CC::NB => CC::B, 891 892 CC::Z => CC::NZ, 893 CC::NZ => CC::Z, 894 895 CC::BE => CC::NBE, 896 CC::NBE => CC::BE, 897 898 CC::S => CC::NS, 899 CC::NS => CC::S, 900 901 CC::L => CC::NL, 902 CC::NL => CC::L, 903 904 CC::LE => CC::NLE, 905 CC::NLE => CC::LE, 906 907 CC::P => CC::NP, 908 CC::NP => CC::P, 909 } 910 } 911 912 pub(crate) fn get_enc(self) -> u8 { 913 self as u8 914 } 915 } 916 917 impl fmt::Debug for CC { 918 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 919 let name = match self { 920 CC::O => "o", 921 CC::NO => "no", 922 CC::B => "b", 923 CC::NB => "nb", 924 CC::Z => "z", 925 CC::NZ => "nz", 926 CC::BE => "be", 927 CC::NBE => "nbe", 928 CC::S => "s", 929 CC::NS => "ns", 930 CC::L => "l", 931 CC::NL => "nl", 932 CC::LE => "le", 933 CC::NLE => "nle", 934 CC::P => "p", 935 CC::NP => "np", 936 }; 937 write!(fmt, "{name}") 938 } 939 } 940 941 impl fmt::Display for CC { 942 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 943 fmt::Debug::fmt(self, f) 944 } 945 } 946 947 /// Encode the ways that floats can be compared. This is used in float comparisons such as `cmpps`, 948 /// e.g.; it is distinguished from other float comparisons (e.g. `ucomiss`) in that those use EFLAGS 949 /// whereas [FcmpImm] is used as an immediate. 950 #[derive(Clone, Copy)] 951 pub enum FcmpImm { 952 /// Equal comparison. 953 Equal = 0x00, 954 /// Less than comparison. 955 LessThan = 0x01, 956 /// Less than or equal comparison. 957 LessThanOrEqual = 0x02, 958 /// Unordered. 959 Unordered = 0x03, 960 /// Not equal comparison. 961 NotEqual = 0x04, 962 /// Unordered of greater than or equal comparison. 963 UnorderedOrGreaterThanOrEqual = 0x05, 964 /// Unordered or greater than comparison. 965 UnorderedOrGreaterThan = 0x06, 966 /// Ordered. 967 Ordered = 0x07, 968 } 969 970 impl FcmpImm { 971 pub(crate) fn encode(self) -> u8 { 972 self as u8 973 } 974 } 975 976 impl From<FloatCC> for FcmpImm { 977 fn from(cond: FloatCC) -> Self { 978 match cond { 979 FloatCC::Equal => FcmpImm::Equal, 980 FloatCC::LessThan => FcmpImm::LessThan, 981 FloatCC::LessThanOrEqual => FcmpImm::LessThanOrEqual, 982 FloatCC::Unordered => FcmpImm::Unordered, 983 FloatCC::NotEqual => FcmpImm::NotEqual, 984 FloatCC::UnorderedOrGreaterThanOrEqual => FcmpImm::UnorderedOrGreaterThanOrEqual, 985 FloatCC::UnorderedOrGreaterThan => FcmpImm::UnorderedOrGreaterThan, 986 FloatCC::Ordered => FcmpImm::Ordered, 987 _ => panic!("unable to create comparison predicate for {cond}"), 988 } 989 } 990 } 991 992 /// Encode the rounding modes used as part of the Rounding Control field. 993 /// Note, these rounding immediates only consider the rounding control field 994 /// (i.e. the rounding mode) which only take up the first two bits when encoded. 995 /// However the rounding immediate which this field helps make up, also includes 996 /// bits 3 and 4 which define the rounding select and precision mask respectively. 997 /// These two bits are not defined here and are implicitly set to zero when encoded. 998 #[derive(Clone, Copy)] 999 pub enum RoundImm { 1000 /// Round to nearest mode. 1001 RoundNearest = 0x00, 1002 /// Round down mode. 1003 RoundDown = 0x01, 1004 /// Round up mode. 1005 RoundUp = 0x02, 1006 /// Round to zero mode. 1007 RoundZero = 0x03, 1008 } 1009 1010 impl RoundImm { 1011 pub(crate) fn encode(self) -> u8 { 1012 self as u8 1013 } 1014 } 1015 1016 /// An operand's size in bits. 1017 #[derive(Clone, Copy, PartialEq)] 1018 pub enum OperandSize { 1019 /// 8-bit. 1020 Size8, 1021 /// 16-bit. 1022 Size16, 1023 /// 32-bit. 1024 Size32, 1025 /// 64-bit. 1026 Size64, 1027 } 1028 1029 impl OperandSize { 1030 pub(crate) fn from_bytes(num_bytes: u32) -> Self { 1031 match num_bytes { 1032 1 => OperandSize::Size8, 1033 2 => OperandSize::Size16, 1034 4 => OperandSize::Size32, 1035 8 => OperandSize::Size64, 1036 _ => unreachable!("Invalid OperandSize: {}", num_bytes), 1037 } 1038 } 1039 1040 // Computes the OperandSize for a given type. 1041 // For vectors, the OperandSize of the lanes is returned. 1042 pub(crate) fn from_ty(ty: Type) -> Self { 1043 Self::from_bytes(ty.lane_type().bytes()) 1044 } 1045 1046 // Check that the value of self is one of the allowed sizes. 1047 pub(crate) fn is_one_of(&self, sizes: &[Self]) -> bool { 1048 sizes.iter().any(|val| *self == *val) 1049 } 1050 1051 pub(crate) fn to_bytes(&self) -> u8 { 1052 match self { 1053 Self::Size8 => 1, 1054 Self::Size16 => 2, 1055 Self::Size32 => 4, 1056 Self::Size64 => 8, 1057 } 1058 } 1059 1060 pub(crate) fn to_bits(&self) -> u8 { 1061 self.to_bytes() * 8 1062 } 1063 } 1064