1use super::regs::{self};
4use crate::ir::MemFlagsData;
5use crate::ir::condcodes::{FloatCC, IntCC};
6use crate::ir::types::*;
7use crate::isa::x64::inst::Inst;
8use crate::isa::x64::inst::regs::pretty_print_reg;
9use crate::machinst::*;
10use alloc::string::String;
11use core::fmt;
12
13pub trait ToWritableReg {
15 fn to_writable_reg(&self) -> Writable<Reg>;
17}
18
19pub trait FromWritableReg: Sized {
21 fn from_writable_reg(w: Writable<Reg>) -> Option<Self>;
23}
24
25macro_rules! newtype_of_reg {
36 (
37 $newtype_reg:ident,
38 $newtype_writable_reg:ident,
39 $newtype_option_writable_reg:ident,
40 reg_mem: ($($newtype_reg_mem:ident
41 $(size:$size:literal)?
42 $(aligned:$aligned:ident)?),*),
43 reg_mem_imm: ($($newtype_reg_mem_imm:ident
44 $(size:$size_imm:literal)?
45 $(aligned:$aligned_imm:ident)?),*),
46 |$check_reg:ident| $check:expr
47 ) => {
48 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
50 pub struct $newtype_reg(Reg);
51
52 impl PartialEq<Reg> for $newtype_reg {
53 fn eq(&self, other: &Reg) -> bool {
54 self.0 == *other
55 }
56 }
57
58 impl From<$newtype_reg> for Reg {
59 fn from(r: $newtype_reg) -> Self {
60 r.0
61 }
62 }
63
64 impl $newtype_reg {
65 pub fn new($check_reg: Reg) -> Option<Self> {
68 if $check {
69 Some(Self($check_reg))
70 } else {
71 None
72 }
73 }
74
75 pub fn unwrap_new($check_reg: Reg) -> Self {
78 if $check {
79 Self($check_reg)
80 } else {
81 panic!(
82 "cannot construct {} from register {:?} with register class {:?}",
83 stringify!($newtype_reg),
84 $check_reg,
85 $check_reg.class(),
86 )
87 }
88 }
89
90 pub fn to_reg(self) -> Reg {
92 self.0
93 }
94 }
95
96 impl core::ops::Deref for $newtype_reg {
103 type Target = Reg;
104
105 fn deref(&self) -> &Reg {
106 &self.0
107 }
108 }
109
110 impl AsMut<Reg> for $newtype_reg {
114 fn as_mut(&mut self) -> &mut Reg {
115 &mut self.0
116 }
117 }
118
119 pub type $newtype_writable_reg = Writable<$newtype_reg>;
121
122 #[allow(dead_code, reason = "Used by some newtypes and not others")]
123 pub type $newtype_option_writable_reg = Option<Writable<$newtype_reg>>;
125
126 impl ToWritableReg for $newtype_writable_reg {
127 fn to_writable_reg(&self) -> Writable<Reg> {
128 Writable::from_reg(self.to_reg().to_reg())
129 }
130 }
131
132 impl FromWritableReg for $newtype_writable_reg {
133 fn from_writable_reg(w: Writable<Reg>) -> Option<Self> {
134 Some(Writable::from_reg($newtype_reg::new(w.to_reg())?))
135 }
136 }
137
138 $(
139 #[derive(Clone, Debug)]
141 pub struct $newtype_reg_mem(RegMem);
142
143 impl From<$newtype_reg_mem> for RegMem {
144 fn from(rm: $newtype_reg_mem) -> Self {
145 rm.0
146 }
147 }
148 impl<'a> From<&'a $newtype_reg_mem> for &'a RegMem {
149 fn from(rm: &'a $newtype_reg_mem) -> &'a RegMem {
150 &rm.0
151 }
152 }
153
154 impl From<$newtype_reg> for $newtype_reg_mem {
155 fn from(r: $newtype_reg) -> Self {
156 $newtype_reg_mem(RegMem::reg(r.into()))
157 }
158 }
159
160 impl $newtype_reg_mem {
161 $(
162 pub const SIZE_BITS: u32 = $size;
166 )?
167
168 pub fn new(rm: RegMem) -> Option<Self> {
172 match rm {
173 RegMem::Mem { addr } => {
174 let mut _allow = true;
175 $(
176 if $aligned {
177 _allow = addr.aligned();
178 }
179 )?
180 if _allow {
181 Some(Self(RegMem::Mem { addr }))
182 } else {
183 None
184 }
185 }
186 RegMem::Reg { reg } => Some($newtype_reg::new(reg)?.into()),
187 }
188 }
189
190 pub fn unwrap_new(rm: RegMem) -> Self {
193 match rm {
194 RegMem::Mem { addr } => {
195 $(
196 if $aligned && !addr.aligned() {
197 panic!(
198 "cannot create {} from an unaligned memory address: {addr:?}",
199 stringify!($newtype_reg_mem),
200 );
201 }
202 )?
203 Self(RegMem::Mem { addr })
204 }
205 RegMem::Reg { reg } => $newtype_reg::unwrap_new(reg).into(),
206 }
207 }
208
209 pub fn to_reg_mem(self) -> RegMem {
211 self.0
212 }
213
214 #[allow(dead_code, reason = "Used by some newtypes and not others")]
215 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
216 self.0.get_operands(collector);
217 }
218 }
219 impl PrettyPrint for $newtype_reg_mem {
220 fn pretty_print(&self, size: u8) -> String {
221 self.0.pretty_print(size)
222 }
223 }
224 )*
225
226 $(
227 #[derive(Clone, Debug)]
229 pub struct $newtype_reg_mem_imm(RegMemImm);
230
231 impl From<$newtype_reg_mem_imm> for RegMemImm {
232 fn from(rmi: $newtype_reg_mem_imm) -> RegMemImm {
233 rmi.0
234 }
235 }
236 impl<'a> From<&'a $newtype_reg_mem_imm> for &'a RegMemImm {
237 fn from(rmi: &'a $newtype_reg_mem_imm) -> &'a RegMemImm {
238 &rmi.0
239 }
240 }
241
242 impl From<$newtype_reg> for $newtype_reg_mem_imm {
243 fn from(r: $newtype_reg) -> Self {
244 $newtype_reg_mem_imm(RegMemImm::reg(r.into()))
245 }
246 }
247
248 impl $newtype_reg_mem_imm {
249 $(
250 pub const SIZE_BITS: u32 = $size_imm;
254 )?
255
256 pub fn new(rmi: RegMemImm) -> Option<Self> {
260 match rmi {
261 RegMemImm::Imm { .. } => Some(Self(rmi)),
262 RegMemImm::Mem { addr } => {
263 let mut _allow = true;
264 $(
265 if $aligned_imm {
266 _allow = addr.aligned();
267 }
268 )?
269 if _allow {
270 Some(Self(RegMemImm::Mem { addr }))
271 } else {
272 None
273 }
274 }
275 RegMemImm::Reg { reg } => Some($newtype_reg::new(reg)?.into()),
276 }
277 }
278
279 pub fn unwrap_new(rmi: RegMemImm) -> Self {
282 match rmi {
283 RegMemImm::Imm { .. } => Self(rmi),
284 RegMemImm::Mem { addr } => {
285 $(
286 if $aligned_imm && !addr.aligned() {
287 panic!(
288 "cannot construct {} from unaligned memory address: {:?}",
289 stringify!($newtype_reg_mem_imm),
290 addr,
291 );
292 }
293 )?
294 Self(RegMemImm::Mem { addr })
295
296 }
297 RegMemImm::Reg { reg } => $newtype_reg::unwrap_new(reg).into(),
298 }
299 }
300
301 #[allow(dead_code, reason = "Used by some newtypes and not others")]
303 pub fn to_reg_mem_imm(self) -> RegMemImm {
304 self.0
305 }
306
307 #[allow(dead_code, reason = "Used by some newtypes and not others")]
308 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
309 self.0.get_operands(collector);
310 }
311 }
312
313 impl PrettyPrint for $newtype_reg_mem_imm {
314 fn pretty_print(&self, size: u8) -> String {
315 self.0.pretty_print(size)
316 }
317 }
318 )*
319 };
320}
321
322newtype_of_reg!(
328 Gpr,
329 WritableGpr,
330 OptionWritableGpr,
331 reg_mem: (GprMem,
332 GprMem8 size:8,
333 GprMem16 size:16,
334 GprMem32 size:32,
335 GprMem64 size:64),
336 reg_mem_imm: (GprMemImm,
337 GprMemImm8 size:8,
338 GprMemImm16 size:16,
339 GprMemImm32 size:32,
340 GprMemImm64 size:64),
341 |reg| reg.class() == RegClass::Int
342);
343
344#[expect(missing_docs, reason = "self-describing fields")]
345impl Gpr {
346 pub const RAX: Gpr = Gpr(regs::rax());
347 pub const RBX: Gpr = Gpr(regs::rbx());
348 pub const RCX: Gpr = Gpr(regs::rcx());
349 pub const RDX: Gpr = Gpr(regs::rdx());
350 pub const RSI: Gpr = Gpr(regs::rsi());
351 pub const RDI: Gpr = Gpr(regs::rdi());
352 pub const RSP: Gpr = Gpr(regs::rsp());
353 pub const RBP: Gpr = Gpr(regs::rbp());
354 pub const R8: Gpr = Gpr(regs::r8());
355 pub const R9: Gpr = Gpr(regs::r9());
356 pub const R10: Gpr = Gpr(regs::r10());
357 pub const R11: Gpr = Gpr(regs::r11());
358 pub const R12: Gpr = Gpr(regs::r12());
359 pub const R13: Gpr = Gpr(regs::r13());
360 pub const R14: Gpr = Gpr(regs::r14());
361 pub const R15: Gpr = Gpr(regs::r15());
362}
363
364newtype_of_reg!(
370 Xmm,
371 WritableXmm,
372 OptionWritableXmm,
373 reg_mem: (XmmMem,
374 XmmMem8 size:8,
375 XmmMem16 size:16,
376 XmmMem32 size:32,
377 XmmMem64 size:64,
378 XmmMem128 size:128,
379 XmmMemAligned aligned:true,
380 XmmMemAligned8 size:8 aligned:true,
381 XmmMemAligned16 size:16 aligned:true,
382 XmmMemAligned32 size:32 aligned:true,
383 XmmMemAligned64 size:64 aligned:true,
384 XmmMemAligned128 size:128 aligned:true),
385 reg_mem_imm: (XmmMemImm,
386 XmmMemImm8 size:8,
387 XmmMemImm16 size:16,
388 XmmMemImm32 size:32,
389 XmmMemImm64 size:64,
390 XmmMemImm128 size:128,
391 XmmMemAlignedImm aligned:true,
392 XmmMemAlignedImm8 size:8 aligned:true,
393 XmmMemAlignedImm16 size:16 aligned:true,
394 XmmMemAlignedImm32 size:32 aligned:true,
395 XmmMemAlignedImm64 size:64 aligned:true,
396 XmmMemAlignedImm128 size:128 aligned:true),
397 |reg| reg.class() == RegClass::Float
398);
399
400pub use crate::isa::x64::lower::isle::generated_code::Amode;
405
406impl Amode {
407 pub fn imm_reg(simm32: i32, base: Reg) -> Self {
409 debug_assert!(base.class() == RegClass::Int);
410 Self::ImmReg {
411 simm32,
412 base,
413 flags: MemFlagsData::trusted(),
414 }
415 }
416
417 pub fn imm_reg_reg_shift(simm32: i32, base: Gpr, index: Gpr, shift: u8) -> Self {
419 debug_assert!(base.class() == RegClass::Int);
420 debug_assert!(index.class() == RegClass::Int);
421 debug_assert!(shift <= 3);
422 Self::ImmRegRegShift {
423 simm32,
424 base,
425 index,
426 shift,
427 flags: MemFlagsData::trusted(),
428 }
429 }
430
431 pub(crate) fn rip_relative(target: MachLabel) -> Self {
432 Self::RipRelative { target }
433 }
434
435 pub fn with_flags(&self, flags: MemFlagsData) -> Self {
437 match self {
438 &Self::ImmReg { simm32, base, .. } => Self::ImmReg {
439 simm32,
440 base,
441 flags,
442 },
443 &Self::ImmRegRegShift {
444 simm32,
445 base,
446 index,
447 shift,
448 ..
449 } => Self::ImmRegRegShift {
450 simm32,
451 base,
452 index,
453 shift,
454 flags,
455 },
456 _ => panic!("Amode {self:?} cannot take memflags"),
457 }
458 }
459
460 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
462 match self {
463 Amode::ImmReg { base, .. } => {
464 if *base != regs::rbp() && *base != regs::rsp() {
465 collector.reg_use(base);
466 }
467 }
468 Amode::ImmRegRegShift { base, index, .. } => {
469 debug_assert_ne!(base.to_reg(), regs::rbp());
470 debug_assert_ne!(base.to_reg(), regs::rsp());
471 collector.reg_use(base);
472 debug_assert_ne!(index.to_reg(), regs::rbp());
473 debug_assert_ne!(index.to_reg(), regs::rsp());
474 collector.reg_use(index);
475 }
476 Amode::RipRelative { .. } => {
477 }
479 }
480 }
481
482 pub(crate) fn get_operands_late(&mut self, collector: &mut impl OperandVisitor) {
484 match self {
485 Amode::ImmReg { base, .. } => {
486 collector.reg_late_use(base);
487 }
488 Amode::ImmRegRegShift { base, index, .. } => {
489 collector.reg_late_use(base);
490 collector.reg_late_use(index);
491 }
492 Amode::RipRelative { .. } => {
493 }
495 }
496 }
497
498 pub(crate) fn get_flags(&self) -> MemFlagsData {
499 match self {
500 Amode::ImmReg { flags, .. } | Amode::ImmRegRegShift { flags, .. } => *flags,
501 Amode::RipRelative { .. } => MemFlagsData::trusted(),
502 }
503 }
504
505 pub(crate) fn offset(&self, offset: i32) -> Option<Self> {
507 let mut ret = self.clone();
508 let simm32 = match &mut ret {
509 Amode::ImmReg { simm32, .. } | Amode::ImmRegRegShift { simm32, .. } => simm32,
510 _ => panic!("Cannot offset amode: {self:?}"),
511 };
512 *simm32 = simm32.checked_add(offset)?;
513 Some(ret)
514 }
515
516 pub(crate) fn aligned(&self) -> bool {
517 self.get_flags().aligned()
518 }
519}
520
521impl PrettyPrint for Amode {
522 fn pretty_print(&self, _size: u8) -> String {
523 match self {
524 Amode::ImmReg { simm32, base, .. } => {
525 format!("{}({})", *simm32, pretty_print_reg(*base, 8))
528 }
529 Amode::ImmRegRegShift {
530 simm32,
531 base,
532 index,
533 shift,
534 ..
535 } => format!(
536 "{}({},{},{})",
537 *simm32,
538 pretty_print_reg(base.to_reg(), 8),
539 pretty_print_reg(index.to_reg(), 8),
540 1 << shift
541 ),
542 Amode::RipRelative { target } => format!("label{}(%rip)", target.as_u32()),
543 }
544 }
545}
546
547#[derive(Clone, Debug)]
551pub enum SyntheticAmode {
552 Real(Amode),
554
555 IncomingArg {
557 offset: u32,
559 },
560
561 SlotOffset {
564 simm32: i32,
566 },
567
568 ConstantOffset(VCodeConstant),
570}
571
572impl SyntheticAmode {
573 pub fn real(amode: Amode) -> Self {
575 Self::Real(amode)
576 }
577
578 pub(crate) fn slot_offset(simm32: i32) -> Self {
579 SyntheticAmode::SlotOffset { simm32 }
580 }
581
582 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
584 match self {
585 SyntheticAmode::Real(addr) => addr.get_operands(collector),
586 SyntheticAmode::IncomingArg { .. } => {
587 }
589 SyntheticAmode::SlotOffset { .. } => {
590 }
592 SyntheticAmode::ConstantOffset(_) => {}
593 }
594 }
595
596 pub(crate) fn get_operands_late(&mut self, collector: &mut impl OperandVisitor) {
598 match self {
599 SyntheticAmode::Real(addr) => addr.get_operands_late(collector),
600 SyntheticAmode::IncomingArg { .. } => {
601 }
603 SyntheticAmode::SlotOffset { .. } => {
604 }
606 SyntheticAmode::ConstantOffset(_) => {}
607 }
608 }
609
610 pub(crate) fn finalize(&self, frame: &FrameLayout, buffer: &mut MachBuffer<Inst>) -> Amode {
611 match self {
612 SyntheticAmode::Real(addr) => addr.clone(),
613 SyntheticAmode::IncomingArg { offset } => {
614 let args_max_fp_offset = frame.tail_args_size + frame.setup_area_size;
617 Amode::imm_reg(
618 i32::try_from(args_max_fp_offset - offset).unwrap(),
619 regs::rbp(),
620 )
621 }
622 SyntheticAmode::SlotOffset { simm32 } => {
623 let off = *simm32 as i64 + i64::from(frame.outgoing_args_size);
624 Amode::imm_reg(off.try_into().expect("invalid sp offset"), regs::rsp())
625 }
626 SyntheticAmode::ConstantOffset(c) => {
627 Amode::rip_relative(buffer.get_label_for_constant(*c))
628 }
629 }
630 }
631
632 pub(crate) fn aligned(&self) -> bool {
633 match self {
634 SyntheticAmode::Real(addr) => addr.aligned(),
635 &SyntheticAmode::IncomingArg { .. }
636 | SyntheticAmode::SlotOffset { .. }
637 | SyntheticAmode::ConstantOffset { .. } => true,
638 }
639 }
640
641 pub(crate) fn offset(&self, offset: i32) -> Option<Self> {
643 let mut ret = self.clone();
644 match &mut ret {
645 SyntheticAmode::Real(amode) => *amode = amode.offset(offset)?,
646 SyntheticAmode::SlotOffset { simm32 } => *simm32 = simm32.checked_add(offset)?,
647 _ => panic!("Cannot offset SyntheticAmode: {self:?}"),
652 }
653 Some(ret)
654 }
655}
656
657impl From<Amode> for SyntheticAmode {
658 fn from(amode: Amode) -> SyntheticAmode {
659 SyntheticAmode::Real(amode)
660 }
661}
662
663impl From<VCodeConstant> for SyntheticAmode {
664 fn from(c: VCodeConstant) -> SyntheticAmode {
665 SyntheticAmode::ConstantOffset(c)
666 }
667}
668
669impl PrettyPrint for SyntheticAmode {
670 fn pretty_print(&self, _size: u8) -> String {
671 match self {
672 SyntheticAmode::Real(addr) => addr.pretty_print(8),
674 &SyntheticAmode::IncomingArg { offset } => {
675 format!("rbp(stack args max - {offset})")
676 }
677 SyntheticAmode::SlotOffset { simm32 } => {
678 format!("rsp({} + virtual offset)", *simm32)
679 }
680 SyntheticAmode::ConstantOffset(c) => format!("const({})", c.as_u32()),
681 }
682 }
683}
684
685#[derive(Clone, Debug)]
690pub enum RegMemImm {
691 Reg {
693 reg: Reg,
695 },
696 Mem {
698 addr: SyntheticAmode,
700 },
701 Imm {
703 simm32: u32,
705 },
706}
707
708impl RegMemImm {
709 pub fn reg(reg: Reg) -> Self {
711 debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float);
712 Self::Reg { reg }
713 }
714
715 pub fn mem(addr: impl Into<SyntheticAmode>) -> Self {
717 Self::Mem { addr: addr.into() }
718 }
719
720 pub fn imm(simm32: u32) -> Self {
722 Self::Imm { simm32 }
723 }
724
725 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
727 match self {
728 Self::Reg { reg } => collector.reg_use(reg),
729 Self::Mem { addr } => addr.get_operands(collector),
730 Self::Imm { .. } => {}
731 }
732 }
733}
734
735impl From<RegMem> for RegMemImm {
736 fn from(rm: RegMem) -> RegMemImm {
737 match rm {
738 RegMem::Reg { reg } => RegMemImm::Reg { reg },
739 RegMem::Mem { addr } => RegMemImm::Mem { addr },
740 }
741 }
742}
743
744impl From<Reg> for RegMemImm {
745 fn from(reg: Reg) -> Self {
746 RegMemImm::Reg { reg }
747 }
748}
749
750impl PrettyPrint for RegMemImm {
751 fn pretty_print(&self, size: u8) -> String {
752 match self {
753 Self::Reg { reg } => pretty_print_reg(*reg, size),
754 Self::Mem { addr } => addr.pretty_print(size),
755 Self::Imm { simm32 } => format!("${}", *simm32 as i32),
756 }
757 }
758}
759
760#[derive(Clone, Debug)]
763pub enum RegMem {
764 Reg {
766 reg: Reg,
768 },
769 Mem {
771 addr: SyntheticAmode,
773 },
774}
775
776impl RegMem {
777 pub fn reg(reg: Reg) -> Self {
779 debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float);
780 Self::Reg { reg }
781 }
782
783 pub fn mem(addr: impl Into<SyntheticAmode>) -> Self {
785 Self::Mem { addr: addr.into() }
786 }
787 pub(crate) fn assert_regclass_is(&self, expected_reg_class: RegClass) {
789 if let Self::Reg { reg } = self {
790 debug_assert_eq!(reg.class(), expected_reg_class);
791 }
792 }
793 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
795 match self {
796 RegMem::Reg { reg } => collector.reg_use(reg),
797 RegMem::Mem { addr, .. } => addr.get_operands(collector),
798 }
799 }
800}
801
802impl From<Reg> for RegMem {
803 fn from(reg: Reg) -> RegMem {
804 RegMem::Reg { reg }
805 }
806}
807
808impl From<Writable<Reg>> for RegMem {
809 fn from(r: Writable<Reg>) -> Self {
810 RegMem::reg(r.to_reg())
811 }
812}
813
814impl PrettyPrint for RegMem {
815 fn pretty_print(&self, size: u8) -> String {
816 match self {
817 RegMem::Reg { reg } => pretty_print_reg(*reg, size),
818 RegMem::Mem { addr, .. } => addr.pretty_print(size),
819 }
820 }
821}
822
823#[derive(Clone, PartialEq)]
827pub enum ExtKind {
828 None,
830 SignExtend,
832 ZeroExtend,
834}
835
836#[derive(Clone, PartialEq)]
839pub enum ExtMode {
840 BL,
842 BQ,
844 WL,
846 WQ,
848 LQ,
850}
851
852impl ExtMode {
853 pub(crate) fn new(from_bits: u16, to_bits: u16) -> Option<ExtMode> {
855 match (from_bits, to_bits) {
856 (1, 8) | (1, 16) | (1, 32) | (8, 16) | (8, 32) => Some(ExtMode::BL),
857 (1, 64) | (8, 64) => Some(ExtMode::BQ),
858 (16, 32) => Some(ExtMode::WL),
859 (16, 64) => Some(ExtMode::WQ),
860 (32, 64) => Some(ExtMode::LQ),
861 _ => None,
862 }
863 }
864}
865
866impl fmt::Debug for ExtMode {
867 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
868 let name = match self {
869 ExtMode::BL => "bl",
870 ExtMode::BQ => "bq",
871 ExtMode::WL => "wl",
872 ExtMode::WQ => "wq",
873 ExtMode::LQ => "lq",
874 };
875 write!(fmt, "{name}")
876 }
877}
878
879impl fmt::Display for ExtMode {
880 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
881 fmt::Debug::fmt(self, f)
882 }
883}
884
885#[derive(Copy, Clone, PartialEq, Eq)]
888#[repr(u8)]
889pub enum CC {
890 O = 0,
892 NO = 1,
894
895 B = 2,
897 NB = 3,
899
900 Z = 4,
902 NZ = 5,
904
905 BE = 6,
907 NBE = 7,
909
910 S = 8,
912 NS = 9,
914
915 L = 12,
917 NL = 13,
919
920 LE = 14,
922 NLE = 15,
924
925 P = 10,
927
928 NP = 11,
930}
931
932impl CC {
933 pub(crate) fn from_intcc(intcc: IntCC) -> Self {
934 match intcc {
935 IntCC::Equal => CC::Z,
936 IntCC::NotEqual => CC::NZ,
937 IntCC::SignedGreaterThanOrEqual => CC::NL,
938 IntCC::SignedGreaterThan => CC::NLE,
939 IntCC::SignedLessThanOrEqual => CC::LE,
940 IntCC::SignedLessThan => CC::L,
941 IntCC::UnsignedGreaterThanOrEqual => CC::NB,
942 IntCC::UnsignedGreaterThan => CC::NBE,
943 IntCC::UnsignedLessThanOrEqual => CC::BE,
944 IntCC::UnsignedLessThan => CC::B,
945 }
946 }
947
948 pub(crate) fn invert(&self) -> Self {
949 match self {
950 CC::O => CC::NO,
951 CC::NO => CC::O,
952
953 CC::B => CC::NB,
954 CC::NB => CC::B,
955
956 CC::Z => CC::NZ,
957 CC::NZ => CC::Z,
958
959 CC::BE => CC::NBE,
960 CC::NBE => CC::BE,
961
962 CC::S => CC::NS,
963 CC::NS => CC::S,
964
965 CC::L => CC::NL,
966 CC::NL => CC::L,
967
968 CC::LE => CC::NLE,
969 CC::NLE => CC::LE,
970
971 CC::P => CC::NP,
972 CC::NP => CC::P,
973 }
974 }
975
976 pub(crate) fn get_enc(self) -> u8 {
977 self as u8
978 }
979}
980
981impl fmt::Debug for CC {
982 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
983 let name = match self {
984 CC::O => "o",
985 CC::NO => "no",
986 CC::B => "b",
987 CC::NB => "nb",
988 CC::Z => "z",
989 CC::NZ => "nz",
990 CC::BE => "be",
991 CC::NBE => "nbe",
992 CC::S => "s",
993 CC::NS => "ns",
994 CC::L => "l",
995 CC::NL => "nl",
996 CC::LE => "le",
997 CC::NLE => "nle",
998 CC::P => "p",
999 CC::NP => "np",
1000 };
1001 write!(fmt, "{name}")
1002 }
1003}
1004
1005impl fmt::Display for CC {
1006 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1007 fmt::Debug::fmt(self, f)
1008 }
1009}
1010
1011#[derive(Clone, Copy)]
1015pub enum FcmpImm {
1016 Equal = 0x00,
1018 LessThan = 0x01,
1020 LessThanOrEqual = 0x02,
1022 Unordered = 0x03,
1024 NotEqual = 0x04,
1026 UnorderedOrGreaterThanOrEqual = 0x05,
1028 UnorderedOrGreaterThan = 0x06,
1030 Ordered = 0x07,
1032}
1033
1034impl FcmpImm {
1035 pub(crate) fn encode(self) -> u8 {
1036 self as u8
1037 }
1038}
1039
1040impl From<FloatCC> for FcmpImm {
1041 fn from(cond: FloatCC) -> Self {
1042 match cond {
1043 FloatCC::Equal => FcmpImm::Equal,
1044 FloatCC::LessThan => FcmpImm::LessThan,
1045 FloatCC::LessThanOrEqual => FcmpImm::LessThanOrEqual,
1046 FloatCC::Unordered => FcmpImm::Unordered,
1047 FloatCC::NotEqual => FcmpImm::NotEqual,
1048 FloatCC::UnorderedOrGreaterThanOrEqual => FcmpImm::UnorderedOrGreaterThanOrEqual,
1049 FloatCC::UnorderedOrGreaterThan => FcmpImm::UnorderedOrGreaterThan,
1050 FloatCC::Ordered => FcmpImm::Ordered,
1051 _ => panic!("unable to create comparison predicate for {cond}"),
1052 }
1053 }
1054}
1055
1056#[derive(Clone, Copy)]
1063pub enum RoundImm {
1064 RoundNearest = 0x00,
1066 RoundDown = 0x01,
1068 RoundUp = 0x02,
1070 RoundZero = 0x03,
1072}
1073
1074impl RoundImm {
1075 pub(crate) fn encode(self) -> u8 {
1076 self as u8
1077 }
1078}
1079
1080#[derive(Clone, Copy, PartialEq)]
1082pub enum OperandSize {
1083 Size8,
1085 Size16,
1087 Size32,
1089 Size64,
1091}
1092
1093impl OperandSize {
1094 pub(crate) fn from_bytes(num_bytes: u32) -> Self {
1095 match num_bytes {
1096 1 => OperandSize::Size8,
1097 2 => OperandSize::Size16,
1098 4 => OperandSize::Size32,
1099 8 => OperandSize::Size64,
1100 _ => unreachable!("Invalid OperandSize: {}", num_bytes),
1101 }
1102 }
1103
1104 pub(crate) fn from_ty(ty: Type) -> Self {
1107 Self::from_bytes(ty.lane_type().bytes())
1108 }
1109
1110 pub(crate) fn is_one_of(&self, sizes: &[Self]) -> bool {
1112 sizes.iter().any(|val| *self == *val)
1113 }
1114
1115 pub(crate) fn to_bytes(&self) -> u8 {
1116 match self {
1117 Self::Size8 => 1,
1118 Self::Size16 => 2,
1119 Self::Size32 => 4,
1120 Self::Size64 => 8,
1121 }
1122 }
1123
1124 pub(crate) fn to_bits(&self) -> u8 {
1125 self.to_bytes() * 8
1126 }
1127}
1128
1129pub use crate::isa::x64::lower::isle::generated_code::Atomic128RmwSeqOp;
1130
1131#[derive(Debug, Clone)]
1134#[expect(missing_docs, reason = "self-describing fields")]
1135pub struct Atomic128RmwSeqArgs {
1136 pub op: Atomic128RmwSeqOp,
1137 pub mem_low: SyntheticAmode,
1138 pub mem_high: SyntheticAmode,
1139 pub operand_low: Gpr,
1140 pub operand_high: Gpr,
1141 pub temp_low: WritableGpr,
1142 pub temp_high: WritableGpr,
1143 pub dst_old_low: WritableGpr,
1144 pub dst_old_high: WritableGpr,
1145}
1146
1147#[derive(Debug, Clone)]
1150#[expect(missing_docs, reason = "self-describing fields")]
1151pub struct Atomic128XchgSeqArgs {
1152 pub mem_low: SyntheticAmode,
1153 pub mem_high: SyntheticAmode,
1154 pub operand_low: Gpr,
1155 pub operand_high: Gpr,
1156 pub dst_old_low: WritableGpr,
1157 pub dst_old_high: WritableGpr,
1158}