1use crate::ir::types::*;
4use crate::isa::aarch64::inst::*;
5
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
11#[repr(u8)]
12pub enum ShiftOp {
13 LSL = 0b00,
15 LSR = 0b01,
17 ASR = 0b10,
19 ROR = 0b11,
21}
22
23impl ShiftOp {
24 pub fn bits(self) -> u8 {
26 self as u8
27 }
28}
29
30#[derive(Clone, Copy, Debug)]
32pub struct ShiftOpShiftImm(u8);
33
34impl ShiftOpShiftImm {
35 pub const MAX_SHIFT: u64 = 63;
37
38 pub fn maybe_from_shift(shift: u64) -> Option<ShiftOpShiftImm> {
40 if shift <= Self::MAX_SHIFT {
41 Some(ShiftOpShiftImm(shift as u8))
42 } else {
43 None
44 }
45 }
46
47 pub fn value(self) -> u8 {
49 self.0
50 }
51
52 pub fn mask(self, bits: u8) -> ShiftOpShiftImm {
54 ShiftOpShiftImm(self.0 & (bits - 1))
55 }
56}
57
58#[derive(Copy, Clone, Debug)]
60pub struct ShiftOpAndAmt {
61 op: ShiftOp,
63 shift: ShiftOpShiftImm,
65}
66
67impl ShiftOpAndAmt {
68 pub fn new(op: ShiftOp, shift: ShiftOpShiftImm) -> ShiftOpAndAmt {
70 ShiftOpAndAmt { op, shift }
71 }
72
73 pub fn op(&self) -> ShiftOp {
75 self.op
76 }
77
78 pub fn amt(&self) -> ShiftOpShiftImm {
80 self.shift
81 }
82}
83
84#[derive(Clone, Copy, Debug)]
86#[repr(u8)]
87pub enum ExtendOp {
88 UXTB = 0b000,
90 UXTH = 0b001,
92 UXTW = 0b010,
94 UXTX = 0b011,
96 SXTB = 0b100,
98 SXTH = 0b101,
100 SXTW = 0b110,
102 SXTX = 0b111,
104}
105
106impl ExtendOp {
107 pub fn bits(self) -> u8 {
109 self as u8
110 }
111
112 pub fn from_bits(self) -> u8 {
114 match self {
115 Self::UXTB | Self::SXTB => 8,
116 Self::UXTH | Self::SXTH => 16,
117 Self::UXTW | Self::SXTW => 32,
118 Self::UXTX | Self::SXTX => 64,
119 }
120 }
121}
122
123#[derive(Clone, Debug)]
128pub enum MemLabel {
129 PCRel(i32),
133 Mach(MachLabel),
136}
137
138impl AMode {
139 pub fn reg(reg: Reg) -> AMode {
141 AMode::UnsignedOffset {
144 rn: reg,
145 uimm12: UImm12Scaled::zero(I64),
146 }
147 }
148
149 pub fn reg_plus_reg_scaled_extended(reg1: Reg, reg2: Reg, op: ExtendOp) -> AMode {
152 AMode::RegScaledExtended {
153 rn: reg1,
154 rm: reg2,
155 extendop: op,
156 }
157 }
158}
159
160pub use crate::isa::aarch64::lower::isle::generated_code::PairAMode;
161
162#[derive(Clone, Copy, Debug, PartialEq, Eq)]
168#[repr(u8)]
169pub enum Cond {
170 Eq = 0,
172 Ne = 1,
174 Hs = 2,
176 Lo = 3,
178 Mi = 4,
180 Pl = 5,
182 Vs = 6,
184 Vc = 7,
186 Hi = 8,
188 Ls = 9,
190 Ge = 10,
192 Lt = 11,
194 Gt = 12,
196 Le = 13,
198 Al = 14,
200 Nv = 15,
202}
203
204impl Cond {
205 pub fn invert(self) -> Cond {
207 match self {
208 Cond::Eq => Cond::Ne,
209 Cond::Ne => Cond::Eq,
210
211 Cond::Hs => Cond::Lo,
212 Cond::Lo => Cond::Hs,
213
214 Cond::Mi => Cond::Pl,
215 Cond::Pl => Cond::Mi,
216
217 Cond::Vs => Cond::Vc,
218 Cond::Vc => Cond::Vs,
219
220 Cond::Hi => Cond::Ls,
221 Cond::Ls => Cond::Hi,
222
223 Cond::Ge => Cond::Lt,
224 Cond::Lt => Cond::Ge,
225
226 Cond::Gt => Cond::Le,
227 Cond::Le => Cond::Gt,
228
229 Cond::Al => Cond::Nv,
230 Cond::Nv => Cond::Al,
231 }
232 }
233
234 pub fn bits(self) -> u32 {
236 self as u32
237 }
238}
239
240#[derive(Clone, Copy, Debug)]
244pub enum CondBrKind {
245 Zero(Reg, OperandSize),
247 NotZero(Reg, OperandSize),
249 Cond(Cond),
251}
252
253impl CondBrKind {
254 pub fn invert(self) -> CondBrKind {
256 match self {
257 CondBrKind::Zero(reg, size) => CondBrKind::NotZero(reg, size),
258 CondBrKind::NotZero(reg, size) => CondBrKind::Zero(reg, size),
259 CondBrKind::Cond(c) => CondBrKind::Cond(c.invert()),
260 }
261 }
262}
263
264#[derive(Clone, Copy, Debug, PartialEq, Eq)]
267pub enum BranchTarget {
268 Label(MachLabel),
271 ResolvedOffset(i32),
273}
274
275impl BranchTarget {
276 pub fn as_label(self) -> Option<MachLabel> {
278 match self {
279 BranchTarget::Label(l) => Some(l),
280 _ => None,
281 }
282 }
283
284 pub fn as_offset14_or_zero(self) -> u32 {
286 self.as_offset_bounded(14)
287 }
288
289 pub fn as_offset19_or_zero(self) -> u32 {
291 self.as_offset_bounded(19)
292 }
293
294 pub fn as_offset26_or_zero(self) -> u32 {
296 self.as_offset_bounded(26)
297 }
298
299 fn as_offset_bounded(self, bits: u32) -> u32 {
300 let off = match self {
301 BranchTarget::ResolvedOffset(off) => off >> 2,
302 _ => 0,
303 };
304 let hi = (1 << (bits - 1)) - 1;
305 let lo = -(1 << bits - 1);
306 assert!(off <= hi);
307 assert!(off >= lo);
308 (off as u32) & ((1 << bits) - 1)
309 }
310}
311
312impl PrettyPrint for ShiftOpAndAmt {
313 fn pretty_print(&self, _: u8) -> String {
314 format!("{:?} {}", self.op(), self.amt().value())
315 }
316}
317
318impl PrettyPrint for ExtendOp {
319 fn pretty_print(&self, _: u8) -> String {
320 format!("{self:?}")
321 }
322}
323
324impl PrettyPrint for MemLabel {
325 fn pretty_print(&self, _: u8) -> String {
326 match self {
327 MemLabel::PCRel(off) => format!("pc+{off}"),
328 MemLabel::Mach(off) => format!("label({})", off.as_u32()),
329 }
330 }
331}
332
333fn shift_for_type(size_bytes: u8) -> usize {
334 match size_bytes {
335 1 => 0,
336 2 => 1,
337 4 => 2,
338 8 => 3,
339 16 => 4,
340 _ => panic!("unknown type size: {size_bytes}"),
341 }
342}
343
344impl PrettyPrint for AMode {
345 fn pretty_print(&self, size_bytes: u8) -> String {
346 debug_assert!(size_bytes != 0);
347 match self {
348 &AMode::Unscaled { rn, simm9 } => {
349 let reg = pretty_print_reg(rn);
350 if simm9.value != 0 {
351 let simm9 = simm9.pretty_print(8);
352 format!("[{reg}, {simm9}]")
353 } else {
354 format!("[{reg}]")
355 }
356 }
357 &AMode::UnsignedOffset { rn, uimm12 } => {
358 let reg = pretty_print_reg(rn);
359 if uimm12.value() != 0 {
360 let uimm12 = uimm12.pretty_print(8);
361 format!("[{reg}, {uimm12}]")
362 } else {
363 format!("[{reg}]")
364 }
365 }
366 &AMode::RegReg { rn, rm } => {
367 let r1 = pretty_print_reg(rn);
368 let r2 = pretty_print_reg(rm);
369 format!("[{r1}, {r2}]")
370 }
371 &AMode::RegScaled { rn, rm } => {
372 let r1 = pretty_print_reg(rn);
373 let r2 = pretty_print_reg(rm);
374 let shift = shift_for_type(size_bytes);
375 format!("[{r1}, {r2}, LSL #{shift}]")
376 }
377 &AMode::RegScaledExtended { rn, rm, extendop } => {
378 let shift = shift_for_type(size_bytes);
379 let size = match extendop {
380 ExtendOp::SXTW | ExtendOp::UXTW => OperandSize::Size32,
381 _ => OperandSize::Size64,
382 };
383 let r1 = pretty_print_reg(rn);
384 let r2 = pretty_print_ireg(rm, size);
385 let op = extendop.pretty_print(0);
386 format!("[{r1}, {r2}, {op} #{shift}]")
387 }
388 &AMode::RegExtended { rn, rm, extendop } => {
389 let size = match extendop {
390 ExtendOp::SXTW | ExtendOp::UXTW => OperandSize::Size32,
391 _ => OperandSize::Size64,
392 };
393 let r1 = pretty_print_reg(rn);
394 let r2 = pretty_print_ireg(rm, size);
395 let op = extendop.pretty_print(0);
396 format!("[{r1}, {r2}, {op}]")
397 }
398 &AMode::Label { ref label } => label.pretty_print(0),
399 &AMode::SPPreIndexed { simm9 } => {
400 let simm9 = simm9.pretty_print(8);
401 format!("[sp, {simm9}]!")
402 }
403 &AMode::SPPostIndexed { simm9 } => {
404 let simm9 = simm9.pretty_print(8);
405 format!("[sp], {simm9}")
406 }
407 AMode::Const { addr } => format!("[const({})]", addr.as_u32()),
408
409 &AMode::SPOffset { .. }
411 | &AMode::FPOffset { .. }
412 | &AMode::IncomingArg { .. }
413 | &AMode::SlotOffset { .. }
414 | &AMode::RegOffset { .. } => {
415 panic!("Unexpected pseudo mem-arg mode: {self:?}")
416 }
417 }
418 }
419}
420
421impl PrettyPrint for PairAMode {
422 fn pretty_print(&self, _: u8) -> String {
423 match self {
424 &PairAMode::SignedOffset { reg, simm7 } => {
425 let reg = pretty_print_reg(reg);
426 if simm7.value != 0 {
427 let simm7 = simm7.pretty_print(8);
428 format!("[{reg}, {simm7}]")
429 } else {
430 format!("[{reg}]")
431 }
432 }
433 &PairAMode::SPPreIndexed { simm7 } => {
434 let simm7 = simm7.pretty_print(8);
435 format!("[sp, {simm7}]!")
436 }
437 &PairAMode::SPPostIndexed { simm7 } => {
438 let simm7 = simm7.pretty_print(8);
439 format!("[sp], {simm7}")
440 }
441 }
442 }
443}
444
445impl PrettyPrint for Cond {
446 fn pretty_print(&self, _: u8) -> String {
447 let mut s = format!("{self:?}");
448 s.make_ascii_lowercase();
449 s
450 }
451}
452
453impl PrettyPrint for BranchTarget {
454 fn pretty_print(&self, _: u8) -> String {
455 match self {
456 &BranchTarget::Label(label) => format!("label{:?}", label.as_u32()),
457 &BranchTarget::ResolvedOffset(off) => format!("{off}"),
458 }
459 }
460}
461
462#[derive(Clone, Copy, Debug, PartialEq, Eq)]
465pub enum OperandSize {
466 Size32,
468 Size64,
470}
471
472impl OperandSize {
473 pub fn is32(self) -> bool {
475 self == OperandSize::Size32
476 }
477
478 pub fn is64(self) -> bool {
480 self == OperandSize::Size64
481 }
482
483 pub fn from_bits<I: Into<usize>>(bits: I) -> OperandSize {
485 let bits: usize = bits.into();
486 assert!(bits <= 64);
487 if bits <= 32 {
488 OperandSize::Size32
489 } else {
490 OperandSize::Size64
491 }
492 }
493
494 pub fn bits(&self) -> u8 {
496 match self {
497 OperandSize::Size32 => 32,
498 OperandSize::Size64 => 64,
499 }
500 }
501
502 pub fn from_ty(ty: Type) -> OperandSize {
504 debug_assert!(!ty.is_vector());
505
506 Self::from_bits(ty_bits(ty))
507 }
508
509 pub fn to_ty(self) -> Type {
511 match self {
512 OperandSize::Size32 => I32,
513 OperandSize::Size64 => I64,
514 }
515 }
516
517 pub fn sf_bit(&self) -> u32 {
521 match self {
522 OperandSize::Size32 => 0,
523 OperandSize::Size64 => 1,
524 }
525 }
526
527 pub fn max_value(&self) -> u64 {
529 match self {
530 OperandSize::Size32 => u32::MAX as u64,
531 OperandSize::Size64 => u64::MAX,
532 }
533 }
534}
535
536#[derive(Clone, Copy, Debug, PartialEq, Eq)]
538pub enum ScalarSize {
539 Size8,
541 Size16,
543 Size32,
545 Size64,
547 Size128,
549}
550
551impl ScalarSize {
552 pub fn operand_size(&self) -> OperandSize {
554 match self {
555 ScalarSize::Size8 | ScalarSize::Size16 | ScalarSize::Size32 => OperandSize::Size32,
556 ScalarSize::Size64 => OperandSize::Size64,
557 _ => panic!("Unexpected operand_size request for: {self:?}"),
558 }
559 }
560
561 pub fn ftype(&self) -> u32 {
564 match self {
565 ScalarSize::Size16 => 0b11,
566 ScalarSize::Size32 => 0b00,
567 ScalarSize::Size64 => 0b01,
568 _ => panic!("Unexpected scalar FP operand size: {self:?}"),
569 }
570 }
571
572 pub fn widen(&self) -> ScalarSize {
574 match self {
575 ScalarSize::Size8 => ScalarSize::Size16,
576 ScalarSize::Size16 => ScalarSize::Size32,
577 ScalarSize::Size32 => ScalarSize::Size64,
578 ScalarSize::Size64 => ScalarSize::Size128,
579 ScalarSize::Size128 => panic!("can't widen 128-bits"),
580 }
581 }
582
583 pub fn narrow(&self) -> ScalarSize {
585 match self {
586 ScalarSize::Size8 => panic!("can't narrow 8-bits"),
587 ScalarSize::Size16 => ScalarSize::Size8,
588 ScalarSize::Size32 => ScalarSize::Size16,
589 ScalarSize::Size64 => ScalarSize::Size32,
590 ScalarSize::Size128 => ScalarSize::Size64,
591 }
592 }
593
594 pub fn ty(&self) -> Type {
596 match self {
597 ScalarSize::Size8 => I8,
598 ScalarSize::Size16 => I16,
599 ScalarSize::Size32 => I32,
600 ScalarSize::Size64 => I64,
601 ScalarSize::Size128 => I128,
602 }
603 }
604}
605
606#[derive(Clone, Copy, Debug, PartialEq, Eq)]
608pub enum VectorSize {
609 Size8x8,
611 Size8x16,
613 Size16x4,
615 Size16x8,
617 Size32x2,
619 Size32x4,
621 Size64x2,
623}
624
625impl VectorSize {
626 pub fn as_scalar8_vector(&self) -> VectorSize {
628 match self {
629 VectorSize::Size8x8 | VectorSize::Size16x4 | VectorSize::Size32x2 => {
631 VectorSize::Size8x8
632 }
633 VectorSize::Size8x16
635 | VectorSize::Size16x8
636 | VectorSize::Size32x4
637 | VectorSize::Size64x2 => VectorSize::Size8x16,
638 }
639 }
640
641 pub fn from_lane_size(size: ScalarSize, is_128bit: bool) -> VectorSize {
643 match (size, is_128bit) {
644 (ScalarSize::Size8, false) => VectorSize::Size8x8,
645 (ScalarSize::Size8, true) => VectorSize::Size8x16,
646 (ScalarSize::Size16, false) => VectorSize::Size16x4,
647 (ScalarSize::Size16, true) => VectorSize::Size16x8,
648 (ScalarSize::Size32, false) => VectorSize::Size32x2,
649 (ScalarSize::Size32, true) => VectorSize::Size32x4,
650 (ScalarSize::Size64, true) => VectorSize::Size64x2,
651 _ => panic!("Unexpected scalar FP operand size: {size:?}"),
652 }
653 }
654
655 pub fn operand_size(&self) -> OperandSize {
657 match self {
658 VectorSize::Size64x2 => OperandSize::Size64,
659 _ => OperandSize::Size32,
660 }
661 }
662
663 pub fn lane_size(&self) -> ScalarSize {
665 match self {
666 VectorSize::Size8x8 | VectorSize::Size8x16 => ScalarSize::Size8,
667 VectorSize::Size16x4 | VectorSize::Size16x8 => ScalarSize::Size16,
668 VectorSize::Size32x2 | VectorSize::Size32x4 => ScalarSize::Size32,
669 VectorSize::Size64x2 => ScalarSize::Size64,
670 }
671 }
672
673 pub fn is_128bits(&self) -> bool {
675 match self {
676 VectorSize::Size8x8 => false,
677 VectorSize::Size8x16 => true,
678 VectorSize::Size16x4 => false,
679 VectorSize::Size16x8 => true,
680 VectorSize::Size32x2 => false,
681 VectorSize::Size32x4 => true,
682 VectorSize::Size64x2 => true,
683 }
684 }
685
686 pub fn enc_size(&self) -> (u32, u32) {
689 let q = self.is_128bits() as u32;
690 let size = match self.lane_size() {
691 ScalarSize::Size8 => 0b00,
692 ScalarSize::Size16 => 0b01,
693 ScalarSize::Size32 => 0b10,
694 ScalarSize::Size64 => 0b11,
695 _ => unreachable!(),
696 };
697
698 (q, size)
699 }
700
701 pub fn enc_float_size(&self) -> u32 {
704 match self.lane_size() {
705 ScalarSize::Size32 => 0b0,
706 ScalarSize::Size64 => 0b1,
707 size => panic!("Unsupported floating-point size for vector op: {size:?}"),
708 }
709 }
710}
711
712impl APIKey {
713 pub fn enc_auti_hint(&self) -> u32 {
716 let (crm, op2) = match self {
717 APIKey::AZ => (0b0011, 0b100),
718 APIKey::ASP => (0b0011, 0b101),
719 APIKey::BZ => (0b0011, 0b110),
720 APIKey::BSP => (0b0011, 0b111),
721 };
722 0xd503201f | (crm << 8) | (op2 << 5)
723 }
724}
725
726#[derive(Clone, Debug)]
733#[expect(missing_docs, reason = "self-describing fields")]
734pub struct AtomicCAS128Args {
735 pub rd_lo: Writable<Reg>,
736 pub rd_hi: Writable<Reg>,
737 pub rs_lo: Reg,
738 pub rs_hi: Reg,
739 pub rt_lo: Reg,
740 pub rt_hi: Reg,
741 pub rn: Reg,
742 pub flags: MemFlagsData,
743}
744
745pub use crate::isa::aarch64::lower::isle::generated_code::TestBitAndBranchKind;
746
747impl TestBitAndBranchKind {
748 pub fn complement(&self) -> TestBitAndBranchKind {
750 match self {
751 TestBitAndBranchKind::Z => TestBitAndBranchKind::NZ,
752 TestBitAndBranchKind::NZ => TestBitAndBranchKind::Z,
753 }
754 }
755}