1use super::regs::{self};
4use crate::ir::MemFlags;
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 std::fmt;
11use std::string::String;
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 {
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 #[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 pub fn new($check_reg: Reg) -> Option<Self> {
56 if $check {
57 Some(Self($check_reg))
58 } else {
59 None
60 }
61 }
62
63 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 pub fn to_reg(self) -> Reg {
80 self.0
81 }
82 }
83
84 impl std::ops::Deref for $newtype_reg {
91 type Target = Reg;
92
93 fn deref(&self) -> &Reg {
94 &self.0
95 }
96 }
97
98 impl AsMut<Reg> for $newtype_reg {
102 fn as_mut(&mut self) -> &mut Reg {
103 &mut self.0
104 }
105 }
106
107 pub type $newtype_writable_reg = Writable<$newtype_reg>;
109
110 #[allow(dead_code, reason = "Used by some newtypes and not others")]
111 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 #[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 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 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 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 #[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 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 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 #[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
296newtype_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")]
307impl 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
326newtype_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
336pub use crate::isa::x64::lower::isle::generated_code::Amode;
341
342impl Amode {
343 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 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 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 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 }
415 }
416 }
417
418 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 }
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 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
457impl PrettyPrint for Amode {
458 fn pretty_print(&self, _size: u8) -> String {
459 match self {
460 Amode::ImmReg { simm32, base, .. } => {
461 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#[derive(Clone, Debug)]
487pub enum SyntheticAmode {
488 Real(Amode),
490
491 IncomingArg {
493 offset: u32,
495 },
496
497 SlotOffset {
500 simm32: i32,
502 },
503
504 ConstantOffset(VCodeConstant),
506}
507
508impl SyntheticAmode {
509 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 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 }
525 SyntheticAmode::SlotOffset { .. } => {
526 }
528 SyntheticAmode::ConstantOffset(_) => {}
529 }
530 }
531
532 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 }
539 SyntheticAmode::SlotOffset { .. } => {
540 }
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 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
578impl From<Amode> for SyntheticAmode {
579 fn from(amode: Amode) -> SyntheticAmode {
580 SyntheticAmode::Real(amode)
581 }
582}
583
584impl From<VCodeConstant> for SyntheticAmode {
585 fn from(c: VCodeConstant) -> SyntheticAmode {
586 SyntheticAmode::ConstantOffset(c)
587 }
588}
589
590impl PrettyPrint for SyntheticAmode {
591 fn pretty_print(&self, _size: u8) -> String {
592 match self {
593 SyntheticAmode::Real(addr) => addr.pretty_print(8),
595 &SyntheticAmode::IncomingArg { offset } => {
596 format!("rbp(stack args max - {offset})")
597 }
598 SyntheticAmode::SlotOffset { simm32 } => {
599 format!("rsp({} + virtual offset)", *simm32)
600 }
601 SyntheticAmode::ConstantOffset(c) => format!("const({})", c.as_u32()),
602 }
603 }
604}
605
606#[derive(Clone, Debug)]
611pub enum RegMemImm {
612 Reg {
614 reg: Reg,
616 },
617 Mem {
619 addr: SyntheticAmode,
621 },
622 Imm {
624 simm32: u32,
626 },
627}
628
629impl RegMemImm {
630 pub fn reg(reg: Reg) -> Self {
632 debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float);
633 Self::Reg { reg }
634 }
635
636 pub fn mem(addr: impl Into<SyntheticAmode>) -> Self {
638 Self::Mem { addr: addr.into() }
639 }
640
641 pub fn imm(simm32: u32) -> Self {
643 Self::Imm { simm32 }
644 }
645
646 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
648 match self {
649 Self::Reg { reg } => collector.reg_use(reg),
650 Self::Mem { addr } => addr.get_operands(collector),
651 Self::Imm { .. } => {}
652 }
653 }
654}
655
656impl From<RegMem> for RegMemImm {
657 fn from(rm: RegMem) -> RegMemImm {
658 match rm {
659 RegMem::Reg { reg } => RegMemImm::Reg { reg },
660 RegMem::Mem { addr } => RegMemImm::Mem { addr },
661 }
662 }
663}
664
665impl From<Reg> for RegMemImm {
666 fn from(reg: Reg) -> Self {
667 RegMemImm::Reg { reg }
668 }
669}
670
671impl PrettyPrint for RegMemImm {
672 fn pretty_print(&self, size: u8) -> String {
673 match self {
674 Self::Reg { reg } => pretty_print_reg(*reg, size),
675 Self::Mem { addr } => addr.pretty_print(size),
676 Self::Imm { simm32 } => format!("${}", *simm32 as i32),
677 }
678 }
679}
680
681#[derive(Clone, Debug)]
684pub enum RegMem {
685 Reg {
687 reg: Reg,
689 },
690 Mem {
692 addr: SyntheticAmode,
694 },
695}
696
697impl RegMem {
698 pub fn reg(reg: Reg) -> Self {
700 debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float);
701 Self::Reg { reg }
702 }
703
704 pub fn mem(addr: impl Into<SyntheticAmode>) -> Self {
706 Self::Mem { addr: addr.into() }
707 }
708 pub(crate) fn assert_regclass_is(&self, expected_reg_class: RegClass) {
710 if let Self::Reg { reg } = self {
711 debug_assert_eq!(reg.class(), expected_reg_class);
712 }
713 }
714 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
716 match self {
717 RegMem::Reg { reg } => collector.reg_use(reg),
718 RegMem::Mem { addr, .. } => addr.get_operands(collector),
719 }
720 }
721}
722
723impl From<Reg> for RegMem {
724 fn from(reg: Reg) -> RegMem {
725 RegMem::Reg { reg }
726 }
727}
728
729impl From<Writable<Reg>> for RegMem {
730 fn from(r: Writable<Reg>) -> Self {
731 RegMem::reg(r.to_reg())
732 }
733}
734
735impl PrettyPrint for RegMem {
736 fn pretty_print(&self, size: u8) -> String {
737 match self {
738 RegMem::Reg { reg } => pretty_print_reg(*reg, size),
739 RegMem::Mem { addr, .. } => addr.pretty_print(size),
740 }
741 }
742}
743
744#[derive(Debug)]
745pub(crate) enum InstructionSet {
746 SSE,
747 SSE2,
748 CMPXCHG16b,
749 SSE3,
750 SSSE3,
751 SSE41,
752 SSE42,
753 Popcnt,
754 Lzcnt,
755 BMI1,
756 BMI2,
757 FMA,
758 AVX,
759 AVX2,
760 AVX512BITALG,
761 AVX512DQ,
762 AVX512F,
763 AVX512VBMI,
764 AVX512VL,
765}
766
767#[derive(Clone, PartialEq)]
771pub enum ExtKind {
772 None,
774 SignExtend,
776 ZeroExtend,
778}
779
780#[derive(Clone, PartialEq)]
783pub enum ExtMode {
784 BL,
786 BQ,
788 WL,
790 WQ,
792 LQ,
794}
795
796impl ExtMode {
797 pub(crate) fn new(from_bits: u16, to_bits: u16) -> Option<ExtMode> {
799 match (from_bits, to_bits) {
800 (1, 8) | (1, 16) | (1, 32) | (8, 16) | (8, 32) => Some(ExtMode::BL),
801 (1, 64) | (8, 64) => Some(ExtMode::BQ),
802 (16, 32) => Some(ExtMode::WL),
803 (16, 64) => Some(ExtMode::WQ),
804 (32, 64) => Some(ExtMode::LQ),
805 _ => None,
806 }
807 }
808}
809
810impl fmt::Debug for ExtMode {
811 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
812 let name = match self {
813 ExtMode::BL => "bl",
814 ExtMode::BQ => "bq",
815 ExtMode::WL => "wl",
816 ExtMode::WQ => "wq",
817 ExtMode::LQ => "lq",
818 };
819 write!(fmt, "{name}")
820 }
821}
822
823impl fmt::Display for ExtMode {
824 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
825 fmt::Debug::fmt(self, f)
826 }
827}
828
829#[derive(Copy, Clone, PartialEq, Eq)]
832#[repr(u8)]
833pub enum CC {
834 O = 0,
836 NO = 1,
838
839 B = 2,
841 NB = 3,
843
844 Z = 4,
846 NZ = 5,
848
849 BE = 6,
851 NBE = 7,
853
854 S = 8,
856 NS = 9,
858
859 L = 12,
861 NL = 13,
863
864 LE = 14,
866 NLE = 15,
868
869 P = 10,
871
872 NP = 11,
874}
875
876impl CC {
877 pub(crate) fn from_intcc(intcc: IntCC) -> Self {
878 match intcc {
879 IntCC::Equal => CC::Z,
880 IntCC::NotEqual => CC::NZ,
881 IntCC::SignedGreaterThanOrEqual => CC::NL,
882 IntCC::SignedGreaterThan => CC::NLE,
883 IntCC::SignedLessThanOrEqual => CC::LE,
884 IntCC::SignedLessThan => CC::L,
885 IntCC::UnsignedGreaterThanOrEqual => CC::NB,
886 IntCC::UnsignedGreaterThan => CC::NBE,
887 IntCC::UnsignedLessThanOrEqual => CC::BE,
888 IntCC::UnsignedLessThan => CC::B,
889 }
890 }
891
892 pub(crate) fn invert(&self) -> Self {
893 match self {
894 CC::O => CC::NO,
895 CC::NO => CC::O,
896
897 CC::B => CC::NB,
898 CC::NB => CC::B,
899
900 CC::Z => CC::NZ,
901 CC::NZ => CC::Z,
902
903 CC::BE => CC::NBE,
904 CC::NBE => CC::BE,
905
906 CC::S => CC::NS,
907 CC::NS => CC::S,
908
909 CC::L => CC::NL,
910 CC::NL => CC::L,
911
912 CC::LE => CC::NLE,
913 CC::NLE => CC::LE,
914
915 CC::P => CC::NP,
916 CC::NP => CC::P,
917 }
918 }
919
920 pub(crate) fn get_enc(self) -> u8 {
921 self as u8
922 }
923}
924
925impl fmt::Debug for CC {
926 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
927 let name = match self {
928 CC::O => "o",
929 CC::NO => "no",
930 CC::B => "b",
931 CC::NB => "nb",
932 CC::Z => "z",
933 CC::NZ => "nz",
934 CC::BE => "be",
935 CC::NBE => "nbe",
936 CC::S => "s",
937 CC::NS => "ns",
938 CC::L => "l",
939 CC::NL => "nl",
940 CC::LE => "le",
941 CC::NLE => "nle",
942 CC::P => "p",
943 CC::NP => "np",
944 };
945 write!(fmt, "{name}")
946 }
947}
948
949impl fmt::Display for CC {
950 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
951 fmt::Debug::fmt(self, f)
952 }
953}
954
955#[derive(Clone, Copy)]
959pub enum FcmpImm {
960 Equal = 0x00,
962 LessThan = 0x01,
964 LessThanOrEqual = 0x02,
966 Unordered = 0x03,
968 NotEqual = 0x04,
970 UnorderedOrGreaterThanOrEqual = 0x05,
972 UnorderedOrGreaterThan = 0x06,
974 Ordered = 0x07,
976}
977
978impl FcmpImm {
979 pub(crate) fn encode(self) -> u8 {
980 self as u8
981 }
982}
983
984impl From<FloatCC> for FcmpImm {
985 fn from(cond: FloatCC) -> Self {
986 match cond {
987 FloatCC::Equal => FcmpImm::Equal,
988 FloatCC::LessThan => FcmpImm::LessThan,
989 FloatCC::LessThanOrEqual => FcmpImm::LessThanOrEqual,
990 FloatCC::Unordered => FcmpImm::Unordered,
991 FloatCC::NotEqual => FcmpImm::NotEqual,
992 FloatCC::UnorderedOrGreaterThanOrEqual => FcmpImm::UnorderedOrGreaterThanOrEqual,
993 FloatCC::UnorderedOrGreaterThan => FcmpImm::UnorderedOrGreaterThan,
994 FloatCC::Ordered => FcmpImm::Ordered,
995 _ => panic!("unable to create comparison predicate for {cond}"),
996 }
997 }
998}
999
1000#[derive(Clone, Copy)]
1007pub enum RoundImm {
1008 RoundNearest = 0x00,
1010 RoundDown = 0x01,
1012 RoundUp = 0x02,
1014 RoundZero = 0x03,
1016}
1017
1018impl RoundImm {
1019 pub(crate) fn encode(self) -> u8 {
1020 self as u8
1021 }
1022}
1023
1024#[derive(Clone, Copy, PartialEq)]
1026pub enum OperandSize {
1027 Size8,
1029 Size16,
1031 Size32,
1033 Size64,
1035}
1036
1037impl OperandSize {
1038 pub(crate) fn from_bytes(num_bytes: u32) -> Self {
1039 match num_bytes {
1040 1 => OperandSize::Size8,
1041 2 => OperandSize::Size16,
1042 4 => OperandSize::Size32,
1043 8 => OperandSize::Size64,
1044 _ => unreachable!("Invalid OperandSize: {}", num_bytes),
1045 }
1046 }
1047
1048 pub(crate) fn from_ty(ty: Type) -> Self {
1051 Self::from_bytes(ty.lane_type().bytes())
1052 }
1053
1054 pub(crate) fn is_one_of(&self, sizes: &[Self]) -> bool {
1056 sizes.iter().any(|val| *self == *val)
1057 }
1058
1059 pub(crate) fn to_bytes(&self) -> u8 {
1060 match self {
1061 Self::Size8 => 1,
1062 Self::Size16 => 2,
1063 Self::Size32 => 4,
1064 Self::Size64 => 8,
1065 }
1066 }
1067
1068 pub(crate) fn to_bits(&self) -> u8 {
1069 self.to_bytes() * 8
1070 }
1071}