cranelift_codegen/isa/aarch64/inst/
mod.rs

1//! This module defines aarch64-specific machine instruction types.
2
3use 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
33//=============================================================================
34// Instructions (top level): definition
35
36pub 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/// A floating-point unit (FPU) operation with two args, a register and an immediate.
44#[derive(Copy, Clone, Debug)]
45pub enum FPUOpRI {
46    /// Unsigned right shift. Rd = Rn << #imm
47    UShr32(FPURightShiftImm),
48    /// Unsigned right shift. Rd = Rn << #imm
49    UShr64(FPURightShiftImm),
50}
51
52/// A floating-point unit (FPU) operation with two args, a register and
53/// an immediate that modifies its dest (so takes that input value as a
54/// separate virtual register).
55#[derive(Copy, Clone, Debug)]
56pub enum FPUOpRIMod {
57    /// Shift left and insert. Rd |= Rn << #imm
58    Sli32(FPULeftShiftImm),
59    /// Shift left and insert. Rd |= Rn << #imm
60    Sli64(FPULeftShiftImm),
61}
62
63impl BitOp {
64    /// Get the assembly mnemonic for this opcode.
65    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/// Additional information for (direct) Call instructions, left out of line to lower the size of
78/// the Inst enum.
79#[derive(Clone, Debug)]
80pub struct CallInfo {
81    /// Call destination.
82    pub dest: ExternalName,
83    /// Arguments to the call instruction.
84    pub uses: CallArgList,
85    /// Return values from the call instruction.
86    pub defs: CallRetList,
87    /// Clobbers register set.
88    pub clobbers: PRegSet,
89    /// Caller calling convention.
90    pub caller_callconv: CallConv,
91    /// Callee calling convention.
92    pub callee_callconv: CallConv,
93    /// The number of bytes that the callee will pop from the stack for the
94    /// caller, if any. (Used for popping stack arguments with the `tail`
95    /// calling convention.)
96    pub callee_pop_size: u32,
97}
98
99/// Additional information for CallInd instructions, left out of line to lower the size of the Inst
100/// enum.
101#[derive(Clone, Debug)]
102pub struct CallIndInfo {
103    /// Function pointer for indirect call.
104    pub rn: Reg,
105    /// Arguments to the call instruction.
106    pub uses: SmallVec<[CallArgPair; 8]>,
107    /// Return values from the call instruction.
108    pub defs: SmallVec<[CallRetPair; 8]>,
109    /// Clobbers register set.
110    pub clobbers: PRegSet,
111    /// Caller calling convention.
112    pub caller_callconv: CallConv,
113    /// Callee calling convention.
114    pub callee_callconv: CallConv,
115    /// The number of bytes that the callee will pop from the stack for the
116    /// caller, if any. (Used for popping stack arguments with the `tail`
117    /// calling convention.)
118    pub callee_pop_size: u32,
119}
120
121/// Additional information for `return_call[_ind]` instructions, left out of
122/// line to lower the size of the `Inst` enum.
123#[derive(Clone, Debug)]
124pub struct ReturnCallInfo {
125    /// Arguments to the call instruction.
126    pub uses: CallArgList,
127    /// The size of the new stack frame's stack arguments. This is necessary
128    /// for copying the frame over our current frame. It must already be
129    /// allocated on the stack.
130    pub new_stack_arg_size: u32,
131    /// API key to use to restore the return address, if any.
132    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    // This test will help with unintentionally growing the size
150    // of the Inst enum.
151    assert_eq!(32, std::mem::size_of::<Inst>());
152}
153
154impl Inst {
155    /// Create an instruction that loads a constant, using one of several options (MOVZ, MOVN,
156    /// logical immediate, or constant pool).
157    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        // NB: this is duplicated in `lower/isle.rs` and `inst.isle` right now,
163        // if modifications are made here before this is deleted after moving to
164        // ISLE then those locations should be updated as well.
165
166        if let Some(imm) = MoveWideConst::maybe_from_u64(value) {
167            // 16-bit immediate (shifted by 0, 16, 32 or 48 bits) in MOVZ
168            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            // 16-bit immediate (shifted by 0, 16, 32 or 48 bits) in MOVN
176            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            // Weird logical-instruction immediate in ORI using zero register
184            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            // If the top 32 bits are zero, use 32-bit `mov` operations.
195            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            // If the number of 0xffff half words is greater than the number of 0x0000 half words
202            // it is more efficient to use `movn` for the first instruction.
203            let first_is_inverted = count_zero_half_words(negated, num_half_words)
204                > count_zero_half_words(value, num_half_words);
205
206            // Either 0xffff or 0x0000 half words can be skipped, depending on the first
207            // instruction used.
208            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    /// Generic constructor for a load (zero-extending where appropriate).
262    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    /// Generic constructor for a store.
313    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    /// What type does this load or store instruction access in memory? When
364    /// uimm12 encoding is used, the size of this type is the amount that
365    /// immediate offsets are scaled by.
366    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
390//=============================================================================
391// Instructions: get_regs
392
393fn 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); // `rn` == `rd`.
508        }
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); // reuse `rs`.
556            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); // reuse `ri`.
618            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); // `rd` == `ri`.
642            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); // `rd` == `ri`.
659            collector.reg_use(ri);
660        }
661
662        Inst::VecTbl2 { rd, rn, rn2, rm } => {
663            // Constrain to v30 / v31 so that we satisfy the "adjacent
664            // registers" constraint without use of pinned vregs in
665            // lowering.
666            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            // Constrain to v30 / v31 so that we satisfy the "adjacent
679            // registers" constraint without use of pinned vregs in
680            // lowering.
681            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); // `rd` == `ri`.
685            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); // `rd` == `ri`.
770            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); // `rd` == `ri`.
797            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); // `rd` == `ri`.
811            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); // `rd` == `ri`.
824            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); // `rd` == `ri`.
839            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            // TODO(https://github.com/bytecodealliance/regalloc2/issues/145):
893            // This shouldn't be a fixed register constraint, but it's not clear how to pick a
894            // register that won't be clobbered by the callee-save restore code emitted with a
895            // return_call_indirect.
896            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            // Neither LR nor SP is an allocatable register, so there is no need
938            // to do anything.
939        }
940        Inst::Bti { .. } => {}
941
942        Inst::ElfTlsGetAddr { rd, tmp, .. } => {
943            // TLSDESC has a very neat calling convention. It is required to preserve
944            // all registers except x0 and x30. X30 is non allocatable in cranelift since
945            // its the link register.
946            //
947            // Additionally we need a second register as a temporary register for the
948            // TLSDESC sequence. This register can be any register other than x0 (and x30).
949            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
971//=============================================================================
972// Instructions: misc functions and external interface
973
974impl MachInst for Inst {
975    type ABIMachineSpec = AArch64MachineDeps;
976    type LabelUse = LabelUse;
977
978    // "CLIF" in hex, to make the trap recognizable during
979    // debugging.
980    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        // We exclude call instructions from the clobber-set when they are calls
1008        // from caller to callee that both clobber the same register (such as
1009        // using the same or similar ABIs). Such calls cannot possibly force any
1010        // new registers to be saved in the prologue, because anything that the
1011        // callee clobbers, the caller is also allowed to clobber. This both
1012        // saves work and enables us to more precisely follow the
1013        // half-caller-save, half-callee-save SysV ABI for some vector
1014        // registers.
1015        //
1016        // See the note in [crate::isa::aarch64::abi::is_caller_save_reg] for
1017        // more information on this ABI-implementation hack.
1018        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            // TODO: verify this carefully
1077            _ => 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        // We can't give a NOP (or any insn) < 4 bytes.
1125        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        // The maximum size, in bytes, of any `Inst`'s emitted code. We have at least one case of
1168        // an 8-instruction sequence (saturating int-to-float conversions) with three embedded
1169        // 64-bit f64 constants.
1170        //
1171        // Note that inline jump-tables handle island/pool insertion separately, so we do not need
1172        // to account for them here (otherwise the worst case would be 2^31 * 4, clearly not
1173        // feasible for other reasons).
1174        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        // We use 32-byte alignment for performance reasons, but for correctness
1196        // we would only need 4-byte alignment.
1197        FunctionAlignment {
1198            minimum: 4,
1199            preferred: 32,
1200        }
1201    }
1202}
1203
1204//=============================================================================
1205// Pretty-printing of instructions.
1206
1207fn 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                    // special-case MOV (used for moving into SP).
1302                    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                // The case of a zero extension from 32 to 64 bits, is implemented
2528                // with a "mov" to a 32-bit (W-reg) dest, because this zeroes
2529                // the top 32 bits.
2530                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                // This instruction addresses 4KiB pages, so multiply it by the page size.
2703                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                // TODO: we really should find a better way to avoid duplication of
2755                // this logic between `emit()` and `show_rru()` -- a separate 1-to-N
2756                // expansion stage (i.e., legalization, but without the slow edit-in-place
2757                // of the existing legalization framework).
2758                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//=============================================================================
2870// Label fixups and jump veneers.
2871
2872/// Different forms of label references for different instruction formats.
2873#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2874pub enum LabelUse {
2875    /// 14-bit branch offset (conditional branches). PC-rel, offset is imm <<
2876    /// 2. Immediate is 14 signed bits, in bits 18:5. Used by tbz and tbnz.
2877    Branch14,
2878    /// 19-bit branch offset (conditional branches). PC-rel, offset is imm << 2. Immediate is 19
2879    /// signed bits, in bits 23:5. Used by cbz, cbnz, b.cond.
2880    Branch19,
2881    /// 26-bit branch offset (unconditional branches). PC-rel, offset is imm << 2. Immediate is 26
2882    /// signed bits, in bits 25:0. Used by b, bl.
2883    Branch26,
2884    #[allow(dead_code)]
2885    /// 19-bit offset for LDR (load literal). PC-rel, offset is imm << 2. Immediate is 19 signed bits,
2886    /// in bits 23:5.
2887    Ldr19,
2888    #[allow(dead_code)]
2889    /// 21-bit offset for ADR (get address of label). PC-rel, offset is not shifted. Immediate is
2890    /// 21 signed bits, with high 19 bits in bits 23:5 and low 2 bits in bits 30:29.
2891    Adr21,
2892    /// 32-bit PC relative constant offset (from address of constant itself),
2893    /// signed. Used in jump tables.
2894    PCRel32,
2895}
2896
2897impl MachInstLabelUse for LabelUse {
2898    /// Alignment for veneer code. Every AArch64 instruction must be 4-byte-aligned.
2899    const ALIGN: CodeOffset = 4;
2900
2901    /// Maximum PC-relative range (positive), inclusive.
2902    fn max_pos_range(self) -> CodeOffset {
2903        match self {
2904            // N-bit immediate, left-shifted by 2, for (N+2) bits of total
2905            // range. Signed, so +2^(N+1) from zero. Likewise for two other
2906            // shifted cases below.
2907            LabelUse::Branch14 => (1 << 15) - 1,
2908            LabelUse::Branch19 => (1 << 20) - 1,
2909            LabelUse::Branch26 => (1 << 27) - 1,
2910            LabelUse::Ldr19 => (1 << 20) - 1,
2911            // Adr does not shift its immediate, so the 21-bit immediate gives 21 bits of total
2912            // range.
2913            LabelUse::Adr21 => (1 << 20) - 1,
2914            LabelUse::PCRel32 => 0x7fffffff,
2915        }
2916    }
2917
2918    /// Maximum PC-relative range (negative).
2919    fn max_neg_range(self) -> CodeOffset {
2920        // All forms are twos-complement signed offsets, so negative limit is one more than
2921        // positive limit.
2922        self.max_pos_range() + 1
2923    }
2924
2925    /// Size of window into code needed to do the patch.
2926    fn patch_size(self) -> CodeOffset {
2927        // Patch is on one instruction only for all of these label reference types.
2928        4
2929    }
2930
2931    /// Perform the patch.
2932    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, // bits 18..5 inclusive
2940            LabelUse::Branch19 => 0x00ffffe0, // bits 23..5 inclusive
2941            LabelUse::Branch26 => 0x03ffffff, // bits 25..0 inclusive
2942            LabelUse::Ldr19 => 0x00ffffe0,    // bits 23..5 inclusive
2943            LabelUse::Adr21 => 0x60ffffe0,    // bits 30..29, 25..5 inclusive
2944            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    /// Is a veneer supported for this label reference type?
2973    fn supports_veneer(self) -> bool {
2974        match self {
2975            LabelUse::Branch14 | LabelUse::Branch19 => true, // veneer is a Branch26
2976            LabelUse::Branch26 => true,                      // veneer is a PCRel32
2977            _ => false,
2978        }
2979    }
2980
2981    /// How large is the veneer, if supported?
2982    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    /// Generate a veneer into the buffer, given that this veneer is at `veneer_offset`, and return
2995    /// an offset and label-use for the veneer's use of the original label.
2996    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                // veneer is a Branch26 (unconditional branch). Just encode directly here -- don't
3004                // bother with constructing an Inst.
3005                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            // This is promoting a 26-bit call/jump to a 32-bit call/jump to
3011            // get a further range. This jump translates to a jump to a
3012            // relative location based on the address of the constant loaded
3013            // from here.
3014            //
3015            // If this path is taken from a call instruction then caller-saved
3016            // registers are available (minus arguments), so x16/x17 are
3017            // available. Otherwise for intra-function jumps we also reserve
3018            // x16/x17 as spill-style registers. In both cases these are
3019            // available for us to use.
3020            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                // ldrsw x16, 16
3026                let ldr = emit::enc_ldst_imm19(0b1001_1000, 16 / 4, tmp1);
3027                // adr x17, 12
3028                let adr = emit::enc_adr(12, tmp2_w);
3029                // add x16, x16, x17
3030                let add = emit::enc_arith_rrr(0b10001011_000, 0, tmp1_w, tmp1, tmp2);
3031                // br x16
3032                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                // the 4-byte signed immediate we'll load is after these
3038                // instructions, 16-bytes in.
3039                (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}