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