1use crate::binemit::{Addend, CodeOffset, Reloc};
4use crate::ir::types::{F128, F16, F32, F64, I128, I16, I32, I64, I8, I8X16};
5use crate::ir::{types, MemFlags, Type};
6use crate::isa::{CallConv, FunctionAlignment};
7use crate::machinst::*;
8use crate::{settings, CodegenError, CodegenResult};
9
10use crate::machinst::{PrettyPrint, Reg, RegClass, Writable};
11
12use alloc::vec::Vec;
13use smallvec::{smallvec, SmallVec};
14use std::fmt::Write;
15use std::string::{String, ToString};
16
17pub(crate) mod regs;
18pub(crate) use self::regs::*;
19pub mod imms;
20pub use self::imms::*;
21pub mod args;
22pub use self::args::*;
23pub mod emit;
24pub(crate) use self::emit::*;
25use crate::isa::aarch64::abi::AArch64MachineDeps;
26
27pub(crate) mod unwind;
28
29#[cfg(test)]
30mod emit_tests;
31
32pub use crate::isa::aarch64::lower::isle::generated_code::{
36 ALUOp, ALUOp3, AMode, APIKey, AtomicRMWLoopOp, AtomicRMWOp, BitOp, BranchTargetType, FPUOp1,
37 FPUOp2, FPUOp3, FpuRoundMode, FpuToIntOp, IntToFpuOp, MInst as Inst, MoveWideOp, VecALUModOp,
38 VecALUOp, VecExtendOp, VecLanesOp, VecMisc2, VecPairOp, VecRRLongOp, VecRRNarrowOp,
39 VecRRPairLongOp, VecRRRLongModOp, VecRRRLongOp, VecShiftImmModOp, VecShiftImmOp,
40};
41
42#[derive(Copy, Clone, Debug)]
44pub enum FPUOpRI {
45 UShr32(FPURightShiftImm),
47 UShr64(FPURightShiftImm),
49}
50
51#[derive(Copy, Clone, Debug)]
55pub enum FPUOpRIMod {
56 Sli32(FPULeftShiftImm),
58 Sli64(FPULeftShiftImm),
60}
61
62impl BitOp {
63 pub fn op_str(&self) -> &'static str {
65 match self {
66 BitOp::RBit => "rbit",
67 BitOp::Clz => "clz",
68 BitOp::Cls => "cls",
69 BitOp::Rev16 => "rev16",
70 BitOp::Rev32 => "rev32",
71 BitOp::Rev64 => "rev64",
72 }
73 }
74}
75
76#[derive(Clone, Debug)]
79pub struct ReturnCallInfo<T> {
80 pub dest: T,
82 pub uses: CallArgList,
84 pub new_stack_arg_size: u32,
88 pub key: Option<APIKey>,
90}
91
92fn count_zero_half_words(mut value: u64, num_half_words: u8) -> usize {
93 let mut count = 0;
94 for _ in 0..num_half_words {
95 if value & 0xffff == 0 {
96 count += 1;
97 }
98 value >>= 16;
99 }
100
101 count
102}
103
104impl Inst {
105 pub fn load_constant<F: FnMut(Type) -> Writable<Reg>>(
108 rd: Writable<Reg>,
109 value: u64,
110 alloc_tmp: &mut F,
111 ) -> SmallVec<[Inst; 4]> {
112 if let Some(imm) = MoveWideConst::maybe_from_u64(value) {
117 smallvec![Inst::MovWide {
119 op: MoveWideOp::MovZ,
120 rd,
121 imm,
122 size: OperandSize::Size64
123 }]
124 } else if let Some(imm) = MoveWideConst::maybe_from_u64(!value) {
125 smallvec![Inst::MovWide {
127 op: MoveWideOp::MovN,
128 rd,
129 imm,
130 size: OperandSize::Size64
131 }]
132 } else if let Some(imml) = ImmLogic::maybe_from_u64(value, I64) {
133 smallvec![Inst::AluRRImmLogic {
135 alu_op: ALUOp::Orr,
136 size: OperandSize::Size64,
137 rd,
138 rn: zero_reg(),
139 imml,
140 }]
141 } else {
142 let mut insts = smallvec![];
143
144 let (num_half_words, size, negated) = if value >> 32 == 0 {
146 (2, OperandSize::Size32, (!value << 32) >> 32)
147 } else {
148 (4, OperandSize::Size64, !value)
149 };
150
151 let first_is_inverted = count_zero_half_words(negated, num_half_words)
154 > count_zero_half_words(value, num_half_words);
155
156 let ignored_halfword = if first_is_inverted { 0xffff } else { 0 };
159
160 let halfwords: SmallVec<[_; 4]> = (0..num_half_words)
161 .filter_map(|i| {
162 let imm16 = (value >> (16 * i)) & 0xffff;
163 if imm16 == ignored_halfword {
164 None
165 } else {
166 Some((i, imm16))
167 }
168 })
169 .collect();
170
171 let mut prev_result = None;
172 let last_index = halfwords.last().unwrap().0;
173 for (i, imm16) in halfwords {
174 let shift = i * 16;
175 let rd = if i == last_index { rd } else { alloc_tmp(I16) };
176
177 if let Some(rn) = prev_result {
178 let imm = MoveWideConst::maybe_with_shift(imm16 as u16, shift).unwrap();
179 insts.push(Inst::MovK { rd, rn, imm, size });
180 } else {
181 if first_is_inverted {
182 let imm =
183 MoveWideConst::maybe_with_shift(((!imm16) & 0xffff) as u16, shift)
184 .unwrap();
185 insts.push(Inst::MovWide {
186 op: MoveWideOp::MovN,
187 rd,
188 imm,
189 size,
190 });
191 } else {
192 let imm = MoveWideConst::maybe_with_shift(imm16 as u16, shift).unwrap();
193 insts.push(Inst::MovWide {
194 op: MoveWideOp::MovZ,
195 rd,
196 imm,
197 size,
198 });
199 }
200 }
201
202 prev_result = Some(rd.to_reg());
203 }
204
205 assert!(prev_result.is_some());
206
207 insts
208 }
209 }
210
211 pub fn gen_load(into_reg: Writable<Reg>, mem: AMode, ty: Type, flags: MemFlags) -> Inst {
213 match ty {
214 I8 => Inst::ULoad8 {
215 rd: into_reg,
216 mem,
217 flags,
218 },
219 I16 => Inst::ULoad16 {
220 rd: into_reg,
221 mem,
222 flags,
223 },
224 I32 => Inst::ULoad32 {
225 rd: into_reg,
226 mem,
227 flags,
228 },
229 I64 => Inst::ULoad64 {
230 rd: into_reg,
231 mem,
232 flags,
233 },
234 F16 => Inst::FpuLoad16 {
235 rd: into_reg,
236 mem,
237 flags,
238 },
239 F32 => Inst::FpuLoad32 {
240 rd: into_reg,
241 mem,
242 flags,
243 },
244 F64 => Inst::FpuLoad64 {
245 rd: into_reg,
246 mem,
247 flags,
248 },
249 _ => {
250 if ty.is_vector() || ty.is_float() {
251 let bits = ty_bits(ty);
252 let rd = into_reg;
253
254 if bits == 128 {
255 Inst::FpuLoad128 { rd, mem, flags }
256 } else {
257 assert_eq!(bits, 64);
258 Inst::FpuLoad64 { rd, mem, flags }
259 }
260 } else {
261 unimplemented!("gen_load({})", ty);
262 }
263 }
264 }
265 }
266
267 pub fn gen_store(mem: AMode, from_reg: Reg, ty: Type, flags: MemFlags) -> Inst {
269 match ty {
270 I8 => Inst::Store8 {
271 rd: from_reg,
272 mem,
273 flags,
274 },
275 I16 => Inst::Store16 {
276 rd: from_reg,
277 mem,
278 flags,
279 },
280 I32 => Inst::Store32 {
281 rd: from_reg,
282 mem,
283 flags,
284 },
285 I64 => Inst::Store64 {
286 rd: from_reg,
287 mem,
288 flags,
289 },
290 F16 => Inst::FpuStore16 {
291 rd: from_reg,
292 mem,
293 flags,
294 },
295 F32 => Inst::FpuStore32 {
296 rd: from_reg,
297 mem,
298 flags,
299 },
300 F64 => Inst::FpuStore64 {
301 rd: from_reg,
302 mem,
303 flags,
304 },
305 _ => {
306 if ty.is_vector() || ty.is_float() {
307 let bits = ty_bits(ty);
308 let rd = from_reg;
309
310 if bits == 128 {
311 Inst::FpuStore128 { rd, mem, flags }
312 } else {
313 assert_eq!(bits, 64);
314 Inst::FpuStore64 { rd, mem, flags }
315 }
316 } else {
317 unimplemented!("gen_store({})", ty);
318 }
319 }
320 }
321 }
322
323 pub fn mem_type(&self) -> Option<Type> {
327 match self {
328 Inst::ULoad8 { .. } => Some(I8),
329 Inst::SLoad8 { .. } => Some(I8),
330 Inst::ULoad16 { .. } => Some(I16),
331 Inst::SLoad16 { .. } => Some(I16),
332 Inst::ULoad32 { .. } => Some(I32),
333 Inst::SLoad32 { .. } => Some(I32),
334 Inst::ULoad64 { .. } => Some(I64),
335 Inst::FpuLoad16 { .. } => Some(F16),
336 Inst::FpuLoad32 { .. } => Some(F32),
337 Inst::FpuLoad64 { .. } => Some(F64),
338 Inst::FpuLoad128 { .. } => Some(I8X16),
339 Inst::Store8 { .. } => Some(I8),
340 Inst::Store16 { .. } => Some(I16),
341 Inst::Store32 { .. } => Some(I32),
342 Inst::Store64 { .. } => Some(I64),
343 Inst::FpuStore16 { .. } => Some(F16),
344 Inst::FpuStore32 { .. } => Some(F32),
345 Inst::FpuStore64 { .. } => Some(F64),
346 Inst::FpuStore128 { .. } => Some(I8X16),
347 _ => None,
348 }
349 }
350}
351
352fn memarg_operands(memarg: &mut AMode, collector: &mut impl OperandVisitor) {
356 match memarg {
357 AMode::Unscaled { rn, .. } | AMode::UnsignedOffset { rn, .. } => {
358 collector.reg_use(rn);
359 }
360 AMode::RegReg { rn, rm, .. }
361 | AMode::RegScaled { rn, rm, .. }
362 | AMode::RegScaledExtended { rn, rm, .. }
363 | AMode::RegExtended { rn, rm, .. } => {
364 collector.reg_use(rn);
365 collector.reg_use(rm);
366 }
367 AMode::Label { .. } => {}
368 AMode::SPPreIndexed { .. } | AMode::SPPostIndexed { .. } => {}
369 AMode::FPOffset { .. } | AMode::IncomingArg { .. } => {}
370 AMode::SPOffset { .. } | AMode::SlotOffset { .. } => {}
371 AMode::RegOffset { rn, .. } => {
372 collector.reg_use(rn);
373 }
374 AMode::Const { .. } => {}
375 }
376}
377
378fn pairmemarg_operands(pairmemarg: &mut PairAMode, collector: &mut impl OperandVisitor) {
379 match pairmemarg {
380 PairAMode::SignedOffset { reg, .. } => {
381 collector.reg_use(reg);
382 }
383 PairAMode::SPPreIndexed { .. } | PairAMode::SPPostIndexed { .. } => {}
384 }
385}
386
387fn aarch64_get_operands(inst: &mut Inst, collector: &mut impl OperandVisitor) {
388 match inst {
389 Inst::AluRRR { rd, rn, rm, .. } => {
390 collector.reg_def(rd);
391 collector.reg_use(rn);
392 collector.reg_use(rm);
393 }
394 Inst::AluRRRR { rd, rn, rm, ra, .. } => {
395 collector.reg_def(rd);
396 collector.reg_use(rn);
397 collector.reg_use(rm);
398 collector.reg_use(ra);
399 }
400 Inst::AluRRImm12 { rd, rn, .. } => {
401 collector.reg_def(rd);
402 collector.reg_use(rn);
403 }
404 Inst::AluRRImmLogic { rd, rn, .. } => {
405 collector.reg_def(rd);
406 collector.reg_use(rn);
407 }
408 Inst::AluRRImmShift { rd, rn, .. } => {
409 collector.reg_def(rd);
410 collector.reg_use(rn);
411 }
412 Inst::AluRRRShift { rd, rn, rm, .. } => {
413 collector.reg_def(rd);
414 collector.reg_use(rn);
415 collector.reg_use(rm);
416 }
417 Inst::AluRRRExtend { rd, rn, rm, .. } => {
418 collector.reg_def(rd);
419 collector.reg_use(rn);
420 collector.reg_use(rm);
421 }
422 Inst::BitRR { rd, rn, .. } => {
423 collector.reg_def(rd);
424 collector.reg_use(rn);
425 }
426 Inst::ULoad8 { rd, mem, .. }
427 | Inst::SLoad8 { rd, mem, .. }
428 | Inst::ULoad16 { rd, mem, .. }
429 | Inst::SLoad16 { rd, mem, .. }
430 | Inst::ULoad32 { rd, mem, .. }
431 | Inst::SLoad32 { rd, mem, .. }
432 | Inst::ULoad64 { rd, mem, .. } => {
433 collector.reg_def(rd);
434 memarg_operands(mem, collector);
435 }
436 Inst::Store8 { rd, mem, .. }
437 | Inst::Store16 { rd, mem, .. }
438 | Inst::Store32 { rd, mem, .. }
439 | Inst::Store64 { rd, mem, .. } => {
440 collector.reg_use(rd);
441 memarg_operands(mem, collector);
442 }
443 Inst::StoreP64 { rt, rt2, mem, .. } => {
444 collector.reg_use(rt);
445 collector.reg_use(rt2);
446 pairmemarg_operands(mem, collector);
447 }
448 Inst::LoadP64 { rt, rt2, mem, .. } => {
449 collector.reg_def(rt);
450 collector.reg_def(rt2);
451 pairmemarg_operands(mem, collector);
452 }
453 Inst::Mov { rd, rm, .. } => {
454 collector.reg_def(rd);
455 collector.reg_use(rm);
456 }
457 Inst::MovFromPReg { rd, rm } => {
458 debug_assert!(rd.to_reg().is_virtual());
459 collector.reg_def(rd);
460 collector.reg_fixed_nonallocatable(*rm);
461 }
462 Inst::MovToPReg { rd, rm } => {
463 debug_assert!(rm.is_virtual());
464 collector.reg_fixed_nonallocatable(*rd);
465 collector.reg_use(rm);
466 }
467 Inst::MovK { rd, rn, .. } => {
468 collector.reg_use(rn);
469 collector.reg_reuse_def(rd, 0); }
471 Inst::MovWide { rd, .. } => {
472 collector.reg_def(rd);
473 }
474 Inst::CSel { rd, rn, rm, .. } => {
475 collector.reg_def(rd);
476 collector.reg_use(rn);
477 collector.reg_use(rm);
478 }
479 Inst::CSNeg { rd, rn, rm, .. } => {
480 collector.reg_def(rd);
481 collector.reg_use(rn);
482 collector.reg_use(rm);
483 }
484 Inst::CSet { rd, .. } | Inst::CSetm { rd, .. } => {
485 collector.reg_def(rd);
486 }
487 Inst::CCmp { rn, rm, .. } => {
488 collector.reg_use(rn);
489 collector.reg_use(rm);
490 }
491 Inst::CCmpImm { rn, .. } => {
492 collector.reg_use(rn);
493 }
494 Inst::AtomicRMWLoop {
495 op,
496 addr,
497 operand,
498 oldval,
499 scratch1,
500 scratch2,
501 ..
502 } => {
503 collector.reg_fixed_use(addr, xreg(25));
504 collector.reg_fixed_use(operand, xreg(26));
505 collector.reg_fixed_def(oldval, xreg(27));
506 collector.reg_fixed_def(scratch1, xreg(24));
507 if *op != AtomicRMWLoopOp::Xchg {
508 collector.reg_fixed_def(scratch2, xreg(28));
509 }
510 }
511 Inst::AtomicRMW { rs, rt, rn, .. } => {
512 collector.reg_use(rs);
513 collector.reg_def(rt);
514 collector.reg_use(rn);
515 }
516 Inst::AtomicCAS { rd, rs, rt, rn, .. } => {
517 collector.reg_reuse_def(rd, 1); collector.reg_use(rs);
519 collector.reg_use(rt);
520 collector.reg_use(rn);
521 }
522 Inst::AtomicCASLoop {
523 addr,
524 expected,
525 replacement,
526 oldval,
527 scratch,
528 ..
529 } => {
530 collector.reg_fixed_use(addr, xreg(25));
531 collector.reg_fixed_use(expected, xreg(26));
532 collector.reg_fixed_use(replacement, xreg(28));
533 collector.reg_fixed_def(oldval, xreg(27));
534 collector.reg_fixed_def(scratch, xreg(24));
535 }
536 Inst::LoadAcquire { rt, rn, .. } => {
537 collector.reg_use(rn);
538 collector.reg_def(rt);
539 }
540 Inst::StoreRelease { rt, rn, .. } => {
541 collector.reg_use(rn);
542 collector.reg_use(rt);
543 }
544 Inst::Fence {} | Inst::Csdb {} => {}
545 Inst::FpuMove32 { rd, rn } => {
546 collector.reg_def(rd);
547 collector.reg_use(rn);
548 }
549 Inst::FpuMove64 { rd, rn } => {
550 collector.reg_def(rd);
551 collector.reg_use(rn);
552 }
553 Inst::FpuMove128 { rd, rn } => {
554 collector.reg_def(rd);
555 collector.reg_use(rn);
556 }
557 Inst::FpuMoveFromVec { rd, rn, .. } => {
558 collector.reg_def(rd);
559 collector.reg_use(rn);
560 }
561 Inst::FpuExtend { rd, rn, .. } => {
562 collector.reg_def(rd);
563 collector.reg_use(rn);
564 }
565 Inst::FpuRR { rd, rn, .. } => {
566 collector.reg_def(rd);
567 collector.reg_use(rn);
568 }
569 Inst::FpuRRR { rd, rn, rm, .. } => {
570 collector.reg_def(rd);
571 collector.reg_use(rn);
572 collector.reg_use(rm);
573 }
574 Inst::FpuRRI { rd, rn, .. } => {
575 collector.reg_def(rd);
576 collector.reg_use(rn);
577 }
578 Inst::FpuRRIMod { rd, ri, rn, .. } => {
579 collector.reg_reuse_def(rd, 1); collector.reg_use(ri);
581 collector.reg_use(rn);
582 }
583 Inst::FpuRRRR { rd, rn, rm, ra, .. } => {
584 collector.reg_def(rd);
585 collector.reg_use(rn);
586 collector.reg_use(rm);
587 collector.reg_use(ra);
588 }
589 Inst::VecMisc { rd, rn, .. } => {
590 collector.reg_def(rd);
591 collector.reg_use(rn);
592 }
593
594 Inst::VecLanes { rd, rn, .. } => {
595 collector.reg_def(rd);
596 collector.reg_use(rn);
597 }
598 Inst::VecShiftImm { rd, rn, .. } => {
599 collector.reg_def(rd);
600 collector.reg_use(rn);
601 }
602 Inst::VecShiftImmMod { rd, ri, rn, .. } => {
603 collector.reg_reuse_def(rd, 1); collector.reg_use(ri);
605 collector.reg_use(rn);
606 }
607 Inst::VecExtract { rd, rn, rm, .. } => {
608 collector.reg_def(rd);
609 collector.reg_use(rn);
610 collector.reg_use(rm);
611 }
612 Inst::VecTbl { rd, rn, rm } => {
613 collector.reg_use(rn);
614 collector.reg_use(rm);
615 collector.reg_def(rd);
616 }
617 Inst::VecTblExt { rd, ri, rn, rm } => {
618 collector.reg_use(rn);
619 collector.reg_use(rm);
620 collector.reg_reuse_def(rd, 3); collector.reg_use(ri);
622 }
623
624 Inst::VecTbl2 { rd, rn, rn2, rm } => {
625 collector.reg_fixed_use(rn, vreg(30));
629 collector.reg_fixed_use(rn2, vreg(31));
630 collector.reg_use(rm);
631 collector.reg_def(rd);
632 }
633 Inst::VecTbl2Ext {
634 rd,
635 ri,
636 rn,
637 rn2,
638 rm,
639 } => {
640 collector.reg_fixed_use(rn, vreg(30));
644 collector.reg_fixed_use(rn2, vreg(31));
645 collector.reg_use(rm);
646 collector.reg_reuse_def(rd, 4); collector.reg_use(ri);
648 }
649 Inst::VecLoadReplicate { rd, rn, .. } => {
650 collector.reg_def(rd);
651 collector.reg_use(rn);
652 }
653 Inst::VecCSel { rd, rn, rm, .. } => {
654 collector.reg_def(rd);
655 collector.reg_use(rn);
656 collector.reg_use(rm);
657 }
658 Inst::FpuCmp { rn, rm, .. } => {
659 collector.reg_use(rn);
660 collector.reg_use(rm);
661 }
662 Inst::FpuLoad16 { rd, mem, .. } => {
663 collector.reg_def(rd);
664 memarg_operands(mem, collector);
665 }
666 Inst::FpuLoad32 { rd, mem, .. } => {
667 collector.reg_def(rd);
668 memarg_operands(mem, collector);
669 }
670 Inst::FpuLoad64 { rd, mem, .. } => {
671 collector.reg_def(rd);
672 memarg_operands(mem, collector);
673 }
674 Inst::FpuLoad128 { rd, mem, .. } => {
675 collector.reg_def(rd);
676 memarg_operands(mem, collector);
677 }
678 Inst::FpuStore16 { rd, mem, .. } => {
679 collector.reg_use(rd);
680 memarg_operands(mem, collector);
681 }
682 Inst::FpuStore32 { rd, mem, .. } => {
683 collector.reg_use(rd);
684 memarg_operands(mem, collector);
685 }
686 Inst::FpuStore64 { rd, mem, .. } => {
687 collector.reg_use(rd);
688 memarg_operands(mem, collector);
689 }
690 Inst::FpuStore128 { rd, mem, .. } => {
691 collector.reg_use(rd);
692 memarg_operands(mem, collector);
693 }
694 Inst::FpuLoadP64 { rt, rt2, mem, .. } => {
695 collector.reg_def(rt);
696 collector.reg_def(rt2);
697 pairmemarg_operands(mem, collector);
698 }
699 Inst::FpuStoreP64 { rt, rt2, mem, .. } => {
700 collector.reg_use(rt);
701 collector.reg_use(rt2);
702 pairmemarg_operands(mem, collector);
703 }
704 Inst::FpuLoadP128 { rt, rt2, mem, .. } => {
705 collector.reg_def(rt);
706 collector.reg_def(rt2);
707 pairmemarg_operands(mem, collector);
708 }
709 Inst::FpuStoreP128 { rt, rt2, mem, .. } => {
710 collector.reg_use(rt);
711 collector.reg_use(rt2);
712 pairmemarg_operands(mem, collector);
713 }
714 Inst::FpuToInt { rd, rn, .. } => {
715 collector.reg_def(rd);
716 collector.reg_use(rn);
717 }
718 Inst::IntToFpu { rd, rn, .. } => {
719 collector.reg_def(rd);
720 collector.reg_use(rn);
721 }
722 Inst::FpuCSel16 { rd, rn, rm, .. }
723 | Inst::FpuCSel32 { rd, rn, rm, .. }
724 | Inst::FpuCSel64 { rd, rn, rm, .. } => {
725 collector.reg_def(rd);
726 collector.reg_use(rn);
727 collector.reg_use(rm);
728 }
729 Inst::FpuRound { rd, rn, .. } => {
730 collector.reg_def(rd);
731 collector.reg_use(rn);
732 }
733 Inst::MovToFpu { rd, rn, .. } => {
734 collector.reg_def(rd);
735 collector.reg_use(rn);
736 }
737 Inst::FpuMoveFPImm { rd, .. } => {
738 collector.reg_def(rd);
739 }
740 Inst::MovToVec { rd, ri, rn, .. } => {
741 collector.reg_reuse_def(rd, 1); collector.reg_use(ri);
743 collector.reg_use(rn);
744 }
745 Inst::MovFromVec { rd, rn, .. } | Inst::MovFromVecSigned { rd, rn, .. } => {
746 collector.reg_def(rd);
747 collector.reg_use(rn);
748 }
749 Inst::VecDup { rd, rn, .. } => {
750 collector.reg_def(rd);
751 collector.reg_use(rn);
752 }
753 Inst::VecDupFromFpu { rd, rn, .. } => {
754 collector.reg_def(rd);
755 collector.reg_use(rn);
756 }
757 Inst::VecDupFPImm { rd, .. } => {
758 collector.reg_def(rd);
759 }
760 Inst::VecDupImm { rd, .. } => {
761 collector.reg_def(rd);
762 }
763 Inst::VecExtend { rd, rn, .. } => {
764 collector.reg_def(rd);
765 collector.reg_use(rn);
766 }
767 Inst::VecMovElement { rd, ri, rn, .. } => {
768 collector.reg_reuse_def(rd, 1); collector.reg_use(ri);
770 collector.reg_use(rn);
771 }
772 Inst::VecRRLong { rd, rn, .. } => {
773 collector.reg_def(rd);
774 collector.reg_use(rn);
775 }
776 Inst::VecRRNarrowLow { rd, rn, .. } => {
777 collector.reg_use(rn);
778 collector.reg_def(rd);
779 }
780 Inst::VecRRNarrowHigh { rd, ri, rn, .. } => {
781 collector.reg_use(rn);
782 collector.reg_reuse_def(rd, 2); collector.reg_use(ri);
784 }
785 Inst::VecRRPair { rd, rn, .. } => {
786 collector.reg_def(rd);
787 collector.reg_use(rn);
788 }
789 Inst::VecRRRLong { rd, rn, rm, .. } => {
790 collector.reg_def(rd);
791 collector.reg_use(rn);
792 collector.reg_use(rm);
793 }
794 Inst::VecRRRLongMod { rd, ri, rn, rm, .. } => {
795 collector.reg_reuse_def(rd, 1); collector.reg_use(ri);
797 collector.reg_use(rn);
798 collector.reg_use(rm);
799 }
800 Inst::VecRRPairLong { rd, rn, .. } => {
801 collector.reg_def(rd);
802 collector.reg_use(rn);
803 }
804 Inst::VecRRR { rd, rn, rm, .. } => {
805 collector.reg_def(rd);
806 collector.reg_use(rn);
807 collector.reg_use(rm);
808 }
809 Inst::VecRRRMod { rd, ri, rn, rm, .. } | Inst::VecFmlaElem { rd, ri, rn, rm, .. } => {
810 collector.reg_reuse_def(rd, 1); collector.reg_use(ri);
812 collector.reg_use(rn);
813 collector.reg_use(rm);
814 }
815 Inst::MovToNZCV { rn } => {
816 collector.reg_use(rn);
817 }
818 Inst::MovFromNZCV { rd } => {
819 collector.reg_def(rd);
820 }
821 Inst::Extend { rd, rn, .. } => {
822 collector.reg_def(rd);
823 collector.reg_use(rn);
824 }
825 Inst::Args { args } => {
826 for ArgPair { vreg, preg } in args {
827 collector.reg_fixed_def(vreg, *preg);
828 }
829 }
830 Inst::Rets { rets } => {
831 for RetPair { vreg, preg } in rets {
832 collector.reg_fixed_use(vreg, *preg);
833 }
834 }
835 Inst::Ret { .. } | Inst::AuthenticatedRet { .. } => {}
836 Inst::Jump { .. } => {}
837 Inst::Call { info, .. } => {
838 let CallInfo { uses, defs, .. } = &mut **info;
839 for CallArgPair { vreg, preg } in uses {
840 collector.reg_fixed_use(vreg, *preg);
841 }
842 for CallRetPair { vreg, preg } in defs {
843 collector.reg_fixed_def(vreg, *preg);
844 }
845 collector.reg_clobbers(info.clobbers);
846 }
847 Inst::CallInd { info, .. } => {
848 let CallInfo {
849 dest, uses, defs, ..
850 } = &mut **info;
851 collector.reg_use(dest);
852 for CallArgPair { vreg, preg } in uses {
853 collector.reg_fixed_use(vreg, *preg);
854 }
855 for CallRetPair { vreg, preg } in defs {
856 collector.reg_fixed_def(vreg, *preg);
857 }
858 collector.reg_clobbers(info.clobbers);
859 }
860 Inst::ReturnCall { info } => {
861 for CallArgPair { vreg, preg } in &mut info.uses {
862 collector.reg_fixed_use(vreg, *preg);
863 }
864 }
865 Inst::ReturnCallInd { info } => {
866 collector.reg_fixed_use(&mut info.dest, xreg(1));
871 for CallArgPair { vreg, preg } in &mut info.uses {
872 collector.reg_fixed_use(vreg, *preg);
873 }
874 }
875 Inst::CondBr { kind, .. } => match kind {
876 CondBrKind::Zero(rt, _) | CondBrKind::NotZero(rt, _) => collector.reg_use(rt),
877 CondBrKind::Cond(_) => {}
878 },
879 Inst::TestBitAndBranch { rn, .. } => {
880 collector.reg_use(rn);
881 }
882 Inst::IndirectBr { rn, .. } => {
883 collector.reg_use(rn);
884 }
885 Inst::Nop0 | Inst::Nop4 => {}
886 Inst::Brk => {}
887 Inst::Udf { .. } => {}
888 Inst::TrapIf { kind, .. } => match kind {
889 CondBrKind::Zero(rt, _) | CondBrKind::NotZero(rt, _) => collector.reg_use(rt),
890 CondBrKind::Cond(_) => {}
891 },
892 Inst::Adr { rd, .. } | Inst::Adrp { rd, .. } => {
893 collector.reg_def(rd);
894 }
895 Inst::Word4 { .. } | Inst::Word8 { .. } => {}
896 Inst::JTSequence {
897 ridx, rtmp1, rtmp2, ..
898 } => {
899 collector.reg_use(ridx);
900 collector.reg_early_def(rtmp1);
901 collector.reg_early_def(rtmp2);
902 }
903 Inst::LoadExtName { rd, .. } => {
904 collector.reg_def(rd);
905 }
906 Inst::LoadAddr { rd, mem } => {
907 collector.reg_def(rd);
908 memarg_operands(mem, collector);
909 }
910 Inst::Paci { .. } | Inst::Xpaclri => {
911 }
914 Inst::Bti { .. } => {}
915
916 Inst::ElfTlsGetAddr { rd, tmp, .. } => {
917 collector.reg_fixed_def(rd, regs::xreg(0));
924 collector.reg_early_def(tmp);
925 }
926 Inst::MachOTlsGetAddr { rd, .. } => {
927 collector.reg_fixed_def(rd, regs::xreg(0));
928 let mut clobbers =
929 AArch64MachineDeps::get_regs_clobbered_by_call(CallConv::AppleAarch64);
930 clobbers.remove(regs::xreg_preg(0));
931 collector.reg_clobbers(clobbers);
932 }
933 Inst::Unwind { .. } => {}
934 Inst::EmitIsland { .. } => {}
935 Inst::DummyUse { reg } => {
936 collector.reg_use(reg);
937 }
938 Inst::StackProbeLoop { start, end, .. } => {
939 collector.reg_early_def(start);
940 collector.reg_use(end);
941 }
942 }
943}
944
945impl MachInst for Inst {
949 type ABIMachineSpec = AArch64MachineDeps;
950 type LabelUse = LabelUse;
951
952 const TRAP_OPCODE: &'static [u8] = &0xc11f_u32.to_le_bytes();
955
956 fn get_operands(&mut self, collector: &mut impl OperandVisitor) {
957 aarch64_get_operands(self, collector);
958 }
959
960 fn is_move(&self) -> Option<(Writable<Reg>, Reg)> {
961 match self {
962 &Inst::Mov {
963 size: OperandSize::Size64,
964 rd,
965 rm,
966 } => Some((rd, rm)),
967 &Inst::FpuMove64 { rd, rn } => Some((rd, rn)),
968 &Inst::FpuMove128 { rd, rn } => Some((rd, rn)),
969 _ => None,
970 }
971 }
972
973 fn is_included_in_clobbers(&self) -> bool {
974 let (caller, callee) = match self {
975 Inst::Args { .. } => return false,
976 Inst::Call { info } => (info.caller_conv, info.callee_conv),
977 Inst::CallInd { info } => (info.caller_conv, info.callee_conv),
978 _ => return true,
979 };
980
981 let caller_clobbers = AArch64MachineDeps::get_regs_clobbered_by_call(caller);
993 let callee_clobbers = AArch64MachineDeps::get_regs_clobbered_by_call(callee);
994
995 let mut all_clobbers = caller_clobbers;
996 all_clobbers.union_from(callee_clobbers);
997 all_clobbers != caller_clobbers
998 }
999
1000 fn is_trap(&self) -> bool {
1001 match self {
1002 Self::Udf { .. } => true,
1003 _ => false,
1004 }
1005 }
1006
1007 fn is_args(&self) -> bool {
1008 match self {
1009 Self::Args { .. } => true,
1010 _ => false,
1011 }
1012 }
1013
1014 fn is_term(&self) -> MachTerminator {
1015 match self {
1016 &Inst::Rets { .. } => MachTerminator::Ret,
1017 &Inst::ReturnCall { .. } | &Inst::ReturnCallInd { .. } => MachTerminator::RetCall,
1018 &Inst::Jump { .. } => MachTerminator::Uncond,
1019 &Inst::CondBr { .. } => MachTerminator::Cond,
1020 &Inst::TestBitAndBranch { .. } => MachTerminator::Cond,
1021 &Inst::IndirectBr { .. } => MachTerminator::Indirect,
1022 &Inst::JTSequence { .. } => MachTerminator::Indirect,
1023 _ => MachTerminator::None,
1024 }
1025 }
1026
1027 fn is_mem_access(&self) -> bool {
1028 match self {
1029 &Inst::ULoad8 { .. }
1030 | &Inst::SLoad8 { .. }
1031 | &Inst::ULoad16 { .. }
1032 | &Inst::SLoad16 { .. }
1033 | &Inst::ULoad32 { .. }
1034 | &Inst::SLoad32 { .. }
1035 | &Inst::ULoad64 { .. }
1036 | &Inst::LoadP64 { .. }
1037 | &Inst::FpuLoad16 { .. }
1038 | &Inst::FpuLoad32 { .. }
1039 | &Inst::FpuLoad64 { .. }
1040 | &Inst::FpuLoad128 { .. }
1041 | &Inst::FpuLoadP64 { .. }
1042 | &Inst::FpuLoadP128 { .. }
1043 | &Inst::Store8 { .. }
1044 | &Inst::Store16 { .. }
1045 | &Inst::Store32 { .. }
1046 | &Inst::Store64 { .. }
1047 | &Inst::StoreP64 { .. }
1048 | &Inst::FpuStore16 { .. }
1049 | &Inst::FpuStore32 { .. }
1050 | &Inst::FpuStore64 { .. }
1051 | &Inst::FpuStore128 { .. } => true,
1052 _ => false,
1054 }
1055 }
1056
1057 fn gen_move(to_reg: Writable<Reg>, from_reg: Reg, ty: Type) -> Inst {
1058 let bits = ty.bits();
1059
1060 assert!(bits <= 128);
1061 assert!(to_reg.to_reg().class() == from_reg.class());
1062 match from_reg.class() {
1063 RegClass::Int => Inst::Mov {
1064 size: OperandSize::Size64,
1065 rd: to_reg,
1066 rm: from_reg,
1067 },
1068 RegClass::Float => {
1069 if bits > 64 {
1070 Inst::FpuMove128 {
1071 rd: to_reg,
1072 rn: from_reg,
1073 }
1074 } else {
1075 Inst::FpuMove64 {
1076 rd: to_reg,
1077 rn: from_reg,
1078 }
1079 }
1080 }
1081 RegClass::Vector => unreachable!(),
1082 }
1083 }
1084
1085 fn is_safepoint(&self) -> bool {
1086 match self {
1087 Inst::Call { .. } | Inst::CallInd { .. } => true,
1088 _ => false,
1089 }
1090 }
1091
1092 fn gen_dummy_use(reg: Reg) -> Inst {
1093 Inst::DummyUse { reg }
1094 }
1095
1096 fn gen_nop(preferred_size: usize) -> Inst {
1097 if preferred_size == 0 {
1098 return Inst::Nop0;
1099 }
1100 assert!(preferred_size >= 4);
1102 Inst::Nop4
1103 }
1104
1105 fn rc_for_type(ty: Type) -> CodegenResult<(&'static [RegClass], &'static [Type])> {
1106 match ty {
1107 I8 => Ok((&[RegClass::Int], &[I8])),
1108 I16 => Ok((&[RegClass::Int], &[I16])),
1109 I32 => Ok((&[RegClass::Int], &[I32])),
1110 I64 => Ok((&[RegClass::Int], &[I64])),
1111 F16 => Ok((&[RegClass::Float], &[F16])),
1112 F32 => Ok((&[RegClass::Float], &[F32])),
1113 F64 => Ok((&[RegClass::Float], &[F64])),
1114 F128 => Ok((&[RegClass::Float], &[F128])),
1115 I128 => Ok((&[RegClass::Int, RegClass::Int], &[I64, I64])),
1116 _ if ty.is_vector() => {
1117 assert!(ty.bits() <= 128);
1118 Ok((&[RegClass::Float], &[I8X16]))
1119 }
1120 _ if ty.is_dynamic_vector() => Ok((&[RegClass::Float], &[I8X16])),
1121 _ => Err(CodegenError::Unsupported(format!(
1122 "Unexpected SSA-value type: {ty}"
1123 ))),
1124 }
1125 }
1126
1127 fn canonical_type_for_rc(rc: RegClass) -> Type {
1128 match rc {
1129 RegClass::Float => types::I8X16,
1130 RegClass::Int => types::I64,
1131 RegClass::Vector => unreachable!(),
1132 }
1133 }
1134
1135 fn gen_jump(target: MachLabel) -> Inst {
1136 Inst::Jump {
1137 dest: BranchTarget::Label(target),
1138 }
1139 }
1140
1141 fn worst_case_size() -> CodeOffset {
1142 44
1150 }
1151
1152 fn ref_type_regclass(_: &settings::Flags) -> RegClass {
1153 RegClass::Int
1154 }
1155
1156 fn gen_block_start(
1157 is_indirect_branch_target: bool,
1158 is_forward_edge_cfi_enabled: bool,
1159 ) -> Option<Self> {
1160 if is_indirect_branch_target && is_forward_edge_cfi_enabled {
1161 Some(Inst::Bti {
1162 targets: BranchTargetType::J,
1163 })
1164 } else {
1165 None
1166 }
1167 }
1168
1169 fn function_alignment() -> FunctionAlignment {
1170 FunctionAlignment {
1173 minimum: 4,
1174 preferred: 32,
1175 }
1176 }
1177}
1178
1179fn mem_finalize_for_show(mem: &AMode, access_ty: Type, state: &EmitState) -> (String, String) {
1183 let (mem_insts, mem) = mem_finalize(None, mem, access_ty, state);
1184 let mut mem_str = mem_insts
1185 .into_iter()
1186 .map(|inst| inst.print_with_state(&mut EmitState::default()))
1187 .collect::<Vec<_>>()
1188 .join(" ; ");
1189 if !mem_str.is_empty() {
1190 mem_str += " ; ";
1191 }
1192
1193 let mem = mem.pretty_print(access_ty.bytes() as u8);
1194 (mem_str, mem)
1195}
1196
1197impl Inst {
1198 fn print_with_state(&self, state: &mut EmitState) -> String {
1199 fn op_name(alu_op: ALUOp) -> &'static str {
1200 match alu_op {
1201 ALUOp::Add => "add",
1202 ALUOp::Sub => "sub",
1203 ALUOp::Orr => "orr",
1204 ALUOp::And => "and",
1205 ALUOp::AndS => "ands",
1206 ALUOp::Eor => "eor",
1207 ALUOp::AddS => "adds",
1208 ALUOp::SubS => "subs",
1209 ALUOp::SMulH => "smulh",
1210 ALUOp::UMulH => "umulh",
1211 ALUOp::SDiv => "sdiv",
1212 ALUOp::UDiv => "udiv",
1213 ALUOp::AndNot => "bic",
1214 ALUOp::OrrNot => "orn",
1215 ALUOp::EorNot => "eon",
1216 ALUOp::RotR => "ror",
1217 ALUOp::Lsr => "lsr",
1218 ALUOp::Asr => "asr",
1219 ALUOp::Lsl => "lsl",
1220 ALUOp::Adc => "adc",
1221 ALUOp::AdcS => "adcs",
1222 ALUOp::Sbc => "sbc",
1223 ALUOp::SbcS => "sbcs",
1224 }
1225 }
1226
1227 match self {
1228 &Inst::Nop0 => "nop-zero-len".to_string(),
1229 &Inst::Nop4 => "nop".to_string(),
1230 &Inst::AluRRR {
1231 alu_op,
1232 size,
1233 rd,
1234 rn,
1235 rm,
1236 } => {
1237 let op = op_name(alu_op);
1238 let rd = pretty_print_ireg(rd.to_reg(), size);
1239 let rn = pretty_print_ireg(rn, size);
1240 let rm = pretty_print_ireg(rm, size);
1241 format!("{op} {rd}, {rn}, {rm}")
1242 }
1243 &Inst::AluRRRR {
1244 alu_op,
1245 size,
1246 rd,
1247 rn,
1248 rm,
1249 ra,
1250 } => {
1251 let (op, da_size) = match alu_op {
1252 ALUOp3::MAdd => ("madd", size),
1253 ALUOp3::MSub => ("msub", size),
1254 ALUOp3::UMAddL => ("umaddl", OperandSize::Size64),
1255 ALUOp3::SMAddL => ("smaddl", OperandSize::Size64),
1256 };
1257 let rd = pretty_print_ireg(rd.to_reg(), da_size);
1258 let rn = pretty_print_ireg(rn, size);
1259 let rm = pretty_print_ireg(rm, size);
1260 let ra = pretty_print_ireg(ra, da_size);
1261
1262 format!("{op} {rd}, {rn}, {rm}, {ra}")
1263 }
1264 &Inst::AluRRImm12 {
1265 alu_op,
1266 size,
1267 rd,
1268 rn,
1269 ref imm12,
1270 } => {
1271 let op = op_name(alu_op);
1272 let rd = pretty_print_ireg(rd.to_reg(), size);
1273 let rn = pretty_print_ireg(rn, size);
1274
1275 if imm12.bits == 0 && alu_op == ALUOp::Add && size.is64() {
1276 format!("mov {rd}, {rn}")
1278 } else {
1279 let imm12 = imm12.pretty_print(0);
1280 format!("{op} {rd}, {rn}, {imm12}")
1281 }
1282 }
1283 &Inst::AluRRImmLogic {
1284 alu_op,
1285 size,
1286 rd,
1287 rn,
1288 ref imml,
1289 } => {
1290 let op = op_name(alu_op);
1291 let rd = pretty_print_ireg(rd.to_reg(), size);
1292 let rn = pretty_print_ireg(rn, size);
1293 let imml = imml.pretty_print(0);
1294 format!("{op} {rd}, {rn}, {imml}")
1295 }
1296 &Inst::AluRRImmShift {
1297 alu_op,
1298 size,
1299 rd,
1300 rn,
1301 ref immshift,
1302 } => {
1303 let op = op_name(alu_op);
1304 let rd = pretty_print_ireg(rd.to_reg(), size);
1305 let rn = pretty_print_ireg(rn, size);
1306 let immshift = immshift.pretty_print(0);
1307 format!("{op} {rd}, {rn}, {immshift}")
1308 }
1309 &Inst::AluRRRShift {
1310 alu_op,
1311 size,
1312 rd,
1313 rn,
1314 rm,
1315 ref shiftop,
1316 } => {
1317 let op = op_name(alu_op);
1318 let rd = pretty_print_ireg(rd.to_reg(), size);
1319 let rn = pretty_print_ireg(rn, size);
1320 let rm = pretty_print_ireg(rm, size);
1321 let shiftop = shiftop.pretty_print(0);
1322 format!("{op} {rd}, {rn}, {rm}, {shiftop}")
1323 }
1324 &Inst::AluRRRExtend {
1325 alu_op,
1326 size,
1327 rd,
1328 rn,
1329 rm,
1330 ref extendop,
1331 } => {
1332 let op = op_name(alu_op);
1333 let rd = pretty_print_ireg(rd.to_reg(), size);
1334 let rn = pretty_print_ireg(rn, size);
1335 let rm = pretty_print_ireg(rm, size);
1336 let extendop = extendop.pretty_print(0);
1337 format!("{op} {rd}, {rn}, {rm}, {extendop}")
1338 }
1339 &Inst::BitRR { op, size, rd, rn } => {
1340 let op = op.op_str();
1341 let rd = pretty_print_ireg(rd.to_reg(), size);
1342 let rn = pretty_print_ireg(rn, size);
1343 format!("{op} {rd}, {rn}")
1344 }
1345 &Inst::ULoad8 { rd, ref mem, .. }
1346 | &Inst::SLoad8 { rd, ref mem, .. }
1347 | &Inst::ULoad16 { rd, ref mem, .. }
1348 | &Inst::SLoad16 { rd, ref mem, .. }
1349 | &Inst::ULoad32 { rd, ref mem, .. }
1350 | &Inst::SLoad32 { rd, ref mem, .. }
1351 | &Inst::ULoad64 { rd, ref mem, .. } => {
1352 let is_unscaled = match &mem {
1353 &AMode::Unscaled { .. } => true,
1354 _ => false,
1355 };
1356 let (op, size) = match (self, is_unscaled) {
1357 (&Inst::ULoad8 { .. }, false) => ("ldrb", OperandSize::Size32),
1358 (&Inst::ULoad8 { .. }, true) => ("ldurb", OperandSize::Size32),
1359 (&Inst::SLoad8 { .. }, false) => ("ldrsb", OperandSize::Size64),
1360 (&Inst::SLoad8 { .. }, true) => ("ldursb", OperandSize::Size64),
1361 (&Inst::ULoad16 { .. }, false) => ("ldrh", OperandSize::Size32),
1362 (&Inst::ULoad16 { .. }, true) => ("ldurh", OperandSize::Size32),
1363 (&Inst::SLoad16 { .. }, false) => ("ldrsh", OperandSize::Size64),
1364 (&Inst::SLoad16 { .. }, true) => ("ldursh", OperandSize::Size64),
1365 (&Inst::ULoad32 { .. }, false) => ("ldr", OperandSize::Size32),
1366 (&Inst::ULoad32 { .. }, true) => ("ldur", OperandSize::Size32),
1367 (&Inst::SLoad32 { .. }, false) => ("ldrsw", OperandSize::Size64),
1368 (&Inst::SLoad32 { .. }, true) => ("ldursw", OperandSize::Size64),
1369 (&Inst::ULoad64 { .. }, false) => ("ldr", OperandSize::Size64),
1370 (&Inst::ULoad64 { .. }, true) => ("ldur", OperandSize::Size64),
1371 _ => unreachable!(),
1372 };
1373
1374 let rd = pretty_print_ireg(rd.to_reg(), size);
1375 let mem = mem.clone();
1376 let access_ty = self.mem_type().unwrap();
1377 let (mem_str, mem) = mem_finalize_for_show(&mem, access_ty, state);
1378
1379 format!("{mem_str}{op} {rd}, {mem}")
1380 }
1381 &Inst::Store8 { rd, ref mem, .. }
1382 | &Inst::Store16 { rd, ref mem, .. }
1383 | &Inst::Store32 { rd, ref mem, .. }
1384 | &Inst::Store64 { rd, ref mem, .. } => {
1385 let is_unscaled = match &mem {
1386 &AMode::Unscaled { .. } => true,
1387 _ => false,
1388 };
1389 let (op, size) = match (self, is_unscaled) {
1390 (&Inst::Store8 { .. }, false) => ("strb", OperandSize::Size32),
1391 (&Inst::Store8 { .. }, true) => ("sturb", OperandSize::Size32),
1392 (&Inst::Store16 { .. }, false) => ("strh", OperandSize::Size32),
1393 (&Inst::Store16 { .. }, true) => ("sturh", OperandSize::Size32),
1394 (&Inst::Store32 { .. }, false) => ("str", OperandSize::Size32),
1395 (&Inst::Store32 { .. }, true) => ("stur", OperandSize::Size32),
1396 (&Inst::Store64 { .. }, false) => ("str", OperandSize::Size64),
1397 (&Inst::Store64 { .. }, true) => ("stur", OperandSize::Size64),
1398 _ => unreachable!(),
1399 };
1400
1401 let rd = pretty_print_ireg(rd, size);
1402 let mem = mem.clone();
1403 let access_ty = self.mem_type().unwrap();
1404 let (mem_str, mem) = mem_finalize_for_show(&mem, access_ty, state);
1405
1406 format!("{mem_str}{op} {rd}, {mem}")
1407 }
1408 &Inst::StoreP64 {
1409 rt, rt2, ref mem, ..
1410 } => {
1411 let rt = pretty_print_ireg(rt, OperandSize::Size64);
1412 let rt2 = pretty_print_ireg(rt2, OperandSize::Size64);
1413 let mem = mem.clone();
1414 let mem = mem.pretty_print_default();
1415 format!("stp {rt}, {rt2}, {mem}")
1416 }
1417 &Inst::LoadP64 {
1418 rt, rt2, ref mem, ..
1419 } => {
1420 let rt = pretty_print_ireg(rt.to_reg(), OperandSize::Size64);
1421 let rt2 = pretty_print_ireg(rt2.to_reg(), OperandSize::Size64);
1422 let mem = mem.clone();
1423 let mem = mem.pretty_print_default();
1424 format!("ldp {rt}, {rt2}, {mem}")
1425 }
1426 &Inst::Mov { size, rd, rm } => {
1427 let rd = pretty_print_ireg(rd.to_reg(), size);
1428 let rm = pretty_print_ireg(rm, size);
1429 format!("mov {rd}, {rm}")
1430 }
1431 &Inst::MovFromPReg { rd, rm } => {
1432 let rd = pretty_print_ireg(rd.to_reg(), OperandSize::Size64);
1433 let rm = show_ireg_sized(rm.into(), OperandSize::Size64);
1434 format!("mov {rd}, {rm}")
1435 }
1436 &Inst::MovToPReg { rd, rm } => {
1437 let rd = show_ireg_sized(rd.into(), OperandSize::Size64);
1438 let rm = pretty_print_ireg(rm, OperandSize::Size64);
1439 format!("mov {rd}, {rm}")
1440 }
1441 &Inst::MovWide {
1442 op,
1443 rd,
1444 ref imm,
1445 size,
1446 } => {
1447 let op_str = match op {
1448 MoveWideOp::MovZ => "movz",
1449 MoveWideOp::MovN => "movn",
1450 };
1451 let rd = pretty_print_ireg(rd.to_reg(), size);
1452 let imm = imm.pretty_print(0);
1453 format!("{op_str} {rd}, {imm}")
1454 }
1455 &Inst::MovK {
1456 rd,
1457 rn,
1458 ref imm,
1459 size,
1460 } => {
1461 let rn = pretty_print_ireg(rn, size);
1462 let rd = pretty_print_ireg(rd.to_reg(), size);
1463 let imm = imm.pretty_print(0);
1464 format!("movk {rd}, {rn}, {imm}")
1465 }
1466 &Inst::CSel { rd, rn, rm, cond } => {
1467 let rd = pretty_print_ireg(rd.to_reg(), OperandSize::Size64);
1468 let rn = pretty_print_ireg(rn, OperandSize::Size64);
1469 let rm = pretty_print_ireg(rm, OperandSize::Size64);
1470 let cond = cond.pretty_print(0);
1471 format!("csel {rd}, {rn}, {rm}, {cond}")
1472 }
1473 &Inst::CSNeg { rd, rn, rm, cond } => {
1474 let rd = pretty_print_ireg(rd.to_reg(), OperandSize::Size64);
1475 let rn = pretty_print_ireg(rn, OperandSize::Size64);
1476 let rm = pretty_print_ireg(rm, OperandSize::Size64);
1477 let cond = cond.pretty_print(0);
1478 format!("csneg {rd}, {rn}, {rm}, {cond}")
1479 }
1480 &Inst::CSet { rd, cond } => {
1481 let rd = pretty_print_ireg(rd.to_reg(), OperandSize::Size64);
1482 let cond = cond.pretty_print(0);
1483 format!("cset {rd}, {cond}")
1484 }
1485 &Inst::CSetm { rd, cond } => {
1486 let rd = pretty_print_ireg(rd.to_reg(), OperandSize::Size64);
1487 let cond = cond.pretty_print(0);
1488 format!("csetm {rd}, {cond}")
1489 }
1490 &Inst::CCmp {
1491 size,
1492 rn,
1493 rm,
1494 nzcv,
1495 cond,
1496 } => {
1497 let rn = pretty_print_ireg(rn, size);
1498 let rm = pretty_print_ireg(rm, size);
1499 let nzcv = nzcv.pretty_print(0);
1500 let cond = cond.pretty_print(0);
1501 format!("ccmp {rn}, {rm}, {nzcv}, {cond}")
1502 }
1503 &Inst::CCmpImm {
1504 size,
1505 rn,
1506 imm,
1507 nzcv,
1508 cond,
1509 } => {
1510 let rn = pretty_print_ireg(rn, size);
1511 let imm = imm.pretty_print(0);
1512 let nzcv = nzcv.pretty_print(0);
1513 let cond = cond.pretty_print(0);
1514 format!("ccmp {rn}, {imm}, {nzcv}, {cond}")
1515 }
1516 &Inst::AtomicRMW {
1517 rs, rt, rn, ty, op, ..
1518 } => {
1519 let op = match op {
1520 AtomicRMWOp::Add => "ldaddal",
1521 AtomicRMWOp::Clr => "ldclral",
1522 AtomicRMWOp::Eor => "ldeoral",
1523 AtomicRMWOp::Set => "ldsetal",
1524 AtomicRMWOp::Smax => "ldsmaxal",
1525 AtomicRMWOp::Umax => "ldumaxal",
1526 AtomicRMWOp::Smin => "ldsminal",
1527 AtomicRMWOp::Umin => "lduminal",
1528 AtomicRMWOp::Swp => "swpal",
1529 };
1530
1531 let size = OperandSize::from_ty(ty);
1532 let rs = pretty_print_ireg(rs, size);
1533 let rt = pretty_print_ireg(rt.to_reg(), size);
1534 let rn = pretty_print_ireg(rn, OperandSize::Size64);
1535
1536 let ty_suffix = match ty {
1537 I8 => "b",
1538 I16 => "h",
1539 _ => "",
1540 };
1541 format!("{op}{ty_suffix} {rs}, {rt}, [{rn}]")
1542 }
1543 &Inst::AtomicRMWLoop {
1544 ty,
1545 op,
1546 addr,
1547 operand,
1548 oldval,
1549 scratch1,
1550 scratch2,
1551 ..
1552 } => {
1553 let op = match op {
1554 AtomicRMWLoopOp::Add => "add",
1555 AtomicRMWLoopOp::Sub => "sub",
1556 AtomicRMWLoopOp::Eor => "eor",
1557 AtomicRMWLoopOp::Orr => "orr",
1558 AtomicRMWLoopOp::And => "and",
1559 AtomicRMWLoopOp::Nand => "nand",
1560 AtomicRMWLoopOp::Smin => "smin",
1561 AtomicRMWLoopOp::Smax => "smax",
1562 AtomicRMWLoopOp::Umin => "umin",
1563 AtomicRMWLoopOp::Umax => "umax",
1564 AtomicRMWLoopOp::Xchg => "xchg",
1565 };
1566 let addr = pretty_print_ireg(addr, OperandSize::Size64);
1567 let operand = pretty_print_ireg(operand, OperandSize::Size64);
1568 let oldval = pretty_print_ireg(oldval.to_reg(), OperandSize::Size64);
1569 let scratch1 = pretty_print_ireg(scratch1.to_reg(), OperandSize::Size64);
1570 let scratch2 = pretty_print_ireg(scratch2.to_reg(), OperandSize::Size64);
1571 format!(
1572 "atomic_rmw_loop_{}_{} addr={} operand={} oldval={} scratch1={} scratch2={}",
1573 op,
1574 ty.bits(),
1575 addr,
1576 operand,
1577 oldval,
1578 scratch1,
1579 scratch2,
1580 )
1581 }
1582 &Inst::AtomicCAS {
1583 rd, rs, rt, rn, ty, ..
1584 } => {
1585 let op = match ty {
1586 I8 => "casalb",
1587 I16 => "casalh",
1588 I32 | I64 => "casal",
1589 _ => panic!("Unsupported type: {ty}"),
1590 };
1591 let size = OperandSize::from_ty(ty);
1592 let rd = pretty_print_ireg(rd.to_reg(), size);
1593 let rs = pretty_print_ireg(rs, size);
1594 let rt = pretty_print_ireg(rt, size);
1595 let rn = pretty_print_ireg(rn, OperandSize::Size64);
1596
1597 format!("{op} {rd}, {rs}, {rt}, [{rn}]")
1598 }
1599 &Inst::AtomicCASLoop {
1600 ty,
1601 addr,
1602 expected,
1603 replacement,
1604 oldval,
1605 scratch,
1606 ..
1607 } => {
1608 let addr = pretty_print_ireg(addr, OperandSize::Size64);
1609 let expected = pretty_print_ireg(expected, OperandSize::Size64);
1610 let replacement = pretty_print_ireg(replacement, OperandSize::Size64);
1611 let oldval = pretty_print_ireg(oldval.to_reg(), OperandSize::Size64);
1612 let scratch = pretty_print_ireg(scratch.to_reg(), OperandSize::Size64);
1613 format!(
1614 "atomic_cas_loop_{} addr={}, expect={}, replacement={}, oldval={}, scratch={}",
1615 ty.bits(),
1616 addr,
1617 expected,
1618 replacement,
1619 oldval,
1620 scratch,
1621 )
1622 }
1623 &Inst::LoadAcquire {
1624 access_ty, rt, rn, ..
1625 } => {
1626 let (op, ty) = match access_ty {
1627 I8 => ("ldarb", I32),
1628 I16 => ("ldarh", I32),
1629 I32 => ("ldar", I32),
1630 I64 => ("ldar", I64),
1631 _ => panic!("Unsupported type: {access_ty}"),
1632 };
1633 let size = OperandSize::from_ty(ty);
1634 let rn = pretty_print_ireg(rn, OperandSize::Size64);
1635 let rt = pretty_print_ireg(rt.to_reg(), size);
1636 format!("{op} {rt}, [{rn}]")
1637 }
1638 &Inst::StoreRelease {
1639 access_ty, rt, rn, ..
1640 } => {
1641 let (op, ty) = match access_ty {
1642 I8 => ("stlrb", I32),
1643 I16 => ("stlrh", I32),
1644 I32 => ("stlr", I32),
1645 I64 => ("stlr", I64),
1646 _ => panic!("Unsupported type: {access_ty}"),
1647 };
1648 let size = OperandSize::from_ty(ty);
1649 let rn = pretty_print_ireg(rn, OperandSize::Size64);
1650 let rt = pretty_print_ireg(rt, size);
1651 format!("{op} {rt}, [{rn}]")
1652 }
1653 &Inst::Fence {} => {
1654 format!("dmb ish")
1655 }
1656 &Inst::Csdb {} => {
1657 format!("csdb")
1658 }
1659 &Inst::FpuMove32 { rd, rn } => {
1660 let rd = pretty_print_vreg_scalar(rd.to_reg(), ScalarSize::Size32);
1661 let rn = pretty_print_vreg_scalar(rn, ScalarSize::Size32);
1662 format!("fmov {rd}, {rn}")
1663 }
1664 &Inst::FpuMove64 { rd, rn } => {
1665 let rd = pretty_print_vreg_scalar(rd.to_reg(), ScalarSize::Size64);
1666 let rn = pretty_print_vreg_scalar(rn, ScalarSize::Size64);
1667 format!("fmov {rd}, {rn}")
1668 }
1669 &Inst::FpuMove128 { rd, rn } => {
1670 let rd = pretty_print_reg(rd.to_reg());
1671 let rn = pretty_print_reg(rn);
1672 format!("mov {rd}.16b, {rn}.16b")
1673 }
1674 &Inst::FpuMoveFromVec { rd, rn, idx, size } => {
1675 let rd = pretty_print_vreg_scalar(rd.to_reg(), size.lane_size());
1676 let rn = pretty_print_vreg_element(rn, idx as usize, size.lane_size());
1677 format!("mov {rd}, {rn}")
1678 }
1679 &Inst::FpuExtend { rd, rn, size } => {
1680 let rd = pretty_print_vreg_scalar(rd.to_reg(), size);
1681 let rn = pretty_print_vreg_scalar(rn, size);
1682 format!("fmov {rd}, {rn}")
1683 }
1684 &Inst::FpuRR {
1685 fpu_op,
1686 size,
1687 rd,
1688 rn,
1689 } => {
1690 let op = match fpu_op {
1691 FPUOp1::Abs => "fabs",
1692 FPUOp1::Neg => "fneg",
1693 FPUOp1::Sqrt => "fsqrt",
1694 FPUOp1::Cvt32To64 | FPUOp1::Cvt64To32 => "fcvt",
1695 };
1696 let dst_size = match fpu_op {
1697 FPUOp1::Cvt32To64 => ScalarSize::Size64,
1698 FPUOp1::Cvt64To32 => ScalarSize::Size32,
1699 _ => size,
1700 };
1701 let rd = pretty_print_vreg_scalar(rd.to_reg(), dst_size);
1702 let rn = pretty_print_vreg_scalar(rn, size);
1703 format!("{op} {rd}, {rn}")
1704 }
1705 &Inst::FpuRRR {
1706 fpu_op,
1707 size,
1708 rd,
1709 rn,
1710 rm,
1711 } => {
1712 let op = match fpu_op {
1713 FPUOp2::Add => "fadd",
1714 FPUOp2::Sub => "fsub",
1715 FPUOp2::Mul => "fmul",
1716 FPUOp2::Div => "fdiv",
1717 FPUOp2::Max => "fmax",
1718 FPUOp2::Min => "fmin",
1719 };
1720 let rd = pretty_print_vreg_scalar(rd.to_reg(), size);
1721 let rn = pretty_print_vreg_scalar(rn, size);
1722 let rm = pretty_print_vreg_scalar(rm, size);
1723 format!("{op} {rd}, {rn}, {rm}")
1724 }
1725 &Inst::FpuRRI { fpu_op, rd, rn } => {
1726 let (op, imm, vector) = match fpu_op {
1727 FPUOpRI::UShr32(imm) => ("ushr", imm.pretty_print(0), true),
1728 FPUOpRI::UShr64(imm) => ("ushr", imm.pretty_print(0), false),
1729 };
1730
1731 let (rd, rn) = if vector {
1732 (
1733 pretty_print_vreg_vector(rd.to_reg(), VectorSize::Size32x2),
1734 pretty_print_vreg_vector(rn, VectorSize::Size32x2),
1735 )
1736 } else {
1737 (
1738 pretty_print_vreg_scalar(rd.to_reg(), ScalarSize::Size64),
1739 pretty_print_vreg_scalar(rn, ScalarSize::Size64),
1740 )
1741 };
1742 format!("{op} {rd}, {rn}, {imm}")
1743 }
1744 &Inst::FpuRRIMod { fpu_op, rd, ri, rn } => {
1745 let (op, imm, vector) = match fpu_op {
1746 FPUOpRIMod::Sli32(imm) => ("sli", imm.pretty_print(0), true),
1747 FPUOpRIMod::Sli64(imm) => ("sli", imm.pretty_print(0), false),
1748 };
1749
1750 let (rd, ri, rn) = if vector {
1751 (
1752 pretty_print_vreg_vector(rd.to_reg(), VectorSize::Size32x2),
1753 pretty_print_vreg_vector(ri, VectorSize::Size32x2),
1754 pretty_print_vreg_vector(rn, VectorSize::Size32x2),
1755 )
1756 } else {
1757 (
1758 pretty_print_vreg_scalar(rd.to_reg(), ScalarSize::Size64),
1759 pretty_print_vreg_scalar(ri, ScalarSize::Size64),
1760 pretty_print_vreg_scalar(rn, ScalarSize::Size64),
1761 )
1762 };
1763 format!("{op} {rd}, {ri}, {rn}, {imm}")
1764 }
1765 &Inst::FpuRRRR {
1766 fpu_op,
1767 size,
1768 rd,
1769 rn,
1770 rm,
1771 ra,
1772 } => {
1773 let op = match fpu_op {
1774 FPUOp3::MAdd => "fmadd",
1775 FPUOp3::MSub => "fmsub",
1776 FPUOp3::NMAdd => "fnmadd",
1777 FPUOp3::NMSub => "fnmsub",
1778 };
1779 let rd = pretty_print_vreg_scalar(rd.to_reg(), size);
1780 let rn = pretty_print_vreg_scalar(rn, size);
1781 let rm = pretty_print_vreg_scalar(rm, size);
1782 let ra = pretty_print_vreg_scalar(ra, size);
1783 format!("{op} {rd}, {rn}, {rm}, {ra}")
1784 }
1785 &Inst::FpuCmp { size, rn, rm } => {
1786 let rn = pretty_print_vreg_scalar(rn, size);
1787 let rm = pretty_print_vreg_scalar(rm, size);
1788 format!("fcmp {rn}, {rm}")
1789 }
1790 &Inst::FpuLoad16 { rd, ref mem, .. } => {
1791 let rd = pretty_print_vreg_scalar(rd.to_reg(), ScalarSize::Size16);
1792 let mem = mem.clone();
1793 let access_ty = self.mem_type().unwrap();
1794 let (mem_str, mem) = mem_finalize_for_show(&mem, access_ty, state);
1795 format!("{mem_str}ldr {rd}, {mem}")
1796 }
1797 &Inst::FpuLoad32 { rd, ref mem, .. } => {
1798 let rd = pretty_print_vreg_scalar(rd.to_reg(), ScalarSize::Size32);
1799 let mem = mem.clone();
1800 let access_ty = self.mem_type().unwrap();
1801 let (mem_str, mem) = mem_finalize_for_show(&mem, access_ty, state);
1802 format!("{mem_str}ldr {rd}, {mem}")
1803 }
1804 &Inst::FpuLoad64 { rd, ref mem, .. } => {
1805 let rd = pretty_print_vreg_scalar(rd.to_reg(), ScalarSize::Size64);
1806 let mem = mem.clone();
1807 let access_ty = self.mem_type().unwrap();
1808 let (mem_str, mem) = mem_finalize_for_show(&mem, access_ty, state);
1809 format!("{mem_str}ldr {rd}, {mem}")
1810 }
1811 &Inst::FpuLoad128 { rd, ref mem, .. } => {
1812 let rd = pretty_print_reg(rd.to_reg());
1813 let rd = "q".to_string() + &rd[1..];
1814 let mem = mem.clone();
1815 let access_ty = self.mem_type().unwrap();
1816 let (mem_str, mem) = mem_finalize_for_show(&mem, access_ty, state);
1817 format!("{mem_str}ldr {rd}, {mem}")
1818 }
1819 &Inst::FpuStore16 { rd, ref mem, .. } => {
1820 let rd = pretty_print_vreg_scalar(rd, ScalarSize::Size16);
1821 let mem = mem.clone();
1822 let access_ty = self.mem_type().unwrap();
1823 let (mem_str, mem) = mem_finalize_for_show(&mem, access_ty, state);
1824 format!("{mem_str}str {rd}, {mem}")
1825 }
1826 &Inst::FpuStore32 { rd, ref mem, .. } => {
1827 let rd = pretty_print_vreg_scalar(rd, ScalarSize::Size32);
1828 let mem = mem.clone();
1829 let access_ty = self.mem_type().unwrap();
1830 let (mem_str, mem) = mem_finalize_for_show(&mem, access_ty, state);
1831 format!("{mem_str}str {rd}, {mem}")
1832 }
1833 &Inst::FpuStore64 { rd, ref mem, .. } => {
1834 let rd = pretty_print_vreg_scalar(rd, ScalarSize::Size64);
1835 let mem = mem.clone();
1836 let access_ty = self.mem_type().unwrap();
1837 let (mem_str, mem) = mem_finalize_for_show(&mem, access_ty, state);
1838 format!("{mem_str}str {rd}, {mem}")
1839 }
1840 &Inst::FpuStore128 { rd, ref mem, .. } => {
1841 let rd = pretty_print_reg(rd);
1842 let rd = "q".to_string() + &rd[1..];
1843 let mem = mem.clone();
1844 let access_ty = self.mem_type().unwrap();
1845 let (mem_str, mem) = mem_finalize_for_show(&mem, access_ty, state);
1846 format!("{mem_str}str {rd}, {mem}")
1847 }
1848 &Inst::FpuLoadP64 {
1849 rt, rt2, ref mem, ..
1850 } => {
1851 let rt = pretty_print_vreg_scalar(rt.to_reg(), ScalarSize::Size64);
1852 let rt2 = pretty_print_vreg_scalar(rt2.to_reg(), ScalarSize::Size64);
1853 let mem = mem.clone();
1854 let mem = mem.pretty_print_default();
1855
1856 format!("ldp {rt}, {rt2}, {mem}")
1857 }
1858 &Inst::FpuStoreP64 {
1859 rt, rt2, ref mem, ..
1860 } => {
1861 let rt = pretty_print_vreg_scalar(rt, ScalarSize::Size64);
1862 let rt2 = pretty_print_vreg_scalar(rt2, ScalarSize::Size64);
1863 let mem = mem.clone();
1864 let mem = mem.pretty_print_default();
1865
1866 format!("stp {rt}, {rt2}, {mem}")
1867 }
1868 &Inst::FpuLoadP128 {
1869 rt, rt2, ref mem, ..
1870 } => {
1871 let rt = pretty_print_vreg_scalar(rt.to_reg(), ScalarSize::Size128);
1872 let rt2 = pretty_print_vreg_scalar(rt2.to_reg(), ScalarSize::Size128);
1873 let mem = mem.clone();
1874 let mem = mem.pretty_print_default();
1875
1876 format!("ldp {rt}, {rt2}, {mem}")
1877 }
1878 &Inst::FpuStoreP128 {
1879 rt, rt2, ref mem, ..
1880 } => {
1881 let rt = pretty_print_vreg_scalar(rt, ScalarSize::Size128);
1882 let rt2 = pretty_print_vreg_scalar(rt2, ScalarSize::Size128);
1883 let mem = mem.clone();
1884 let mem = mem.pretty_print_default();
1885
1886 format!("stp {rt}, {rt2}, {mem}")
1887 }
1888 &Inst::FpuToInt { op, rd, rn } => {
1889 let (op, sizesrc, sizedest) = match op {
1890 FpuToIntOp::F32ToI32 => ("fcvtzs", ScalarSize::Size32, OperandSize::Size32),
1891 FpuToIntOp::F32ToU32 => ("fcvtzu", ScalarSize::Size32, OperandSize::Size32),
1892 FpuToIntOp::F32ToI64 => ("fcvtzs", ScalarSize::Size32, OperandSize::Size64),
1893 FpuToIntOp::F32ToU64 => ("fcvtzu", ScalarSize::Size32, OperandSize::Size64),
1894 FpuToIntOp::F64ToI32 => ("fcvtzs", ScalarSize::Size64, OperandSize::Size32),
1895 FpuToIntOp::F64ToU32 => ("fcvtzu", ScalarSize::Size64, OperandSize::Size32),
1896 FpuToIntOp::F64ToI64 => ("fcvtzs", ScalarSize::Size64, OperandSize::Size64),
1897 FpuToIntOp::F64ToU64 => ("fcvtzu", ScalarSize::Size64, OperandSize::Size64),
1898 };
1899 let rd = pretty_print_ireg(rd.to_reg(), sizedest);
1900 let rn = pretty_print_vreg_scalar(rn, sizesrc);
1901 format!("{op} {rd}, {rn}")
1902 }
1903 &Inst::IntToFpu { op, rd, rn } => {
1904 let (op, sizesrc, sizedest) = match op {
1905 IntToFpuOp::I32ToF32 => ("scvtf", OperandSize::Size32, ScalarSize::Size32),
1906 IntToFpuOp::U32ToF32 => ("ucvtf", OperandSize::Size32, ScalarSize::Size32),
1907 IntToFpuOp::I64ToF32 => ("scvtf", OperandSize::Size64, ScalarSize::Size32),
1908 IntToFpuOp::U64ToF32 => ("ucvtf", OperandSize::Size64, ScalarSize::Size32),
1909 IntToFpuOp::I32ToF64 => ("scvtf", OperandSize::Size32, ScalarSize::Size64),
1910 IntToFpuOp::U32ToF64 => ("ucvtf", OperandSize::Size32, ScalarSize::Size64),
1911 IntToFpuOp::I64ToF64 => ("scvtf", OperandSize::Size64, ScalarSize::Size64),
1912 IntToFpuOp::U64ToF64 => ("ucvtf", OperandSize::Size64, ScalarSize::Size64),
1913 };
1914 let rd = pretty_print_vreg_scalar(rd.to_reg(), sizedest);
1915 let rn = pretty_print_ireg(rn, sizesrc);
1916 format!("{op} {rd}, {rn}")
1917 }
1918 &Inst::FpuCSel16 { rd, rn, rm, cond } => {
1919 let rd = pretty_print_vreg_scalar(rd.to_reg(), ScalarSize::Size16);
1920 let rn = pretty_print_vreg_scalar(rn, ScalarSize::Size16);
1921 let rm = pretty_print_vreg_scalar(rm, ScalarSize::Size16);
1922 let cond = cond.pretty_print(0);
1923 format!("fcsel {rd}, {rn}, {rm}, {cond}")
1924 }
1925 &Inst::FpuCSel32 { rd, rn, rm, cond } => {
1926 let rd = pretty_print_vreg_scalar(rd.to_reg(), ScalarSize::Size32);
1927 let rn = pretty_print_vreg_scalar(rn, ScalarSize::Size32);
1928 let rm = pretty_print_vreg_scalar(rm, ScalarSize::Size32);
1929 let cond = cond.pretty_print(0);
1930 format!("fcsel {rd}, {rn}, {rm}, {cond}")
1931 }
1932 &Inst::FpuCSel64 { rd, rn, rm, cond } => {
1933 let rd = pretty_print_vreg_scalar(rd.to_reg(), ScalarSize::Size64);
1934 let rn = pretty_print_vreg_scalar(rn, ScalarSize::Size64);
1935 let rm = pretty_print_vreg_scalar(rm, ScalarSize::Size64);
1936 let cond = cond.pretty_print(0);
1937 format!("fcsel {rd}, {rn}, {rm}, {cond}")
1938 }
1939 &Inst::FpuRound { op, rd, rn } => {
1940 let (inst, size) = match op {
1941 FpuRoundMode::Minus32 => ("frintm", ScalarSize::Size32),
1942 FpuRoundMode::Minus64 => ("frintm", ScalarSize::Size64),
1943 FpuRoundMode::Plus32 => ("frintp", ScalarSize::Size32),
1944 FpuRoundMode::Plus64 => ("frintp", ScalarSize::Size64),
1945 FpuRoundMode::Zero32 => ("frintz", ScalarSize::Size32),
1946 FpuRoundMode::Zero64 => ("frintz", ScalarSize::Size64),
1947 FpuRoundMode::Nearest32 => ("frintn", ScalarSize::Size32),
1948 FpuRoundMode::Nearest64 => ("frintn", ScalarSize::Size64),
1949 };
1950 let rd = pretty_print_vreg_scalar(rd.to_reg(), size);
1951 let rn = pretty_print_vreg_scalar(rn, size);
1952 format!("{inst} {rd}, {rn}")
1953 }
1954 &Inst::MovToFpu { rd, rn, size } => {
1955 let operand_size = size.operand_size();
1956 let rd = pretty_print_vreg_scalar(rd.to_reg(), size);
1957 let rn = pretty_print_ireg(rn, operand_size);
1958 format!("fmov {rd}, {rn}")
1959 }
1960 &Inst::FpuMoveFPImm { rd, imm, size } => {
1961 let imm = imm.pretty_print(0);
1962 let rd = pretty_print_vreg_scalar(rd.to_reg(), size);
1963
1964 format!("fmov {rd}, {imm}")
1965 }
1966 &Inst::MovToVec {
1967 rd,
1968 ri,
1969 rn,
1970 idx,
1971 size,
1972 } => {
1973 let rd = pretty_print_vreg_element(rd.to_reg(), idx as usize, size.lane_size());
1974 let ri = pretty_print_vreg_element(ri, idx as usize, size.lane_size());
1975 let rn = pretty_print_ireg(rn, size.operand_size());
1976 format!("mov {rd}, {ri}, {rn}")
1977 }
1978 &Inst::MovFromVec { rd, rn, idx, size } => {
1979 let op = match size {
1980 ScalarSize::Size8 => "umov",
1981 ScalarSize::Size16 => "umov",
1982 ScalarSize::Size32 => "mov",
1983 ScalarSize::Size64 => "mov",
1984 _ => unimplemented!(),
1985 };
1986 let rd = pretty_print_ireg(rd.to_reg(), size.operand_size());
1987 let rn = pretty_print_vreg_element(rn, idx as usize, size);
1988 format!("{op} {rd}, {rn}")
1989 }
1990 &Inst::MovFromVecSigned {
1991 rd,
1992 rn,
1993 idx,
1994 size,
1995 scalar_size,
1996 } => {
1997 let rd = pretty_print_ireg(rd.to_reg(), scalar_size);
1998 let rn = pretty_print_vreg_element(rn, idx as usize, size.lane_size());
1999 format!("smov {rd}, {rn}")
2000 }
2001 &Inst::VecDup { rd, rn, size } => {
2002 let rd = pretty_print_vreg_vector(rd.to_reg(), size);
2003 let rn = pretty_print_ireg(rn, size.operand_size());
2004 format!("dup {rd}, {rn}")
2005 }
2006 &Inst::VecDupFromFpu { rd, rn, size, lane } => {
2007 let rd = pretty_print_vreg_vector(rd.to_reg(), size);
2008 let rn = pretty_print_vreg_element(rn, lane.into(), size.lane_size());
2009 format!("dup {rd}, {rn}")
2010 }
2011 &Inst::VecDupFPImm { rd, imm, size } => {
2012 let imm = imm.pretty_print(0);
2013 let rd = pretty_print_vreg_vector(rd.to_reg(), size);
2014
2015 format!("fmov {rd}, {imm}")
2016 }
2017 &Inst::VecDupImm {
2018 rd,
2019 imm,
2020 invert,
2021 size,
2022 } => {
2023 let imm = imm.pretty_print(0);
2024 let op = if invert { "mvni" } else { "movi" };
2025 let rd = pretty_print_vreg_vector(rd.to_reg(), size);
2026
2027 format!("{op} {rd}, {imm}")
2028 }
2029 &Inst::VecExtend {
2030 t,
2031 rd,
2032 rn,
2033 high_half,
2034 lane_size,
2035 } => {
2036 let vec64 = VectorSize::from_lane_size(lane_size.narrow(), false);
2037 let vec128 = VectorSize::from_lane_size(lane_size.narrow(), true);
2038 let rd_size = VectorSize::from_lane_size(lane_size, true);
2039 let (op, rn_size) = match (t, high_half) {
2040 (VecExtendOp::Sxtl, false) => ("sxtl", vec64),
2041 (VecExtendOp::Sxtl, true) => ("sxtl2", vec128),
2042 (VecExtendOp::Uxtl, false) => ("uxtl", vec64),
2043 (VecExtendOp::Uxtl, true) => ("uxtl2", vec128),
2044 };
2045 let rd = pretty_print_vreg_vector(rd.to_reg(), rd_size);
2046 let rn = pretty_print_vreg_vector(rn, rn_size);
2047 format!("{op} {rd}, {rn}")
2048 }
2049 &Inst::VecMovElement {
2050 rd,
2051 ri,
2052 rn,
2053 dest_idx,
2054 src_idx,
2055 size,
2056 } => {
2057 let rd =
2058 pretty_print_vreg_element(rd.to_reg(), dest_idx as usize, size.lane_size());
2059 let ri = pretty_print_vreg_element(ri, dest_idx as usize, size.lane_size());
2060 let rn = pretty_print_vreg_element(rn, src_idx as usize, size.lane_size());
2061 format!("mov {rd}, {ri}, {rn}")
2062 }
2063 &Inst::VecRRLong {
2064 op,
2065 rd,
2066 rn,
2067 high_half,
2068 } => {
2069 let (op, rd_size, size, suffix) = match (op, high_half) {
2070 (VecRRLongOp::Fcvtl16, false) => {
2071 ("fcvtl", VectorSize::Size32x4, VectorSize::Size16x4, "")
2072 }
2073 (VecRRLongOp::Fcvtl16, true) => {
2074 ("fcvtl2", VectorSize::Size32x4, VectorSize::Size16x8, "")
2075 }
2076 (VecRRLongOp::Fcvtl32, false) => {
2077 ("fcvtl", VectorSize::Size64x2, VectorSize::Size32x2, "")
2078 }
2079 (VecRRLongOp::Fcvtl32, true) => {
2080 ("fcvtl2", VectorSize::Size64x2, VectorSize::Size32x4, "")
2081 }
2082 (VecRRLongOp::Shll8, false) => {
2083 ("shll", VectorSize::Size16x8, VectorSize::Size8x8, ", #8")
2084 }
2085 (VecRRLongOp::Shll8, true) => {
2086 ("shll2", VectorSize::Size16x8, VectorSize::Size8x16, ", #8")
2087 }
2088 (VecRRLongOp::Shll16, false) => {
2089 ("shll", VectorSize::Size32x4, VectorSize::Size16x4, ", #16")
2090 }
2091 (VecRRLongOp::Shll16, true) => {
2092 ("shll2", VectorSize::Size32x4, VectorSize::Size16x8, ", #16")
2093 }
2094 (VecRRLongOp::Shll32, false) => {
2095 ("shll", VectorSize::Size64x2, VectorSize::Size32x2, ", #32")
2096 }
2097 (VecRRLongOp::Shll32, true) => {
2098 ("shll2", VectorSize::Size64x2, VectorSize::Size32x4, ", #32")
2099 }
2100 };
2101 let rd = pretty_print_vreg_vector(rd.to_reg(), rd_size);
2102 let rn = pretty_print_vreg_vector(rn, size);
2103
2104 format!("{op} {rd}, {rn}{suffix}")
2105 }
2106 &Inst::VecRRNarrowLow {
2107 op,
2108 rd,
2109 rn,
2110 lane_size,
2111 ..
2112 }
2113 | &Inst::VecRRNarrowHigh {
2114 op,
2115 rd,
2116 rn,
2117 lane_size,
2118 ..
2119 } => {
2120 let vec64 = VectorSize::from_lane_size(lane_size, false);
2121 let vec128 = VectorSize::from_lane_size(lane_size, true);
2122 let rn_size = VectorSize::from_lane_size(lane_size.widen(), true);
2123 let high_half = match self {
2124 &Inst::VecRRNarrowLow { .. } => false,
2125 &Inst::VecRRNarrowHigh { .. } => true,
2126 _ => unreachable!(),
2127 };
2128 let (op, rd_size) = match (op, high_half) {
2129 (VecRRNarrowOp::Xtn, false) => ("xtn", vec64),
2130 (VecRRNarrowOp::Xtn, true) => ("xtn2", vec128),
2131 (VecRRNarrowOp::Sqxtn, false) => ("sqxtn", vec64),
2132 (VecRRNarrowOp::Sqxtn, true) => ("sqxtn2", vec128),
2133 (VecRRNarrowOp::Sqxtun, false) => ("sqxtun", vec64),
2134 (VecRRNarrowOp::Sqxtun, true) => ("sqxtun2", vec128),
2135 (VecRRNarrowOp::Uqxtn, false) => ("uqxtn", vec64),
2136 (VecRRNarrowOp::Uqxtn, true) => ("uqxtn2", vec128),
2137 (VecRRNarrowOp::Fcvtn, false) => ("fcvtn", vec64),
2138 (VecRRNarrowOp::Fcvtn, true) => ("fcvtn2", vec128),
2139 };
2140 let rn = pretty_print_vreg_vector(rn, rn_size);
2141 let rd = pretty_print_vreg_vector(rd.to_reg(), rd_size);
2142 let ri = match self {
2143 &Inst::VecRRNarrowLow { .. } => "".to_string(),
2144 &Inst::VecRRNarrowHigh { ri, .. } => {
2145 format!("{}, ", pretty_print_vreg_vector(ri, rd_size))
2146 }
2147 _ => unreachable!(),
2148 };
2149
2150 format!("{op} {rd}, {ri}{rn}")
2151 }
2152 &Inst::VecRRPair { op, rd, rn } => {
2153 let op = match op {
2154 VecPairOp::Addp => "addp",
2155 };
2156 let rd = pretty_print_vreg_scalar(rd.to_reg(), ScalarSize::Size64);
2157 let rn = pretty_print_vreg_vector(rn, VectorSize::Size64x2);
2158
2159 format!("{op} {rd}, {rn}")
2160 }
2161 &Inst::VecRRPairLong { op, rd, rn } => {
2162 let (op, dest, src) = match op {
2163 VecRRPairLongOp::Saddlp8 => {
2164 ("saddlp", VectorSize::Size16x8, VectorSize::Size8x16)
2165 }
2166 VecRRPairLongOp::Saddlp16 => {
2167 ("saddlp", VectorSize::Size32x4, VectorSize::Size16x8)
2168 }
2169 VecRRPairLongOp::Uaddlp8 => {
2170 ("uaddlp", VectorSize::Size16x8, VectorSize::Size8x16)
2171 }
2172 VecRRPairLongOp::Uaddlp16 => {
2173 ("uaddlp", VectorSize::Size32x4, VectorSize::Size16x8)
2174 }
2175 };
2176 let rd = pretty_print_vreg_vector(rd.to_reg(), dest);
2177 let rn = pretty_print_vreg_vector(rn, src);
2178
2179 format!("{op} {rd}, {rn}")
2180 }
2181 &Inst::VecRRR {
2182 rd,
2183 rn,
2184 rm,
2185 alu_op,
2186 size,
2187 } => {
2188 let (op, size) = match alu_op {
2189 VecALUOp::Sqadd => ("sqadd", size),
2190 VecALUOp::Uqadd => ("uqadd", size),
2191 VecALUOp::Sqsub => ("sqsub", size),
2192 VecALUOp::Uqsub => ("uqsub", size),
2193 VecALUOp::Cmeq => ("cmeq", size),
2194 VecALUOp::Cmge => ("cmge", size),
2195 VecALUOp::Cmgt => ("cmgt", size),
2196 VecALUOp::Cmhs => ("cmhs", size),
2197 VecALUOp::Cmhi => ("cmhi", size),
2198 VecALUOp::Fcmeq => ("fcmeq", size),
2199 VecALUOp::Fcmgt => ("fcmgt", size),
2200 VecALUOp::Fcmge => ("fcmge", size),
2201 VecALUOp::And => ("and", VectorSize::Size8x16),
2202 VecALUOp::Bic => ("bic", VectorSize::Size8x16),
2203 VecALUOp::Orr => ("orr", VectorSize::Size8x16),
2204 VecALUOp::Eor => ("eor", VectorSize::Size8x16),
2205 VecALUOp::Umaxp => ("umaxp", size),
2206 VecALUOp::Add => ("add", size),
2207 VecALUOp::Sub => ("sub", size),
2208 VecALUOp::Mul => ("mul", size),
2209 VecALUOp::Sshl => ("sshl", size),
2210 VecALUOp::Ushl => ("ushl", size),
2211 VecALUOp::Umin => ("umin", size),
2212 VecALUOp::Smin => ("smin", size),
2213 VecALUOp::Umax => ("umax", size),
2214 VecALUOp::Smax => ("smax", size),
2215 VecALUOp::Urhadd => ("urhadd", size),
2216 VecALUOp::Fadd => ("fadd", size),
2217 VecALUOp::Fsub => ("fsub", size),
2218 VecALUOp::Fdiv => ("fdiv", size),
2219 VecALUOp::Fmax => ("fmax", size),
2220 VecALUOp::Fmin => ("fmin", size),
2221 VecALUOp::Fmul => ("fmul", size),
2222 VecALUOp::Addp => ("addp", size),
2223 VecALUOp::Zip1 => ("zip1", size),
2224 VecALUOp::Zip2 => ("zip2", size),
2225 VecALUOp::Sqrdmulh => ("sqrdmulh", size),
2226 VecALUOp::Uzp1 => ("uzp1", size),
2227 VecALUOp::Uzp2 => ("uzp2", size),
2228 VecALUOp::Trn1 => ("trn1", size),
2229 VecALUOp::Trn2 => ("trn2", size),
2230 };
2231 let rd = pretty_print_vreg_vector(rd.to_reg(), size);
2232 let rn = pretty_print_vreg_vector(rn, size);
2233 let rm = pretty_print_vreg_vector(rm, size);
2234 format!("{op} {rd}, {rn}, {rm}")
2235 }
2236 &Inst::VecRRRMod {
2237 rd,
2238 ri,
2239 rn,
2240 rm,
2241 alu_op,
2242 size,
2243 } => {
2244 let (op, size) = match alu_op {
2245 VecALUModOp::Bsl => ("bsl", VectorSize::Size8x16),
2246 VecALUModOp::Fmla => ("fmla", size),
2247 VecALUModOp::Fmls => ("fmls", size),
2248 };
2249 let rd = pretty_print_vreg_vector(rd.to_reg(), size);
2250 let ri = pretty_print_vreg_vector(ri, size);
2251 let rn = pretty_print_vreg_vector(rn, size);
2252 let rm = pretty_print_vreg_vector(rm, size);
2253 format!("{op} {rd}, {ri}, {rn}, {rm}")
2254 }
2255 &Inst::VecFmlaElem {
2256 rd,
2257 ri,
2258 rn,
2259 rm,
2260 alu_op,
2261 size,
2262 idx,
2263 } => {
2264 let (op, size) = match alu_op {
2265 VecALUModOp::Fmla => ("fmla", size),
2266 VecALUModOp::Fmls => ("fmls", size),
2267 _ => unreachable!(),
2268 };
2269 let rd = pretty_print_vreg_vector(rd.to_reg(), size);
2270 let ri = pretty_print_vreg_vector(ri, size);
2271 let rn = pretty_print_vreg_vector(rn, size);
2272 let rm = pretty_print_vreg_element(rm, idx.into(), size.lane_size());
2273 format!("{op} {rd}, {ri}, {rn}, {rm}")
2274 }
2275 &Inst::VecRRRLong {
2276 rd,
2277 rn,
2278 rm,
2279 alu_op,
2280 high_half,
2281 } => {
2282 let (op, dest_size, src_size) = match (alu_op, high_half) {
2283 (VecRRRLongOp::Smull8, false) => {
2284 ("smull", VectorSize::Size16x8, VectorSize::Size8x8)
2285 }
2286 (VecRRRLongOp::Smull8, true) => {
2287 ("smull2", VectorSize::Size16x8, VectorSize::Size8x16)
2288 }
2289 (VecRRRLongOp::Smull16, false) => {
2290 ("smull", VectorSize::Size32x4, VectorSize::Size16x4)
2291 }
2292 (VecRRRLongOp::Smull16, true) => {
2293 ("smull2", VectorSize::Size32x4, VectorSize::Size16x8)
2294 }
2295 (VecRRRLongOp::Smull32, false) => {
2296 ("smull", VectorSize::Size64x2, VectorSize::Size32x2)
2297 }
2298 (VecRRRLongOp::Smull32, true) => {
2299 ("smull2", VectorSize::Size64x2, VectorSize::Size32x4)
2300 }
2301 (VecRRRLongOp::Umull8, false) => {
2302 ("umull", VectorSize::Size16x8, VectorSize::Size8x8)
2303 }
2304 (VecRRRLongOp::Umull8, true) => {
2305 ("umull2", VectorSize::Size16x8, VectorSize::Size8x16)
2306 }
2307 (VecRRRLongOp::Umull16, false) => {
2308 ("umull", VectorSize::Size32x4, VectorSize::Size16x4)
2309 }
2310 (VecRRRLongOp::Umull16, true) => {
2311 ("umull2", VectorSize::Size32x4, VectorSize::Size16x8)
2312 }
2313 (VecRRRLongOp::Umull32, false) => {
2314 ("umull", VectorSize::Size64x2, VectorSize::Size32x2)
2315 }
2316 (VecRRRLongOp::Umull32, true) => {
2317 ("umull2", VectorSize::Size64x2, VectorSize::Size32x4)
2318 }
2319 };
2320 let rd = pretty_print_vreg_vector(rd.to_reg(), dest_size);
2321 let rn = pretty_print_vreg_vector(rn, src_size);
2322 let rm = pretty_print_vreg_vector(rm, src_size);
2323 format!("{op} {rd}, {rn}, {rm}")
2324 }
2325 &Inst::VecRRRLongMod {
2326 rd,
2327 ri,
2328 rn,
2329 rm,
2330 alu_op,
2331 high_half,
2332 } => {
2333 let (op, dest_size, src_size) = match (alu_op, high_half) {
2334 (VecRRRLongModOp::Umlal8, false) => {
2335 ("umlal", VectorSize::Size16x8, VectorSize::Size8x8)
2336 }
2337 (VecRRRLongModOp::Umlal8, true) => {
2338 ("umlal2", VectorSize::Size16x8, VectorSize::Size8x16)
2339 }
2340 (VecRRRLongModOp::Umlal16, false) => {
2341 ("umlal", VectorSize::Size32x4, VectorSize::Size16x4)
2342 }
2343 (VecRRRLongModOp::Umlal16, true) => {
2344 ("umlal2", VectorSize::Size32x4, VectorSize::Size16x8)
2345 }
2346 (VecRRRLongModOp::Umlal32, false) => {
2347 ("umlal", VectorSize::Size64x2, VectorSize::Size32x2)
2348 }
2349 (VecRRRLongModOp::Umlal32, true) => {
2350 ("umlal2", VectorSize::Size64x2, VectorSize::Size32x4)
2351 }
2352 };
2353 let rd = pretty_print_vreg_vector(rd.to_reg(), dest_size);
2354 let ri = pretty_print_vreg_vector(ri, dest_size);
2355 let rn = pretty_print_vreg_vector(rn, src_size);
2356 let rm = pretty_print_vreg_vector(rm, src_size);
2357 format!("{op} {rd}, {ri}, {rn}, {rm}")
2358 }
2359 &Inst::VecMisc { op, rd, rn, size } => {
2360 let (op, size, suffix) = match op {
2361 VecMisc2::Not => (
2362 "mvn",
2363 if size.is_128bits() {
2364 VectorSize::Size8x16
2365 } else {
2366 VectorSize::Size8x8
2367 },
2368 "",
2369 ),
2370 VecMisc2::Neg => ("neg", size, ""),
2371 VecMisc2::Abs => ("abs", size, ""),
2372 VecMisc2::Fabs => ("fabs", size, ""),
2373 VecMisc2::Fneg => ("fneg", size, ""),
2374 VecMisc2::Fsqrt => ("fsqrt", size, ""),
2375 VecMisc2::Rev16 => ("rev16", size, ""),
2376 VecMisc2::Rev32 => ("rev32", size, ""),
2377 VecMisc2::Rev64 => ("rev64", size, ""),
2378 VecMisc2::Fcvtzs => ("fcvtzs", size, ""),
2379 VecMisc2::Fcvtzu => ("fcvtzu", size, ""),
2380 VecMisc2::Scvtf => ("scvtf", size, ""),
2381 VecMisc2::Ucvtf => ("ucvtf", size, ""),
2382 VecMisc2::Frintn => ("frintn", size, ""),
2383 VecMisc2::Frintz => ("frintz", size, ""),
2384 VecMisc2::Frintm => ("frintm", size, ""),
2385 VecMisc2::Frintp => ("frintp", size, ""),
2386 VecMisc2::Cnt => ("cnt", size, ""),
2387 VecMisc2::Cmeq0 => ("cmeq", size, ", #0"),
2388 VecMisc2::Cmge0 => ("cmge", size, ", #0"),
2389 VecMisc2::Cmgt0 => ("cmgt", size, ", #0"),
2390 VecMisc2::Cmle0 => ("cmle", size, ", #0"),
2391 VecMisc2::Cmlt0 => ("cmlt", size, ", #0"),
2392 VecMisc2::Fcmeq0 => ("fcmeq", size, ", #0.0"),
2393 VecMisc2::Fcmge0 => ("fcmge", size, ", #0.0"),
2394 VecMisc2::Fcmgt0 => ("fcmgt", size, ", #0.0"),
2395 VecMisc2::Fcmle0 => ("fcmle", size, ", #0.0"),
2396 VecMisc2::Fcmlt0 => ("fcmlt", size, ", #0.0"),
2397 };
2398 let rd = pretty_print_vreg_vector(rd.to_reg(), size);
2399 let rn = pretty_print_vreg_vector(rn, size);
2400 format!("{op} {rd}, {rn}{suffix}")
2401 }
2402 &Inst::VecLanes { op, rd, rn, size } => {
2403 let op = match op {
2404 VecLanesOp::Uminv => "uminv",
2405 VecLanesOp::Addv => "addv",
2406 };
2407 let rd = pretty_print_vreg_scalar(rd.to_reg(), size.lane_size());
2408 let rn = pretty_print_vreg_vector(rn, size);
2409 format!("{op} {rd}, {rn}")
2410 }
2411 &Inst::VecShiftImm {
2412 op,
2413 rd,
2414 rn,
2415 size,
2416 imm,
2417 } => {
2418 let op = match op {
2419 VecShiftImmOp::Shl => "shl",
2420 VecShiftImmOp::Ushr => "ushr",
2421 VecShiftImmOp::Sshr => "sshr",
2422 };
2423 let rd = pretty_print_vreg_vector(rd.to_reg(), size);
2424 let rn = pretty_print_vreg_vector(rn, size);
2425 format!("{op} {rd}, {rn}, #{imm}")
2426 }
2427 &Inst::VecShiftImmMod {
2428 op,
2429 rd,
2430 ri,
2431 rn,
2432 size,
2433 imm,
2434 } => {
2435 let op = match op {
2436 VecShiftImmModOp::Sli => "sli",
2437 };
2438 let rd = pretty_print_vreg_vector(rd.to_reg(), size);
2439 let ri = pretty_print_vreg_vector(ri, size);
2440 let rn = pretty_print_vreg_vector(rn, size);
2441 format!("{op} {rd}, {ri}, {rn}, #{imm}")
2442 }
2443 &Inst::VecExtract { rd, rn, rm, imm4 } => {
2444 let rd = pretty_print_vreg_vector(rd.to_reg(), VectorSize::Size8x16);
2445 let rn = pretty_print_vreg_vector(rn, VectorSize::Size8x16);
2446 let rm = pretty_print_vreg_vector(rm, VectorSize::Size8x16);
2447 format!("ext {rd}, {rn}, {rm}, #{imm4}")
2448 }
2449 &Inst::VecTbl { rd, rn, rm } => {
2450 let rn = pretty_print_vreg_vector(rn, VectorSize::Size8x16);
2451 let rm = pretty_print_vreg_vector(rm, VectorSize::Size8x16);
2452 let rd = pretty_print_vreg_vector(rd.to_reg(), VectorSize::Size8x16);
2453 format!("tbl {rd}, {{ {rn} }}, {rm}")
2454 }
2455 &Inst::VecTblExt { rd, ri, rn, rm } => {
2456 let rn = pretty_print_vreg_vector(rn, VectorSize::Size8x16);
2457 let rm = pretty_print_vreg_vector(rm, VectorSize::Size8x16);
2458 let rd = pretty_print_vreg_vector(rd.to_reg(), VectorSize::Size8x16);
2459 let ri = pretty_print_vreg_vector(ri, VectorSize::Size8x16);
2460 format!("tbx {rd}, {ri}, {{ {rn} }}, {rm}")
2461 }
2462 &Inst::VecTbl2 { rd, rn, rn2, rm } => {
2463 let rn = pretty_print_vreg_vector(rn, VectorSize::Size8x16);
2464 let rn2 = pretty_print_vreg_vector(rn2, VectorSize::Size8x16);
2465 let rm = pretty_print_vreg_vector(rm, VectorSize::Size8x16);
2466 let rd = pretty_print_vreg_vector(rd.to_reg(), VectorSize::Size8x16);
2467 format!("tbl {rd}, {{ {rn}, {rn2} }}, {rm}")
2468 }
2469 &Inst::VecTbl2Ext {
2470 rd,
2471 ri,
2472 rn,
2473 rn2,
2474 rm,
2475 } => {
2476 let rn = pretty_print_vreg_vector(rn, VectorSize::Size8x16);
2477 let rn2 = pretty_print_vreg_vector(rn2, VectorSize::Size8x16);
2478 let rm = pretty_print_vreg_vector(rm, VectorSize::Size8x16);
2479 let rd = pretty_print_vreg_vector(rd.to_reg(), VectorSize::Size8x16);
2480 let ri = pretty_print_vreg_vector(ri, VectorSize::Size8x16);
2481 format!("tbx {rd}, {ri}, {{ {rn}, {rn2} }}, {rm}")
2482 }
2483 &Inst::VecLoadReplicate { rd, rn, size, .. } => {
2484 let rd = pretty_print_vreg_vector(rd.to_reg(), size);
2485 let rn = pretty_print_reg(rn);
2486
2487 format!("ld1r {{ {rd} }}, [{rn}]")
2488 }
2489 &Inst::VecCSel { rd, rn, rm, cond } => {
2490 let rd = pretty_print_vreg_vector(rd.to_reg(), VectorSize::Size8x16);
2491 let rn = pretty_print_vreg_vector(rn, VectorSize::Size8x16);
2492 let rm = pretty_print_vreg_vector(rm, VectorSize::Size8x16);
2493 let cond = cond.pretty_print(0);
2494 format!("vcsel {rd}, {rn}, {rm}, {cond} (if-then-else diamond)")
2495 }
2496 &Inst::MovToNZCV { rn } => {
2497 let rn = pretty_print_reg(rn);
2498 format!("msr nzcv, {rn}")
2499 }
2500 &Inst::MovFromNZCV { rd } => {
2501 let rd = pretty_print_reg(rd.to_reg());
2502 format!("mrs {rd}, nzcv")
2503 }
2504 &Inst::Extend {
2505 rd,
2506 rn,
2507 signed: false,
2508 from_bits: 1,
2509 ..
2510 } => {
2511 let rd = pretty_print_ireg(rd.to_reg(), OperandSize::Size32);
2512 let rn = pretty_print_ireg(rn, OperandSize::Size32);
2513 format!("and {rd}, {rn}, #1")
2514 }
2515 &Inst::Extend {
2516 rd,
2517 rn,
2518 signed: false,
2519 from_bits: 32,
2520 to_bits: 64,
2521 } => {
2522 let rd = pretty_print_ireg(rd.to_reg(), OperandSize::Size32);
2526 let rn = pretty_print_ireg(rn, OperandSize::Size32);
2527 format!("mov {rd}, {rn}")
2528 }
2529 &Inst::Extend {
2530 rd,
2531 rn,
2532 signed,
2533 from_bits,
2534 to_bits,
2535 } => {
2536 assert!(from_bits <= to_bits);
2537 let op = match (signed, from_bits) {
2538 (false, 8) => "uxtb",
2539 (true, 8) => "sxtb",
2540 (false, 16) => "uxth",
2541 (true, 16) => "sxth",
2542 (true, 32) => "sxtw",
2543 (true, _) => "sbfx",
2544 (false, _) => "ubfx",
2545 };
2546 if op == "sbfx" || op == "ubfx" {
2547 let dest_size = OperandSize::from_bits(to_bits);
2548 let rd = pretty_print_ireg(rd.to_reg(), dest_size);
2549 let rn = pretty_print_ireg(rn, dest_size);
2550 format!("{op} {rd}, {rn}, #0, #{from_bits}")
2551 } else {
2552 let dest_size = if signed {
2553 OperandSize::from_bits(to_bits)
2554 } else {
2555 OperandSize::Size32
2556 };
2557 let rd = pretty_print_ireg(rd.to_reg(), dest_size);
2558 let rn = pretty_print_ireg(rn, OperandSize::from_bits(from_bits));
2559 format!("{op} {rd}, {rn}")
2560 }
2561 }
2562 &Inst::Call { .. } => format!("bl 0"),
2563 &Inst::CallInd { ref info } => {
2564 let rn = pretty_print_reg(info.dest);
2565 format!("blr {rn}")
2566 }
2567 &Inst::ReturnCall { ref info } => {
2568 let mut s = format!(
2569 "return_call {:?} new_stack_arg_size:{}",
2570 info.dest, info.new_stack_arg_size
2571 );
2572 for ret in &info.uses {
2573 let preg = pretty_print_reg(ret.preg);
2574 let vreg = pretty_print_reg(ret.vreg);
2575 write!(&mut s, " {vreg}={preg}").unwrap();
2576 }
2577 s
2578 }
2579 &Inst::ReturnCallInd { ref info } => {
2580 let callee = pretty_print_reg(info.dest);
2581 let mut s = format!(
2582 "return_call_ind {callee} new_stack_arg_size:{}",
2583 info.new_stack_arg_size
2584 );
2585 for ret in &info.uses {
2586 let preg = pretty_print_reg(ret.preg);
2587 let vreg = pretty_print_reg(ret.vreg);
2588 write!(&mut s, " {vreg}={preg}").unwrap();
2589 }
2590 s
2591 }
2592 &Inst::Args { ref args } => {
2593 let mut s = "args".to_string();
2594 for arg in args {
2595 let preg = pretty_print_reg(arg.preg);
2596 let def = pretty_print_reg(arg.vreg.to_reg());
2597 write!(&mut s, " {def}={preg}").unwrap();
2598 }
2599 s
2600 }
2601 &Inst::Rets { ref rets } => {
2602 let mut s = "rets".to_string();
2603 for ret in rets {
2604 let preg = pretty_print_reg(ret.preg);
2605 let vreg = pretty_print_reg(ret.vreg);
2606 write!(&mut s, " {vreg}={preg}").unwrap();
2607 }
2608 s
2609 }
2610 &Inst::Ret {} => "ret".to_string(),
2611 &Inst::AuthenticatedRet { key, is_hint } => {
2612 let key = match key {
2613 APIKey::AZ => "az",
2614 APIKey::BZ => "bz",
2615 APIKey::ASP => "asp",
2616 APIKey::BSP => "bsp",
2617 };
2618 match is_hint {
2619 false => format!("reta{key}"),
2620 true => format!("auti{key} ; ret"),
2621 }
2622 }
2623 &Inst::Jump { ref dest } => {
2624 let dest = dest.pretty_print(0);
2625 format!("b {dest}")
2626 }
2627 &Inst::CondBr {
2628 ref taken,
2629 ref not_taken,
2630 ref kind,
2631 } => {
2632 let taken = taken.pretty_print(0);
2633 let not_taken = not_taken.pretty_print(0);
2634 match kind {
2635 &CondBrKind::Zero(reg, size) => {
2636 let reg = pretty_print_reg_sized(reg, size);
2637 format!("cbz {reg}, {taken} ; b {not_taken}")
2638 }
2639 &CondBrKind::NotZero(reg, size) => {
2640 let reg = pretty_print_reg_sized(reg, size);
2641 format!("cbnz {reg}, {taken} ; b {not_taken}")
2642 }
2643 &CondBrKind::Cond(c) => {
2644 let c = c.pretty_print(0);
2645 format!("b.{c} {taken} ; b {not_taken}")
2646 }
2647 }
2648 }
2649 &Inst::TestBitAndBranch {
2650 kind,
2651 ref taken,
2652 ref not_taken,
2653 rn,
2654 bit,
2655 } => {
2656 let cond = match kind {
2657 TestBitAndBranchKind::Z => "z",
2658 TestBitAndBranchKind::NZ => "nz",
2659 };
2660 let taken = taken.pretty_print(0);
2661 let not_taken = not_taken.pretty_print(0);
2662 let rn = pretty_print_reg(rn);
2663 format!("tb{cond} {rn}, #{bit}, {taken} ; b {not_taken}")
2664 }
2665 &Inst::IndirectBr { rn, .. } => {
2666 let rn = pretty_print_reg(rn);
2667 format!("br {rn}")
2668 }
2669 &Inst::Brk => "brk #0".to_string(),
2670 &Inst::Udf { .. } => "udf #0xc11f".to_string(),
2671 &Inst::TrapIf {
2672 ref kind,
2673 trap_code,
2674 } => match kind {
2675 &CondBrKind::Zero(reg, size) => {
2676 let reg = pretty_print_reg_sized(reg, size);
2677 format!("cbz {reg}, #trap={trap_code}")
2678 }
2679 &CondBrKind::NotZero(reg, size) => {
2680 let reg = pretty_print_reg_sized(reg, size);
2681 format!("cbnz {reg}, #trap={trap_code}")
2682 }
2683 &CondBrKind::Cond(c) => {
2684 let c = c.pretty_print(0);
2685 format!("b.{c} #trap={trap_code}")
2686 }
2687 },
2688 &Inst::Adr { rd, off } => {
2689 let rd = pretty_print_reg(rd.to_reg());
2690 format!("adr {rd}, pc+{off}")
2691 }
2692 &Inst::Adrp { rd, off } => {
2693 let rd = pretty_print_reg(rd.to_reg());
2694 let byte_offset = off * 4096;
2696 format!("adrp {rd}, pc+{byte_offset}")
2697 }
2698 &Inst::Word4 { data } => format!("data.i32 {data}"),
2699 &Inst::Word8 { data } => format!("data.i64 {data}"),
2700 &Inst::JTSequence {
2701 default,
2702 ref targets,
2703 ridx,
2704 rtmp1,
2705 rtmp2,
2706 ..
2707 } => {
2708 let ridx = pretty_print_reg(ridx);
2709 let rtmp1 = pretty_print_reg(rtmp1.to_reg());
2710 let rtmp2 = pretty_print_reg(rtmp2.to_reg());
2711 let default_target = BranchTarget::Label(default).pretty_print(0);
2712 format!(
2713 concat!(
2714 "b.hs {} ; ",
2715 "csel {}, xzr, {}, hs ; ",
2716 "csdb ; ",
2717 "adr {}, pc+16 ; ",
2718 "ldrsw {}, [{}, {}, uxtw #2] ; ",
2719 "add {}, {}, {} ; ",
2720 "br {} ; ",
2721 "jt_entries {:?}"
2722 ),
2723 default_target,
2724 rtmp2,
2725 ridx,
2726 rtmp1,
2727 rtmp2,
2728 rtmp1,
2729 rtmp2,
2730 rtmp1,
2731 rtmp1,
2732 rtmp2,
2733 rtmp1,
2734 targets
2735 )
2736 }
2737 &Inst::LoadExtName {
2738 rd,
2739 ref name,
2740 offset,
2741 } => {
2742 let rd = pretty_print_reg(rd.to_reg());
2743 format!("load_ext_name {rd}, {name:?}+{offset}")
2744 }
2745 &Inst::LoadAddr { rd, ref mem } => {
2746 let mem = mem.clone();
2751 let (mem_insts, mem) = mem_finalize(None, &mem, I8, state);
2752 let mut ret = String::new();
2753 for inst in mem_insts.into_iter() {
2754 ret.push_str(&inst.print_with_state(&mut EmitState::default()));
2755 }
2756 let (reg, index_reg, offset) = match mem {
2757 AMode::RegExtended { rn, rm, extendop } => (rn, Some((rm, extendop)), 0),
2758 AMode::Unscaled { rn, simm9 } => (rn, None, simm9.value()),
2759 AMode::UnsignedOffset { rn, uimm12 } => (rn, None, uimm12.value() as i32),
2760 _ => panic!("Unsupported case for LoadAddr: {mem:?}"),
2761 };
2762 let abs_offset = if offset < 0 {
2763 -offset as u64
2764 } else {
2765 offset as u64
2766 };
2767 let alu_op = if offset < 0 { ALUOp::Sub } else { ALUOp::Add };
2768
2769 if let Some((idx, extendop)) = index_reg {
2770 let add = Inst::AluRRRExtend {
2771 alu_op: ALUOp::Add,
2772 size: OperandSize::Size64,
2773 rd,
2774 rn: reg,
2775 rm: idx,
2776 extendop,
2777 };
2778
2779 ret.push_str(&add.print_with_state(&mut EmitState::default()));
2780 } else if offset == 0 {
2781 let mov = Inst::gen_move(rd, reg, I64);
2782 ret.push_str(&mov.print_with_state(&mut EmitState::default()));
2783 } else if let Some(imm12) = Imm12::maybe_from_u64(abs_offset) {
2784 let add = Inst::AluRRImm12 {
2785 alu_op,
2786 size: OperandSize::Size64,
2787 rd,
2788 rn: reg,
2789 imm12,
2790 };
2791 ret.push_str(&add.print_with_state(&mut EmitState::default()));
2792 } else {
2793 let tmp = writable_spilltmp_reg();
2794 for inst in Inst::load_constant(tmp, abs_offset, &mut |_| tmp).into_iter() {
2795 ret.push_str(&inst.print_with_state(&mut EmitState::default()));
2796 }
2797 let add = Inst::AluRRR {
2798 alu_op,
2799 size: OperandSize::Size64,
2800 rd,
2801 rn: reg,
2802 rm: tmp.to_reg(),
2803 };
2804 ret.push_str(&add.print_with_state(&mut EmitState::default()));
2805 }
2806 ret
2807 }
2808 &Inst::Paci { key } => {
2809 let key = match key {
2810 APIKey::AZ => "az",
2811 APIKey::BZ => "bz",
2812 APIKey::ASP => "asp",
2813 APIKey::BSP => "bsp",
2814 };
2815
2816 "paci".to_string() + key
2817 }
2818 &Inst::Xpaclri => "xpaclri".to_string(),
2819 &Inst::Bti { targets } => {
2820 let targets = match targets {
2821 BranchTargetType::None => "",
2822 BranchTargetType::C => " c",
2823 BranchTargetType::J => " j",
2824 BranchTargetType::JC => " jc",
2825 };
2826
2827 "bti".to_string() + targets
2828 }
2829 &Inst::EmitIsland { needed_space } => format!("emit_island {needed_space}"),
2830
2831 &Inst::ElfTlsGetAddr {
2832 ref symbol,
2833 rd,
2834 tmp,
2835 } => {
2836 let rd = pretty_print_reg(rd.to_reg());
2837 let tmp = pretty_print_reg(tmp.to_reg());
2838 format!("elf_tls_get_addr {}, {}, {}", rd, tmp, symbol.display(None))
2839 }
2840 &Inst::MachOTlsGetAddr { ref symbol, rd } => {
2841 let rd = pretty_print_reg(rd.to_reg());
2842 format!("macho_tls_get_addr {}, {}", rd, symbol.display(None))
2843 }
2844 &Inst::Unwind { ref inst } => {
2845 format!("unwind {inst:?}")
2846 }
2847 &Inst::DummyUse { reg } => {
2848 let reg = pretty_print_reg(reg);
2849 format!("dummy_use {reg}")
2850 }
2851 &Inst::StackProbeLoop { start, end, step } => {
2852 let start = pretty_print_reg(start.to_reg());
2853 let end = pretty_print_reg(end);
2854 let step = step.pretty_print(0);
2855 format!("stack_probe_loop {start}, {end}, {step}")
2856 }
2857 }
2858 }
2859}
2860
2861#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2866pub enum LabelUse {
2867 Branch14,
2870 Branch19,
2873 Branch26,
2876 #[allow(dead_code)]
2877 Ldr19,
2880 #[allow(dead_code)]
2881 Adr21,
2884 PCRel32,
2887}
2888
2889impl MachInstLabelUse for LabelUse {
2890 const ALIGN: CodeOffset = 4;
2892
2893 fn max_pos_range(self) -> CodeOffset {
2895 match self {
2896 LabelUse::Branch14 => (1 << 15) - 1,
2900 LabelUse::Branch19 => (1 << 20) - 1,
2901 LabelUse::Branch26 => (1 << 27) - 1,
2902 LabelUse::Ldr19 => (1 << 20) - 1,
2903 LabelUse::Adr21 => (1 << 20) - 1,
2906 LabelUse::PCRel32 => 0x7fffffff,
2907 }
2908 }
2909
2910 fn max_neg_range(self) -> CodeOffset {
2912 self.max_pos_range() + 1
2915 }
2916
2917 fn patch_size(self) -> CodeOffset {
2919 4
2921 }
2922
2923 fn patch(self, buffer: &mut [u8], use_offset: CodeOffset, label_offset: CodeOffset) {
2925 let pc_rel = (label_offset as i64) - (use_offset as i64);
2926 debug_assert!(pc_rel <= self.max_pos_range() as i64);
2927 debug_assert!(pc_rel >= -(self.max_neg_range() as i64));
2928 let pc_rel = pc_rel as u32;
2929 let insn_word = u32::from_le_bytes([buffer[0], buffer[1], buffer[2], buffer[3]]);
2930 let mask = match self {
2931 LabelUse::Branch14 => 0x0007ffe0, LabelUse::Branch19 => 0x00ffffe0, LabelUse::Branch26 => 0x03ffffff, LabelUse::Ldr19 => 0x00ffffe0, LabelUse::Adr21 => 0x60ffffe0, LabelUse::PCRel32 => 0xffffffff,
2937 };
2938 let pc_rel_shifted = match self {
2939 LabelUse::Adr21 | LabelUse::PCRel32 => pc_rel,
2940 _ => {
2941 debug_assert!(pc_rel & 3 == 0);
2942 pc_rel >> 2
2943 }
2944 };
2945 let pc_rel_inserted = match self {
2946 LabelUse::Branch14 => (pc_rel_shifted & 0x3fff) << 5,
2947 LabelUse::Branch19 | LabelUse::Ldr19 => (pc_rel_shifted & 0x7ffff) << 5,
2948 LabelUse::Branch26 => pc_rel_shifted & 0x3ffffff,
2949 LabelUse::Adr21 => (pc_rel_shifted & 0x7ffff) << 5 | (pc_rel_shifted & 0x180000) << 10,
2950 LabelUse::PCRel32 => pc_rel_shifted,
2951 };
2952 let is_add = match self {
2953 LabelUse::PCRel32 => true,
2954 _ => false,
2955 };
2956 let insn_word = if is_add {
2957 insn_word.wrapping_add(pc_rel_inserted)
2958 } else {
2959 (insn_word & !mask) | pc_rel_inserted
2960 };
2961 buffer[0..4].clone_from_slice(&u32::to_le_bytes(insn_word));
2962 }
2963
2964 fn supports_veneer(self) -> bool {
2966 match self {
2967 LabelUse::Branch14 | LabelUse::Branch19 => true, LabelUse::Branch26 => true, _ => false,
2970 }
2971 }
2972
2973 fn veneer_size(self) -> CodeOffset {
2975 match self {
2976 LabelUse::Branch14 | LabelUse::Branch19 => 4,
2977 LabelUse::Branch26 => 20,
2978 _ => unreachable!(),
2979 }
2980 }
2981
2982 fn worst_case_veneer_size() -> CodeOffset {
2983 20
2984 }
2985
2986 fn generate_veneer(
2989 self,
2990 buffer: &mut [u8],
2991 veneer_offset: CodeOffset,
2992 ) -> (CodeOffset, LabelUse) {
2993 match self {
2994 LabelUse::Branch14 | LabelUse::Branch19 => {
2995 let insn_word = 0b000101 << 26;
2998 buffer[0..4].clone_from_slice(&u32::to_le_bytes(insn_word));
2999 (veneer_offset, LabelUse::Branch26)
3000 }
3001
3002 LabelUse::Branch26 => {
3013 let tmp1 = regs::spilltmp_reg();
3014 let tmp1_w = regs::writable_spilltmp_reg();
3015 let tmp2 = regs::tmp2_reg();
3016 let tmp2_w = regs::writable_tmp2_reg();
3017 let ldr = emit::enc_ldst_imm19(0b1001_1000, 16 / 4, tmp1);
3019 let adr = emit::enc_adr(12, tmp2_w);
3021 let add = emit::enc_arith_rrr(0b10001011_000, 0, tmp1_w, tmp1, tmp2);
3023 let br = emit::enc_br(tmp1);
3025 buffer[0..4].clone_from_slice(&u32::to_le_bytes(ldr));
3026 buffer[4..8].clone_from_slice(&u32::to_le_bytes(adr));
3027 buffer[8..12].clone_from_slice(&u32::to_le_bytes(add));
3028 buffer[12..16].clone_from_slice(&u32::to_le_bytes(br));
3029 (veneer_offset + 16, LabelUse::PCRel32)
3032 }
3033
3034 _ => panic!("Unsupported label-reference type for veneer generation!"),
3035 }
3036 }
3037
3038 fn from_reloc(reloc: Reloc, addend: Addend) -> Option<LabelUse> {
3039 match (reloc, addend) {
3040 (Reloc::Arm64Call, 0) => Some(LabelUse::Branch26),
3041 _ => None,
3042 }
3043 }
3044}
3045
3046#[cfg(test)]
3047mod tests {
3048 use super::*;
3049
3050 #[test]
3051 fn inst_size_test() {
3052 let expected = if cfg!(target_pointer_width = "32") && !cfg!(target_arch = "arm") {
3055 28
3056 } else {
3057 32
3058 };
3059 assert_eq!(expected, std::mem::size_of::<Inst>());
3060 }
3061}