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 smallvec::{SmallVec, smallvec};
11use std::fmt;
12use std::string::String;
13
14pub trait ToWritableReg {
16 fn to_writable_reg(&self) -> Writable<Reg>;
18}
19
20pub trait FromWritableReg: Sized {
22 fn from_writable_reg(w: Writable<Reg>) -> Option<Self>;
24}
25
26macro_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 #[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 pub fn new($check_reg: Reg) -> Option<Self> {
57 if $check {
58 Some(Self($check_reg))
59 } else {
60 None
61 }
62 }
63
64 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 pub fn to_reg(self) -> Reg {
81 self.0
82 }
83 }
84
85 impl std::ops::Deref for $newtype_reg {
92 type Target = Reg;
93
94 fn deref(&self) -> &Reg {
95 &self.0
96 }
97 }
98
99 impl AsMut<Reg> for $newtype_reg {
103 fn as_mut(&mut self) -> &mut Reg {
104 &mut self.0
105 }
106 }
107
108 pub type $newtype_writable_reg = Writable<$newtype_reg>;
110
111 #[allow(dead_code)] 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 #[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 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 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 pub fn to_reg_mem(self) -> RegMem {
193 self.0
194 }
195
196 #[allow(dead_code)] 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 #[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 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 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 #[allow(dead_code)] pub fn to_reg_mem_imm(self) -> RegMemImm {
279 self.0
280 }
281
282 #[allow(dead_code)] 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
297newtype_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#[expect(missing_docs, reason = "self-describing fields")]
308impl Gpr {
309 pub const RAX: Gpr = Gpr(regs::rax());
310 pub const RBX: Gpr = Gpr(regs::rbx());
311 pub const RCX: Gpr = Gpr(regs::rcx());
312 pub const RDX: Gpr = Gpr(regs::rdx());
313 pub const RSI: Gpr = Gpr(regs::rsi());
314 pub const RDI: Gpr = Gpr(regs::rdi());
315 pub const RSP: Gpr = Gpr(regs::rsp());
316 pub const RBP: Gpr = Gpr(regs::rbp());
317 pub const R8: Gpr = Gpr(regs::r8());
318 pub const R9: Gpr = Gpr(regs::r9());
319 pub const R10: Gpr = Gpr(regs::r10());
320 pub const R11: Gpr = Gpr(regs::r11());
321 pub const R12: Gpr = Gpr(regs::r12());
322 pub const R13: Gpr = Gpr(regs::r13());
323 pub const R14: Gpr = Gpr(regs::r14());
324 pub const R15: Gpr = Gpr(regs::r15());
325}
326
327newtype_of_reg!(
329 Xmm,
330 WritableXmm,
331 OptionWritableXmm,
332 reg_mem: (XmmMem, XmmMemAligned aligned:true),
333 reg_mem_imm: (XmmMemImm, XmmMemAlignedImm aligned:true),
334 |reg| reg.class() == RegClass::Float
335);
336
337pub use crate::isa::x64::lower::isle::generated_code::Amode;
342
343impl Amode {
344 pub fn imm_reg(simm32: i32, base: Reg) -> Self {
346 debug_assert!(base.class() == RegClass::Int);
347 Self::ImmReg {
348 simm32,
349 base,
350 flags: MemFlags::trusted(),
351 }
352 }
353
354 pub fn imm_reg_reg_shift(simm32: i32, base: Gpr, index: Gpr, shift: u8) -> Self {
356 debug_assert!(base.class() == RegClass::Int);
357 debug_assert!(index.class() == RegClass::Int);
358 debug_assert!(shift <= 3);
359 Self::ImmRegRegShift {
360 simm32,
361 base,
362 index,
363 shift,
364 flags: MemFlags::trusted(),
365 }
366 }
367
368 pub(crate) fn rip_relative(target: MachLabel) -> Self {
369 Self::RipRelative { target }
370 }
371
372 pub fn with_flags(&self, flags: MemFlags) -> Self {
374 match self {
375 &Self::ImmReg { simm32, base, .. } => Self::ImmReg {
376 simm32,
377 base,
378 flags,
379 },
380 &Self::ImmRegRegShift {
381 simm32,
382 base,
383 index,
384 shift,
385 ..
386 } => Self::ImmRegRegShift {
387 simm32,
388 base,
389 index,
390 shift,
391 flags,
392 },
393 _ => panic!("Amode {self:?} cannot take memflags"),
394 }
395 }
396
397 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
399 match self {
400 Amode::ImmReg { base, .. } => {
401 if *base != regs::rbp() && *base != regs::rsp() {
402 collector.reg_use(base);
403 }
404 }
405 Amode::ImmRegRegShift { base, index, .. } => {
406 debug_assert_ne!(base.to_reg(), regs::rbp());
407 debug_assert_ne!(base.to_reg(), regs::rsp());
408 collector.reg_use(base);
409 debug_assert_ne!(index.to_reg(), regs::rbp());
410 debug_assert_ne!(index.to_reg(), regs::rsp());
411 collector.reg_use(index);
412 }
413 Amode::RipRelative { .. } => {
414 }
416 }
417 }
418
419 pub(crate) fn get_operands_late(&mut self, collector: &mut impl OperandVisitor) {
421 match self {
422 Amode::ImmReg { base, .. } => {
423 collector.reg_late_use(base);
424 }
425 Amode::ImmRegRegShift { base, index, .. } => {
426 collector.reg_late_use(base);
427 collector.reg_late_use(index);
428 }
429 Amode::RipRelative { .. } => {
430 }
432 }
433 }
434
435 pub(crate) fn get_flags(&self) -> MemFlags {
436 match self {
437 Amode::ImmReg { flags, .. } | Amode::ImmRegRegShift { flags, .. } => *flags,
438 Amode::RipRelative { .. } => MemFlags::trusted(),
439 }
440 }
441
442 pub(crate) fn offset(&self, offset: i32) -> Self {
444 let mut ret = self.clone();
445 match &mut ret {
446 &mut Amode::ImmReg { ref mut simm32, .. } => *simm32 += offset,
447 &mut Amode::ImmRegRegShift { ref mut simm32, .. } => *simm32 += offset,
448 _ => panic!("Cannot offset amode: {self:?}"),
449 }
450 ret
451 }
452
453 pub(crate) fn aligned(&self) -> bool {
454 self.get_flags().aligned()
455 }
456}
457
458impl PrettyPrint for Amode {
459 fn pretty_print(&self, _size: u8) -> String {
460 match self {
461 Amode::ImmReg { simm32, base, .. } => {
462 format!("{}({})", *simm32, pretty_print_reg(*base, 8))
465 }
466 Amode::ImmRegRegShift {
467 simm32,
468 base,
469 index,
470 shift,
471 ..
472 } => format!(
473 "{}({},{},{})",
474 *simm32,
475 pretty_print_reg(base.to_reg(), 8),
476 pretty_print_reg(index.to_reg(), 8),
477 1 << shift
478 ),
479 Amode::RipRelative { target } => format!("label{}(%rip)", target.as_u32()),
480 }
481 }
482}
483
484#[derive(Clone, Debug)]
488pub enum SyntheticAmode {
489 Real(Amode),
491
492 IncomingArg {
494 offset: u32,
496 },
497
498 SlotOffset {
501 simm32: i32,
503 },
504
505 ConstantOffset(VCodeConstant),
507}
508
509impl SyntheticAmode {
510 pub fn real(amode: Amode) -> Self {
512 Self::Real(amode)
513 }
514
515 pub(crate) fn slot_offset(simm32: i32) -> Self {
516 SyntheticAmode::SlotOffset { simm32 }
517 }
518
519 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
521 match self {
522 SyntheticAmode::Real(addr) => addr.get_operands(collector),
523 SyntheticAmode::IncomingArg { .. } => {
524 }
526 SyntheticAmode::SlotOffset { .. } => {
527 }
529 SyntheticAmode::ConstantOffset(_) => {}
530 }
531 }
532
533 pub(crate) fn get_operands_late(&mut self, collector: &mut impl OperandVisitor) {
535 match self {
536 SyntheticAmode::Real(addr) => addr.get_operands_late(collector),
537 SyntheticAmode::IncomingArg { .. } => {
538 }
540 SyntheticAmode::SlotOffset { .. } => {
541 }
543 SyntheticAmode::ConstantOffset(_) => {}
544 }
545 }
546
547 pub(crate) fn finalize(&self, frame: &FrameLayout, buffer: &mut MachBuffer<Inst>) -> Amode {
548 match self {
549 SyntheticAmode::Real(addr) => addr.clone(),
550 SyntheticAmode::IncomingArg { offset } => {
551 let args_max_fp_offset = frame.tail_args_size + frame.setup_area_size;
554 Amode::imm_reg(
555 i32::try_from(args_max_fp_offset - offset).unwrap(),
556 regs::rbp(),
557 )
558 }
559 SyntheticAmode::SlotOffset { simm32 } => {
560 let off = *simm32 as i64 + i64::from(frame.outgoing_args_size);
561 Amode::imm_reg(off.try_into().expect("invalid sp offset"), regs::rsp())
562 }
563 SyntheticAmode::ConstantOffset(c) => {
564 Amode::rip_relative(buffer.get_label_for_constant(*c))
565 }
566 }
567 }
568
569 pub(crate) fn aligned(&self) -> bool {
570 match self {
571 SyntheticAmode::Real(addr) => addr.aligned(),
572 &SyntheticAmode::IncomingArg { .. }
573 | SyntheticAmode::SlotOffset { .. }
574 | SyntheticAmode::ConstantOffset { .. } => true,
575 }
576 }
577}
578
579impl From<Amode> for SyntheticAmode {
580 fn from(amode: Amode) -> SyntheticAmode {
581 SyntheticAmode::Real(amode)
582 }
583}
584
585impl From<VCodeConstant> for SyntheticAmode {
586 fn from(c: VCodeConstant) -> SyntheticAmode {
587 SyntheticAmode::ConstantOffset(c)
588 }
589}
590
591impl PrettyPrint for SyntheticAmode {
592 fn pretty_print(&self, _size: u8) -> String {
593 match self {
594 SyntheticAmode::Real(addr) => addr.pretty_print(8),
596 &SyntheticAmode::IncomingArg { offset } => {
597 format!("rbp(stack args max - {offset})")
598 }
599 SyntheticAmode::SlotOffset { simm32 } => {
600 format!("rsp({} + virtual offset)", *simm32)
601 }
602 SyntheticAmode::ConstantOffset(c) => format!("const({})", c.as_u32()),
603 }
604 }
605}
606
607#[derive(Clone, Debug)]
612pub enum RegMemImm {
613 Reg {
615 reg: Reg,
617 },
618 Mem {
620 addr: SyntheticAmode,
622 },
623 Imm {
625 simm32: u32,
627 },
628}
629
630impl RegMemImm {
631 pub fn reg(reg: Reg) -> Self {
633 debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float);
634 Self::Reg { reg }
635 }
636
637 pub fn mem(addr: impl Into<SyntheticAmode>) -> Self {
639 Self::Mem { addr: addr.into() }
640 }
641
642 pub fn imm(simm32: u32) -> Self {
644 Self::Imm { simm32 }
645 }
646
647 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
649 match self {
650 Self::Reg { reg } => collector.reg_use(reg),
651 Self::Mem { addr } => addr.get_operands(collector),
652 Self::Imm { .. } => {}
653 }
654 }
655}
656
657impl From<RegMem> for RegMemImm {
658 fn from(rm: RegMem) -> RegMemImm {
659 match rm {
660 RegMem::Reg { reg } => RegMemImm::Reg { reg },
661 RegMem::Mem { addr } => RegMemImm::Mem { addr },
662 }
663 }
664}
665
666impl From<Reg> for RegMemImm {
667 fn from(reg: Reg) -> Self {
668 RegMemImm::Reg { reg }
669 }
670}
671
672impl PrettyPrint for RegMemImm {
673 fn pretty_print(&self, size: u8) -> String {
674 match self {
675 Self::Reg { reg } => pretty_print_reg(*reg, size),
676 Self::Mem { addr } => addr.pretty_print(size),
677 Self::Imm { simm32 } => format!("${}", *simm32 as i32),
678 }
679 }
680}
681
682#[derive(Clone, Debug)]
685pub enum RegMem {
686 Reg {
688 reg: Reg,
690 },
691 Mem {
693 addr: SyntheticAmode,
695 },
696}
697
698impl RegMem {
699 pub fn reg(reg: Reg) -> Self {
701 debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float);
702 Self::Reg { reg }
703 }
704
705 pub fn mem(addr: impl Into<SyntheticAmode>) -> Self {
707 Self::Mem { addr: addr.into() }
708 }
709 pub(crate) fn assert_regclass_is(&self, expected_reg_class: RegClass) {
711 if let Self::Reg { reg } = self {
712 debug_assert_eq!(reg.class(), expected_reg_class);
713 }
714 }
715 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
717 match self {
718 RegMem::Reg { reg } => collector.reg_use(reg),
719 RegMem::Mem { addr, .. } => addr.get_operands(collector),
720 }
721 }
722}
723
724impl From<Reg> for RegMem {
725 fn from(reg: Reg) -> RegMem {
726 RegMem::Reg { reg }
727 }
728}
729
730impl From<Writable<Reg>> for RegMem {
731 fn from(r: Writable<Reg>) -> Self {
732 RegMem::reg(r.to_reg())
733 }
734}
735
736impl PrettyPrint for RegMem {
737 fn pretty_print(&self, size: u8) -> String {
738 match self {
739 RegMem::Reg { reg } => pretty_print_reg(*reg, size),
740 RegMem::Mem { addr, .. } => addr.pretty_print(size),
741 }
742 }
743}
744
745#[derive(Debug)]
746pub(crate) enum InstructionSet {
747 SSE,
748 SSE2,
749 CMPXCHG16b,
750 SSE3,
751 SSSE3,
752 SSE41,
753 SSE42,
754 Popcnt,
755 Lzcnt,
756 BMI1,
757 #[allow(dead_code)] BMI2,
759 FMA,
760 AVX,
761 AVX2,
762 AVX512BITALG,
763 AVX512DQ,
764 AVX512F,
765 AVX512VBMI,
766 AVX512VL,
767}
768
769#[derive(Copy, Clone, PartialEq)]
770#[allow(missing_docs)]
771pub enum Avx512TupleType {
772 Full,
773 FullMem,
774 Mem128,
775}
776
777pub use crate::isa::x64::lower::isle::generated_code::Avx512Opcode;
778
779impl Avx512Opcode {
780 pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> {
782 match self {
783 Avx512Opcode::Vcvtudq2ps
784 | Avx512Opcode::Vpabsq
785 | Avx512Opcode::Vpsraq
786 | Avx512Opcode::VpsraqImm => {
787 smallvec![InstructionSet::AVX512F, InstructionSet::AVX512VL]
788 }
789 Avx512Opcode::Vpermi2b => {
790 smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512VBMI]
791 }
792 Avx512Opcode::Vpmullq => smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512DQ],
793 Avx512Opcode::Vpopcntb => {
794 smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512BITALG]
795 }
796 }
797 }
798
799 pub fn tuple_type(&self) -> Avx512TupleType {
806 use Avx512Opcode::*;
807 use Avx512TupleType::*;
808
809 match self {
810 Vcvtudq2ps | Vpabsq | Vpmullq | VpsraqImm => Full,
811 Vpermi2b | Vpopcntb => FullMem,
812 Vpsraq => Mem128,
813 }
814 }
815}
816
817impl fmt::Display for Avx512Opcode {
818 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
819 let s = format!("{self:?}");
820 f.write_str(&s.to_lowercase())
821 }
822}
823
824#[allow(dead_code)]
828#[derive(Clone, PartialEq)]
829pub enum ExtKind {
830 None,
832 SignExtend,
834 ZeroExtend,
836}
837
838#[derive(Clone, PartialEq)]
841pub enum ExtMode {
842 BL,
844 BQ,
846 WL,
848 WQ,
850 LQ,
852}
853
854impl ExtMode {
855 pub(crate) fn new(from_bits: u16, to_bits: u16) -> Option<ExtMode> {
857 match (from_bits, to_bits) {
858 (1, 8) | (1, 16) | (1, 32) | (8, 16) | (8, 32) => Some(ExtMode::BL),
859 (1, 64) | (8, 64) => Some(ExtMode::BQ),
860 (16, 32) => Some(ExtMode::WL),
861 (16, 64) => Some(ExtMode::WQ),
862 (32, 64) => Some(ExtMode::LQ),
863 _ => None,
864 }
865 }
866}
867
868impl fmt::Debug for ExtMode {
869 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
870 let name = match self {
871 ExtMode::BL => "bl",
872 ExtMode::BQ => "bq",
873 ExtMode::WL => "wl",
874 ExtMode::WQ => "wq",
875 ExtMode::LQ => "lq",
876 };
877 write!(fmt, "{name}")
878 }
879}
880
881impl fmt::Display for ExtMode {
882 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
883 fmt::Debug::fmt(self, f)
884 }
885}
886
887#[derive(Copy, Clone, PartialEq, Eq)]
890#[repr(u8)]
891pub enum CC {
892 O = 0,
894 NO = 1,
896
897 B = 2,
899 NB = 3,
901
902 Z = 4,
904 NZ = 5,
906
907 BE = 6,
909 NBE = 7,
911
912 S = 8,
914 NS = 9,
916
917 L = 12,
919 NL = 13,
921
922 LE = 14,
924 NLE = 15,
926
927 P = 10,
929
930 NP = 11,
932}
933
934impl CC {
935 pub(crate) fn from_intcc(intcc: IntCC) -> Self {
936 match intcc {
937 IntCC::Equal => CC::Z,
938 IntCC::NotEqual => CC::NZ,
939 IntCC::SignedGreaterThanOrEqual => CC::NL,
940 IntCC::SignedGreaterThan => CC::NLE,
941 IntCC::SignedLessThanOrEqual => CC::LE,
942 IntCC::SignedLessThan => CC::L,
943 IntCC::UnsignedGreaterThanOrEqual => CC::NB,
944 IntCC::UnsignedGreaterThan => CC::NBE,
945 IntCC::UnsignedLessThanOrEqual => CC::BE,
946 IntCC::UnsignedLessThan => CC::B,
947 }
948 }
949
950 pub(crate) fn invert(&self) -> Self {
951 match self {
952 CC::O => CC::NO,
953 CC::NO => CC::O,
954
955 CC::B => CC::NB,
956 CC::NB => CC::B,
957
958 CC::Z => CC::NZ,
959 CC::NZ => CC::Z,
960
961 CC::BE => CC::NBE,
962 CC::NBE => CC::BE,
963
964 CC::S => CC::NS,
965 CC::NS => CC::S,
966
967 CC::L => CC::NL,
968 CC::NL => CC::L,
969
970 CC::LE => CC::NLE,
971 CC::NLE => CC::LE,
972
973 CC::P => CC::NP,
974 CC::NP => CC::P,
975 }
976 }
977
978 pub(crate) fn get_enc(self) -> u8 {
979 self as u8
980 }
981}
982
983impl fmt::Debug for CC {
984 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
985 let name = match self {
986 CC::O => "o",
987 CC::NO => "no",
988 CC::B => "b",
989 CC::NB => "nb",
990 CC::Z => "z",
991 CC::NZ => "nz",
992 CC::BE => "be",
993 CC::NBE => "nbe",
994 CC::S => "s",
995 CC::NS => "ns",
996 CC::L => "l",
997 CC::NL => "nl",
998 CC::LE => "le",
999 CC::NLE => "nle",
1000 CC::P => "p",
1001 CC::NP => "np",
1002 };
1003 write!(fmt, "{name}")
1004 }
1005}
1006
1007impl fmt::Display for CC {
1008 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1009 fmt::Debug::fmt(self, f)
1010 }
1011}
1012
1013#[derive(Clone, Copy)]
1017pub enum FcmpImm {
1018 Equal = 0x00,
1020 LessThan = 0x01,
1022 LessThanOrEqual = 0x02,
1024 Unordered = 0x03,
1026 NotEqual = 0x04,
1028 UnorderedOrGreaterThanOrEqual = 0x05,
1030 UnorderedOrGreaterThan = 0x06,
1032 Ordered = 0x07,
1034}
1035
1036impl FcmpImm {
1037 pub(crate) fn encode(self) -> u8 {
1038 self as u8
1039 }
1040}
1041
1042impl From<FloatCC> for FcmpImm {
1043 fn from(cond: FloatCC) -> Self {
1044 match cond {
1045 FloatCC::Equal => FcmpImm::Equal,
1046 FloatCC::LessThan => FcmpImm::LessThan,
1047 FloatCC::LessThanOrEqual => FcmpImm::LessThanOrEqual,
1048 FloatCC::Unordered => FcmpImm::Unordered,
1049 FloatCC::NotEqual => FcmpImm::NotEqual,
1050 FloatCC::UnorderedOrGreaterThanOrEqual => FcmpImm::UnorderedOrGreaterThanOrEqual,
1051 FloatCC::UnorderedOrGreaterThan => FcmpImm::UnorderedOrGreaterThan,
1052 FloatCC::Ordered => FcmpImm::Ordered,
1053 _ => panic!("unable to create comparison predicate for {cond}"),
1054 }
1055 }
1056}
1057
1058#[derive(Clone, Copy)]
1065pub enum RoundImm {
1066 RoundNearest = 0x00,
1068 RoundDown = 0x01,
1070 RoundUp = 0x02,
1072 RoundZero = 0x03,
1074}
1075
1076impl RoundImm {
1077 pub(crate) fn encode(self) -> u8 {
1078 self as u8
1079 }
1080}
1081
1082#[derive(Clone, Copy, PartialEq)]
1084pub enum OperandSize {
1085 Size8,
1087 Size16,
1089 Size32,
1091 Size64,
1093}
1094
1095impl OperandSize {
1096 pub(crate) fn from_bytes(num_bytes: u32) -> Self {
1097 match num_bytes {
1098 1 => OperandSize::Size8,
1099 2 => OperandSize::Size16,
1100 4 => OperandSize::Size32,
1101 8 => OperandSize::Size64,
1102 _ => unreachable!("Invalid OperandSize: {}", num_bytes),
1103 }
1104 }
1105
1106 pub(crate) fn from_ty(ty: Type) -> Self {
1109 Self::from_bytes(ty.lane_type().bytes())
1110 }
1111
1112 pub(crate) fn is_one_of(&self, sizes: &[Self]) -> bool {
1114 sizes.iter().any(|val| *self == *val)
1115 }
1116
1117 pub(crate) fn to_bytes(&self) -> u8 {
1118 match self {
1119 Self::Size8 => 1,
1120 Self::Size16 => 2,
1121 Self::Size32 => 4,
1122 Self::Size64 => 8,
1123 }
1124 }
1125
1126 pub(crate) fn to_bits(&self) -> u8 {
1127 self.to_bytes() * 8
1128 }
1129}