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
307newtype_of_reg!(
309 Xmm,
310 WritableXmm,
311 OptionWritableXmm,
312 reg_mem: (XmmMem, XmmMemAligned aligned:true),
313 reg_mem_imm: (XmmMemImm, XmmMemAlignedImm aligned:true),
314 |reg| reg.class() == RegClass::Float
315);
316
317pub use crate::isa::x64::lower::isle::generated_code::Amode;
322
323impl Amode {
324 pub fn imm_reg(simm32: i32, base: Reg) -> Self {
326 debug_assert!(base.class() == RegClass::Int);
327 Self::ImmReg {
328 simm32,
329 base,
330 flags: MemFlags::trusted(),
331 }
332 }
333
334 pub fn imm_reg_reg_shift(simm32: i32, base: Gpr, index: Gpr, shift: u8) -> Self {
336 debug_assert!(base.class() == RegClass::Int);
337 debug_assert!(index.class() == RegClass::Int);
338 debug_assert!(shift <= 3);
339 Self::ImmRegRegShift {
340 simm32,
341 base,
342 index,
343 shift,
344 flags: MemFlags::trusted(),
345 }
346 }
347
348 pub(crate) fn rip_relative(target: MachLabel) -> Self {
349 Self::RipRelative { target }
350 }
351
352 pub fn with_flags(&self, flags: MemFlags) -> Self {
354 match self {
355 &Self::ImmReg { simm32, base, .. } => Self::ImmReg {
356 simm32,
357 base,
358 flags,
359 },
360 &Self::ImmRegRegShift {
361 simm32,
362 base,
363 index,
364 shift,
365 ..
366 } => Self::ImmRegRegShift {
367 simm32,
368 base,
369 index,
370 shift,
371 flags,
372 },
373 _ => panic!("Amode {self:?} cannot take memflags"),
374 }
375 }
376
377 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
379 match self {
380 Amode::ImmReg { base, .. } => {
381 if *base != regs::rbp() && *base != regs::rsp() {
382 collector.reg_use(base);
383 }
384 }
385 Amode::ImmRegRegShift { base, index, .. } => {
386 debug_assert_ne!(base.to_reg(), regs::rbp());
387 debug_assert_ne!(base.to_reg(), regs::rsp());
388 collector.reg_use(base);
389 debug_assert_ne!(index.to_reg(), regs::rbp());
390 debug_assert_ne!(index.to_reg(), regs::rsp());
391 collector.reg_use(index);
392 }
393 Amode::RipRelative { .. } => {
394 }
396 }
397 }
398
399 pub(crate) fn get_operands_late(&mut self, collector: &mut impl OperandVisitor) {
401 match self {
402 Amode::ImmReg { base, .. } => {
403 collector.reg_late_use(base);
404 }
405 Amode::ImmRegRegShift { base, index, .. } => {
406 collector.reg_late_use(base);
407 collector.reg_late_use(index);
408 }
409 Amode::RipRelative { .. } => {
410 }
412 }
413 }
414
415 pub(crate) fn get_flags(&self) -> MemFlags {
416 match self {
417 Amode::ImmReg { flags, .. } | Amode::ImmRegRegShift { flags, .. } => *flags,
418 Amode::RipRelative { .. } => MemFlags::trusted(),
419 }
420 }
421
422 pub(crate) fn offset(&self, offset: i32) -> Self {
424 let mut ret = self.clone();
425 match &mut ret {
426 &mut Amode::ImmReg { ref mut simm32, .. } => *simm32 += offset,
427 &mut Amode::ImmRegRegShift { ref mut simm32, .. } => *simm32 += offset,
428 _ => panic!("Cannot offset amode: {self:?}"),
429 }
430 ret
431 }
432
433 pub(crate) fn aligned(&self) -> bool {
434 self.get_flags().aligned()
435 }
436}
437
438impl PrettyPrint for Amode {
439 fn pretty_print(&self, _size: u8) -> String {
440 match self {
441 Amode::ImmReg { simm32, base, .. } => {
442 format!("{}({})", *simm32, pretty_print_reg(*base, 8))
445 }
446 Amode::ImmRegRegShift {
447 simm32,
448 base,
449 index,
450 shift,
451 ..
452 } => format!(
453 "{}({},{},{})",
454 *simm32,
455 pretty_print_reg(base.to_reg(), 8),
456 pretty_print_reg(index.to_reg(), 8),
457 1 << shift
458 ),
459 Amode::RipRelative { target } => format!("label{}(%rip)", target.as_u32()),
460 }
461 }
462}
463
464#[derive(Clone, Debug)]
468pub enum SyntheticAmode {
469 Real(Amode),
471
472 IncomingArg {
474 offset: u32,
476 },
477
478 SlotOffset {
481 simm32: i32,
483 },
484
485 ConstantOffset(VCodeConstant),
487}
488
489impl SyntheticAmode {
490 pub fn real(amode: Amode) -> Self {
492 Self::Real(amode)
493 }
494
495 pub(crate) fn slot_offset(simm32: i32) -> Self {
496 SyntheticAmode::SlotOffset { simm32 }
497 }
498
499 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
501 match self {
502 SyntheticAmode::Real(addr) => addr.get_operands(collector),
503 SyntheticAmode::IncomingArg { .. } => {
504 }
506 SyntheticAmode::SlotOffset { .. } => {
507 }
509 SyntheticAmode::ConstantOffset(_) => {}
510 }
511 }
512
513 pub(crate) fn get_operands_late(&mut self, collector: &mut impl OperandVisitor) {
515 match self {
516 SyntheticAmode::Real(addr) => addr.get_operands_late(collector),
517 SyntheticAmode::IncomingArg { .. } => {
518 }
520 SyntheticAmode::SlotOffset { .. } => {
521 }
523 SyntheticAmode::ConstantOffset(_) => {}
524 }
525 }
526
527 pub(crate) fn finalize(&self, frame: &FrameLayout, buffer: &mut MachBuffer<Inst>) -> Amode {
528 match self {
529 SyntheticAmode::Real(addr) => addr.clone(),
530 SyntheticAmode::IncomingArg { offset } => {
531 let args_max_fp_offset = frame.tail_args_size + frame.setup_area_size;
534 Amode::imm_reg(
535 i32::try_from(args_max_fp_offset - offset).unwrap(),
536 regs::rbp(),
537 )
538 }
539 SyntheticAmode::SlotOffset { simm32 } => {
540 let off = *simm32 as i64 + i64::from(frame.outgoing_args_size);
541 Amode::imm_reg(off.try_into().expect("invalid sp offset"), regs::rsp())
542 }
543 SyntheticAmode::ConstantOffset(c) => {
544 Amode::rip_relative(buffer.get_label_for_constant(*c))
545 }
546 }
547 }
548
549 pub(crate) fn aligned(&self) -> bool {
550 match self {
551 SyntheticAmode::Real(addr) => addr.aligned(),
552 &SyntheticAmode::IncomingArg { .. }
553 | SyntheticAmode::SlotOffset { .. }
554 | SyntheticAmode::ConstantOffset { .. } => true,
555 }
556 }
557}
558
559impl From<Amode> for SyntheticAmode {
560 fn from(amode: Amode) -> SyntheticAmode {
561 SyntheticAmode::Real(amode)
562 }
563}
564
565impl From<VCodeConstant> for SyntheticAmode {
566 fn from(c: VCodeConstant) -> SyntheticAmode {
567 SyntheticAmode::ConstantOffset(c)
568 }
569}
570
571impl PrettyPrint for SyntheticAmode {
572 fn pretty_print(&self, _size: u8) -> String {
573 match self {
574 SyntheticAmode::Real(addr) => addr.pretty_print(8),
576 &SyntheticAmode::IncomingArg { offset } => {
577 format!("rbp(stack args max - {offset})")
578 }
579 SyntheticAmode::SlotOffset { simm32 } => {
580 format!("rsp({} + virtual offset)", *simm32)
581 }
582 SyntheticAmode::ConstantOffset(c) => format!("const({})", c.as_u32()),
583 }
584 }
585}
586
587#[derive(Clone, Debug)]
592pub enum RegMemImm {
593 Reg {
595 reg: Reg,
597 },
598 Mem {
600 addr: SyntheticAmode,
602 },
603 Imm {
605 simm32: u32,
607 },
608}
609
610impl RegMemImm {
611 pub fn reg(reg: Reg) -> Self {
613 debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float);
614 Self::Reg { reg }
615 }
616
617 pub fn mem(addr: impl Into<SyntheticAmode>) -> Self {
619 Self::Mem { addr: addr.into() }
620 }
621
622 pub fn imm(simm32: u32) -> Self {
624 Self::Imm { simm32 }
625 }
626
627 pub(crate) fn assert_regclass_is(&self, expected_reg_class: RegClass) {
629 if let Self::Reg { reg } = self {
630 debug_assert_eq!(reg.class(), expected_reg_class);
631 }
632 }
633
634 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
636 match self {
637 Self::Reg { reg } => collector.reg_use(reg),
638 Self::Mem { addr } => addr.get_operands(collector),
639 Self::Imm { .. } => {}
640 }
641 }
642}
643
644impl From<RegMem> for RegMemImm {
645 fn from(rm: RegMem) -> RegMemImm {
646 match rm {
647 RegMem::Reg { reg } => RegMemImm::Reg { reg },
648 RegMem::Mem { addr } => RegMemImm::Mem { addr },
649 }
650 }
651}
652
653impl From<Reg> for RegMemImm {
654 fn from(reg: Reg) -> Self {
655 RegMemImm::Reg { reg }
656 }
657}
658
659impl PrettyPrint for RegMemImm {
660 fn pretty_print(&self, size: u8) -> String {
661 match self {
662 Self::Reg { reg } => pretty_print_reg(*reg, size),
663 Self::Mem { addr } => addr.pretty_print(size),
664 Self::Imm { simm32 } => format!("${}", *simm32 as i32),
665 }
666 }
667}
668
669#[derive(Clone, Debug)]
672pub enum RegMem {
673 Reg {
675 reg: Reg,
677 },
678 Mem {
680 addr: SyntheticAmode,
682 },
683}
684
685impl RegMem {
686 pub fn reg(reg: Reg) -> Self {
688 debug_assert!(reg.class() == RegClass::Int || reg.class() == RegClass::Float);
689 Self::Reg { reg }
690 }
691
692 pub fn mem(addr: impl Into<SyntheticAmode>) -> Self {
694 Self::Mem { addr: addr.into() }
695 }
696 pub(crate) fn assert_regclass_is(&self, expected_reg_class: RegClass) {
698 if let Self::Reg { reg } = self {
699 debug_assert_eq!(reg.class(), expected_reg_class);
700 }
701 }
702 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
704 match self {
705 RegMem::Reg { reg } => collector.reg_use(reg),
706 RegMem::Mem { addr, .. } => addr.get_operands(collector),
707 }
708 }
709}
710
711impl From<Reg> for RegMem {
712 fn from(reg: Reg) -> RegMem {
713 RegMem::Reg { reg }
714 }
715}
716
717impl From<Writable<Reg>> for RegMem {
718 fn from(r: Writable<Reg>) -> Self {
719 RegMem::reg(r.to_reg())
720 }
721}
722
723impl PrettyPrint for RegMem {
724 fn pretty_print(&self, size: u8) -> String {
725 match self {
726 RegMem::Reg { reg } => pretty_print_reg(*reg, size),
727 RegMem::Mem { addr, .. } => addr.pretty_print(size),
728 }
729 }
730}
731
732#[derive(Clone, Copy, PartialEq)]
733pub enum CmpOpcode {
735 Cmp,
737 Test,
739}
740
741#[derive(Debug)]
742pub(crate) enum InstructionSet {
743 SSE,
744 SSE2,
745 CMPXCHG16b,
746 SSE3,
747 SSSE3,
748 SSE41,
749 SSE42,
750 Popcnt,
751 Lzcnt,
752 BMI1,
753 #[allow(dead_code)] BMI2,
755 FMA,
756 AVX,
757 AVX2,
758 AVX512BITALG,
759 AVX512DQ,
760 AVX512F,
761 AVX512VBMI,
762 AVX512VL,
763}
764
765#[derive(Clone, Copy, PartialEq)]
767#[allow(dead_code)] #[allow(missing_docs)]
769pub enum SseOpcode {
770 Blendvpd,
771 Blendvps,
772 Comiss,
773 Comisd,
774 Cmpps,
775 Cmppd,
776 Cmpss,
777 Cmpsd,
778 Insertps,
779 Movlhps,
780 Pabsb,
781 Pabsw,
782 Pabsd,
783 Packssdw,
784 Packsswb,
785 Packusdw,
786 Packuswb,
787 Palignr,
788 Pavgb,
789 Pavgw,
790 Pblendvb,
791 Pcmpeqb,
792 Pcmpeqw,
793 Pcmpeqd,
794 Pcmpeqq,
795 Pcmpgtb,
796 Pcmpgtw,
797 Pcmpgtd,
798 Pcmpgtq,
799 Pmaddubsw,
800 Pmaddwd,
801 Pshufb,
802 Pshufd,
803 Ptest,
804 Rcpss,
805 Roundps,
806 Roundpd,
807 Roundss,
808 Roundsd,
809 Rsqrtss,
810 Shufps,
811 Ucomiss,
812 Ucomisd,
813 Pshuflw,
814 Pshufhw,
815 Pblendw,
816}
817
818impl SseOpcode {
819 pub(crate) fn available_from(&self) -> InstructionSet {
821 use InstructionSet::*;
822 match self {
823 SseOpcode::Comiss
824 | SseOpcode::Cmpps
825 | SseOpcode::Cmpss
826 | SseOpcode::Movlhps
827 | SseOpcode::Rcpss
828 | SseOpcode::Rsqrtss
829 | SseOpcode::Shufps
830 | SseOpcode::Ucomiss => SSE,
831
832 SseOpcode::Cmppd
833 | SseOpcode::Cmpsd
834 | SseOpcode::Comisd
835 | SseOpcode::Packssdw
836 | SseOpcode::Packsswb
837 | SseOpcode::Packuswb
838 | SseOpcode::Pavgb
839 | SseOpcode::Pavgw
840 | SseOpcode::Pcmpeqb
841 | SseOpcode::Pcmpeqw
842 | SseOpcode::Pcmpeqd
843 | SseOpcode::Pcmpgtb
844 | SseOpcode::Pcmpgtw
845 | SseOpcode::Pcmpgtd
846 | SseOpcode::Pmaddwd
847 | SseOpcode::Pshufd
848 | SseOpcode::Ucomisd
849 | SseOpcode::Pshuflw
850 | SseOpcode::Pshufhw => SSE2,
851
852 SseOpcode::Pabsb
853 | SseOpcode::Pabsw
854 | SseOpcode::Pabsd
855 | SseOpcode::Palignr
856 | SseOpcode::Pshufb
857 | SseOpcode::Pmaddubsw => SSSE3,
858
859 SseOpcode::Blendvpd
860 | SseOpcode::Blendvps
861 | SseOpcode::Insertps
862 | SseOpcode::Packusdw
863 | SseOpcode::Pblendvb
864 | SseOpcode::Pcmpeqq
865 | SseOpcode::Ptest
866 | SseOpcode::Roundps
867 | SseOpcode::Roundpd
868 | SseOpcode::Roundss
869 | SseOpcode::Roundsd
870 | SseOpcode::Pblendw => SSE41,
871
872 SseOpcode::Pcmpgtq => SSE42,
873 }
874 }
875
876 pub(crate) fn src_size(&self) -> u8 {
878 match self {
879 _ => 8,
880 }
881 }
882
883 pub(crate) fn has_scalar_src2(self) -> bool {
885 false
886 }
887}
888
889impl fmt::Debug for SseOpcode {
890 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
891 let name = match self {
892 SseOpcode::Blendvpd => "blendvpd",
893 SseOpcode::Blendvps => "blendvps",
894 SseOpcode::Cmpps => "cmpps",
895 SseOpcode::Cmppd => "cmppd",
896 SseOpcode::Cmpss => "cmpss",
897 SseOpcode::Cmpsd => "cmpsd",
898 SseOpcode::Comiss => "comiss",
899 SseOpcode::Comisd => "comisd",
900 SseOpcode::Insertps => "insertps",
901 SseOpcode::Movlhps => "movlhps",
902 SseOpcode::Pabsb => "pabsb",
903 SseOpcode::Pabsw => "pabsw",
904 SseOpcode::Pabsd => "pabsd",
905 SseOpcode::Packssdw => "packssdw",
906 SseOpcode::Packsswb => "packsswb",
907 SseOpcode::Packusdw => "packusdw",
908 SseOpcode::Packuswb => "packuswb",
909 SseOpcode::Palignr => "palignr",
910 SseOpcode::Pavgb => "pavgb",
911 SseOpcode::Pavgw => "pavgw",
912 SseOpcode::Pblendvb => "pblendvb",
913 SseOpcode::Pcmpeqb => "pcmpeqb",
914 SseOpcode::Pcmpeqw => "pcmpeqw",
915 SseOpcode::Pcmpeqd => "pcmpeqd",
916 SseOpcode::Pcmpeqq => "pcmpeqq",
917 SseOpcode::Pcmpgtb => "pcmpgtb",
918 SseOpcode::Pcmpgtw => "pcmpgtw",
919 SseOpcode::Pcmpgtd => "pcmpgtd",
920 SseOpcode::Pcmpgtq => "pcmpgtq",
921 SseOpcode::Pmaddubsw => "pmaddubsw",
922 SseOpcode::Pmaddwd => "pmaddwd",
923 SseOpcode::Pshufb => "pshufb",
924 SseOpcode::Pshufd => "pshufd",
925 SseOpcode::Ptest => "ptest",
926 SseOpcode::Rcpss => "rcpss",
927 SseOpcode::Roundps => "roundps",
928 SseOpcode::Roundpd => "roundpd",
929 SseOpcode::Roundss => "roundss",
930 SseOpcode::Roundsd => "roundsd",
931 SseOpcode::Rsqrtss => "rsqrtss",
932 SseOpcode::Shufps => "shufps",
933 SseOpcode::Ucomiss => "ucomiss",
934 SseOpcode::Ucomisd => "ucomisd",
935 SseOpcode::Pshuflw => "pshuflw",
936 SseOpcode::Pshufhw => "pshufhw",
937 SseOpcode::Pblendw => "pblendw",
938 };
939 write!(fmt, "{name}")
940 }
941}
942
943impl fmt::Display for SseOpcode {
944 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
945 fmt::Debug::fmt(self, f)
946 }
947}
948
949pub use crate::isa::x64::lower::isle::generated_code::AvxOpcode;
950
951impl AvxOpcode {
952 pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> {
954 match self {
955 AvxOpcode::Vfmadd213ss
956 | AvxOpcode::Vfmadd213sd
957 | AvxOpcode::Vfmadd213ps
958 | AvxOpcode::Vfmadd213pd
959 | AvxOpcode::Vfmadd132ss
960 | AvxOpcode::Vfmadd132sd
961 | AvxOpcode::Vfmadd132ps
962 | AvxOpcode::Vfmadd132pd
963 | AvxOpcode::Vfnmadd213ss
964 | AvxOpcode::Vfnmadd213sd
965 | AvxOpcode::Vfnmadd213ps
966 | AvxOpcode::Vfnmadd213pd
967 | AvxOpcode::Vfnmadd132ss
968 | AvxOpcode::Vfnmadd132sd
969 | AvxOpcode::Vfnmadd132ps
970 | AvxOpcode::Vfnmadd132pd
971 | AvxOpcode::Vfmsub213ss
972 | AvxOpcode::Vfmsub213sd
973 | AvxOpcode::Vfmsub213ps
974 | AvxOpcode::Vfmsub213pd
975 | AvxOpcode::Vfmsub132ss
976 | AvxOpcode::Vfmsub132sd
977 | AvxOpcode::Vfmsub132ps
978 | AvxOpcode::Vfmsub132pd
979 | AvxOpcode::Vfnmsub213ss
980 | AvxOpcode::Vfnmsub213sd
981 | AvxOpcode::Vfnmsub213ps
982 | AvxOpcode::Vfnmsub213pd
983 | AvxOpcode::Vfnmsub132ss
984 | AvxOpcode::Vfnmsub132sd
985 | AvxOpcode::Vfnmsub132ps
986 | AvxOpcode::Vfnmsub132pd => smallvec![InstructionSet::FMA],
987 AvxOpcode::Vminps
988 | AvxOpcode::Vminpd
989 | AvxOpcode::Vmaxps
990 | AvxOpcode::Vmaxpd
991 | AvxOpcode::Vandnps
992 | AvxOpcode::Vandnpd
993 | AvxOpcode::Vpandn
994 | AvxOpcode::Vcmpps
995 | AvxOpcode::Vcmppd
996 | AvxOpcode::Vpsrlw
997 | AvxOpcode::Vpsrld
998 | AvxOpcode::Vpsrlq
999 | AvxOpcode::Vpaddb
1000 | AvxOpcode::Vpaddw
1001 | AvxOpcode::Vpaddd
1002 | AvxOpcode::Vpaddq
1003 | AvxOpcode::Vpaddsb
1004 | AvxOpcode::Vpaddsw
1005 | AvxOpcode::Vpaddusb
1006 | AvxOpcode::Vpaddusw
1007 | AvxOpcode::Vpsubb
1008 | AvxOpcode::Vpsubw
1009 | AvxOpcode::Vpsubd
1010 | AvxOpcode::Vpsubq
1011 | AvxOpcode::Vpsubsb
1012 | AvxOpcode::Vpsubsw
1013 | AvxOpcode::Vpsubusb
1014 | AvxOpcode::Vpsubusw
1015 | AvxOpcode::Vpavgb
1016 | AvxOpcode::Vpavgw
1017 | AvxOpcode::Vpand
1018 | AvxOpcode::Vandps
1019 | AvxOpcode::Vandpd
1020 | AvxOpcode::Vpor
1021 | AvxOpcode::Vorps
1022 | AvxOpcode::Vorpd
1023 | AvxOpcode::Vpxor
1024 | AvxOpcode::Vxorps
1025 | AvxOpcode::Vxorpd
1026 | AvxOpcode::Vpmullw
1027 | AvxOpcode::Vpmulld
1028 | AvxOpcode::Vpmulhw
1029 | AvxOpcode::Vpmulhd
1030 | AvxOpcode::Vpmulhrsw
1031 | AvxOpcode::Vpmulhuw
1032 | AvxOpcode::Vpmuldq
1033 | AvxOpcode::Vpmuludq
1034 | AvxOpcode::Vpunpckhwd
1035 | AvxOpcode::Vpunpcklwd
1036 | AvxOpcode::Vunpcklps
1037 | AvxOpcode::Vunpckhps
1038 | AvxOpcode::Vaddps
1039 | AvxOpcode::Vaddpd
1040 | AvxOpcode::Vsubps
1041 | AvxOpcode::Vsubpd
1042 | AvxOpcode::Vmulps
1043 | AvxOpcode::Vmulpd
1044 | AvxOpcode::Vdivps
1045 | AvxOpcode::Vdivpd
1046 | AvxOpcode::Vpcmpeqb
1047 | AvxOpcode::Vpcmpeqw
1048 | AvxOpcode::Vpcmpeqd
1049 | AvxOpcode::Vpcmpeqq
1050 | AvxOpcode::Vpcmpgtb
1051 | AvxOpcode::Vpcmpgtw
1052 | AvxOpcode::Vpcmpgtd
1053 | AvxOpcode::Vpcmpgtq
1054 | AvxOpcode::Vblendvps
1055 | AvxOpcode::Vblendvpd
1056 | AvxOpcode::Vpblendvb
1057 | AvxOpcode::Vmovlhps
1058 | AvxOpcode::Vpminsb
1059 | AvxOpcode::Vpminsw
1060 | AvxOpcode::Vpminsd
1061 | AvxOpcode::Vpminub
1062 | AvxOpcode::Vpminuw
1063 | AvxOpcode::Vpminud
1064 | AvxOpcode::Vpmaxsb
1065 | AvxOpcode::Vpmaxsw
1066 | AvxOpcode::Vpmaxsd
1067 | AvxOpcode::Vpmaxub
1068 | AvxOpcode::Vpmaxuw
1069 | AvxOpcode::Vpmaxud
1070 | AvxOpcode::Vpunpcklbw
1071 | AvxOpcode::Vpunpckhbw
1072 | AvxOpcode::Vpacksswb
1073 | AvxOpcode::Vpackssdw
1074 | AvxOpcode::Vpackuswb
1075 | AvxOpcode::Vpackusdw
1076 | AvxOpcode::Vpalignr
1077 | AvxOpcode::Vpmaddwd
1078 | AvxOpcode::Vpmaddubsw
1079 | AvxOpcode::Vinsertps
1080 | AvxOpcode::Vpshufb
1081 | AvxOpcode::Vshufps
1082 | AvxOpcode::Vpsllw
1083 | AvxOpcode::Vpslld
1084 | AvxOpcode::Vpsllq
1085 | AvxOpcode::Vpsraw
1086 | AvxOpcode::Vpsrad
1087 | AvxOpcode::Vpmovsxbw
1088 | AvxOpcode::Vpmovzxbw
1089 | AvxOpcode::Vpmovsxwd
1090 | AvxOpcode::Vpmovzxwd
1091 | AvxOpcode::Vpmovsxdq
1092 | AvxOpcode::Vpmovzxdq
1093 | AvxOpcode::Vaddss
1094 | AvxOpcode::Vaddsd
1095 | AvxOpcode::Vmulss
1096 | AvxOpcode::Vmulsd
1097 | AvxOpcode::Vsubss
1098 | AvxOpcode::Vsubsd
1099 | AvxOpcode::Vdivss
1100 | AvxOpcode::Vdivsd
1101 | AvxOpcode::Vpabsb
1102 | AvxOpcode::Vpabsw
1103 | AvxOpcode::Vpabsd
1104 | AvxOpcode::Vminss
1105 | AvxOpcode::Vminsd
1106 | AvxOpcode::Vmaxss
1107 | AvxOpcode::Vmaxsd
1108 | AvxOpcode::Vsqrtps
1109 | AvxOpcode::Vsqrtpd
1110 | AvxOpcode::Vroundpd
1111 | AvxOpcode::Vroundps
1112 | AvxOpcode::Vphaddw
1113 | AvxOpcode::Vphaddd
1114 | AvxOpcode::Vpunpckldq
1115 | AvxOpcode::Vpunpckhdq
1116 | AvxOpcode::Vpunpcklqdq
1117 | AvxOpcode::Vpunpckhqdq
1118 | AvxOpcode::Vpshuflw
1119 | AvxOpcode::Vpshufhw
1120 | AvxOpcode::Vpshufd
1121 | AvxOpcode::Vmovss
1122 | AvxOpcode::Vmovsd
1123 | AvxOpcode::Vmovups
1124 | AvxOpcode::Vmovupd
1125 | AvxOpcode::Vmovdqu
1126 | AvxOpcode::Vpextrb
1127 | AvxOpcode::Vpextrw
1128 | AvxOpcode::Vpextrd
1129 | AvxOpcode::Vpextrq
1130 | AvxOpcode::Vpblendw
1131 | AvxOpcode::Vbroadcastss
1132 | AvxOpcode::Vsqrtss
1133 | AvxOpcode::Vsqrtsd
1134 | AvxOpcode::Vroundss
1135 | AvxOpcode::Vroundsd
1136 | AvxOpcode::Vunpcklpd
1137 | AvxOpcode::Vptest
1138 | AvxOpcode::Vucomiss
1139 | AvxOpcode::Vucomisd => {
1140 smallvec![InstructionSet::AVX]
1141 }
1142
1143 AvxOpcode::Vpbroadcastb | AvxOpcode::Vpbroadcastw | AvxOpcode::Vpbroadcastd => {
1144 smallvec![InstructionSet::AVX2]
1145 }
1146 }
1147 }
1148
1149 pub(crate) fn is_commutative(&self) -> bool {
1154 match *self {
1155 AvxOpcode::Vpaddb
1156 | AvxOpcode::Vpaddw
1157 | AvxOpcode::Vpaddd
1158 | AvxOpcode::Vpaddq
1159 | AvxOpcode::Vpaddsb
1160 | AvxOpcode::Vpaddsw
1161 | AvxOpcode::Vpaddusb
1162 | AvxOpcode::Vpaddusw
1163 | AvxOpcode::Vpand
1164 | AvxOpcode::Vandps
1165 | AvxOpcode::Vandpd
1166 | AvxOpcode::Vpor
1167 | AvxOpcode::Vorps
1168 | AvxOpcode::Vorpd
1169 | AvxOpcode::Vpxor
1170 | AvxOpcode::Vxorps
1171 | AvxOpcode::Vxorpd
1172 | AvxOpcode::Vpmuldq
1173 | AvxOpcode::Vpmuludq
1174 | AvxOpcode::Vaddps
1175 | AvxOpcode::Vaddpd
1176 | AvxOpcode::Vmulps
1177 | AvxOpcode::Vmulpd
1178 | AvxOpcode::Vpcmpeqb
1179 | AvxOpcode::Vpcmpeqw
1180 | AvxOpcode::Vpcmpeqd
1181 | AvxOpcode::Vpcmpeqq
1182 | AvxOpcode::Vaddss
1183 | AvxOpcode::Vaddsd
1184 | AvxOpcode::Vmulss
1185 | AvxOpcode::Vmulsd => true,
1186 _ => false,
1187 }
1188 }
1189}
1190
1191impl fmt::Display for AvxOpcode {
1192 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1193 format!("{self:?}").to_lowercase().fmt(f)
1194 }
1195}
1196
1197#[derive(Copy, Clone, PartialEq)]
1198#[allow(missing_docs)]
1199pub enum Avx512TupleType {
1200 Full,
1201 FullMem,
1202 Mem128,
1203}
1204
1205pub use crate::isa::x64::lower::isle::generated_code::Avx512Opcode;
1206
1207impl Avx512Opcode {
1208 pub(crate) fn available_from(&self) -> SmallVec<[InstructionSet; 2]> {
1210 match self {
1211 Avx512Opcode::Vcvtudq2ps
1212 | Avx512Opcode::Vpabsq
1213 | Avx512Opcode::Vpsraq
1214 | Avx512Opcode::VpsraqImm => {
1215 smallvec![InstructionSet::AVX512F, InstructionSet::AVX512VL]
1216 }
1217 Avx512Opcode::Vpermi2b => {
1218 smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512VBMI]
1219 }
1220 Avx512Opcode::Vpmullq => smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512DQ],
1221 Avx512Opcode::Vpopcntb => {
1222 smallvec![InstructionSet::AVX512VL, InstructionSet::AVX512BITALG]
1223 }
1224 }
1225 }
1226
1227 pub fn tuple_type(&self) -> Avx512TupleType {
1234 use Avx512Opcode::*;
1235 use Avx512TupleType::*;
1236
1237 match self {
1238 Vcvtudq2ps | Vpabsq | Vpmullq | VpsraqImm => Full,
1239 Vpermi2b | Vpopcntb => FullMem,
1240 Vpsraq => Mem128,
1241 }
1242 }
1243}
1244
1245impl fmt::Display for Avx512Opcode {
1246 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1247 let s = format!("{self:?}");
1248 f.write_str(&s.to_lowercase())
1249 }
1250}
1251
1252#[allow(dead_code)]
1256#[derive(Clone, PartialEq)]
1257pub enum ExtKind {
1258 None,
1260 SignExtend,
1262 ZeroExtend,
1264}
1265
1266#[derive(Clone, PartialEq)]
1269pub enum ExtMode {
1270 BL,
1272 BQ,
1274 WL,
1276 WQ,
1278 LQ,
1280}
1281
1282impl ExtMode {
1283 pub(crate) fn new(from_bits: u16, to_bits: u16) -> Option<ExtMode> {
1285 match (from_bits, to_bits) {
1286 (1, 8) | (1, 16) | (1, 32) | (8, 16) | (8, 32) => Some(ExtMode::BL),
1287 (1, 64) | (8, 64) => Some(ExtMode::BQ),
1288 (16, 32) => Some(ExtMode::WL),
1289 (16, 64) => Some(ExtMode::WQ),
1290 (32, 64) => Some(ExtMode::LQ),
1291 _ => None,
1292 }
1293 }
1294}
1295
1296impl fmt::Debug for ExtMode {
1297 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1298 let name = match self {
1299 ExtMode::BL => "bl",
1300 ExtMode::BQ => "bq",
1301 ExtMode::WL => "wl",
1302 ExtMode::WQ => "wq",
1303 ExtMode::LQ => "lq",
1304 };
1305 write!(fmt, "{name}")
1306 }
1307}
1308
1309impl fmt::Display for ExtMode {
1310 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1311 fmt::Debug::fmt(self, f)
1312 }
1313}
1314
1315#[derive(Copy, Clone, PartialEq, Eq)]
1318#[repr(u8)]
1319pub enum CC {
1320 O = 0,
1322 NO = 1,
1324
1325 B = 2,
1327 NB = 3,
1329
1330 Z = 4,
1332 NZ = 5,
1334
1335 BE = 6,
1337 NBE = 7,
1339
1340 S = 8,
1342 NS = 9,
1344
1345 L = 12,
1347 NL = 13,
1349
1350 LE = 14,
1352 NLE = 15,
1354
1355 P = 10,
1357
1358 NP = 11,
1360}
1361
1362impl CC {
1363 pub(crate) fn from_intcc(intcc: IntCC) -> Self {
1364 match intcc {
1365 IntCC::Equal => CC::Z,
1366 IntCC::NotEqual => CC::NZ,
1367 IntCC::SignedGreaterThanOrEqual => CC::NL,
1368 IntCC::SignedGreaterThan => CC::NLE,
1369 IntCC::SignedLessThanOrEqual => CC::LE,
1370 IntCC::SignedLessThan => CC::L,
1371 IntCC::UnsignedGreaterThanOrEqual => CC::NB,
1372 IntCC::UnsignedGreaterThan => CC::NBE,
1373 IntCC::UnsignedLessThanOrEqual => CC::BE,
1374 IntCC::UnsignedLessThan => CC::B,
1375 }
1376 }
1377
1378 pub(crate) fn invert(&self) -> Self {
1379 match self {
1380 CC::O => CC::NO,
1381 CC::NO => CC::O,
1382
1383 CC::B => CC::NB,
1384 CC::NB => CC::B,
1385
1386 CC::Z => CC::NZ,
1387 CC::NZ => CC::Z,
1388
1389 CC::BE => CC::NBE,
1390 CC::NBE => CC::BE,
1391
1392 CC::S => CC::NS,
1393 CC::NS => CC::S,
1394
1395 CC::L => CC::NL,
1396 CC::NL => CC::L,
1397
1398 CC::LE => CC::NLE,
1399 CC::NLE => CC::LE,
1400
1401 CC::P => CC::NP,
1402 CC::NP => CC::P,
1403 }
1404 }
1405
1406 pub(crate) fn get_enc(self) -> u8 {
1407 self as u8
1408 }
1409}
1410
1411impl fmt::Debug for CC {
1412 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1413 let name = match self {
1414 CC::O => "o",
1415 CC::NO => "no",
1416 CC::B => "b",
1417 CC::NB => "nb",
1418 CC::Z => "z",
1419 CC::NZ => "nz",
1420 CC::BE => "be",
1421 CC::NBE => "nbe",
1422 CC::S => "s",
1423 CC::NS => "ns",
1424 CC::L => "l",
1425 CC::NL => "nl",
1426 CC::LE => "le",
1427 CC::NLE => "nle",
1428 CC::P => "p",
1429 CC::NP => "np",
1430 };
1431 write!(fmt, "{name}")
1432 }
1433}
1434
1435impl fmt::Display for CC {
1436 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1437 fmt::Debug::fmt(self, f)
1438 }
1439}
1440
1441#[derive(Clone, Copy)]
1445pub enum FcmpImm {
1446 Equal = 0x00,
1448 LessThan = 0x01,
1450 LessThanOrEqual = 0x02,
1452 Unordered = 0x03,
1454 NotEqual = 0x04,
1456 UnorderedOrGreaterThanOrEqual = 0x05,
1458 UnorderedOrGreaterThan = 0x06,
1460 Ordered = 0x07,
1462}
1463
1464impl FcmpImm {
1465 pub(crate) fn encode(self) -> u8 {
1466 self as u8
1467 }
1468}
1469
1470impl From<FloatCC> for FcmpImm {
1471 fn from(cond: FloatCC) -> Self {
1472 match cond {
1473 FloatCC::Equal => FcmpImm::Equal,
1474 FloatCC::LessThan => FcmpImm::LessThan,
1475 FloatCC::LessThanOrEqual => FcmpImm::LessThanOrEqual,
1476 FloatCC::Unordered => FcmpImm::Unordered,
1477 FloatCC::NotEqual => FcmpImm::NotEqual,
1478 FloatCC::UnorderedOrGreaterThanOrEqual => FcmpImm::UnorderedOrGreaterThanOrEqual,
1479 FloatCC::UnorderedOrGreaterThan => FcmpImm::UnorderedOrGreaterThan,
1480 FloatCC::Ordered => FcmpImm::Ordered,
1481 _ => panic!("unable to create comparison predicate for {cond}"),
1482 }
1483 }
1484}
1485
1486#[derive(Clone, Copy)]
1493pub enum RoundImm {
1494 RoundNearest = 0x00,
1496 RoundDown = 0x01,
1498 RoundUp = 0x02,
1500 RoundZero = 0x03,
1502}
1503
1504impl RoundImm {
1505 pub(crate) fn encode(self) -> u8 {
1506 self as u8
1507 }
1508}
1509
1510#[derive(Clone, Copy, PartialEq)]
1512pub enum OperandSize {
1513 Size8,
1515 Size16,
1517 Size32,
1519 Size64,
1521}
1522
1523impl OperandSize {
1524 pub(crate) fn from_bytes(num_bytes: u32) -> Self {
1525 match num_bytes {
1526 1 => OperandSize::Size8,
1527 2 => OperandSize::Size16,
1528 4 => OperandSize::Size32,
1529 8 => OperandSize::Size64,
1530 _ => unreachable!("Invalid OperandSize: {}", num_bytes),
1531 }
1532 }
1533
1534 pub(crate) fn from_ty(ty: Type) -> Self {
1537 Self::from_bytes(ty.lane_type().bytes())
1538 }
1539
1540 pub(crate) fn is_one_of(&self, sizes: &[Self]) -> bool {
1542 sizes.iter().any(|val| *self == *val)
1543 }
1544
1545 pub(crate) fn to_bytes(&self) -> u8 {
1546 match self {
1547 Self::Size8 => 1,
1548 Self::Size16 => 2,
1549 Self::Size32 => 4,
1550 Self::Size64 => 8,
1551 }
1552 }
1553
1554 pub(crate) fn to_bits(&self) -> u8 {
1555 self.to_bytes() * 8
1556 }
1557
1558 pub(crate) fn to_type(&self) -> Type {
1559 match self {
1560 Self::Size8 => I8,
1561 Self::Size16 => I16,
1562 Self::Size32 => I32,
1563 Self::Size64 => I64,
1564 }
1565 }
1566}
1567
1568#[derive(Clone)]
1570#[allow(dead_code)]
1571pub enum FenceKind {
1572 MFence,
1574 LFence,
1576 SFence,
1578}