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 // Define a newtype of `Reg` for XMM registers. 308 newtype_of_reg!( 309 Xmm, 310 WritableXmm, 311 OptionWritableXmm, 312 reg_mem: (XmmMem, XmmMemAligned aligned:true), 313 reg_mem_imm: (XmmMemImm, XmmMemAlignedImm aligned:true), 314 |reg| reg.class() == RegClass::Float 315 ); 316 317 // N.B.: `Amode` is defined in `inst.isle`. We add some convenience 318 // constructors here. 319 320 // Re-export the type from the ISLE generated code. 321 pub use crate::isa::x64::lower::isle::generated_code::Amode; 322 323 impl Amode { 324 /// Create an immediate sign-extended and register addressing mode. 325 pub fn imm_reg(simm32: i32, base: Reg) -> Self { 326 debug_assert!(base.class() == RegClass::Int); 327 Self::ImmReg { 328 simm32, 329 base, 330 flags: MemFlags::trusted(), 331 } 332 } 333 334 /// Create a sign-extended-32-to-64 with register and shift addressing mode. 335 pub fn imm_reg_reg_shift(simm32: i32, base: Gpr, index: Gpr, shift: u8) -> Self { 336 debug_assert!(base.class() == RegClass::Int); 337 debug_assert!(index.class() == RegClass::Int); 338 debug_assert!(shift <= 3); 339 Self::ImmRegRegShift { 340 simm32, 341 base, 342 index, 343 shift, 344 flags: MemFlags::trusted(), 345 } 346 } 347 348 pub(crate) fn rip_relative(target: MachLabel) -> Self { 349 Self::RipRelative { target } 350 } 351 352 /// Set the specified [MemFlags] to the [Amode]. 353 pub fn with_flags(&self, flags: MemFlags) -> Self { 354 match self { 355 &Self::ImmReg { simm32, base, .. } => Self::ImmReg { 356 simm32, 357 base, 358 flags, 359 }, 360 &Self::ImmRegRegShift { 361 simm32, 362 base, 363 index, 364 shift, 365 .. 366 } => Self::ImmRegRegShift { 367 simm32, 368 base, 369 index, 370 shift, 371 flags, 372 }, 373 _ => panic!("Amode {self:?} cannot take memflags"), 374 } 375 } 376 377 /// Add the registers mentioned by `self` to `collector`. 378 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { 379 match self { 380 Amode::ImmReg { base, .. } => { 381 if *base != regs::rbp() && *base != regs::rsp() { 382 collector.reg_use(base); 383 } 384 } 385 Amode::ImmRegRegShift { base, index, .. } => { 386 debug_assert_ne!(base.to_reg(), regs::rbp()); 387 debug_assert_ne!(base.to_reg(), regs::rsp()); 388 collector.reg_use(base); 389 debug_assert_ne!(index.to_reg(), regs::rbp()); 390 debug_assert_ne!(index.to_reg(), regs::rsp()); 391 collector.reg_use(index); 392 } 393 Amode::RipRelative { .. } => { 394 // RIP isn't involved in regalloc. 395 } 396 } 397 } 398 399 /// Same as `get_operands`, but add the registers in the "late" phase. 400 pub(crate) fn get_operands_late(&mut self, collector: &mut impl OperandVisitor) { 401 match self { 402 Amode::ImmReg { base, .. } => { 403 collector.reg_late_use(base); 404 } 405 Amode::ImmRegRegShift { base, index, .. } => { 406 collector.reg_late_use(base); 407 collector.reg_late_use(index); 408 } 409 Amode::RipRelative { .. } => { 410 // RIP isn't involved in regalloc. 411 } 412 } 413 } 414 415 pub(crate) fn get_flags(&self) -> MemFlags { 416 match self { 417 Amode::ImmReg { flags, .. } | Amode::ImmRegRegShift { flags, .. } => *flags, 418 Amode::RipRelative { .. } => MemFlags::trusted(), 419 } 420 } 421 422 /// Offset the amode by a fixed offset. 423 pub(crate) fn offset(&self, offset: i32) -> Self { 424 let mut ret = self.clone(); 425 match &mut ret { 426 &mut Amode::ImmReg { ref mut simm32, .. } => *simm32 += offset, 427 &mut Amode::ImmRegRegShift { ref mut simm32, .. } => *simm32 += offset, 428 _ => panic!("Cannot offset amode: {self:?}"), 429 } 430 ret 431 } 432 433 pub(crate) fn aligned(&self) -> bool { 434 self.get_flags().aligned() 435 } 436 } 437 438 impl PrettyPrint for Amode { 439 fn pretty_print(&self, _size: u8) -> String { 440 match self { 441 Amode::ImmReg { simm32, base, .. } => { 442 // Note: size is always 8; the address is 64 bits, 443 // even if the addressed operand is smaller. 444 format!("{}({})", *simm32, pretty_print_reg(*base, 8)) 445 } 446 Amode::ImmRegRegShift { 447 simm32, 448 base, 449 index, 450 shift, 451 .. 452 } => format!( 453 "{}({},{},{})", 454 *simm32, 455 pretty_print_reg(base.to_reg(), 8), 456 pretty_print_reg(index.to_reg(), 8), 457 1 << shift 458 ), 459 Amode::RipRelative { target } => format!("label{}(%rip)", target.as_u32()), 460 } 461 } 462 } 463 464 /// A Memory Address. These denote a 64-bit value only. 465 /// Used for usual addressing modes as well as addressing modes used during compilation, when the 466 /// moving SP offset is not known. 467 #[derive(Clone, Debug)] 468 pub enum SyntheticAmode { 469 /// A real amode. 470 Real(Amode), 471 472 /// A (virtual) offset into the incoming argument area. 473 IncomingArg { 474 /// The downward offset from the start of the incoming argument area. 475 offset: u32, 476 }, 477 478 /// A (virtual) offset to the slot area of the function frame, which lies just above the 479 /// outgoing arguments. 480 SlotOffset { 481 /// The offset into the slot area. 482 simm32: i32, 483 }, 484 485 /// A virtual offset to a constant that will be emitted in the constant section of the buffer. 486 ConstantOffset(VCodeConstant), 487 } 488 489 impl SyntheticAmode { 490 /// Create a real addressing mode. 491 pub fn real(amode: Amode) -> Self { 492 Self::Real(amode) 493 } 494 495 pub(crate) fn slot_offset(simm32: i32) -> Self { 496 SyntheticAmode::SlotOffset { simm32 } 497 } 498 499 /// Add the registers mentioned by `self` to `collector`. 500 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { 501 match self { 502 SyntheticAmode::Real(addr) => addr.get_operands(collector), 503 SyntheticAmode::IncomingArg { .. } => { 504 // Nothing to do; the base is known and isn't involved in regalloc. 505 } 506 SyntheticAmode::SlotOffset { .. } => { 507 // Nothing to do; the base is SP and isn't involved in regalloc. 508 } 509 SyntheticAmode::ConstantOffset(_) => {} 510 } 511 } 512 513 /// Same as `get_operands`, but add the register in the "late" phase. 514 pub(crate) fn get_operands_late(&mut self, collector: &mut impl OperandVisitor) { 515 match self { 516 SyntheticAmode::Real(addr) => addr.get_operands_late(collector), 517 SyntheticAmode::IncomingArg { .. } => { 518 // Nothing to do; the base is known and isn't involved in regalloc. 519 } 520 SyntheticAmode::SlotOffset { .. } => { 521 // Nothing to do; the base is SP and isn't involved in regalloc. 522 } 523 SyntheticAmode::ConstantOffset(_) => {} 524 } 525 } 526 527 pub(crate) fn finalize(&self, frame: &FrameLayout, buffer: &mut MachBuffer<Inst>) -> Amode { 528 match self { 529 SyntheticAmode::Real(addr) => addr.clone(), 530 SyntheticAmode::IncomingArg { offset } => { 531 // NOTE: this could be made relative to RSP by adding additional 532 // offsets from the frame_layout. 533 let args_max_fp_offset = frame.tail_args_size + frame.setup_area_size; 534 Amode::imm_reg( 535 i32::try_from(args_max_fp_offset - offset).unwrap(), 536 regs::rbp(), 537 ) 538 } 539 SyntheticAmode::SlotOffset { simm32 } => { 540 let off = *simm32 as i64 + i64::from(frame.outgoing_args_size); 541 Amode::imm_reg(off.try_into().expect("invalid sp offset"), regs::rsp()) 542 } 543 SyntheticAmode::ConstantOffset(c) => { 544 Amode::rip_relative(buffer.get_label_for_constant(*c)) 545 } 546 } 547 } 548 549 pub(crate) fn aligned(&self) -> bool { 550 match self { 551 SyntheticAmode::Real(addr) => addr.aligned(), 552 &SyntheticAmode::IncomingArg { .. } 553 | SyntheticAmode::SlotOffset { .. } 554 | SyntheticAmode::ConstantOffset { .. } => true, 555 } 556 } 557 } 558 559 impl From<Amode> for SyntheticAmode { 560 fn from(amode: Amode) -> SyntheticAmode { 561 SyntheticAmode::Real(amode) 562 } 563 } 564 565 impl From<VCodeConstant> for SyntheticAmode { 566 fn from(c: VCodeConstant) -> SyntheticAmode { 567 SyntheticAmode::ConstantOffset(c) 568 } 569 } 570 571 impl PrettyPrint for SyntheticAmode { 572 fn pretty_print(&self, _size: u8) -> String { 573 match self { 574 // See note in `Amode` regarding constant size of `8`. 575 SyntheticAmode::Real(addr) => addr.pretty_print(8), 576 &SyntheticAmode::IncomingArg { offset } => { 577 format!("rbp(stack args max - {offset})") 578 } 579 SyntheticAmode::SlotOffset { simm32 } => { 580 format!("rsp({} + virtual offset)", *simm32) 581 } 582 SyntheticAmode::ConstantOffset(c) => format!("const({})", c.as_u32()), 583 } 584 } 585 } 586 587 /// An operand which is either an integer Register, a value in Memory or an Immediate. This can 588 /// denote an 8, 16, 32 or 64 bit value. For the Immediate form, in the 8- and 16-bit case, only 589 /// the lower 8 or 16 bits of `simm32` is relevant. In the 64-bit case, the value denoted by 590 /// `simm32` is its sign-extension out to 64 bits. 591 #[derive(Clone, Debug)] 592 pub enum RegMemImm { 593 /// A register operand. 594 Reg { 595 /// The underlying register. 596 reg: Reg, 597 }, 598 /// A memory operand. 599 Mem { 600 /// The memory address. 601 addr: SyntheticAmode, 602 }, 603 /// An immediate operand. 604 Imm { 605 /// The immediate value. 606 simm32: u32, 607 }, 608 } 609 610 impl RegMemImm { 611 /// Create a register operand. 612 pub fn reg(reg: Reg) -> Self { 613 debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float); 614 Self::Reg { reg } 615 } 616 617 /// Create a memory operand. 618 pub fn mem(addr: impl Into<SyntheticAmode>) -> Self { 619 Self::Mem { addr: addr.into() } 620 } 621 622 /// Create an immediate operand. 623 pub fn imm(simm32: u32) -> Self { 624 Self::Imm { simm32 } 625 } 626 627 /// Asserts that in register mode, the reg class is the one that's expected. 628 pub(crate) fn assert_regclass_is(&self, expected_reg_class: RegClass) { 629 if let Self::Reg { reg } = self { 630 debug_assert_eq!(reg.class(), expected_reg_class); 631 } 632 } 633 634 /// Add the regs mentioned by `self` to `collector`. 635 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { 636 match self { 637 Self::Reg { reg } => collector.reg_use(reg), 638 Self::Mem { addr } => addr.get_operands(collector), 639 Self::Imm { .. } => {} 640 } 641 } 642 } 643 644 impl From<RegMem> for RegMemImm { 645 fn from(rm: RegMem) -> RegMemImm { 646 match rm { 647 RegMem::Reg { reg } => RegMemImm::Reg { reg }, 648 RegMem::Mem { addr } => RegMemImm::Mem { addr }, 649 } 650 } 651 } 652 653 impl From<Reg> for RegMemImm { 654 fn from(reg: Reg) -> Self { 655 RegMemImm::Reg { reg } 656 } 657 } 658 659 impl PrettyPrint for RegMemImm { 660 fn pretty_print(&self, size: u8) -> String { 661 match self { 662 Self::Reg { reg } => pretty_print_reg(*reg, size), 663 Self::Mem { addr } => addr.pretty_print(size), 664 Self::Imm { simm32 } => format!("${}", *simm32 as i32), 665 } 666 } 667 } 668 669 /// An operand which is either an integer Register or a value in Memory. This can denote an 8, 16, 670 /// 32, 64, or 128 bit value. 671 #[derive(Clone, Debug)] 672 pub enum RegMem { 673 /// A register operand. 674 Reg { 675 /// The underlying register. 676 reg: Reg, 677 }, 678 /// A memory operand. 679 Mem { 680 /// The memory address. 681 addr: SyntheticAmode, 682 }, 683 } 684 685 impl RegMem { 686 /// Create a register operand. 687 pub fn reg(reg: Reg) -> Self { 688 debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float); 689 Self::Reg { reg } 690 } 691 692 /// Create a memory operand. 693 pub fn mem(addr: impl Into<SyntheticAmode>) -> Self { 694 Self::Mem { addr: addr.into() } 695 } 696 /// Asserts that in register mode, the reg class is the one that's expected. 697 pub(crate) fn assert_regclass_is(&self, expected_reg_class: RegClass) { 698 if let Self::Reg { reg } = self { 699 debug_assert_eq!(reg.class(), expected_reg_class); 700 } 701 } 702 /// Add the regs mentioned by `self` to `collector`. 703 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { 704 match self { 705 RegMem::Reg { reg } => collector.reg_use(reg), 706 RegMem::Mem { addr, .. } => addr.get_operands(collector), 707 } 708 } 709 } 710 711 impl From<Reg> for RegMem { 712 fn from(reg: Reg) -> RegMem { 713 RegMem::Reg { reg } 714 } 715 } 716 717 impl From<Writable<Reg>> for RegMem { 718 fn from(r: Writable<Reg>) -> Self { 719 RegMem::reg(r.to_reg()) 720 } 721 } 722 723 impl PrettyPrint for RegMem { 724 fn pretty_print(&self, size: u8) -> String { 725 match self { 726 RegMem::Reg { reg } => pretty_print_reg(*reg, size), 727 RegMem::Mem { addr, .. } => addr.pretty_print(size), 728 } 729 } 730 } 731 732 #[derive(Clone, Copy, PartialEq)] 733 /// Comparison operations. 734 pub enum CmpOpcode { 735 /// CMP instruction: compute `a - b` and set flags from result. 736 Cmp, 737 /// TEST instruction: compute `a & b` and set flags from result. 738 Test, 739 } 740 741 #[derive(Debug)] 742 pub(crate) enum InstructionSet { 743 SSE, 744 SSE2, 745 CMPXCHG16b, 746 SSE3, 747 SSSE3, 748 SSE41, 749 SSE42, 750 Popcnt, 751 Lzcnt, 752 BMI1, 753 #[allow(dead_code)] // never constructed (yet). 754 BMI2, 755 FMA, 756 AVX, 757 AVX2, 758 AVX512BITALG, 759 AVX512DQ, 760 AVX512F, 761 AVX512VBMI, 762 AVX512VL, 763 } 764 765 /// Some SSE operations requiring 2 operands r/m and r. 766 #[derive(Clone, Copy, PartialEq)] 767 #[allow(dead_code)] // some variants here aren't used just yet 768 #[allow(missing_docs)] 769 pub enum SseOpcode { 770 Blendvpd, 771 Blendvps, 772 Insertps, 773 Pabsb, 774 Pabsw, 775 Pabsd, 776 Packssdw, 777 Packsswb, 778 Packusdw, 779 Packuswb, 780 Palignr, 781 Pavgb, 782 Pavgw, 783 Pblendvb, 784 Pcmpeqb, 785 Pcmpeqw, 786 Pcmpeqd, 787 Pcmpeqq, 788 Pcmpgtb, 789 Pcmpgtw, 790 Pcmpgtd, 791 Pcmpgtq, 792 Pmaddubsw, 793 Pmaddwd, 794 Pshufb, 795 Pshufd, 796 Ptest, 797 Rcpss, 798 Roundps, 799 Roundpd, 800 Roundss, 801 Roundsd, 802 Rsqrtss, 803 Shufps, 804 Pshuflw, 805 Pshufhw, 806 Pblendw, 807 } 808 809 impl SseOpcode { 810 /// Which `InstructionSet` is the first supporting this opcode? 811 pub(crate) fn available_from(&self) -> InstructionSet { 812 use InstructionSet::*; 813 match self { 814 SseOpcode::Rcpss | SseOpcode::Rsqrtss | SseOpcode::Shufps => SSE, 815 816 SseOpcode::Packssdw 817 | SseOpcode::Packsswb 818 | SseOpcode::Packuswb 819 | SseOpcode::Pavgb 820 | SseOpcode::Pavgw 821 | SseOpcode::Pcmpeqb 822 | SseOpcode::Pcmpeqw 823 | SseOpcode::Pcmpeqd 824 | SseOpcode::Pcmpgtb 825 | SseOpcode::Pcmpgtw 826 | SseOpcode::Pcmpgtd 827 | SseOpcode::Pmaddwd 828 | SseOpcode::Pshufd 829 | SseOpcode::Pshuflw 830 | SseOpcode::Pshufhw => SSE2, 831 832 SseOpcode::Pabsb 833 | SseOpcode::Pabsw 834 | SseOpcode::Pabsd 835 | SseOpcode::Palignr 836 | SseOpcode::Pshufb 837 | SseOpcode::Pmaddubsw => SSSE3, 838 839 SseOpcode::Blendvpd 840 | SseOpcode::Blendvps 841 | SseOpcode::Insertps 842 | SseOpcode::Packusdw 843 | SseOpcode::Pblendvb 844 | SseOpcode::Pcmpeqq 845 | SseOpcode::Ptest 846 | SseOpcode::Roundps 847 | SseOpcode::Roundpd 848 | SseOpcode::Roundss 849 | SseOpcode::Roundsd 850 | SseOpcode::Pblendw => SSE41, 851 852 SseOpcode::Pcmpgtq => SSE42, 853 } 854 } 855 856 /// Returns the src operand size for an instruction. 857 pub(crate) fn src_size(&self) -> u8 { 858 match self { 859 _ => 8, 860 } 861 } 862 863 /// Is `src2` with this opcode a scalar, as for lane insertions? 864 pub(crate) fn has_scalar_src2(self) -> bool { 865 false 866 } 867 } 868 869 impl fmt::Debug for SseOpcode { 870 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 871 let name = match self { 872 SseOpcode::Blendvpd => "blendvpd", 873 SseOpcode::Blendvps => "blendvps", 874 SseOpcode::Insertps => "insertps", 875 SseOpcode::Pabsb => "pabsb", 876 SseOpcode::Pabsw => "pabsw", 877 SseOpcode::Pabsd => "pabsd", 878 SseOpcode::Packssdw => "packssdw", 879 SseOpcode::Packsswb => "packsswb", 880 SseOpcode::Packusdw => "packusdw", 881 SseOpcode::Packuswb => "packuswb", 882 SseOpcode::Palignr => "palignr", 883 SseOpcode::Pavgb => "pavgb", 884 SseOpcode::Pavgw => "pavgw", 885 SseOpcode::Pblendvb => "pblendvb", 886 SseOpcode::Pcmpeqb => "pcmpeqb", 887 SseOpcode::Pcmpeqw => "pcmpeqw", 888 SseOpcode::Pcmpeqd => "pcmpeqd", 889 SseOpcode::Pcmpeqq => "pcmpeqq", 890 SseOpcode::Pcmpgtb => "pcmpgtb", 891 SseOpcode::Pcmpgtw => "pcmpgtw", 892 SseOpcode::Pcmpgtd => "pcmpgtd", 893 SseOpcode::Pcmpgtq => "pcmpgtq", 894 SseOpcode::Pmaddubsw => "pmaddubsw", 895 SseOpcode::Pmaddwd => "pmaddwd", 896 SseOpcode::Pshufb => "pshufb", 897 SseOpcode::Pshufd => "pshufd", 898 SseOpcode::Ptest => "ptest", 899 SseOpcode::Rcpss => "rcpss", 900 SseOpcode::Roundps => "roundps", 901 SseOpcode::Roundpd => "roundpd", 902 SseOpcode::Roundss => "roundss", 903 SseOpcode::Roundsd => "roundsd", 904 SseOpcode::Rsqrtss => "rsqrtss", 905 SseOpcode::Shufps => "shufps", 906 SseOpcode::Pshuflw => "pshuflw", 907 SseOpcode::Pshufhw => "pshufhw", 908 SseOpcode::Pblendw => "pblendw", 909 }; 910 write!(fmt, "{name}") 911 } 912 } 913 914 impl fmt::Display for SseOpcode { 915 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 916 fmt::Debug::fmt(self, f) 917 } 918 } 919 920 pub use crate::isa::x64::lower::isle::generated_code::AvxOpcode; 921 922 impl AvxOpcode { 923 /// Which `InstructionSet`s support the opcode? 924 pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> { 925 match self { 926 AvxOpcode::Vfmadd213ss 927 | AvxOpcode::Vfmadd213sd 928 | AvxOpcode::Vfmadd213ps 929 | AvxOpcode::Vfmadd213pd 930 | AvxOpcode::Vfmadd132ss 931 | AvxOpcode::Vfmadd132sd 932 | AvxOpcode::Vfmadd132ps 933 | AvxOpcode::Vfmadd132pd 934 | AvxOpcode::Vfnmadd213ss 935 | AvxOpcode::Vfnmadd213sd 936 | AvxOpcode::Vfnmadd213ps 937 | AvxOpcode::Vfnmadd213pd 938 | AvxOpcode::Vfnmadd132ss 939 | AvxOpcode::Vfnmadd132sd 940 | AvxOpcode::Vfnmadd132ps 941 | AvxOpcode::Vfnmadd132pd 942 | AvxOpcode::Vfmsub213ss 943 | AvxOpcode::Vfmsub213sd 944 | AvxOpcode::Vfmsub213ps 945 | AvxOpcode::Vfmsub213pd 946 | AvxOpcode::Vfmsub132ss 947 | AvxOpcode::Vfmsub132sd 948 | AvxOpcode::Vfmsub132ps 949 | AvxOpcode::Vfmsub132pd 950 | AvxOpcode::Vfnmsub213ss 951 | AvxOpcode::Vfnmsub213sd 952 | AvxOpcode::Vfnmsub213ps 953 | AvxOpcode::Vfnmsub213pd 954 | AvxOpcode::Vfnmsub132ss 955 | AvxOpcode::Vfnmsub132sd 956 | AvxOpcode::Vfnmsub132ps 957 | AvxOpcode::Vfnmsub132pd => smallvec![InstructionSet::FMA], 958 AvxOpcode::Vminps 959 | AvxOpcode::Vminpd 960 | AvxOpcode::Vmaxps 961 | AvxOpcode::Vmaxpd 962 | AvxOpcode::Vandnps 963 | AvxOpcode::Vandnpd 964 | AvxOpcode::Vpandn 965 | AvxOpcode::Vcmpps 966 | AvxOpcode::Vcmppd 967 | AvxOpcode::Vpsrlw 968 | AvxOpcode::Vpsrld 969 | AvxOpcode::Vpsrlq 970 | AvxOpcode::Vpaddb 971 | AvxOpcode::Vpaddw 972 | AvxOpcode::Vpaddd 973 | AvxOpcode::Vpaddq 974 | AvxOpcode::Vpaddsb 975 | AvxOpcode::Vpaddsw 976 | AvxOpcode::Vpaddusb 977 | AvxOpcode::Vpaddusw 978 | AvxOpcode::Vpsubb 979 | AvxOpcode::Vpsubw 980 | AvxOpcode::Vpsubd 981 | AvxOpcode::Vpsubq 982 | AvxOpcode::Vpsubsb 983 | AvxOpcode::Vpsubsw 984 | AvxOpcode::Vpsubusb 985 | AvxOpcode::Vpsubusw 986 | AvxOpcode::Vpavgb 987 | AvxOpcode::Vpavgw 988 | AvxOpcode::Vpand 989 | AvxOpcode::Vandps 990 | AvxOpcode::Vandpd 991 | AvxOpcode::Vpor 992 | AvxOpcode::Vorps 993 | AvxOpcode::Vorpd 994 | AvxOpcode::Vpxor 995 | AvxOpcode::Vxorps 996 | AvxOpcode::Vxorpd 997 | AvxOpcode::Vpmullw 998 | AvxOpcode::Vpmulld 999 | AvxOpcode::Vpmulhw 1000 | AvxOpcode::Vpmulhd 1001 | AvxOpcode::Vpmulhrsw 1002 | AvxOpcode::Vpmulhuw 1003 | AvxOpcode::Vpmuldq 1004 | AvxOpcode::Vpmuludq 1005 | AvxOpcode::Vpunpckhwd 1006 | AvxOpcode::Vpunpcklwd 1007 | AvxOpcode::Vunpcklps 1008 | AvxOpcode::Vunpckhps 1009 | AvxOpcode::Vaddps 1010 | AvxOpcode::Vaddpd 1011 | AvxOpcode::Vsubps 1012 | AvxOpcode::Vsubpd 1013 | AvxOpcode::Vmulps 1014 | AvxOpcode::Vmulpd 1015 | AvxOpcode::Vdivps 1016 | AvxOpcode::Vdivpd 1017 | AvxOpcode::Vpcmpeqb 1018 | AvxOpcode::Vpcmpeqw 1019 | AvxOpcode::Vpcmpeqd 1020 | AvxOpcode::Vpcmpeqq 1021 | AvxOpcode::Vpcmpgtb 1022 | AvxOpcode::Vpcmpgtw 1023 | AvxOpcode::Vpcmpgtd 1024 | AvxOpcode::Vpcmpgtq 1025 | AvxOpcode::Vpminsb 1026 | AvxOpcode::Vpminsw 1027 | AvxOpcode::Vpminsd 1028 | AvxOpcode::Vpminub 1029 | AvxOpcode::Vpminuw 1030 | AvxOpcode::Vpminud 1031 | AvxOpcode::Vpmaxsb 1032 | AvxOpcode::Vpmaxsw 1033 | AvxOpcode::Vpmaxsd 1034 | AvxOpcode::Vpmaxub 1035 | AvxOpcode::Vpmaxuw 1036 | AvxOpcode::Vpmaxud 1037 | AvxOpcode::Vpunpcklbw 1038 | AvxOpcode::Vpunpckhbw 1039 | AvxOpcode::Vpacksswb 1040 | AvxOpcode::Vpackssdw 1041 | AvxOpcode::Vpackuswb 1042 | AvxOpcode::Vpackusdw 1043 | AvxOpcode::Vpalignr 1044 | AvxOpcode::Vpmaddwd 1045 | AvxOpcode::Vpmaddubsw 1046 | AvxOpcode::Vinsertps 1047 | AvxOpcode::Vpshufb 1048 | AvxOpcode::Vshufps 1049 | AvxOpcode::Vpsllw 1050 | AvxOpcode::Vpslld 1051 | AvxOpcode::Vpsllq 1052 | AvxOpcode::Vpsraw 1053 | AvxOpcode::Vpsrad 1054 | AvxOpcode::Vpmovsxbw 1055 | AvxOpcode::Vpmovzxbw 1056 | AvxOpcode::Vpmovsxwd 1057 | AvxOpcode::Vpmovzxwd 1058 | AvxOpcode::Vpmovsxdq 1059 | AvxOpcode::Vpmovzxdq 1060 | AvxOpcode::Vaddss 1061 | AvxOpcode::Vaddsd 1062 | AvxOpcode::Vmulss 1063 | AvxOpcode::Vmulsd 1064 | AvxOpcode::Vsubss 1065 | AvxOpcode::Vsubsd 1066 | AvxOpcode::Vdivss 1067 | AvxOpcode::Vdivsd 1068 | AvxOpcode::Vpabsb 1069 | AvxOpcode::Vpabsw 1070 | AvxOpcode::Vpabsd 1071 | AvxOpcode::Vminss 1072 | AvxOpcode::Vminsd 1073 | AvxOpcode::Vmaxss 1074 | AvxOpcode::Vmaxsd 1075 | AvxOpcode::Vsqrtps 1076 | AvxOpcode::Vsqrtpd 1077 | AvxOpcode::Vphaddw 1078 | AvxOpcode::Vphaddd 1079 | AvxOpcode::Vpunpckldq 1080 | AvxOpcode::Vpunpckhdq 1081 | AvxOpcode::Vpunpcklqdq 1082 | AvxOpcode::Vpunpckhqdq 1083 | AvxOpcode::Vmovss 1084 | AvxOpcode::Vmovsd 1085 | AvxOpcode::Vmovups 1086 | AvxOpcode::Vmovupd 1087 | AvxOpcode::Vmovdqu 1088 | AvxOpcode::Vpextrb 1089 | AvxOpcode::Vpextrw 1090 | AvxOpcode::Vpextrd 1091 | AvxOpcode::Vpextrq 1092 | AvxOpcode::Vpblendw 1093 | AvxOpcode::Vbroadcastss 1094 | AvxOpcode::Vsqrtss 1095 | AvxOpcode::Vsqrtsd 1096 | AvxOpcode::Vunpcklpd 1097 | AvxOpcode::Vptest 1098 | AvxOpcode::Vucomiss 1099 | AvxOpcode::Vucomisd => { 1100 smallvec![InstructionSet::AVX] 1101 } 1102 1103 AvxOpcode::Vpbroadcastb | AvxOpcode::Vpbroadcastw | AvxOpcode::Vpbroadcastd => { 1104 smallvec![InstructionSet::AVX2] 1105 } 1106 } 1107 } 1108 1109 /// Is the opcode known to be commutative? 1110 /// 1111 /// Note that this method is not exhaustive, and there may be commutative 1112 /// opcodes that we don't recognize as commutative. 1113 pub(crate) fn is_commutative(&self) -> bool { 1114 match *self { 1115 AvxOpcode::Vpaddb 1116 | AvxOpcode::Vpaddw 1117 | AvxOpcode::Vpaddd 1118 | AvxOpcode::Vpaddq 1119 | AvxOpcode::Vpaddsb 1120 | AvxOpcode::Vpaddsw 1121 | AvxOpcode::Vpaddusb 1122 | AvxOpcode::Vpaddusw 1123 | AvxOpcode::Vpand 1124 | AvxOpcode::Vandps 1125 | AvxOpcode::Vandpd 1126 | AvxOpcode::Vpor 1127 | AvxOpcode::Vorps 1128 | AvxOpcode::Vorpd 1129 | AvxOpcode::Vpxor 1130 | AvxOpcode::Vxorps 1131 | AvxOpcode::Vxorpd 1132 | AvxOpcode::Vpmuldq 1133 | AvxOpcode::Vpmuludq 1134 | AvxOpcode::Vaddps 1135 | AvxOpcode::Vaddpd 1136 | AvxOpcode::Vmulps 1137 | AvxOpcode::Vmulpd 1138 | AvxOpcode::Vpcmpeqb 1139 | AvxOpcode::Vpcmpeqw 1140 | AvxOpcode::Vpcmpeqd 1141 | AvxOpcode::Vpcmpeqq 1142 | AvxOpcode::Vaddss 1143 | AvxOpcode::Vaddsd 1144 | AvxOpcode::Vmulss 1145 | AvxOpcode::Vmulsd => true, 1146 _ => false, 1147 } 1148 } 1149 } 1150 1151 impl fmt::Display for AvxOpcode { 1152 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1153 format!("{self:?}").to_lowercase().fmt(f) 1154 } 1155 } 1156 1157 #[derive(Copy, Clone, PartialEq)] 1158 #[allow(missing_docs)] 1159 pub enum Avx512TupleType { 1160 Full, 1161 FullMem, 1162 Mem128, 1163 } 1164 1165 pub use crate::isa::x64::lower::isle::generated_code::Avx512Opcode; 1166 1167 impl Avx512Opcode { 1168 /// Which `InstructionSet`s support the opcode? 1169 pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> { 1170 match self { 1171 Avx512Opcode::Vcvtudq2ps 1172 | Avx512Opcode::Vpabsq 1173 | Avx512Opcode::Vpsraq 1174 | Avx512Opcode::VpsraqImm => { 1175 smallvec![InstructionSet::AVX512F, InstructionSet::AVX512VL] 1176 } 1177 Avx512Opcode::Vpermi2b => { 1178 smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512VBMI] 1179 } 1180 Avx512Opcode::Vpmullq => smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512DQ], 1181 Avx512Opcode::Vpopcntb => { 1182 smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512BITALG] 1183 } 1184 } 1185 } 1186 1187 /// What is the "TupleType" of this opcode, which affects the scaling factor 1188 /// for 8-bit displacements when this instruction uses memory operands. 1189 /// 1190 /// This can be found in the encoding table for each instruction and is 1191 /// interpreted according to Table 2-34 and 2-35 in the Intel instruction 1192 /// manual. 1193 pub fn tuple_type(&self) -> Avx512TupleType { 1194 use Avx512Opcode::*; 1195 use Avx512TupleType::*; 1196 1197 match self { 1198 Vcvtudq2ps | Vpabsq | Vpmullq | VpsraqImm => Full, 1199 Vpermi2b | Vpopcntb => FullMem, 1200 Vpsraq => Mem128, 1201 } 1202 } 1203 } 1204 1205 impl fmt::Display for Avx512Opcode { 1206 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1207 let s = format!("{self:?}"); 1208 f.write_str(&s.to_lowercase()) 1209 } 1210 } 1211 1212 /// This defines the ways a value can be extended: either signed- or zero-extension, or none for 1213 /// types that are not extended. Contrast with [ExtMode], which defines the widths from and to which 1214 /// values can be extended. 1215 #[allow(dead_code)] 1216 #[derive(Clone, PartialEq)] 1217 pub enum ExtKind { 1218 /// No extension. 1219 None, 1220 /// Sign-extend. 1221 SignExtend, 1222 /// Zero-extend. 1223 ZeroExtend, 1224 } 1225 1226 /// These indicate ways of extending (widening) a value, using the Intel 1227 /// naming: B(yte) = u8, W(ord) = u16, L(ong)word = u32, Q(uad)word = u64 1228 #[derive(Clone, PartialEq)] 1229 pub enum ExtMode { 1230 /// Byte -> Longword. 1231 BL, 1232 /// Byte -> Quadword. 1233 BQ, 1234 /// Word -> Longword. 1235 WL, 1236 /// Word -> Quadword. 1237 WQ, 1238 /// Longword -> Quadword. 1239 LQ, 1240 } 1241 1242 impl ExtMode { 1243 /// Calculate the `ExtMode` from passed bit lengths of the from/to types. 1244 pub(crate) fn new(from_bits: u16, to_bits: u16) -> Option<ExtMode> { 1245 match (from_bits, to_bits) { 1246 (1, 8) | (1, 16) | (1, 32) | (8, 16) | (8, 32) => Some(ExtMode::BL), 1247 (1, 64) | (8, 64) => Some(ExtMode::BQ), 1248 (16, 32) => Some(ExtMode::WL), 1249 (16, 64) => Some(ExtMode::WQ), 1250 (32, 64) => Some(ExtMode::LQ), 1251 _ => None, 1252 } 1253 } 1254 } 1255 1256 impl fmt::Debug for ExtMode { 1257 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 1258 let name = match self { 1259 ExtMode::BL => "bl", 1260 ExtMode::BQ => "bq", 1261 ExtMode::WL => "wl", 1262 ExtMode::WQ => "wq", 1263 ExtMode::LQ => "lq", 1264 }; 1265 write!(fmt, "{name}") 1266 } 1267 } 1268 1269 impl fmt::Display for ExtMode { 1270 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1271 fmt::Debug::fmt(self, f) 1272 } 1273 } 1274 1275 /// These indicate condition code tests. Not all are represented since not all are useful in 1276 /// compiler-generated code. 1277 #[derive(Copy, Clone, PartialEq, Eq)] 1278 #[repr(u8)] 1279 pub enum CC { 1280 /// overflow 1281 O = 0, 1282 /// no overflow 1283 NO = 1, 1284 1285 /// < unsigned 1286 B = 2, 1287 /// >= unsigned 1288 NB = 3, 1289 1290 /// zero 1291 Z = 4, 1292 /// not-zero 1293 NZ = 5, 1294 1295 /// <= unsigned 1296 BE = 6, 1297 /// > unsigned 1298 NBE = 7, 1299 1300 /// negative 1301 S = 8, 1302 /// not-negative 1303 NS = 9, 1304 1305 /// < signed 1306 L = 12, 1307 /// >= signed 1308 NL = 13, 1309 1310 /// <= signed 1311 LE = 14, 1312 /// > signed 1313 NLE = 15, 1314 1315 /// parity 1316 P = 10, 1317 1318 /// not parity 1319 NP = 11, 1320 } 1321 1322 impl CC { 1323 pub(crate) fn from_intcc(intcc: IntCC) -> Self { 1324 match intcc { 1325 IntCC::Equal => CC::Z, 1326 IntCC::NotEqual => CC::NZ, 1327 IntCC::SignedGreaterThanOrEqual => CC::NL, 1328 IntCC::SignedGreaterThan => CC::NLE, 1329 IntCC::SignedLessThanOrEqual => CC::LE, 1330 IntCC::SignedLessThan => CC::L, 1331 IntCC::UnsignedGreaterThanOrEqual => CC::NB, 1332 IntCC::UnsignedGreaterThan => CC::NBE, 1333 IntCC::UnsignedLessThanOrEqual => CC::BE, 1334 IntCC::UnsignedLessThan => CC::B, 1335 } 1336 } 1337 1338 pub(crate) fn invert(&self) -> Self { 1339 match self { 1340 CC::O => CC::NO, 1341 CC::NO => CC::O, 1342 1343 CC::B => CC::NB, 1344 CC::NB => CC::B, 1345 1346 CC::Z => CC::NZ, 1347 CC::NZ => CC::Z, 1348 1349 CC::BE => CC::NBE, 1350 CC::NBE => CC::BE, 1351 1352 CC::S => CC::NS, 1353 CC::NS => CC::S, 1354 1355 CC::L => CC::NL, 1356 CC::NL => CC::L, 1357 1358 CC::LE => CC::NLE, 1359 CC::NLE => CC::LE, 1360 1361 CC::P => CC::NP, 1362 CC::NP => CC::P, 1363 } 1364 } 1365 1366 pub(crate) fn get_enc(self) -> u8 { 1367 self as u8 1368 } 1369 } 1370 1371 impl fmt::Debug for CC { 1372 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 1373 let name = match self { 1374 CC::O => "o", 1375 CC::NO => "no", 1376 CC::B => "b", 1377 CC::NB => "nb", 1378 CC::Z => "z", 1379 CC::NZ => "nz", 1380 CC::BE => "be", 1381 CC::NBE => "nbe", 1382 CC::S => "s", 1383 CC::NS => "ns", 1384 CC::L => "l", 1385 CC::NL => "nl", 1386 CC::LE => "le", 1387 CC::NLE => "nle", 1388 CC::P => "p", 1389 CC::NP => "np", 1390 }; 1391 write!(fmt, "{name}") 1392 } 1393 } 1394 1395 impl fmt::Display for CC { 1396 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1397 fmt::Debug::fmt(self, f) 1398 } 1399 } 1400 1401 /// Encode the ways that floats can be compared. This is used in float comparisons such as `cmpps`, 1402 /// e.g.; it is distinguished from other float comparisons (e.g. `ucomiss`) in that those use EFLAGS 1403 /// whereas [FcmpImm] is used as an immediate. 1404 #[derive(Clone, Copy)] 1405 pub enum FcmpImm { 1406 /// Equal comparison. 1407 Equal = 0x00, 1408 /// Less than comparison. 1409 LessThan = 0x01, 1410 /// Less than or equal comparison. 1411 LessThanOrEqual = 0x02, 1412 /// Unordered. 1413 Unordered = 0x03, 1414 /// Not equal comparison. 1415 NotEqual = 0x04, 1416 /// Unordered of greater than or equal comparison. 1417 UnorderedOrGreaterThanOrEqual = 0x05, 1418 /// Unordered or greater than comparison. 1419 UnorderedOrGreaterThan = 0x06, 1420 /// Ordered. 1421 Ordered = 0x07, 1422 } 1423 1424 impl FcmpImm { 1425 pub(crate) fn encode(self) -> u8 { 1426 self as u8 1427 } 1428 } 1429 1430 impl From<FloatCC> for FcmpImm { 1431 fn from(cond: FloatCC) -> Self { 1432 match cond { 1433 FloatCC::Equal => FcmpImm::Equal, 1434 FloatCC::LessThan => FcmpImm::LessThan, 1435 FloatCC::LessThanOrEqual => FcmpImm::LessThanOrEqual, 1436 FloatCC::Unordered => FcmpImm::Unordered, 1437 FloatCC::NotEqual => FcmpImm::NotEqual, 1438 FloatCC::UnorderedOrGreaterThanOrEqual => FcmpImm::UnorderedOrGreaterThanOrEqual, 1439 FloatCC::UnorderedOrGreaterThan => FcmpImm::UnorderedOrGreaterThan, 1440 FloatCC::Ordered => FcmpImm::Ordered, 1441 _ => panic!("unable to create comparison predicate for {cond}"), 1442 } 1443 } 1444 } 1445 1446 /// Encode the rounding modes used as part of the Rounding Control field. 1447 /// Note, these rounding immediates only consider the rounding control field 1448 /// (i.e. the rounding mode) which only take up the first two bits when encoded. 1449 /// However the rounding immediate which this field helps make up, also includes 1450 /// bits 3 and 4 which define the rounding select and precision mask respectively. 1451 /// These two bits are not defined here and are implicitly set to zero when encoded. 1452 #[derive(Clone, Copy)] 1453 pub enum RoundImm { 1454 /// Round to nearest mode. 1455 RoundNearest = 0x00, 1456 /// Round down mode. 1457 RoundDown = 0x01, 1458 /// Round up mode. 1459 RoundUp = 0x02, 1460 /// Round to zero mode. 1461 RoundZero = 0x03, 1462 } 1463 1464 impl RoundImm { 1465 pub(crate) fn encode(self) -> u8 { 1466 self as u8 1467 } 1468 } 1469 1470 /// An operand's size in bits. 1471 #[derive(Clone, Copy, PartialEq)] 1472 pub enum OperandSize { 1473 /// 8-bit. 1474 Size8, 1475 /// 16-bit. 1476 Size16, 1477 /// 32-bit. 1478 Size32, 1479 /// 64-bit. 1480 Size64, 1481 } 1482 1483 impl OperandSize { 1484 pub(crate) fn from_bytes(num_bytes: u32) -> Self { 1485 match num_bytes { 1486 1 => OperandSize::Size8, 1487 2 => OperandSize::Size16, 1488 4 => OperandSize::Size32, 1489 8 => OperandSize::Size64, 1490 _ => unreachable!("Invalid OperandSize: {}", num_bytes), 1491 } 1492 } 1493 1494 // Computes the OperandSize for a given type. 1495 // For vectors, the OperandSize of the lanes is returned. 1496 pub(crate) fn from_ty(ty: Type) -> Self { 1497 Self::from_bytes(ty.lane_type().bytes()) 1498 } 1499 1500 // Check that the value of self is one of the allowed sizes. 1501 pub(crate) fn is_one_of(&self, sizes: &[Self]) -> bool { 1502 sizes.iter().any(|val| *self == *val) 1503 } 1504 1505 pub(crate) fn to_bytes(&self) -> u8 { 1506 match self { 1507 Self::Size8 => 1, 1508 Self::Size16 => 2, 1509 Self::Size32 => 4, 1510 Self::Size64 => 8, 1511 } 1512 } 1513 1514 pub(crate) fn to_bits(&self) -> u8 { 1515 self.to_bytes() * 8 1516 } 1517 1518 pub(crate) fn to_type(&self) -> Type { 1519 match self { 1520 Self::Size8 => I8, 1521 Self::Size16 => I16, 1522 Self::Size32 => I32, 1523 Self::Size64 => I64, 1524 } 1525 } 1526 } 1527