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 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 _ => panic!("Cannot offset SyntheticAmode: {self:?}"),
588 }
589 ret
590 }
591}
592
593impl From<Amode> for SyntheticAmode {
594 fn from(amode: Amode) -> SyntheticAmode {
595 SyntheticAmode::Real(amode)
596 }
597}
598
599impl From<VCodeConstant> for SyntheticAmode {
600 fn from(c: VCodeConstant) -> SyntheticAmode {
601 SyntheticAmode::ConstantOffset(c)
602 }
603}
604
605impl PrettyPrint for SyntheticAmode {
606 fn pretty_print(&self, _size: u8) -> String {
607 match self {
608 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#[derive(Clone, Debug)]
626pub enum RegMemImm {
627 Reg {
629 reg: Reg,
631 },
632 Mem {
634 addr: SyntheticAmode,
636 },
637 Imm {
639 simm32: u32,
641 },
642}
643
644impl RegMemImm {
645 pub fn reg(reg: Reg) -> Self {
647 debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float);
648 Self::Reg { reg }
649 }
650
651 pub fn mem(addr: impl Into<SyntheticAmode>) -> Self {
653 Self::Mem { addr: addr.into() }
654 }
655
656 pub fn imm(simm32: u32) -> Self {
658 Self::Imm { simm32 }
659 }
660
661 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
671impl 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
680impl From<Reg> for RegMemImm {
681 fn from(reg: Reg) -> Self {
682 RegMemImm::Reg { reg }
683 }
684}
685
686impl 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#[derive(Clone, Debug)]
699pub enum RegMem {
700 Reg {
702 reg: Reg,
704 },
705 Mem {
707 addr: SyntheticAmode,
709 },
710}
711
712impl RegMem {
713 pub fn reg(reg: Reg) -> Self {
715 debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float);
716 Self::Reg { reg }
717 }
718
719 pub fn mem(addr: impl Into<SyntheticAmode>) -> Self {
721 Self::Mem { addr: addr.into() }
722 }
723 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 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
738impl From<Reg> for RegMem {
739 fn from(reg: Reg) -> RegMem {
740 RegMem::Reg { reg }
741 }
742}
743
744impl From<Writable<Reg>> for RegMem {
745 fn from(r: Writable<Reg>) -> Self {
746 RegMem::reg(r.to_reg())
747 }
748}
749
750impl 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#[derive(Clone, PartialEq)]
763pub enum ExtKind {
764 None,
766 SignExtend,
768 ZeroExtend,
770}
771
772#[derive(Clone, PartialEq)]
775pub enum ExtMode {
776 BL,
778 BQ,
780 WL,
782 WQ,
784 LQ,
786}
787
788impl ExtMode {
789 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
802impl 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
815impl fmt::Display for ExtMode {
816 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
817 fmt::Debug::fmt(self, f)
818 }
819}
820
821#[derive(Copy, Clone, PartialEq, Eq)]
824#[repr(u8)]
825pub enum CC {
826 O = 0,
828 NO = 1,
830
831 B = 2,
833 NB = 3,
835
836 Z = 4,
838 NZ = 5,
840
841 BE = 6,
843 NBE = 7,
845
846 S = 8,
848 NS = 9,
850
851 L = 12,
853 NL = 13,
855
856 LE = 14,
858 NLE = 15,
860
861 P = 10,
863
864 NP = 11,
866}
867
868impl 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
917impl 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
941impl fmt::Display for CC {
942 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
943 fmt::Debug::fmt(self, f)
944 }
945}
946
947#[derive(Clone, Copy)]
951pub enum FcmpImm {
952 Equal = 0x00,
954 LessThan = 0x01,
956 LessThanOrEqual = 0x02,
958 Unordered = 0x03,
960 NotEqual = 0x04,
962 UnorderedOrGreaterThanOrEqual = 0x05,
964 UnorderedOrGreaterThan = 0x06,
966 Ordered = 0x07,
968}
969
970impl FcmpImm {
971 pub(crate) fn encode(self) -> u8 {
972 self as u8
973 }
974}
975
976impl 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#[derive(Clone, Copy)]
999pub enum RoundImm {
1000 RoundNearest = 0x00,
1002 RoundDown = 0x01,
1004 RoundUp = 0x02,
1006 RoundZero = 0x03,
1008}
1009
1010impl RoundImm {
1011 pub(crate) fn encode(self) -> u8 {
1012 self as u8
1013 }
1014}
1015
1016#[derive(Clone, Copy, PartialEq)]
1018pub enum OperandSize {
1019 Size8,
1021 Size16,
1023 Size32,
1025 Size64,
1027}
1028
1029impl 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 pub(crate) fn from_ty(ty: Type) -> Self {
1043 Self::from_bytes(ty.lane_type().bytes())
1044 }
1045
1046 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}