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(Clone, PartialEq)]
748pub enum ExtKind {
749 None,
751 SignExtend,
753 ZeroExtend,
755}
756
757#[derive(Clone, PartialEq)]
760pub enum ExtMode {
761 BL,
763 BQ,
765 WL,
767 WQ,
769 LQ,
771}
772
773impl ExtMode {
774 pub(crate) fn new(from_bits: u16, to_bits: u16) -> Option<ExtMode> {
776 match (from_bits, to_bits) {
777 (1, 8) | (1, 16) | (1, 32) | (8, 16) | (8, 32) => Some(ExtMode::BL),
778 (1, 64) | (8, 64) => Some(ExtMode::BQ),
779 (16, 32) => Some(ExtMode::WL),
780 (16, 64) => Some(ExtMode::WQ),
781 (32, 64) => Some(ExtMode::LQ),
782 _ => None,
783 }
784 }
785}
786
787impl fmt::Debug for ExtMode {
788 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
789 let name = match self {
790 ExtMode::BL => "bl",
791 ExtMode::BQ => "bq",
792 ExtMode::WL => "wl",
793 ExtMode::WQ => "wq",
794 ExtMode::LQ => "lq",
795 };
796 write!(fmt, "{name}")
797 }
798}
799
800impl fmt::Display for ExtMode {
801 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
802 fmt::Debug::fmt(self, f)
803 }
804}
805
806#[derive(Copy, Clone, PartialEq, Eq)]
809#[repr(u8)]
810pub enum CC {
811 O = 0,
813 NO = 1,
815
816 B = 2,
818 NB = 3,
820
821 Z = 4,
823 NZ = 5,
825
826 BE = 6,
828 NBE = 7,
830
831 S = 8,
833 NS = 9,
835
836 L = 12,
838 NL = 13,
840
841 LE = 14,
843 NLE = 15,
845
846 P = 10,
848
849 NP = 11,
851}
852
853impl CC {
854 pub(crate) fn from_intcc(intcc: IntCC) -> Self {
855 match intcc {
856 IntCC::Equal => CC::Z,
857 IntCC::NotEqual => CC::NZ,
858 IntCC::SignedGreaterThanOrEqual => CC::NL,
859 IntCC::SignedGreaterThan => CC::NLE,
860 IntCC::SignedLessThanOrEqual => CC::LE,
861 IntCC::SignedLessThan => CC::L,
862 IntCC::UnsignedGreaterThanOrEqual => CC::NB,
863 IntCC::UnsignedGreaterThan => CC::NBE,
864 IntCC::UnsignedLessThanOrEqual => CC::BE,
865 IntCC::UnsignedLessThan => CC::B,
866 }
867 }
868
869 pub(crate) fn invert(&self) -> Self {
870 match self {
871 CC::O => CC::NO,
872 CC::NO => CC::O,
873
874 CC::B => CC::NB,
875 CC::NB => CC::B,
876
877 CC::Z => CC::NZ,
878 CC::NZ => CC::Z,
879
880 CC::BE => CC::NBE,
881 CC::NBE => CC::BE,
882
883 CC::S => CC::NS,
884 CC::NS => CC::S,
885
886 CC::L => CC::NL,
887 CC::NL => CC::L,
888
889 CC::LE => CC::NLE,
890 CC::NLE => CC::LE,
891
892 CC::P => CC::NP,
893 CC::NP => CC::P,
894 }
895 }
896
897 pub(crate) fn get_enc(self) -> u8 {
898 self as u8
899 }
900}
901
902impl fmt::Debug for CC {
903 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
904 let name = match self {
905 CC::O => "o",
906 CC::NO => "no",
907 CC::B => "b",
908 CC::NB => "nb",
909 CC::Z => "z",
910 CC::NZ => "nz",
911 CC::BE => "be",
912 CC::NBE => "nbe",
913 CC::S => "s",
914 CC::NS => "ns",
915 CC::L => "l",
916 CC::NL => "nl",
917 CC::LE => "le",
918 CC::NLE => "nle",
919 CC::P => "p",
920 CC::NP => "np",
921 };
922 write!(fmt, "{name}")
923 }
924}
925
926impl fmt::Display for CC {
927 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
928 fmt::Debug::fmt(self, f)
929 }
930}
931
932#[derive(Clone, Copy)]
936pub enum FcmpImm {
937 Equal = 0x00,
939 LessThan = 0x01,
941 LessThanOrEqual = 0x02,
943 Unordered = 0x03,
945 NotEqual = 0x04,
947 UnorderedOrGreaterThanOrEqual = 0x05,
949 UnorderedOrGreaterThan = 0x06,
951 Ordered = 0x07,
953}
954
955impl FcmpImm {
956 pub(crate) fn encode(self) -> u8 {
957 self as u8
958 }
959}
960
961impl From<FloatCC> for FcmpImm {
962 fn from(cond: FloatCC) -> Self {
963 match cond {
964 FloatCC::Equal => FcmpImm::Equal,
965 FloatCC::LessThan => FcmpImm::LessThan,
966 FloatCC::LessThanOrEqual => FcmpImm::LessThanOrEqual,
967 FloatCC::Unordered => FcmpImm::Unordered,
968 FloatCC::NotEqual => FcmpImm::NotEqual,
969 FloatCC::UnorderedOrGreaterThanOrEqual => FcmpImm::UnorderedOrGreaterThanOrEqual,
970 FloatCC::UnorderedOrGreaterThan => FcmpImm::UnorderedOrGreaterThan,
971 FloatCC::Ordered => FcmpImm::Ordered,
972 _ => panic!("unable to create comparison predicate for {cond}"),
973 }
974 }
975}
976
977#[derive(Clone, Copy)]
984pub enum RoundImm {
985 RoundNearest = 0x00,
987 RoundDown = 0x01,
989 RoundUp = 0x02,
991 RoundZero = 0x03,
993}
994
995impl RoundImm {
996 pub(crate) fn encode(self) -> u8 {
997 self as u8
998 }
999}
1000
1001#[derive(Clone, Copy, PartialEq)]
1003pub enum OperandSize {
1004 Size8,
1006 Size16,
1008 Size32,
1010 Size64,
1012}
1013
1014impl OperandSize {
1015 pub(crate) fn from_bytes(num_bytes: u32) -> Self {
1016 match num_bytes {
1017 1 => OperandSize::Size8,
1018 2 => OperandSize::Size16,
1019 4 => OperandSize::Size32,
1020 8 => OperandSize::Size64,
1021 _ => unreachable!("Invalid OperandSize: {}", num_bytes),
1022 }
1023 }
1024
1025 pub(crate) fn from_ty(ty: Type) -> Self {
1028 Self::from_bytes(ty.lane_type().bytes())
1029 }
1030
1031 pub(crate) fn is_one_of(&self, sizes: &[Self]) -> bool {
1033 sizes.iter().any(|val| *self == *val)
1034 }
1035
1036 pub(crate) fn to_bytes(&self) -> u8 {
1037 match self {
1038 Self::Size8 => 1,
1039 Self::Size16 => 2,
1040 Self::Size32 => 4,
1041 Self::Size64 => 8,
1042 }
1043 }
1044
1045 pub(crate) fn to_bits(&self) -> u8 {
1046 self.to_bytes() * 8
1047 }
1048}