Skip to main content

objdiff_core/arch/
arm64.rs

1use alloc::{format, string::ToString, vec::Vec};
2use core::cmp::Ordering;
3
4use anyhow::Result;
5use object::elf;
6use yaxpeax_arch::{Arch as YaxpeaxArch, Decoder, Reader, U8Reader};
7use yaxpeax_arm::armv8::a64::{
8    ARMv8, DecodeError, InstDecoder, Instruction, Opcode, Operand, SIMDSizeCode, ShiftStyle,
9    SizeCode,
10};
11
12use crate::{
13    arch::{Arch, OPCODE_INVALID},
14    diff::{DiffObjConfig, display::InstructionPart},
15    obj::{
16        InstructionRef, Relocation, RelocationFlags, ResolvedInstructionRef, ResolvedRelocation,
17    },
18};
19
20#[derive(Debug)]
21pub struct ArchArm64 {}
22
23impl ArchArm64 {
24    pub fn new(_file: &object::File) -> Result<Self> { Ok(Self {}) }
25}
26
27impl Arch for ArchArm64 {
28    fn scan_instructions_internal(
29        &self,
30        address: u64,
31        code: &[u8],
32        _section_index: usize,
33        _relocations: &[Relocation],
34        _diff_config: &DiffObjConfig,
35    ) -> Result<Vec<InstructionRef>> {
36        let start_address = address;
37        let mut ops = Vec::<InstructionRef>::with_capacity(code.len() / 4);
38
39        let mut reader = U8Reader::new(code);
40        let decoder = InstDecoder::default();
41        let mut ins = Instruction::default();
42        loop {
43            // This is ridiculous...
44            let offset = <U8Reader<'_> as Reader<
45                <ARMv8 as YaxpeaxArch>::Address,
46                <ARMv8 as YaxpeaxArch>::Word,
47            >>::total_offset(&mut reader);
48            let address = start_address + offset;
49            match decoder.decode_into(&mut ins, &mut reader) {
50                Ok(()) => {}
51                Err(e) => match e {
52                    DecodeError::ExhaustedInput => break,
53                    DecodeError::InvalidOpcode
54                    | DecodeError::InvalidOperand
55                    | DecodeError::IncompleteDecoder => {
56                        ops.push(InstructionRef {
57                            address,
58                            size: 4,
59                            opcode: OPCODE_INVALID,
60                            branch_dest: None,
61                        });
62                        continue;
63                    }
64                },
65            }
66
67            let opcode = opcode_to_u16(ins.opcode);
68            let branch_dest =
69                branch_dest(opcode, address, &code[offset as usize..offset as usize + 4]);
70            ops.push(InstructionRef { address, size: 4, opcode, branch_dest });
71        }
72
73        Ok(ops)
74    }
75
76    fn display_instruction(
77        &self,
78        resolved: ResolvedInstructionRef,
79        _diff_config: &DiffObjConfig,
80        cb: &mut dyn FnMut(InstructionPart) -> Result<()>,
81    ) -> Result<()> {
82        let mut reader = U8Reader::new(resolved.code);
83        let decoder = InstDecoder::default();
84        let mut ins = Instruction::default();
85        if decoder.decode_into(&mut ins, &mut reader).is_err() {
86            cb(InstructionPart::opcode("<invalid>", OPCODE_INVALID))?;
87            return Ok(());
88        }
89
90        let mut ctx = DisplayCtx {
91            address: resolved.ins_ref.address,
92            section_index: 0,
93            start_address: resolved.symbol.address,
94            end_address: resolved.symbol.address + resolved.symbol.size,
95            reloc: resolved.relocation,
96        };
97
98        let mut display_args = Vec::with_capacity(16);
99        let mnemonic = display_instruction(&mut |ret| display_args.push(ret), &ins, &mut ctx);
100        cb(InstructionPart::opcode(mnemonic, resolved.ins_ref.opcode))?;
101        for arg in display_args {
102            cb(arg)?;
103        }
104        Ok(())
105    }
106
107    fn reloc_name(&self, flags: RelocationFlags) -> Option<&'static str> {
108        match flags {
109            RelocationFlags::Elf(r_type) => match r_type {
110                elf::R_AARCH64_NONE => Some("R_AARCH64_NONE"),
111                elf::R_AARCH64_ABS64 => Some("R_AARCH64_ABS64"),
112                elf::R_AARCH64_ABS32 => Some("R_AARCH64_ABS32"),
113                elf::R_AARCH64_ABS16 => Some("R_AARCH64_ABS16"),
114                elf::R_AARCH64_PREL64 => Some("R_AARCH64_PREL64"),
115                elf::R_AARCH64_PREL32 => Some("R_AARCH64_PREL32"),
116                elf::R_AARCH64_PREL16 => Some("R_AARCH64_PREL16"),
117                elf::R_AARCH64_ADR_PREL_PG_HI21 => Some("R_AARCH64_ADR_PREL_PG_HI21"),
118                elf::R_AARCH64_ADD_ABS_LO12_NC => Some("R_AARCH64_ADD_ABS_LO12_NC"),
119                elf::R_AARCH64_JUMP26 => Some("R_AARCH64_JUMP26"),
120                elf::R_AARCH64_CALL26 => Some("R_AARCH64_CALL26"),
121                elf::R_AARCH64_LDST32_ABS_LO12_NC => Some("R_AARCH64_LDST32_ABS_LO12_NC"),
122                elf::R_AARCH64_ADR_GOT_PAGE => Some("R_AARCH64_ADR_GOT_PAGE"),
123                elf::R_AARCH64_LD64_GOT_LO12_NC => Some("R_AARCH64_LD64_GOT_LO12_NC"),
124                _ => None,
125            },
126            _ => None,
127        }
128    }
129
130    fn data_reloc_size(&self, flags: RelocationFlags) -> usize {
131        match flags {
132            RelocationFlags::Elf(r_type) => match r_type {
133                elf::R_AARCH64_ABS64 => 8,
134                elf::R_AARCH64_ABS32 => 4,
135                elf::R_AARCH64_ABS16 => 2,
136                elf::R_AARCH64_PREL64 => 8,
137                elf::R_AARCH64_PREL32 => 4,
138                elf::R_AARCH64_PREL16 => 2,
139                _ => 1,
140            },
141            _ => 1,
142        }
143    }
144}
145
146fn branch_dest(opcode: u16, address: u64, code: &[u8]) -> Option<u64> {
147    const OPCODE_B: u16 = opcode_to_u16(Opcode::B);
148    const OPCODE_BL: u16 = opcode_to_u16(Opcode::BL);
149    const OPCODE_BCC: u16 = opcode_to_u16(Opcode::Bcc(0));
150    const OPCODE_CBZ: u16 = opcode_to_u16(Opcode::CBZ);
151    const OPCODE_CBNZ: u16 = opcode_to_u16(Opcode::CBNZ);
152    const OPCODE_TBZ: u16 = opcode_to_u16(Opcode::TBZ);
153    const OPCODE_TBNZ: u16 = opcode_to_u16(Opcode::TBNZ);
154
155    let word = u32::from_le_bytes(code.try_into().ok()?);
156    match opcode {
157        OPCODE_B | OPCODE_BL => {
158            let offset = ((word & 0x03ff_ffff) << 2) as i32;
159            let extended_offset = (offset << 4) >> 4;
160            address.checked_add_signed(extended_offset as i64)
161        }
162        OPCODE_BCC | OPCODE_CBZ | OPCODE_CBNZ => {
163            let offset = (word as i32 & 0x00ff_ffe0) >> 3;
164            let extended_offset = (offset << 11) >> 11;
165            address.checked_add_signed(extended_offset as i64)
166        }
167        OPCODE_TBZ | OPCODE_TBNZ => {
168            let offset = (word as i32 & 0x0007_ffe0) >> 3;
169            let extended_offset = (offset << 16) >> 16;
170            address.checked_add_signed(extended_offset as i64)
171        }
172        _ => None,
173    }
174}
175
176struct DisplayCtx<'a> {
177    address: u64,
178    section_index: usize,
179    start_address: u64,
180    end_address: u64,
181    reloc: Option<ResolvedRelocation<'a>>,
182}
183
184// Source: https://github.com/iximeow/yaxpeax-arm/blob/716a6e3fc621f5fe3300f3309e56943b8e1e65ad/src/armv8/a64.rs#L317
185// License: 0BSD
186// Reworked for more structured output. The library only gives us a Display impl, and no way to
187// capture any of this information, so it needs to be reimplemented here.
188fn display_instruction<Cb>(args: &mut Cb, ins: &Instruction, ctx: &mut DisplayCtx) -> &'static str
189where Cb: FnMut(InstructionPart<'static>) {
190    let mnemonic = match ins.opcode {
191        Opcode::Invalid => return "<invalid>",
192        Opcode::UDF => "udf",
193        Opcode::MOVN => {
194            let imm = if let Operand::ImmShift(imm, shift) = ins.operands[1] {
195                !((imm as u64) << shift)
196            } else {
197                unreachable!("movn operand 1 is always ImmShift");
198            };
199            let imm = if let Operand::Register(size, _) = ins.operands[0] {
200                if size == SizeCode::W { imm as u32 as u64 } else { imm }
201            } else {
202                unreachable!("movn operand 0 is always Register");
203            };
204            push_operand(args, &ins.operands[0], ctx);
205            push_separator(args);
206            push_unsigned(args, imm);
207            return "mov";
208        }
209        Opcode::MOVK => "movk",
210        Opcode::MOVZ => {
211            let imm = if let Operand::ImmShift(imm, shift) = ins.operands[1] {
212                (imm as u64) << shift
213            } else {
214                unreachable!("movz operand is always ImmShift");
215            };
216            let imm = if let Operand::Register(size, _) = ins.operands[0] {
217                if size == SizeCode::W { imm as u32 as u64 } else { imm }
218            } else {
219                unreachable!("movz operand 0 is always Register");
220            };
221            push_operand(args, &ins.operands[0], ctx);
222            push_separator(args);
223            push_unsigned(args, imm);
224            return "mov";
225        }
226        Opcode::ADC => "adc",
227        Opcode::ADCS => "adcs",
228        Opcode::SBC => {
229            if let Operand::Register(_, 31) = ins.operands[1] {
230                push_operand(args, &ins.operands[0], ctx);
231                push_separator(args);
232                push_operand(args, &ins.operands[2], ctx);
233                return "ngc";
234            } else {
235                "sbc"
236            }
237        }
238        Opcode::SBCS => {
239            if let Operand::Register(_, 31) = ins.operands[1] {
240                push_operand(args, &ins.operands[0], ctx);
241                push_separator(args);
242                push_operand(args, &ins.operands[2], ctx);
243                return "ngcs";
244            } else {
245                "sbcs"
246            }
247        }
248        Opcode::AND => "and",
249        Opcode::ORR => {
250            if let Operand::Register(_, 31) = ins.operands[1] {
251                if let Operand::Immediate(0) = ins.operands[2] {
252                    push_operand(args, &ins.operands[0], ctx);
253                    push_separator(args);
254                    push_operand(args, &ins.operands[1], ctx);
255                    return "mov";
256                } else if let Operand::RegShift(style, amt, size, r) = ins.operands[2] {
257                    if style == ShiftStyle::LSL && amt == 0 {
258                        push_operand(args, &ins.operands[0], ctx);
259                        push_separator(args);
260                        push_register(args, size, r, false);
261                        return "mov";
262                    }
263                } else {
264                    push_operand(args, &ins.operands[0], ctx);
265                    push_separator(args);
266                    push_operand(args, &ins.operands[2], ctx);
267                    return "mov";
268                }
269            } else if ins.operands[1] == ins.operands[2] {
270                push_operand(args, &ins.operands[0], ctx);
271                push_separator(args);
272                push_operand(args, &ins.operands[1], ctx);
273                return "mov";
274            }
275            "orr"
276        }
277        Opcode::ORN => {
278            if let Operand::Register(_, 31) = ins.operands[1] {
279                push_operand(args, &ins.operands[0], ctx);
280                push_separator(args);
281                push_operand(args, &ins.operands[2], ctx);
282                return "mvn";
283            }
284            "orn"
285        }
286        Opcode::EOR => "eor",
287        Opcode::EON => "eon",
288        Opcode::BIC => "bic",
289        Opcode::BICS => "bics",
290        Opcode::ANDS => {
291            if let Operand::Register(_, 31) = ins.operands[0] {
292                push_operand(args, &ins.operands[1], ctx);
293                push_separator(args);
294                push_operand(args, &ins.operands[2], ctx);
295                return "tst";
296            }
297            "ands"
298        }
299        Opcode::ADDS => {
300            if let Operand::Register(_, 31) = ins.operands[0] {
301                push_operand(args, &ins.operands[1], ctx);
302                push_separator(args);
303                push_operand(args, &ins.operands[2], ctx);
304                return "cmn";
305            } else if let Operand::RegShift(ShiftStyle::LSL, 0, size, reg) = ins.operands[2] {
306                push_operand(args, &ins.operands[0], ctx);
307                push_separator(args);
308                push_operand(args, &ins.operands[1], ctx);
309                push_separator(args);
310                push_register(args, size, reg, false);
311                return "adds";
312            }
313            "adds"
314        }
315        Opcode::ADD => {
316            if let Operand::Immediate(0) = ins.operands[2] {
317                if let Operand::RegisterOrSP(size, 31) = ins.operands[0] {
318                    push_register(args, size, 31, true);
319                    push_separator(args);
320                    push_operand(args, &ins.operands[1], ctx);
321                    return "mov";
322                } else if let Operand::RegisterOrSP(size, 31) = ins.operands[1] {
323                    push_operand(args, &ins.operands[0], ctx);
324                    push_separator(args);
325                    push_register(args, size, 31, true);
326                    return "mov";
327                }
328            } else if let Operand::RegShift(ShiftStyle::LSL, 0, size, reg) = ins.operands[2] {
329                push_operand(args, &ins.operands[0], ctx);
330                push_separator(args);
331                push_operand(args, &ins.operands[1], ctx);
332                push_separator(args);
333                push_register(args, size, reg, false);
334                return "add";
335            }
336            "add"
337        }
338        Opcode::SUBS => {
339            if let Operand::Register(_, 31) = ins.operands[0] {
340                push_operand(args, &ins.operands[1], ctx);
341                push_separator(args);
342                push_operand(args, &ins.operands[2], ctx);
343                return "cmp";
344            } else if let Operand::Register(_, 31) = ins.operands[1] {
345                push_operand(args, &ins.operands[0], ctx);
346                push_separator(args);
347                push_operand(args, &ins.operands[2], ctx);
348                return "negs";
349            } else if let Operand::RegShift(ShiftStyle::LSL, 0, size, reg) = ins.operands[2] {
350                push_operand(args, &ins.operands[0], ctx);
351                push_separator(args);
352                push_operand(args, &ins.operands[1], ctx);
353                push_separator(args);
354                push_register(args, size, reg, false);
355                return "subs";
356            }
357            "subs"
358        }
359        Opcode::SUB => {
360            if let Operand::Register(_, 31) = ins.operands[1] {
361                push_operand(args, &ins.operands[0], ctx);
362                push_separator(args);
363                push_operand(args, &ins.operands[2], ctx);
364                return "neg";
365            } else if let Operand::RegShift(ShiftStyle::LSL, 0, size, reg) = ins.operands[2] {
366                push_operand(args, &ins.operands[0], ctx);
367                push_separator(args);
368                push_operand(args, &ins.operands[1], ctx);
369                push_separator(args);
370                push_register(args, size, reg, false);
371                return "sub";
372            }
373            "sub"
374        }
375        Opcode::BFM => {
376            if let (Operand::Immediate(immr), Operand::Immediate(imms)) =
377                (ins.operands[2], ins.operands[3])
378            {
379                if imms < immr {
380                    if let Operand::Register(sz, rn) = ins.operands[1] {
381                        let width = imms + 1;
382                        let lsb = if sz == SizeCode::W {
383                            ((-(immr as i8)) as u8) & 0x1f
384                        } else {
385                            ((-(immr as i8)) as u8) & 0x3f
386                        };
387                        return if rn == 31 {
388                            push_operand(args, &ins.operands[0], ctx);
389                            push_separator(args);
390                            push_unsigned(args, lsb as u64);
391                            push_separator(args);
392                            push_unsigned(args, width as u64);
393                            "bfc"
394                        } else {
395                            push_operand(args, &ins.operands[0], ctx);
396                            push_separator(args);
397                            push_operand(args, &ins.operands[1], ctx);
398                            push_separator(args);
399                            push_unsigned(args, lsb as u64);
400                            push_separator(args);
401                            push_unsigned(args, width as u64);
402                            "bfi"
403                        };
404                    }
405                } else {
406                    // bfxil
407                    let lsb = immr;
408                    let width = imms + 1 - lsb;
409                    push_operand(args, &ins.operands[0], ctx);
410                    push_separator(args);
411                    push_operand(args, &ins.operands[1], ctx);
412                    push_separator(args);
413                    push_unsigned(args, lsb as u64);
414                    push_separator(args);
415                    push_unsigned(args, width as u64);
416                    return "bfxil";
417                }
418            }
419            "bfm"
420        }
421        Opcode::UBFM => {
422            // TODO: handle ubfx alias
423            if let (
424                Operand::Register(SizeCode::W, _),
425                Operand::Register(SizeCode::W, _),
426                Operand::Immediate(0),
427            ) = (ins.operands[0], ins.operands[1], ins.operands[2])
428            {
429                if let Operand::Immediate(7) = ins.operands[3] {
430                    push_operand(args, &ins.operands[0], ctx);
431                    push_separator(args);
432                    push_operand(args, &ins.operands[1], ctx);
433                    return "uxtb";
434                } else if let Operand::Immediate(15) = ins.operands[3] {
435                    push_operand(args, &ins.operands[0], ctx);
436                    push_separator(args);
437                    push_operand(args, &ins.operands[1], ctx);
438                    return "uxth";
439                }
440            }
441            if let Operand::Immediate(imms) = ins.operands[3] {
442                let size = if let Operand::Register(size, _) = ins.operands[0] {
443                    size
444                } else {
445                    unreachable!("operand 0 is a register");
446                };
447                match (imms, size) {
448                    (63, SizeCode::X) | (31, SizeCode::W) => {
449                        push_operand(args, &ins.operands[0], ctx);
450                        push_separator(args);
451                        push_operand(args, &ins.operands[1], ctx);
452                        push_separator(args);
453                        push_operand(args, &ins.operands[2], ctx);
454                        return "lsr";
455                    }
456                    _ => {
457                        let size = if size == SizeCode::X { 64 } else { 32 };
458                        let immr = if let Operand::Immediate(immr) = ins.operands[2] {
459                            immr
460                        } else {
461                            unreachable!("operand 3 is a register");
462                        };
463                        if imms + 1 == immr {
464                            push_operand(args, &ins.operands[0], ctx);
465                            push_separator(args);
466                            push_operand(args, &ins.operands[1], ctx);
467                            push_separator(args);
468                            push_unsigned(args, (size - imms - 1) as u64);
469                            return "lsl";
470                        }
471                        if imms < immr {
472                            push_operand(args, &ins.operands[0], ctx);
473                            push_separator(args);
474                            push_operand(args, &ins.operands[1], ctx);
475                            push_separator(args);
476                            push_unsigned(args, (size - immr) as u64);
477                            push_separator(args);
478                            push_unsigned(args, (imms + 1) as u64);
479                            return "ubfiz";
480                        }
481                    }
482                }
483            }
484            // `ubfm` is never actually displayed: in the remaining case, it is always aliased to `ubfx`
485            let width = if let (Operand::Immediate(lsb), Operand::Immediate(width)) =
486                (ins.operands[2], ins.operands[3])
487            {
488                Operand::Immediate(width - lsb + 1)
489            } else {
490                unreachable!("last two operands of ubfm are always immediates");
491            };
492            push_operand(args, &ins.operands[0], ctx);
493            push_separator(args);
494            push_operand(args, &ins.operands[1], ctx);
495            push_separator(args);
496            push_operand(args, &ins.operands[2], ctx);
497            push_separator(args);
498            push_operand(args, &width, ctx);
499            return "ubfx";
500        }
501        Opcode::SBFM => {
502            if let Operand::Immediate(63) = ins.operands[3]
503                && let Operand::Register(SizeCode::X, _) = ins.operands[0]
504            {
505                push_operand(args, &ins.operands[0], ctx);
506                push_separator(args);
507                push_operand(args, &ins.operands[1], ctx);
508                push_separator(args);
509                push_operand(args, &ins.operands[2], ctx);
510                return "asr";
511            }
512            if let Operand::Immediate(31) = ins.operands[3]
513                && let Operand::Register(SizeCode::W, _) = ins.operands[0]
514            {
515                push_operand(args, &ins.operands[0], ctx);
516                push_separator(args);
517                push_operand(args, &ins.operands[1], ctx);
518                push_separator(args);
519                push_operand(args, &ins.operands[2], ctx);
520                return "asr";
521            }
522            if let Operand::Immediate(0) = ins.operands[2] {
523                let newsrc = if let Operand::Register(_size, srcnum) = ins.operands[1] {
524                    Operand::Register(SizeCode::W, srcnum)
525                } else {
526                    unreachable!("operand 1 is always a register");
527                };
528                if let Operand::Immediate(7) = ins.operands[3] {
529                    push_operand(args, &ins.operands[0], ctx);
530                    push_separator(args);
531                    push_operand(args, &newsrc, ctx);
532                    return "sxtb";
533                } else if let Operand::Immediate(15) = ins.operands[3] {
534                    push_operand(args, &ins.operands[0], ctx);
535                    push_separator(args);
536                    push_operand(args, &newsrc, ctx);
537                    return "sxth";
538                } else if let Operand::Immediate(31) = ins.operands[3] {
539                    push_operand(args, &ins.operands[0], ctx);
540                    push_separator(args);
541                    push_operand(args, &newsrc, ctx);
542                    return "sxtw";
543                }
544            }
545            if let (Operand::Immediate(imms), Operand::Immediate(immr)) =
546                (ins.operands[2], ins.operands[3])
547                && immr < imms
548            {
549                let size = if let Operand::Register(size, _) = ins.operands[0] {
550                    if size == SizeCode::W { 32 } else { 64 }
551                } else {
552                    unreachable!("operand 0 is always a register");
553                };
554                push_operand(args, &ins.operands[0], ctx);
555                push_separator(args);
556                push_operand(args, &ins.operands[1], ctx);
557                push_separator(args);
558                push_unsigned(args, (size - imms) as u64);
559                push_separator(args);
560                push_unsigned(args, (immr + 1) as u64);
561                return "sbfiz";
562            }
563            // `sbfm` is never actually displayed: in the remaining case, it is always aliased to `sbfx`
564            let width = if let (Operand::Immediate(lsb), Operand::Immediate(width)) =
565                (ins.operands[2], ins.operands[3])
566            {
567                Operand::Immediate(width - lsb + 1)
568            } else {
569                unreachable!("last two operands of sbfm are always immediates");
570            };
571            push_operand(args, &ins.operands[0], ctx);
572            push_separator(args);
573            push_operand(args, &ins.operands[1], ctx);
574            push_separator(args);
575            push_operand(args, &ins.operands[2], ctx);
576            push_separator(args);
577            push_operand(args, &width, ctx);
578            return "sbfx";
579        }
580        Opcode::ADR => "adr",
581        Opcode::ADRP => "adrp",
582        Opcode::EXTR => {
583            if let (Operand::Register(_, rn), Operand::Register(_, rm)) =
584                (ins.operands[1], ins.operands[2])
585                && rn == rm
586            {
587                push_operand(args, &ins.operands[0], ctx);
588                push_separator(args);
589                push_operand(args, &ins.operands[2], ctx);
590                push_separator(args);
591                push_operand(args, &ins.operands[3], ctx);
592                return "ror";
593            }
594            "extr"
595        }
596        Opcode::LDAR => "ldar",
597        Opcode::LDLAR => "ldlar",
598        Opcode::LDARB => "ldarb",
599        Opcode::LDLARB => "ldlarb",
600        Opcode::LDAXRB => "ldaxrb",
601        Opcode::LDARH => "ldarh",
602        Opcode::LDLARH => "ldlarh",
603        Opcode::LDAXP => "ldaxp",
604        Opcode::LDAXR => "ldaxr",
605        Opcode::LDAXRH => "ldaxrh",
606        Opcode::LDP => "ldp",
607        Opcode::LDPSW => "ldpsw",
608        Opcode::LDR => "ldr",
609        Opcode::LDRB => "ldrb",
610        Opcode::LDRSB => "ldrsb",
611        Opcode::LDRSW => "ldrsw",
612        Opcode::LDRSH => "ldrsh",
613        Opcode::LDRH => "ldrh",
614        Opcode::LDTR => "ldtr",
615        Opcode::LDTRB => "ldtrb",
616        Opcode::LDTRH => "ldtrh",
617        Opcode::LDTRSB => "ldtrsb",
618        Opcode::LDTRSH => "ldtrsh",
619        Opcode::LDTRSW => "ldtrsw",
620        Opcode::LDUR => "ldur",
621        Opcode::LDURB => "ldurb",
622        Opcode::LDURSB => "ldursb",
623        Opcode::LDURSW => "ldursw",
624        Opcode::LDURSH => "ldursh",
625        Opcode::LDURH => "ldurh",
626        Opcode::LDXP => "ldxp",
627        Opcode::LDXR => "ldxr",
628        Opcode::LDXRB => "ldxrb",
629        Opcode::LDXRH => "ldxrh",
630        Opcode::STLR => "stlr",
631        Opcode::STLRB => "stlrb",
632        Opcode::STLRH => "stlrh",
633        Opcode::STLXP => "stlxp",
634        Opcode::STLLRB => "stllrb",
635        Opcode::STLLRH => "stllrh",
636        Opcode::STLLR => "stllr",
637        Opcode::STLXR => "stlxr",
638        Opcode::STLXRB => "stlxrb",
639        Opcode::STLXRH => "stlxrh",
640        Opcode::STP => "stp",
641        Opcode::STR => "str",
642        Opcode::STTR => "sttr",
643        Opcode::STTRB => "sttrb",
644        Opcode::STTRH => "sttrh",
645        Opcode::STRB => "strb",
646        Opcode::STRH => "strh",
647        Opcode::STRW => "strw",
648        Opcode::STUR => "stur",
649        Opcode::STURB => "sturb",
650        Opcode::STURH => "sturh",
651        Opcode::STXP => "stxp",
652        Opcode::STXR => "stxr",
653        Opcode::STXRB => "stxrb",
654        Opcode::STXRH => "stxrh",
655        Opcode::TBZ => "tbz",
656        Opcode::TBNZ => "tbnz",
657        Opcode::CBZ => "cbz",
658        Opcode::CBNZ => "cbnz",
659        Opcode::B => "b",
660        Opcode::BR => "br",
661        Opcode::Bcc(cond) => match cond {
662            0b0000 => "b.eq",
663            0b0001 => "b.ne",
664            0b0010 => "b.hs",
665            0b0011 => "b.lo",
666            0b0100 => "b.mi",
667            0b0101 => "b.pl",
668            0b0110 => "b.vs",
669            0b0111 => "b.vc",
670            0b1000 => "b.hi",
671            0b1001 => "b.ls",
672            0b1010 => "b.ge",
673            0b1011 => "b.lt",
674            0b1100 => "b.gt",
675            0b1101 => "b.le",
676            0b1110 => "b.al",
677            0b1111 => "b.nv",
678            _ => return "<invalid>",
679        },
680        Opcode::BL => "bl",
681        Opcode::BLR => "blr",
682        Opcode::SVC => "svc",
683        Opcode::HVC => "hvc",
684        Opcode::SMC => "smc",
685        Opcode::BRK => "brk",
686        Opcode::HLT => "hlt",
687        Opcode::DCPS1 => "dcps1",
688        Opcode::DCPS2 => "dcps2",
689        Opcode::DCPS3 => "dcps3",
690        Opcode::RET => {
691            if let Operand::Register(SizeCode::X, 30) = ins.operands[0] {
692                // C5.6.148:  Defaults to X30 if absent.
693                return "ret";
694            }
695            "ret"
696        }
697        Opcode::ERET => "eret",
698        Opcode::DRPS => "drps",
699        Opcode::MSR => "msr",
700        Opcode::MRS => "mrs",
701        Opcode::SYS(ops) => {
702            push_unsigned(args, ops.op1() as u64);
703            push_separator(args);
704            push_operand(args, &ins.operands[1], ctx);
705            push_separator(args);
706            push_operand(args, &ins.operands[2], ctx);
707            push_separator(args);
708            push_unsigned(args, ops.op2() as u64);
709            push_separator(args);
710            push_operand(args, &ins.operands[0], ctx);
711            return "sys";
712        }
713        Opcode::SYSL(ops) => {
714            push_operand(args, &ins.operands[2], ctx);
715            push_separator(args);
716            push_unsigned(args, ops.op1() as u64);
717            push_separator(args);
718            push_operand(args, &ins.operands[0], ctx);
719            push_separator(args);
720            push_operand(args, &ins.operands[1], ctx);
721            push_separator(args);
722            push_unsigned(args, ops.op2() as u64);
723            return "sysl";
724        }
725        Opcode::ISB => {
726            // the default/reserved/expected value for the immediate in `isb` is `0b1111`.
727            if let Operand::Imm16(15) = ins.operands[0] {
728                return "isb";
729            }
730            "isb"
731        }
732        Opcode::DSB(option) => {
733            push_barrier(args, option);
734            return "dsb";
735        }
736        Opcode::DMB(option) => {
737            push_barrier(args, option);
738            return "dmb";
739        }
740        Opcode::SB => "sb",
741        Opcode::SSSB => "sssb",
742        Opcode::HINT => {
743            if let (Operand::ControlReg(crn), Operand::Immediate(op2)) =
744                (ins.operands[0], ins.operands[1])
745            {
746                let hint_num = (crn << 3) | op2 as u16;
747                return match hint_num & 0b111111 {
748                    0 => "nop",
749                    1 => "yield",
750                    2 => "wfe",
751                    3 => "wfi",
752                    4 => "sev",
753                    0x10 => "esb",
754                    0x11 => {
755                        push_opaque(args, "csync");
756                        "psb"
757                    }
758                    0x12 => {
759                        push_opaque(args, "csync");
760                        "tsb"
761                    }
762                    0x14 => "csdb",
763                    0x15 => "sevl",
764                    _ => {
765                        push_unsigned(args, hint_num as u64);
766                        "hint"
767                    }
768                };
769            }
770            "hint"
771        }
772        Opcode::CLREX => "clrex",
773        Opcode::CSEL => "csel",
774        Opcode::CSNEG => {
775            if let (
776                Operand::Register(_size, rn),
777                Operand::Register(_, rm),
778                Operand::ConditionCode(cond),
779            ) = (ins.operands[1], ins.operands[2], ins.operands[3])
780            {
781                if cond < 0b1110 && rn == rm {
782                    push_operand(args, &ins.operands[0], ctx);
783                    push_separator(args);
784                    push_operand(args, &ins.operands[2], ctx);
785                    push_separator(args);
786                    push_condition_code(args, cond ^ 0x01);
787                    return "cneg";
788                }
789            } else {
790                unreachable!("operands 2 and 3 are always registers");
791            }
792            "csneg"
793        }
794        Opcode::CSINC => {
795            if let (Operand::Register(_, n), Operand::Register(_, m), Operand::ConditionCode(cond)) =
796                (ins.operands[1], ins.operands[2], ins.operands[3])
797                && n == m
798                && cond < 0b1110
799            {
800                return if n == 31 {
801                    push_operand(args, &ins.operands[0], ctx);
802                    push_separator(args);
803                    push_condition_code(args, cond ^ 0x01);
804                    "cset"
805                } else {
806                    push_operand(args, &ins.operands[0], ctx);
807                    push_separator(args);
808                    push_operand(args, &ins.operands[1], ctx);
809                    push_separator(args);
810                    push_condition_code(args, cond ^ 0x01);
811                    "cinc"
812                };
813            }
814            "csinc"
815        }
816        Opcode::CSINV => {
817            if let (
818                Operand::Register(_, n),
819                Operand::Register(_, m),
820                Operand::ConditionCode(cond),
821            ) = (ins.operands[1], ins.operands[2], ins.operands[3])
822            {
823                if n == m && n != 31 && cond < 0b1110 {
824                    push_operand(args, &ins.operands[0], ctx);
825                    push_separator(args);
826                    push_operand(args, &ins.operands[1], ctx);
827                    push_separator(args);
828                    push_condition_code(args, cond ^ 0x01);
829                    return "cinv";
830                } else if n == m && n == 31 && cond < 0b1110 {
831                    push_operand(args, &ins.operands[0], ctx);
832                    push_separator(args);
833                    push_condition_code(args, cond ^ 0x01);
834                    return "csetm";
835                }
836            }
837            "csinv"
838        }
839        Opcode::CCMN => "ccmn",
840        Opcode::CCMP => "ccmp",
841        Opcode::RBIT => "rbit",
842        Opcode::REV16 => "rev16",
843        Opcode::REV => "rev",
844        Opcode::REV32 => "rev32",
845        Opcode::CLZ => "clz",
846        Opcode::CLS => "cls",
847        Opcode::MADD => {
848            if let Operand::Register(_, 31) = ins.operands[3] {
849                push_operand(args, &ins.operands[0], ctx);
850                push_separator(args);
851                push_operand(args, &ins.operands[1], ctx);
852                push_separator(args);
853                push_operand(args, &ins.operands[2], ctx);
854                return "mul";
855            }
856            "madd"
857        }
858        Opcode::MSUB => {
859            if let Operand::Register(_, 31) = ins.operands[3] {
860                push_operand(args, &ins.operands[0], ctx);
861                push_separator(args);
862                push_operand(args, &ins.operands[1], ctx);
863                push_separator(args);
864                push_operand(args, &ins.operands[2], ctx);
865                return "mneg";
866            }
867            "msub"
868        }
869        Opcode::SMADDL => {
870            if let Operand::Register(_, 31) = ins.operands[3] {
871                push_operand(args, &ins.operands[0], ctx);
872                push_separator(args);
873                push_operand(args, &ins.operands[1], ctx);
874                push_separator(args);
875                push_operand(args, &ins.operands[2], ctx);
876                return "smull";
877            }
878            "smaddl"
879        }
880        Opcode::SMSUBL => {
881            if let Operand::Register(_, 31) = ins.operands[3] {
882                push_operand(args, &ins.operands[0], ctx);
883                push_separator(args);
884                push_operand(args, &ins.operands[1], ctx);
885                push_separator(args);
886                push_operand(args, &ins.operands[2], ctx);
887                return "smnegl";
888            }
889            "smsubl"
890        }
891        Opcode::SMULH => "smulh",
892        Opcode::UMADDL => {
893            if let Operand::Register(_, 31) = ins.operands[3] {
894                push_operand(args, &ins.operands[0], ctx);
895                push_separator(args);
896                push_operand(args, &ins.operands[1], ctx);
897                push_separator(args);
898                push_operand(args, &ins.operands[2], ctx);
899                return "umull";
900            }
901            "umaddl"
902        }
903        Opcode::UMSUBL => {
904            if let Operand::Register(_, 31) = ins.operands[3] {
905                push_operand(args, &ins.operands[0], ctx);
906                push_separator(args);
907                push_operand(args, &ins.operands[1], ctx);
908                push_separator(args);
909                push_operand(args, &ins.operands[2], ctx);
910                return "umnegl";
911            }
912            "umsubl"
913        }
914        Opcode::UMULH => "umulh",
915        Opcode::UDIV => "udiv",
916        Opcode::SDIV => "sdiv",
917        // lslv == lsl (register) and, quoth the manual, `lsl is always the preferred disassembly`.
918        Opcode::LSLV => "lsl",
919        // lsrv == lsr (register) and, quoth the manual, `lsr is always the preferred disassembly`.
920        Opcode::LSRV => "lsr",
921        // asrv == asr (register) and, quoth the manual, `asr is always the preferred disassembly`.
922        Opcode::ASRV => "asr",
923        // rorv == ror (register) and, quoth the manual, `ror is always the preferred disassembly`.
924        Opcode::RORV => "ror",
925        Opcode::CRC32B => "crc32b",
926        Opcode::CRC32H => "crc32h",
927        Opcode::CRC32W => "crc32w",
928        Opcode::CRC32X => "crc32x",
929        Opcode::CRC32CB => "crc32cb",
930        Opcode::CRC32CH => "crc32ch",
931        Opcode::CRC32CW => "crc32cw",
932        Opcode::CRC32CX => "crc32cx",
933        Opcode::STNP => "stnp",
934        Opcode::LDNP => "ldnp",
935        Opcode::ST1 => "st1",
936        Opcode::ST2 => "st2",
937        Opcode::ST3 => "st3",
938        Opcode::ST4 => "st4",
939        Opcode::LD1 => "ld1",
940        Opcode::LD2 => "ld2",
941        Opcode::LD3 => "ld3",
942        Opcode::LD4 => "ld4",
943        Opcode::LD1R => "ld1r",
944        Opcode::LD2R => "ld2r",
945        Opcode::LD3R => "ld3r",
946        Opcode::LD4R => "ld4r",
947        Opcode::FMADD => "fmadd",
948        Opcode::FMSUB => "fmsub",
949        Opcode::FNMADD => "fnmadd",
950        Opcode::FNMSUB => "fnmsub",
951        Opcode::SCVTF => "scvtf",
952        Opcode::UCVTF => "ucvtf",
953        Opcode::FCVTZS => "fcvtzs",
954        Opcode::FCVTZU => "fcvtzu",
955        Opcode::FMOV => "fmov",
956        Opcode::FABS => "fabs",
957        Opcode::FNEG => "fneg",
958        Opcode::FSQRT => "fsqrt",
959        Opcode::FRINTN => "frintn",
960        Opcode::FRINTP => "frintp",
961        Opcode::FRINTM => "frintm",
962        Opcode::FRINTZ => "frintz",
963        Opcode::FRINTA => "frinta",
964        Opcode::FRINTX => "frintx",
965        Opcode::FRINTI => "frinti",
966        Opcode::FRINT32Z => "frint32z",
967        Opcode::FRINT32X => "frint32x",
968        Opcode::FRINT64Z => "frint64z",
969        Opcode::FRINT64X => "frint64x",
970        Opcode::BFCVT => "bfcvt",
971        Opcode::FCVT => "fcvt",
972        Opcode::FCMP => "fcmp",
973        Opcode::FCMPE => "fcmpe",
974        Opcode::FMUL => "fmul",
975        Opcode::FDIV => "fdiv",
976        Opcode::FADD => "fadd",
977        Opcode::FSUB => "fsub",
978        Opcode::FMAX => "fmax",
979        Opcode::FMIN => "fmin",
980        Opcode::FMAXNM => "fmaxnm",
981        Opcode::FMINNM => "fminnm",
982        Opcode::FNMUL => "fnmul",
983        Opcode::FCSEL => "fcsel",
984        Opcode::FCCMP => "fccmp",
985        Opcode::FCCMPE => "fccmpe",
986        Opcode::FMULX => "fmulx",
987        Opcode::FMLSL => "fmlsl",
988        Opcode::FMLAL => "fmlal",
989        Opcode::SQRDMLSH => "sqrdmlsh",
990        Opcode::UDOT => "udot",
991        Opcode::SQRDMLAH => "sqrdmlah",
992        Opcode::UMULL => "umull",
993        Opcode::UMULL2 => "umull2",
994        Opcode::UMLSL => "umlsl",
995        Opcode::UMLSL2 => "umlsl2",
996        Opcode::MLS => "mls",
997        Opcode::UMLAL => "umlal",
998        Opcode::UMLAL2 => "umlal2",
999        Opcode::MLA => "mla",
1000        Opcode::SDOT => "sdot",
1001        Opcode::SQDMULH => "sqdmulh",
1002        Opcode::SQDMULL => "sqdmull",
1003        Opcode::SQDMULL2 => "sqdmull2",
1004        Opcode::SMULL => "smull",
1005        Opcode::SMULL2 => "smull2",
1006        Opcode::MUL => "mul",
1007        Opcode::SQDMLSL => "sqdmlsl",
1008        Opcode::SQDMLSL2 => "sqdmlsl2",
1009        Opcode::SMLSL => "smlsl",
1010        Opcode::SMLSL2 => "smlsl2",
1011        Opcode::SQDMLAL => "sqdmlal",
1012        Opcode::SQDMLAL2 => "sqdmlal2",
1013        Opcode::SMLAL => "smlal",
1014        Opcode::SMLAL2 => "smlal2",
1015        Opcode::SQRDMULH => "sqrdmulh",
1016        Opcode::FCMLA => "fcmla",
1017        Opcode::SSHR => "sshr",
1018        Opcode::SSRA => "ssra",
1019        Opcode::SRSHR => "srshr",
1020        Opcode::SRSRA => "srsra",
1021        Opcode::SHL => "shl",
1022        Opcode::SQSHL => "sqshl",
1023        Opcode::SHRN => "shrn",
1024        Opcode::SHRN2 => "shrn2",
1025        Opcode::RSHRN => "rshrn",
1026        Opcode::SQSHRN => "sqshrn",
1027        Opcode::SQRSHRN => "sqrshrn",
1028        Opcode::SSHLL => "sshll",
1029        Opcode::USHLL => "ushll",
1030        Opcode::USHR => "ushr",
1031        Opcode::USRA => "usra",
1032        Opcode::URSHR => "urshr",
1033        Opcode::URSRA => "ursra",
1034        Opcode::SRI => "sri",
1035        Opcode::SLI => "sli",
1036        Opcode::SQSHLU => "sqshlu",
1037        Opcode::UQSHL => "uqshl",
1038        Opcode::SQSHRUN => "sqshrun",
1039        Opcode::SQRSHRUN => "sqrshrun",
1040        Opcode::UQSHRN => "uqshrn",
1041        Opcode::UQRSHRN => "uqrshrn",
1042        Opcode::MOVI => "movi",
1043        Opcode::MVNI => "mvni",
1044        Opcode::SHADD => "shadd",
1045        Opcode::SQADD => "sqadd",
1046        Opcode::SRHADD => "srhadd",
1047        Opcode::SHSUB => "shsub",
1048        Opcode::SQSUB => "sqsub",
1049        Opcode::CMGT => "cmgt",
1050        Opcode::CMGE => "cmge",
1051        Opcode::SSHL => "sshl",
1052        Opcode::SRSHL => "srshl",
1053        Opcode::SQRSHL => "sqrshl",
1054        Opcode::SMAX => "smax",
1055        Opcode::SMIN => "smin",
1056        Opcode::SABD => "sabd",
1057        Opcode::SABA => "saba",
1058        Opcode::CMTST => "cmtst",
1059        Opcode::SMAXP => "smaxp",
1060        Opcode::SMINP => "sminp",
1061        Opcode::ADDP => "addp",
1062        Opcode::UHADD => "uhadd",
1063        Opcode::UQADD => "uqadd",
1064        Opcode::URHADD => "urhadd",
1065        Opcode::UHSUB => "uhsub",
1066        Opcode::UQSUB => "uqsub",
1067        Opcode::CMHI => "cmhi",
1068        Opcode::CMHS => "cmhs",
1069        Opcode::USHL => "ushl",
1070        Opcode::URSHL => "urshl",
1071        Opcode::UQRSHL => "uqrshl",
1072        Opcode::UMAX => "umax",
1073        Opcode::UMIN => "umin",
1074        Opcode::UABD => "uabd",
1075        Opcode::UABA => "uaba",
1076        Opcode::CMEQ => "cmeq",
1077        Opcode::PMUL => "pmul",
1078        Opcode::UMAXP => "umaxp",
1079        Opcode::UMINP => "uminp",
1080        Opcode::FMLA => "fmla",
1081        Opcode::FCMEQ => "fcmeq",
1082        Opcode::FRECPS => "frecps",
1083        Opcode::BSL => "bsl",
1084        Opcode::BIT => "bit",
1085        Opcode::BIF => "bif",
1086        Opcode::FMAXNMP => "fmaxnmp",
1087        Opcode::FMINMNP => "fminmnp",
1088        Opcode::FADDP => "faddp",
1089        Opcode::FCMGE => "fcmge",
1090        Opcode::FACGE => "facge",
1091        Opcode::FMAXP => "fmaxp",
1092        Opcode::SADDL => "saddl",
1093        Opcode::SADDL2 => "saddl2",
1094        Opcode::SADDW => "saddw",
1095        Opcode::SADDW2 => "saddw2",
1096        Opcode::SSUBL => "ssubl",
1097        Opcode::SSUBL2 => "ssubl2",
1098        Opcode::SSUBW => "ssubw",
1099        Opcode::SSUBW2 => "ssubw2",
1100        Opcode::ADDHN => "addhn",
1101        Opcode::ADDHN2 => "addhn2",
1102        Opcode::SABAL => "sabal",
1103        Opcode::SABAL2 => "sabal2",
1104        Opcode::SUBHN => "subhn",
1105        Opcode::SUBHN2 => "subhn2",
1106        Opcode::SABDL => "sabdl",
1107        Opcode::SABDL2 => "sabdl2",
1108        Opcode::PMULL => "pmull",
1109        Opcode::PMULL2 => "pmull2",
1110        Opcode::UADDL => "uaddl",
1111        Opcode::UADDL2 => "uaddl2",
1112        Opcode::UADDW => "uaddw",
1113        Opcode::UADDW2 => "uaddw2",
1114        Opcode::USUBL => "usubl",
1115        Opcode::USUBL2 => "usubl2",
1116        Opcode::USUBW => "usubw",
1117        Opcode::USUBW2 => "usubw2",
1118        Opcode::RADDHN => "raddhn",
1119        Opcode::RADDHN2 => "raddhn2",
1120        Opcode::RSUBHN => "rsubhn",
1121        Opcode::RSUBHN2 => "rsubhn2",
1122        Opcode::UABAL => "uabal",
1123        Opcode::UABAL2 => "uabal2",
1124        Opcode::UABDL => "uabdl",
1125        Opcode::UABDL2 => "uabdl2",
1126        Opcode::REV64 => "rev64",
1127        Opcode::SADDLP => "saddlp",
1128        Opcode::SUQADD => "suqadd",
1129        Opcode::CNT => "cnt",
1130        Opcode::SADALP => "sadalp",
1131        Opcode::SQABS => "sqabs",
1132        Opcode::CMLT => "cmlt",
1133        Opcode::ABS => "abs",
1134        Opcode::XTN => "xtn",
1135        Opcode::XTN2 => "xtn2",
1136        Opcode::SQXTN => "sqxtn",
1137        Opcode::SQXTN2 => "sqxtn2",
1138        Opcode::FCVTN => "fcvtn",
1139        Opcode::FCVTN2 => "fcvtn2",
1140        Opcode::FCMGT => "fcmgt",
1141        Opcode::FCVTL => "fcvtl",
1142        Opcode::FCVTL2 => "fcvtl2",
1143        Opcode::FCVTNS => "fcvtns",
1144        Opcode::FCVTPS => "fcvtps",
1145        Opcode::FCVTMS => "fcvtms",
1146        Opcode::FCVTAS => "fcvtas",
1147        Opcode::URECPE => "urecpe",
1148        Opcode::FRECPE => "frecpe",
1149        Opcode::UADDLP => "uaddlp",
1150        Opcode::USQADD => "usqadd",
1151        Opcode::UADALP => "uadalp",
1152        Opcode::SQNEG => "sqneg",
1153        Opcode::CMLE => "cmle",
1154        Opcode::NEG => "neg",
1155        Opcode::SQXTUN => "sqxtun",
1156        Opcode::SQXTUN2 => "sqxtun2",
1157        Opcode::SHLL => "shll",
1158        Opcode::SHLL2 => "shll2",
1159        Opcode::UQXTN => "uqxtn",
1160        Opcode::UQXTN2 => "uqxtn2",
1161        Opcode::FCVTXN => "fcvtxn",
1162        Opcode::FCVTXN2 => "fcvtxn2",
1163        Opcode::FCVTNU => "fcvtnu",
1164        Opcode::FCVTMU => "fcvtmu",
1165        Opcode::FCVTAU => "fcvtau",
1166        // `ins (element)` and `ins (general)` both have `mov` as an alias. manual reports that `mov` is the preferred disassembly.
1167        Opcode::INS => "mov",
1168        Opcode::EXT => "ext",
1169        Opcode::DUP => {
1170            if let Operand::Register(_, _) = ins.operands[1] {
1171                "dup"
1172            } else {
1173                "mov"
1174            }
1175        }
1176        Opcode::UZP1 => "uzp1",
1177        Opcode::TRN1 => "trn1",
1178        Opcode::ZIP1 => "zip1",
1179        Opcode::UZP2 => "uzp2",
1180        Opcode::TRN2 => "trn2",
1181        Opcode::ZIP2 => "zip2",
1182        Opcode::SMOV => "smov",
1183        Opcode::UMOV => {
1184            if let (
1185                Operand::Register(reg_sz, _),
1186                Operand::SIMDRegisterElementsLane(_, _, elem_sz, _),
1187            ) = (ins.operands[0], ins.operands[1])
1188                && ((reg_sz == SizeCode::W && elem_sz == SIMDSizeCode::S)
1189                    || (reg_sz == SizeCode::X && elem_sz == SIMDSizeCode::D))
1190            {
1191                push_operand(args, &ins.operands[0], ctx);
1192                push_separator(args);
1193                push_operand(args, &ins.operands[1], ctx);
1194                return "mov";
1195            }
1196            "umov"
1197        }
1198        Opcode::SQSHRN2 => "sqshrn2",
1199        Opcode::SQRSHRN2 => "sqrshrn2",
1200        Opcode::SQSHRUN2 => "sqshrun2",
1201        Opcode::UQSHRN2 => "uqshrn2",
1202        Opcode::UQRSHRN2 => "uqrshrn2",
1203        Opcode::FMLS => "fmls",
1204        Opcode::FRECPX => "frecpx",
1205        Opcode::FRSQRTE => "frsqrte",
1206        Opcode::FCVTPU => "fcvtpu",
1207        Opcode::FCMLT => "fcmlt",
1208        Opcode::FCMLE => "fcmle",
1209        Opcode::FMAXNMV => "fmaxnmv",
1210        Opcode::FMINNMV => "fminnmv",
1211        Opcode::FMAXV => "fmaxv",
1212        Opcode::FMINV => "fminv",
1213        Opcode::UADDLV => "uaddlv",
1214        Opcode::SADDLV => "saddlv",
1215        Opcode::UMAXV => "umaxv",
1216        Opcode::SMAXV => "smaxv",
1217        Opcode::UMINV => "uminv",
1218        Opcode::SMINV => "sminv",
1219        Opcode::ADDV => "addv",
1220        Opcode::FRSQRTS => "frsqrts",
1221        Opcode::FMINNMP => "fminnmp",
1222        Opcode::FMLAL2 => "fmlal2",
1223        Opcode::FMLSL2 => "fmlsl2",
1224        Opcode::FABD => "fabd",
1225        Opcode::FACGT => "facgt",
1226        Opcode::FMINP => "fminp",
1227        Opcode::FJCVTZS => "fjcvtzs",
1228        Opcode::URSQRTE => "ursqrte",
1229        Opcode::PRFM => "prfm",
1230        Opcode::PRFUM => "prfum",
1231        Opcode::AESE => "aese",
1232        Opcode::AESD => "aesd",
1233        Opcode::AESMC => "aesmc",
1234        Opcode::AESIMC => "aesimc",
1235        Opcode::SHA1H => "sha1h",
1236        Opcode::SHA1SU1 => "sha1su1",
1237        Opcode::SHA256SU0 => "sha256su0",
1238        Opcode::SM3TT1A => "sm3tt1a",
1239        Opcode::SM3TT1B => "sm3tt1b",
1240        Opcode::SM3TT2A => "sm3tt2a",
1241        Opcode::SM3TT2B => "sm3tt2b",
1242        Opcode::SHA512H => "sha512h",
1243        Opcode::SHA512H2 => "sha512h2",
1244        Opcode::SHA512SU1 => "sha512su1",
1245        Opcode::RAX1 => "rax1",
1246        Opcode::SM3PARTW1 => "sm3partw1",
1247        Opcode::SM3PARTW2 => "sm3partw2",
1248        Opcode::SM4EKEY => "sm4ekey",
1249        Opcode::BCAX => "bcax",
1250        Opcode::SM3SS1 => "sm3ss1",
1251        Opcode::SHA512SU0 => "sha512su0",
1252        Opcode::SM4E => "sm4e",
1253        Opcode::EOR3 => "eor3",
1254        Opcode::XAR => "xar",
1255        Opcode::LDRAA => "ldraa",
1256        Opcode::LDRAB => "ldrab",
1257        Opcode::LDAPR => "ldapr",
1258        Opcode::LDAPRH => "ldaprh",
1259        Opcode::LDAPRB => "ldaprb",
1260        Opcode::SWP(ar) => {
1261            if ar == 0 {
1262                "swp"
1263            } else if ar == 0b01 {
1264                "swpl"
1265            } else if ar == 0b10 {
1266                "swpa"
1267            } else {
1268                "swpal"
1269            }
1270        }
1271        Opcode::SWPB(ar) => {
1272            if ar == 0 {
1273                "swpb"
1274            } else if ar == 0b01 {
1275                "swplb"
1276            } else if ar == 0b10 {
1277                "swpab"
1278            } else {
1279                "swpalb"
1280            }
1281        }
1282        Opcode::SWPH(ar) => {
1283            if ar == 0 {
1284                "swph"
1285            } else if ar == 0b01 {
1286                "swplh"
1287            } else if ar == 0b10 {
1288                "swpah"
1289            } else {
1290                "swpalh"
1291            }
1292        }
1293        Opcode::LDADDB(ar) => {
1294            if let Operand::Register(_, rt) = ins.operands[1]
1295                && rt == 31
1296                && ar & 0b10 == 0b00
1297            {
1298                let inst = if ar & 0b01 == 0b00 { "staddb" } else { "staddlb" };
1299                push_operand(args, &ins.operands[0], ctx);
1300                push_separator(args);
1301                push_operand(args, &ins.operands[2], ctx);
1302                return inst;
1303            }
1304            if ar == 0 {
1305                "ldaddb"
1306            } else if ar == 0b01 {
1307                "ldaddlb"
1308            } else if ar == 0b10 {
1309                "ldaddab"
1310            } else {
1311                "ldaddalb"
1312            }
1313        }
1314        Opcode::LDCLRB(ar) => {
1315            if let Operand::Register(_, rt) = ins.operands[1]
1316                && rt == 31
1317                && ar & 0b10 == 0b00
1318            {
1319                let inst = if ar & 0b01 == 0b00 { "stclrb" } else { "stclrlb" };
1320                push_operand(args, &ins.operands[0], ctx);
1321                push_separator(args);
1322                push_operand(args, &ins.operands[2], ctx);
1323                return inst;
1324            }
1325            if ar == 0 {
1326                "ldclrb"
1327            } else if ar == 0b01 {
1328                "ldclrlb"
1329            } else if ar == 0b10 {
1330                "ldclrab"
1331            } else {
1332                "ldclralb"
1333            }
1334        }
1335        Opcode::LDEORB(ar) => {
1336            if let Operand::Register(_, rt) = ins.operands[1]
1337                && rt == 31
1338                && ar & 0b10 == 0b00
1339            {
1340                let inst = if ar & 0b01 == 0b00 { "steorb" } else { "steorlb" };
1341                push_operand(args, &ins.operands[0], ctx);
1342                push_separator(args);
1343                push_operand(args, &ins.operands[2], ctx);
1344                return inst;
1345            }
1346            if ar == 0 {
1347                "ldeorb"
1348            } else if ar == 0b01 {
1349                "ldeorlb"
1350            } else if ar == 0b10 {
1351                "ldeorab"
1352            } else {
1353                "ldeoralb"
1354            }
1355        }
1356        Opcode::LDSETB(ar) => {
1357            if let Operand::Register(_, rt) = ins.operands[1]
1358                && rt == 31
1359                && ar & 0b10 == 0b00
1360            {
1361                let inst = if ar & 0b01 == 0b00 { "stsetb" } else { "stsetlb" };
1362                push_operand(args, &ins.operands[0], ctx);
1363                push_separator(args);
1364                push_operand(args, &ins.operands[2], ctx);
1365                return inst;
1366            }
1367            if ar == 0 {
1368                "ldsetb"
1369            } else if ar == 0b01 {
1370                "ldsetlb"
1371            } else if ar == 0b10 {
1372                "ldsetab"
1373            } else {
1374                "ldsetalb"
1375            }
1376        }
1377        Opcode::LDSMAXB(ar) => {
1378            if let Operand::Register(_, rt) = ins.operands[1]
1379                && rt == 31
1380                && ar & 0b10 == 0b00
1381            {
1382                let inst = if ar & 0b01 == 0b00 { "stsmaxb" } else { "stsmaxlb" };
1383                push_operand(args, &ins.operands[0], ctx);
1384                push_separator(args);
1385                push_operand(args, &ins.operands[2], ctx);
1386                return inst;
1387            }
1388            if ar == 0 {
1389                "ldsmaxb"
1390            } else if ar == 0b01 {
1391                "ldsmaxlb"
1392            } else if ar == 0b10 {
1393                "ldsmaxab"
1394            } else {
1395                "ldsmaxalb"
1396            }
1397        }
1398        Opcode::LDSMINB(ar) => {
1399            if let Operand::Register(_, rt) = ins.operands[1]
1400                && rt == 31
1401                && ar & 0b10 == 0b00
1402            {
1403                let inst = if ar & 0b01 == 0b00 { "stsminb" } else { "stsminlb" };
1404                push_operand(args, &ins.operands[0], ctx);
1405                push_separator(args);
1406                push_operand(args, &ins.operands[2], ctx);
1407                return inst;
1408            }
1409            if ar == 0 {
1410                "ldsminb"
1411            } else if ar == 0b01 {
1412                "ldsminlb"
1413            } else if ar == 0b10 {
1414                "ldsminab"
1415            } else {
1416                "ldsminalb"
1417            }
1418        }
1419        Opcode::LDUMAXB(ar) => {
1420            if let Operand::Register(_, rt) = ins.operands[1]
1421                && rt == 31
1422                && ar & 0b10 == 0b00
1423            {
1424                let inst = if ar & 0b01 == 0b00 { "stumaxb" } else { "stumaxlb" };
1425                push_operand(args, &ins.operands[0], ctx);
1426                push_separator(args);
1427                push_operand(args, &ins.operands[2], ctx);
1428                return inst;
1429            }
1430            if ar == 0 {
1431                "ldumaxb"
1432            } else if ar == 0b01 {
1433                "ldumaxlb"
1434            } else if ar == 0b10 {
1435                "ldumaxab"
1436            } else {
1437                "ldumaxalb"
1438            }
1439        }
1440        Opcode::LDUMINB(ar) => {
1441            if let Operand::Register(_, rt) = ins.operands[1]
1442                && rt == 31
1443                && ar & 0b10 == 0b00
1444            {
1445                let inst = if ar & 0b01 == 0b00 { "stuminb" } else { "stuminlb" };
1446                push_operand(args, &ins.operands[0], ctx);
1447                push_separator(args);
1448                push_operand(args, &ins.operands[2], ctx);
1449                return inst;
1450            }
1451            // write!(fmt, "{}", self.opcode)?;
1452            if ar == 0 {
1453                "lduminb"
1454            } else if ar == 0b01 {
1455                "lduminlb"
1456            } else if ar == 0b10 {
1457                "lduminab"
1458            } else {
1459                "lduminalb"
1460            }
1461        }
1462        Opcode::LDADDH(ar) => {
1463            if let Operand::Register(_, rt) = ins.operands[1]
1464                && rt == 31
1465                && ar & 0b10 == 0b00
1466            {
1467                let inst = if ar & 0b01 == 0b00 { "staddh" } else { "staddlh" };
1468                push_operand(args, &ins.operands[0], ctx);
1469                push_separator(args);
1470                push_operand(args, &ins.operands[2], ctx);
1471                return inst;
1472            }
1473            if ar == 0 {
1474                "ldaddh"
1475            } else if ar == 0b01 {
1476                "ldaddlh"
1477            } else if ar == 0b10 {
1478                "ldaddah"
1479            } else {
1480                "ldaddalh"
1481            }
1482        }
1483        Opcode::LDCLRH(ar) => {
1484            if let Operand::Register(_, rt) = ins.operands[1]
1485                && rt == 31
1486                && ar & 0b10 == 0b00
1487            {
1488                let inst = if ar & 0b01 == 0b00 { "stclrh" } else { "stclrlh" };
1489                push_operand(args, &ins.operands[0], ctx);
1490                push_separator(args);
1491                push_operand(args, &ins.operands[2], ctx);
1492                return inst;
1493            }
1494            if ar == 0 {
1495                "ldclrh"
1496            } else if ar == 0b01 {
1497                "ldclrlh"
1498            } else if ar == 0b10 {
1499                "ldclrah"
1500            } else {
1501                "ldclralh"
1502            }
1503        }
1504        Opcode::LDEORH(ar) => {
1505            if let Operand::Register(_, rt) = ins.operands[1]
1506                && rt == 31
1507                && ar & 0b10 == 0b00
1508            {
1509                let inst = if ar & 0b01 == 0b00 { "steorh" } else { "steorlh" };
1510                push_operand(args, &ins.operands[0], ctx);
1511                push_separator(args);
1512                push_operand(args, &ins.operands[2], ctx);
1513                return inst;
1514            }
1515            if ar == 0 {
1516                "ldeorh"
1517            } else if ar == 0b01 {
1518                "ldeorlh"
1519            } else if ar == 0b10 {
1520                "ldeorah"
1521            } else {
1522                "ldeoralh"
1523            }
1524        }
1525        Opcode::LDSETH(ar) => {
1526            if let Operand::Register(_, rt) = ins.operands[1]
1527                && rt == 31
1528                && ar & 0b10 == 0b00
1529            {
1530                let inst = if ar & 0b01 == 0b00 { "stseth" } else { "stsetlh" };
1531                push_operand(args, &ins.operands[0], ctx);
1532                push_separator(args);
1533                push_operand(args, &ins.operands[2], ctx);
1534                return inst;
1535            }
1536            if ar == 0 {
1537                "ldseth"
1538            } else if ar == 0b01 {
1539                "ldsetlh"
1540            } else if ar == 0b10 {
1541                "ldsetah"
1542            } else {
1543                "ldsetalh"
1544            }
1545        }
1546        Opcode::LDSMAXH(ar) => {
1547            if let Operand::Register(_, rt) = ins.operands[1]
1548                && rt == 31
1549                && ar & 0b10 == 0b00
1550            {
1551                let inst = if ar & 0b01 == 0b00 { "stsmaxh" } else { "stsmaxlh" };
1552                push_operand(args, &ins.operands[0], ctx);
1553                push_separator(args);
1554                push_operand(args, &ins.operands[2], ctx);
1555                return inst;
1556            }
1557            if ar == 0 {
1558                "ldsmaxh"
1559            } else if ar == 0b01 {
1560                "ldsmaxlh"
1561            } else if ar == 0b10 {
1562                "ldsmaxah"
1563            } else {
1564                "ldsmaxalh"
1565            }
1566        }
1567        Opcode::LDSMINH(ar) => {
1568            if let Operand::Register(_, rt) = ins.operands[1]
1569                && rt == 31
1570                && ar & 0b10 == 0b00
1571            {
1572                let inst = if ar & 0b01 == 0b00 { "stsminh" } else { "stsminlh" };
1573                push_operand(args, &ins.operands[0], ctx);
1574                push_separator(args);
1575                push_operand(args, &ins.operands[2], ctx);
1576                return inst;
1577            }
1578            if ar == 0 {
1579                "ldsminh"
1580            } else if ar == 0b01 {
1581                "ldsminlh"
1582            } else if ar == 0b10 {
1583                "ldsminah"
1584            } else {
1585                "ldsminalh"
1586            }
1587        }
1588        Opcode::LDUMAXH(ar) => {
1589            if let Operand::Register(_, rt) = ins.operands[1]
1590                && rt == 31
1591                && ar & 0b10 == 0b00
1592            {
1593                let inst = if ar & 0b01 == 0b00 { "stumaxh" } else { "stumaxlh" };
1594                push_operand(args, &ins.operands[0], ctx);
1595                push_separator(args);
1596                push_operand(args, &ins.operands[2], ctx);
1597                return inst;
1598            }
1599            if ar == 0 {
1600                "ldumaxh"
1601            } else if ar == 0b01 {
1602                "ldumaxlh"
1603            } else if ar == 0b10 {
1604                "ldumaxah"
1605            } else {
1606                "ldumaxalh"
1607            }
1608        }
1609        Opcode::LDUMINH(ar) => {
1610            if let Operand::Register(_, rt) = ins.operands[1]
1611                && rt == 31
1612                && ar & 0b10 == 0b00
1613            {
1614                let inst = if ar & 0b01 == 0b00 { "stuminh" } else { "stuminlh" };
1615                push_operand(args, &ins.operands[0], ctx);
1616                push_separator(args);
1617                push_operand(args, &ins.operands[2], ctx);
1618                return inst;
1619            }
1620            if ar == 0 {
1621                "lduminh"
1622            } else if ar == 0b01 {
1623                "lduminlh"
1624            } else if ar == 0b10 {
1625                "lduminah"
1626            } else {
1627                "lduminalh"
1628            }
1629        }
1630        Opcode::LDADD(ar) => {
1631            if let Operand::Register(_, rt) = ins.operands[1]
1632                && rt == 31
1633                && ar & 0b10 == 0b00
1634            {
1635                let inst = if ar & 0b01 == 0b00 { "stadd" } else { "staddl" };
1636                push_operand(args, &ins.operands[0], ctx);
1637                push_separator(args);
1638                push_operand(args, &ins.operands[2], ctx);
1639                return inst;
1640            }
1641            if ar == 0 {
1642                "ldadd"
1643            } else if ar == 0b01 {
1644                "ldaddl"
1645            } else if ar == 0b10 {
1646                "ldadda"
1647            } else {
1648                "ldaddal"
1649            }
1650        }
1651        Opcode::LDCLR(ar) => {
1652            if let Operand::Register(_, rt) = ins.operands[1]
1653                && rt == 31
1654                && ar & 0b10 == 0b00
1655            {
1656                let inst = if ar & 0b01 == 0b00 { "stclr" } else { "stclrl" };
1657                push_operand(args, &ins.operands[0], ctx);
1658                push_separator(args);
1659                push_operand(args, &ins.operands[2], ctx);
1660                return inst;
1661            }
1662            if ar == 0 {
1663                "ldclr"
1664            } else if ar == 0b01 {
1665                "ldclrl"
1666            } else if ar == 0b10 {
1667                "ldclra"
1668            } else {
1669                "ldclral"
1670            }
1671        }
1672        Opcode::LDEOR(ar) => {
1673            if let Operand::Register(_, rt) = ins.operands[1]
1674                && rt == 31
1675                && ar & 0b10 == 0b00
1676            {
1677                let inst = if ar & 0b01 == 0b00 { "steor" } else { "steorl" };
1678                push_operand(args, &ins.operands[0], ctx);
1679                push_separator(args);
1680                push_operand(args, &ins.operands[2], ctx);
1681                return inst;
1682            }
1683            if ar == 0 {
1684                "ldeor"
1685            } else if ar == 0b01 {
1686                "ldeorl"
1687            } else if ar == 0b10 {
1688                "ldeora"
1689            } else {
1690                "ldeoral"
1691            }
1692        }
1693        Opcode::LDSET(ar) => {
1694            if let Operand::Register(_, rt) = ins.operands[1]
1695                && rt == 31
1696                && ar & 0b10 == 0b00
1697            {
1698                let inst = if ar & 0b01 == 0b00 { "stset" } else { "stsetl" };
1699                push_operand(args, &ins.operands[0], ctx);
1700                push_separator(args);
1701                push_operand(args, &ins.operands[2], ctx);
1702                return inst;
1703            }
1704            if ar == 0 {
1705                "ldset"
1706            } else if ar == 0b01 {
1707                "ldsetl"
1708            } else if ar == 0b10 {
1709                "ldseta"
1710            } else {
1711                "ldsetal"
1712            }
1713        }
1714        Opcode::LDSMAX(ar) => {
1715            if let Operand::Register(_, rt) = ins.operands[1]
1716                && rt == 31
1717                && ar & 0b10 == 0b00
1718            {
1719                let inst = if ar & 0b01 == 0b00 { "stsmax" } else { "stsmaxl" };
1720                push_operand(args, &ins.operands[0], ctx);
1721                push_separator(args);
1722                push_operand(args, &ins.operands[2], ctx);
1723                return inst;
1724            }
1725            if ar == 0 {
1726                "ldsmax"
1727            } else if ar == 0b01 {
1728                "ldsmaxl"
1729            } else if ar == 0b10 {
1730                "ldsmaxa"
1731            } else {
1732                "ldsmaxal"
1733            }
1734        }
1735        Opcode::LDSMIN(ar) => {
1736            if let Operand::Register(_, rt) = ins.operands[1]
1737                && rt == 31
1738                && ar & 0b10 == 0b00
1739            {
1740                let inst = if ar & 0b01 == 0b00 { "stsmin" } else { "stsminl" };
1741                push_operand(args, &ins.operands[0], ctx);
1742                push_separator(args);
1743                push_operand(args, &ins.operands[2], ctx);
1744                return inst;
1745            }
1746            if ar == 0 {
1747                "ldsmin"
1748            } else if ar == 0b01 {
1749                "ldsminl"
1750            } else if ar == 0b10 {
1751                "ldsmina"
1752            } else {
1753                "ldsminal"
1754            }
1755        }
1756        Opcode::LDUMAX(ar) => {
1757            if let Operand::Register(_, rt) = ins.operands[1]
1758                && rt == 31
1759                && ar & 0b10 == 0b00
1760            {
1761                let inst = if ar & 0b01 == 0b00 { "stumax" } else { "stumaxl" };
1762                push_operand(args, &ins.operands[0], ctx);
1763                push_separator(args);
1764                push_operand(args, &ins.operands[2], ctx);
1765                return inst;
1766            }
1767            if ar == 0 {
1768                "ldumax"
1769            } else if ar == 0b01 {
1770                "ldumaxl"
1771            } else if ar == 0b10 {
1772                "ldumaxa"
1773            } else {
1774                "ldumaxal"
1775            }
1776        }
1777        Opcode::LDUMIN(ar) => {
1778            if let Operand::Register(_, rt) = ins.operands[1]
1779                && rt == 31
1780                && ar & 0b10 == 0b00
1781            {
1782                let inst = if ar & 0b01 == 0b00 { "stumin" } else { "stuminl" };
1783                push_operand(args, &ins.operands[0], ctx);
1784                push_separator(args);
1785                push_operand(args, &ins.operands[2], ctx);
1786                return inst;
1787            }
1788            if ar == 0 {
1789                "ldumin"
1790            } else if ar == 0b01 {
1791                "lduminl"
1792            } else if ar == 0b10 {
1793                "ldumina"
1794            } else {
1795                "lduminal"
1796            }
1797        }
1798        Opcode::CAS(ar) => {
1799            if ar == 0 {
1800                "cas"
1801            } else if ar == 0b01 {
1802                "casl"
1803            } else if ar == 0b10 {
1804                "casa"
1805            } else {
1806                "casal"
1807            }
1808        }
1809        Opcode::CASH(ar) => {
1810            if ar == 0 {
1811                "cash"
1812            } else if ar == 0b01 {
1813                "caslh"
1814            } else if ar == 0b10 {
1815                "casah"
1816            } else {
1817                "casalh"
1818            }
1819        }
1820        Opcode::CASB(ar) => {
1821            if ar == 0 {
1822                "casb"
1823            } else if ar == 0b01 {
1824                "caslb"
1825            } else if ar == 0b10 {
1826                "casab"
1827            } else {
1828                "casalb"
1829            }
1830        }
1831        Opcode::CASP(ar) => {
1832            if ar == 0 {
1833                "casp"
1834            } else if ar == 0b01 {
1835                "caspl"
1836            } else if ar == 0b10 {
1837                "caspa"
1838            } else {
1839                "caspal"
1840            }
1841        }
1842        Opcode::TBL => "tbl",
1843        Opcode::TBX => "tbx",
1844        Opcode::FCADD => "fcadd",
1845        Opcode::LDGM => "ldgm",
1846        Opcode::LDG => "ldm",
1847        Opcode::STGM => "stgm",
1848        Opcode::STZGM => "stzgm",
1849        Opcode::STG => "stg",
1850        Opcode::STZG => "stzg",
1851        Opcode::ST2G => "st2g",
1852        Opcode::STZ2G => "stz2g",
1853        Opcode::LDAPUR => "ldapur",
1854        Opcode::LDAPURB => "ldapurb",
1855        Opcode::LDAPURH => "ldapurh",
1856        Opcode::LDAPURSB => "ldapursb",
1857        Opcode::LDAPURSH => "ldapursh",
1858        Opcode::LDAPURSW => "ldapursw",
1859        Opcode::STLUR => "stlur",
1860        Opcode::STLURB => "stlurb",
1861        Opcode::STLURH => "stlurh",
1862        Opcode::SETF8 => "setf8",
1863        Opcode::SETF16 => "setf16",
1864        Opcode::RMIF => "rmif",
1865        // `This instruction is used by the alias MVN. The alias is always the preferred disassembly.`
1866        Opcode::NOT => "mvn",
1867        Opcode::RSHRN2 => "rshrn2",
1868        Opcode::SQRSHRUN2 => "sqrshrun2",
1869        Opcode::USHLL2 => "ushll2",
1870        Opcode::SSHLL2 => "sshll2",
1871        Opcode::SHA1C => "sha1c",
1872        Opcode::SHA1P => "sha1p",
1873        Opcode::SHA1M => "sha1m",
1874        Opcode::SHA1SU0 => "sha1su0",
1875        Opcode::SHA256H => "sha256h",
1876        Opcode::SHA256H2 => "sha256h2",
1877        Opcode::SHA256SU1 => "sha256su1",
1878        Opcode::BLRAA => "blraa",
1879        Opcode::BLRAAZ => "blraaz",
1880        Opcode::BLRAB => "blrab",
1881        Opcode::BLRABZ => "blrabz",
1882        Opcode::BRAA => "braa",
1883        Opcode::BRAAZ => "braaz",
1884        Opcode::BRAB => "brab",
1885        Opcode::BRABZ => "brabz",
1886        Opcode::ERETAA => "eretaa",
1887        Opcode::ERETAB => "eretab",
1888        Opcode::RETAA => "retaa",
1889        Opcode::RETAB => "retab",
1890        Opcode::PACIA => "pacia",
1891        Opcode::PACIB => "pacib",
1892        Opcode::PACDA => "pacda",
1893        Opcode::PACDB => "pacdb",
1894        Opcode::AUTIA => "autia",
1895        Opcode::AUTIB => "autib",
1896        Opcode::AUTDA => "autda",
1897        Opcode::AUTDB => "autdb",
1898        Opcode::PACIZA => "paciza",
1899        Opcode::PACIZB => "pacizb",
1900        Opcode::PACDZA => "pacdza",
1901        Opcode::PACDZB => "pacdzb",
1902        Opcode::AUTIZA => "autiza",
1903        Opcode::AUTIZB => "autizb",
1904        Opcode::AUTDZA => "autdza",
1905        Opcode::AUTDZB => "autdzb",
1906        Opcode::XPACI => "xpaci",
1907        Opcode::XPACD => "xpacd",
1908        Opcode::PACGA => "pacga",
1909        Opcode::GMI => "gmi",
1910        Opcode::IRG => "irg",
1911        Opcode::SUBP => "subp",
1912        Opcode::SUBPS => "subps",
1913    };
1914
1915    // Regular logic for formatting the operands
1916    for (i, o) in ins.operands.iter().enumerate() {
1917        if let Operand::Nothing = o {
1918            break;
1919        }
1920        if i > 0 {
1921            push_separator(args);
1922        }
1923        push_operand(args, o, ctx);
1924    }
1925    mnemonic
1926}
1927
1928const REG_NAMES_X: [&str; 31] = [
1929    "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14",
1930    "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27",
1931    "x28", "x29", "x30",
1932];
1933
1934const REG_NAMES_W: [&str; 31] = [
1935    "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", "w8", "w9", "w10", "w11", "w12", "w13", "w14",
1936    "w15", "w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23", "w24", "w25", "w26", "w27",
1937    "w28", "w29", "w30",
1938];
1939
1940fn reg_name(size: SizeCode, reg: u16, sp: bool) -> &'static str {
1941    match reg.cmp(&31) {
1942        Ordering::Less => match size {
1943            SizeCode::X => REG_NAMES_X[reg as usize],
1944            SizeCode::W => REG_NAMES_W[reg as usize],
1945        },
1946        Ordering::Equal => {
1947            if sp {
1948                match size {
1949                    SizeCode::X => "sp",
1950                    SizeCode::W => "wsp",
1951                }
1952            } else {
1953                match size {
1954                    SizeCode::X => "xzr",
1955                    SizeCode::W => "wzr",
1956                }
1957            }
1958        }
1959        Ordering::Greater => "<invalid>",
1960    }
1961}
1962
1963fn shift_style(style: ShiftStyle) -> &'static str {
1964    match style {
1965        ShiftStyle::LSL => "lsl",
1966        ShiftStyle::LSR => "lsr",
1967        ShiftStyle::ASR => "asr",
1968        ShiftStyle::ROR => "ror",
1969        ShiftStyle::UXTB => "uxtb",
1970        ShiftStyle::UXTH => "uxth",
1971        ShiftStyle::UXTW => "uxtw",
1972        ShiftStyle::UXTX => "uxtx",
1973        ShiftStyle::SXTB => "sxtb",
1974        ShiftStyle::SXTH => "sxth",
1975        ShiftStyle::SXTW => "sxtw",
1976        ShiftStyle::SXTX => "sxtx",
1977    }
1978}
1979
1980fn condition_code(cond: u8) -> &'static str {
1981    match cond {
1982        0b0000 => "eq",
1983        0b0010 => "hs",
1984        0b0100 => "mi",
1985        0b0110 => "vs",
1986        0b1000 => "hi",
1987        0b1010 => "ge",
1988        0b1100 => "gt",
1989        0b1110 => "al",
1990        0b0001 => "ne",
1991        0b0011 => "lo",
1992        0b0101 => "pl",
1993        0b0111 => "vc",
1994        0b1001 => "ls",
1995        0b1011 => "lt",
1996        0b1101 => "le",
1997        0b1111 => "nv",
1998        _ => "<invalid>",
1999    }
2000}
2001
2002#[inline]
2003fn push_register<Cb>(args: &mut Cb, size: SizeCode, reg: u16, sp: bool)
2004where Cb: FnMut(InstructionPart<'static>) {
2005    push_opaque(args, reg_name(size, reg, sp));
2006}
2007
2008#[inline]
2009fn push_shift<Cb>(args: &mut Cb, style: ShiftStyle, amount: u8)
2010where Cb: FnMut(InstructionPart<'static>) {
2011    push_opaque(args, shift_style(style));
2012    if amount != 0 {
2013        push_plain(args, " ");
2014        push_unsigned(args, amount as u64);
2015    }
2016}
2017
2018#[inline]
2019fn push_condition_code<Cb>(args: &mut Cb, cond: u8)
2020where Cb: FnMut(InstructionPart<'static>) {
2021    push_opaque(args, condition_code(cond));
2022}
2023
2024fn push_barrier<Cb>(args: &mut Cb, option: u8)
2025where Cb: FnMut(InstructionPart<'static>) {
2026    match option {
2027        0b0001 => push_opaque(args, "oshld"),
2028        0b0010 => push_opaque(args, "oshst"),
2029        0b0011 => push_opaque(args, "osh"),
2030        0b0101 => push_opaque(args, "nshld"),
2031        0b0110 => push_opaque(args, "nshst"),
2032        0b0111 => push_opaque(args, "nsh"),
2033        0b1001 => push_opaque(args, "ishld"),
2034        0b1010 => push_opaque(args, "ishst"),
2035        0b1011 => push_opaque(args, "ish"),
2036        0b1101 => push_opaque(args, "ld"),
2037        0b1110 => push_opaque(args, "st"),
2038        0b1111 => push_opaque(args, "sy"),
2039        _ => push_unsigned(args, option as u64),
2040    }
2041}
2042
2043#[inline]
2044fn push_opaque<'a, Cb>(args: &mut Cb, text: &'a str)
2045where Cb: FnMut(InstructionPart<'a>) {
2046    args(InstructionPart::opaque(text));
2047}
2048
2049#[inline]
2050fn push_plain<Cb>(args: &mut Cb, text: &'static str)
2051where Cb: FnMut(InstructionPart<'static>) {
2052    args(InstructionPart::basic(text));
2053}
2054
2055#[inline]
2056fn push_separator<Cb>(args: &mut Cb)
2057where Cb: FnMut(InstructionPart<'static>) {
2058    args(InstructionPart::separator());
2059}
2060
2061#[inline]
2062fn push_unsigned<Cb>(args: &mut Cb, v: u64)
2063where Cb: FnMut(InstructionPart<'static>) {
2064    push_plain(args, "#");
2065    args(InstructionPart::unsigned(v));
2066}
2067
2068#[inline]
2069fn push_signed<Cb>(args: &mut Cb, v: i64)
2070where Cb: FnMut(InstructionPart<'static>) {
2071    push_plain(args, "#");
2072    args(InstructionPart::signed(v));
2073}
2074
2075/// Relocations that appear in Operand::PCOffset.
2076fn is_pc_offset_reloc(reloc: Option<ResolvedRelocation>) -> Option<ResolvedRelocation> {
2077    if let Some(resolved) = reloc
2078        && let RelocationFlags::Elf(
2079            elf::R_AARCH64_ADR_PREL_PG_HI21
2080            | elf::R_AARCH64_JUMP26
2081            | elf::R_AARCH64_CALL26
2082            | elf::R_AARCH64_ADR_GOT_PAGE,
2083        ) = resolved.relocation.flags
2084    {
2085        return Some(resolved);
2086    }
2087    None
2088}
2089
2090/// Relocations that appear in Operand::Immediate.
2091fn is_imm_reloc(resolved: Option<ResolvedRelocation>) -> bool {
2092    resolved.is_some_and(|r| {
2093        matches!(r.relocation.flags, RelocationFlags::Elf(elf::R_AARCH64_ADD_ABS_LO12_NC))
2094    })
2095}
2096
2097/// Relocations that appear in Operand::RegPreIndex/RegPostIndex.
2098fn is_reg_index_reloc(resolved: Option<ResolvedRelocation>) -> bool {
2099    resolved.is_some_and(|r| {
2100        matches!(
2101            r.relocation.flags,
2102            RelocationFlags::Elf(
2103                elf::R_AARCH64_LDST32_ABS_LO12_NC | elf::R_AARCH64_LD64_GOT_LO12_NC
2104            )
2105        )
2106    })
2107}
2108
2109fn push_operand<Cb>(args: &mut Cb, o: &Operand, ctx: &mut DisplayCtx)
2110where Cb: FnMut(InstructionPart<'static>) {
2111    match o {
2112        Operand::Nothing => unreachable!(),
2113        Operand::PCOffset(off) => {
2114            if let Some(resolved) = is_pc_offset_reloc(ctx.reloc) {
2115                let target_address =
2116                    resolved.symbol.address.checked_add_signed(resolved.relocation.addend);
2117                if resolved.symbol.section == Some(ctx.section_index)
2118                    && matches!(target_address, Some(addr) if addr > ctx.start_address && addr < ctx.end_address)
2119                {
2120                    let dest = target_address.unwrap();
2121                    push_plain(args, "$");
2122                    args(InstructionPart::branch_dest(dest));
2123                } else {
2124                    args(InstructionPart::reloc());
2125                }
2126            } else {
2127                let dest = ctx.address.saturating_add_signed(*off);
2128                push_plain(args, "$");
2129                args(InstructionPart::branch_dest(dest));
2130            }
2131        }
2132        Operand::Immediate(imm) => {
2133            if is_imm_reloc(ctx.reloc) {
2134                args(InstructionPart::reloc());
2135            } else {
2136                push_unsigned(args, *imm as u64);
2137            }
2138        }
2139        Operand::Imm64(imm) => {
2140            push_unsigned(args, *imm);
2141        }
2142        Operand::Imm16(imm) => {
2143            push_unsigned(args, *imm as u64);
2144        }
2145        Operand::Register(size, reg) => {
2146            push_register(args, *size, *reg, false);
2147        }
2148        Operand::RegisterPair(size, reg) => {
2149            push_register(args, *size, *reg, false);
2150            push_separator(args);
2151            push_register(args, *size, *reg + 1, false);
2152        }
2153        Operand::RegisterOrSP(size, reg) => {
2154            push_register(args, *size, *reg, true);
2155        }
2156        Operand::ConditionCode(cond) => match cond {
2157            0b0000 => push_opaque(args, "eq"),
2158            0b0010 => push_opaque(args, "hs"),
2159            0b0100 => push_opaque(args, "mi"),
2160            0b0110 => push_opaque(args, "vs"),
2161            0b1000 => push_opaque(args, "hi"),
2162            0b1010 => push_opaque(args, "ge"),
2163            0b1100 => push_opaque(args, "gt"),
2164            0b1110 => push_opaque(args, "al"),
2165            0b0001 => push_opaque(args, "ne"),
2166            0b0011 => push_opaque(args, "lo"),
2167            0b0101 => push_opaque(args, "pl"),
2168            0b0111 => push_opaque(args, "vc"),
2169            0b1001 => push_opaque(args, "ls"),
2170            0b1011 => push_opaque(args, "lt"),
2171            0b1101 => push_opaque(args, "le"),
2172            0b1111 => push_opaque(args, "nv"),
2173            _ => unreachable!(),
2174        },
2175        Operand::ImmShift(i, shift) => {
2176            push_unsigned(args, *i as u64);
2177            if *shift > 0 {
2178                push_separator(args);
2179                push_opaque(args, "lsl");
2180                push_plain(args, " ");
2181                push_unsigned(args, *shift as u64);
2182            }
2183        }
2184        Operand::ImmShiftMSL(i, shift) => {
2185            push_unsigned(args, *i as u64);
2186            if *shift > 0 {
2187                push_separator(args);
2188                push_opaque(args, "msl");
2189                push_plain(args, " ");
2190                push_unsigned(args, *shift as u64);
2191            }
2192        }
2193        Operand::RegShift(shift_type, amount, size, reg) => match size {
2194            SizeCode::X => {
2195                push_register(args, SizeCode::X, *reg, false);
2196                if (*shift_type == ShiftStyle::LSL || *shift_type == ShiftStyle::UXTX)
2197                    && *amount == 0
2198                {
2199                    // pass
2200                } else {
2201                    push_separator(args);
2202                    push_shift(args, *shift_type, *amount);
2203                }
2204            }
2205            SizeCode::W => {
2206                push_register(args, SizeCode::W, *reg, false);
2207                if *shift_type == ShiftStyle::LSL && *amount == 0 {
2208                    // pass
2209                } else {
2210                    push_separator(args);
2211                    push_shift(args, *shift_type, *amount);
2212                }
2213            }
2214        },
2215        Operand::RegRegOffset(reg, index_reg, index_size, extend, amount) => {
2216            push_plain(args, "[");
2217            push_register(args, SizeCode::X, *reg, true);
2218            push_separator(args);
2219            push_register(args, *index_size, *index_reg, false);
2220            if extend == &ShiftStyle::LSL && *amount == 0 {
2221                // pass
2222            } else if ((extend == &ShiftStyle::UXTW && index_size == &SizeCode::W)
2223                || (extend == &ShiftStyle::UXTX && index_size == &SizeCode::X))
2224                && *amount == 0
2225            {
2226                push_separator(args);
2227                push_shift(args, *extend, 0);
2228            } else {
2229                push_separator(args);
2230                push_shift(args, *extend, *amount);
2231            }
2232            push_plain(args, "]");
2233        }
2234        Operand::RegPreIndex(reg, offset, wback_bit) => {
2235            push_plain(args, "[");
2236            push_register(args, SizeCode::X, *reg, true);
2237            if is_reg_index_reloc(ctx.reloc) {
2238                push_separator(args);
2239                args(InstructionPart::reloc());
2240            } else if *offset != 0 || *wback_bit {
2241                push_separator(args);
2242                push_signed(args, *offset as i64);
2243            }
2244            push_plain(args, "]");
2245            if *wback_bit {
2246                push_plain(args, "!");
2247            }
2248        }
2249        Operand::RegPostIndex(reg, offset) => {
2250            push_plain(args, "[");
2251            push_register(args, SizeCode::X, *reg, true);
2252            push_plain(args, "]");
2253            push_separator(args);
2254            if is_reg_index_reloc(ctx.reloc) {
2255                args(InstructionPart::reloc());
2256            } else {
2257                push_signed(args, *offset as i64);
2258            }
2259        }
2260        Operand::RegPostIndexReg(reg, offset_reg) => {
2261            push_plain(args, "[");
2262            push_register(args, SizeCode::X, *reg, true);
2263            push_plain(args, "]");
2264            push_separator(args);
2265            // TODO does 31 have to be handled separate?
2266            args(InstructionPart::opaque(format!("x{offset_reg}")));
2267        }
2268        // Fall back to original logic
2269        Operand::SIMDRegister(_, _)
2270        | Operand::SIMDRegisterElements(_, _, _)
2271        | Operand::SIMDRegisterElementsLane(_, _, _, _)
2272        | Operand::SIMDRegisterElementsMultipleLane(_, _, _, _, _)
2273        | Operand::SIMDRegisterGroup(_, _, _, _)
2274        | Operand::SIMDRegisterGroupLane(_, _, _, _)
2275        | Operand::ImmediateDouble(_)
2276        | Operand::PrefetchOp(_)
2277        | Operand::SystemReg(_)
2278        | Operand::ControlReg(_)
2279        | Operand::PstateField(_) => {
2280            args(InstructionPart::opaque(o.to_string()));
2281        }
2282    }
2283}
2284
2285// Opcode is #[repr(u16)], but the tuple variants negate that, so we have to do this instead.
2286const fn opcode_to_u16(opcode: Opcode) -> u16 {
2287    match opcode {
2288        Opcode::Invalid => OPCODE_INVALID,
2289        Opcode::UDF => 0,
2290        Opcode::MOVN => 1,
2291        Opcode::MOVK => 2,
2292        Opcode::MOVZ => 3,
2293        Opcode::ADC => 4,
2294        Opcode::ADCS => 5,
2295        Opcode::SBC => 6,
2296        Opcode::SBCS => 7,
2297        Opcode::AND => 8,
2298        Opcode::ORR => 9,
2299        Opcode::ORN => 10,
2300        Opcode::EOR => 11,
2301        Opcode::EON => 12,
2302        Opcode::BIC => 13,
2303        Opcode::BICS => 14,
2304        Opcode::ANDS => 15,
2305        Opcode::ADDS => 16,
2306        Opcode::ADD => 17,
2307        Opcode::SUBS => 18,
2308        Opcode::SUB => 19,
2309        Opcode::BFM => 20,
2310        Opcode::UBFM => 21,
2311        Opcode::SBFM => 22,
2312        Opcode::ADR => 23,
2313        Opcode::ADRP => 24,
2314        Opcode::EXTR => 25,
2315        Opcode::LDAR => 26,
2316        Opcode::LDLAR => 27,
2317        Opcode::LDARB => 28,
2318        Opcode::LDLARB => 29,
2319        Opcode::LDAXRB => 30,
2320        Opcode::LDARH => 31,
2321        Opcode::LDLARH => 32,
2322        Opcode::LDAXP => 33,
2323        Opcode::LDAXR => 34,
2324        Opcode::LDAXRH => 35,
2325        Opcode::LDP => 36,
2326        Opcode::LDPSW => 37,
2327        Opcode::LDR => 38,
2328        Opcode::LDRB => 39,
2329        Opcode::LDRSB => 40,
2330        Opcode::LDRSW => 41,
2331        Opcode::LDRSH => 42,
2332        Opcode::LDRH => 43,
2333        Opcode::LDTR => 44,
2334        Opcode::LDTRB => 45,
2335        Opcode::LDTRH => 46,
2336        Opcode::LDTRSB => 47,
2337        Opcode::LDTRSH => 48,
2338        Opcode::LDTRSW => 49,
2339        Opcode::LDUR => 50,
2340        Opcode::LDURB => 51,
2341        Opcode::LDURSB => 52,
2342        Opcode::LDURSW => 53,
2343        Opcode::LDURSH => 54,
2344        Opcode::LDURH => 55,
2345        Opcode::LDXP => 56,
2346        Opcode::LDXR => 57,
2347        Opcode::LDXRB => 58,
2348        Opcode::LDXRH => 59,
2349        Opcode::STLR => 60,
2350        Opcode::STLLR => 61,
2351        Opcode::STLRB => 62,
2352        Opcode::STLLRB => 63,
2353        Opcode::STLRH => 64,
2354        Opcode::STLLRH => 65,
2355        Opcode::STLXP => 66,
2356        Opcode::STLXR => 67,
2357        Opcode::STLXRB => 68,
2358        Opcode::STLXRH => 69,
2359        Opcode::STP => 70,
2360        Opcode::STR => 71,
2361        Opcode::STTR => 72,
2362        Opcode::STTRB => 73,
2363        Opcode::STTRH => 74,
2364        Opcode::STRB => 75,
2365        Opcode::STRH => 76,
2366        Opcode::STRW => 77,
2367        Opcode::STUR => 78,
2368        Opcode::STURB => 79,
2369        Opcode::STURH => 80,
2370        Opcode::STXP => 81,
2371        Opcode::STXR => 82,
2372        Opcode::STXRB => 83,
2373        Opcode::STXRH => 84,
2374        Opcode::TBZ => 85,
2375        Opcode::TBNZ => 86,
2376        Opcode::CBZ => 87,
2377        Opcode::CBNZ => 88,
2378        Opcode::B => 89,
2379        Opcode::BR => 90,
2380        Opcode::Bcc(_) => 91,
2381        Opcode::BL => 92,
2382        Opcode::BLR => 93,
2383        Opcode::SVC => 94,
2384        Opcode::HVC => 95,
2385        Opcode::SMC => 96,
2386        Opcode::BRK => 97,
2387        Opcode::HLT => 98,
2388        Opcode::DCPS1 => 99,
2389        Opcode::DCPS2 => 100,
2390        Opcode::DCPS3 => 101,
2391        Opcode::RET => 102,
2392        Opcode::ERET => 103,
2393        Opcode::DRPS => 104,
2394        Opcode::MSR => 105,
2395        Opcode::MRS => 106,
2396        Opcode::SYS(_) => 107,
2397        Opcode::SYSL(_) => 108,
2398        Opcode::ISB => 109,
2399        Opcode::DSB(_) => 110,
2400        Opcode::DMB(_) => 111,
2401        Opcode::SB => 112,
2402        Opcode::SSSB => 113,
2403        Opcode::HINT => 114,
2404        Opcode::CLREX => 115,
2405        Opcode::CSEL => 116,
2406        Opcode::CSNEG => 117,
2407        Opcode::CSINC => 118,
2408        Opcode::CSINV => 119,
2409        Opcode::CCMN => 120,
2410        Opcode::CCMP => 121,
2411        Opcode::RBIT => 122,
2412        Opcode::REV16 => 123,
2413        Opcode::REV => 124,
2414        Opcode::REV32 => 125,
2415        Opcode::CLZ => 126,
2416        Opcode::CLS => 127,
2417        Opcode::MADD => 128,
2418        Opcode::MSUB => 129,
2419        Opcode::SMADDL => 130,
2420        Opcode::SMSUBL => 131,
2421        Opcode::SMULH => 132,
2422        Opcode::UMADDL => 133,
2423        Opcode::UMSUBL => 134,
2424        Opcode::UMULH => 135,
2425        Opcode::UDIV => 136,
2426        Opcode::SDIV => 137,
2427        Opcode::LSLV => 138,
2428        Opcode::LSRV => 139,
2429        Opcode::ASRV => 140,
2430        Opcode::RORV => 141,
2431        Opcode::CRC32B => 142,
2432        Opcode::CRC32H => 143,
2433        Opcode::CRC32W => 144,
2434        Opcode::CRC32X => 145,
2435        Opcode::CRC32CB => 146,
2436        Opcode::CRC32CH => 147,
2437        Opcode::CRC32CW => 148,
2438        Opcode::CRC32CX => 149,
2439        Opcode::STNP => 150,
2440        Opcode::LDNP => 151,
2441        Opcode::ST1 => 152,
2442        Opcode::ST2 => 153,
2443        Opcode::ST3 => 154,
2444        Opcode::ST4 => 155,
2445        Opcode::LD1 => 156,
2446        Opcode::LD2 => 157,
2447        Opcode::LD3 => 158,
2448        Opcode::LD4 => 159,
2449        Opcode::LD1R => 160,
2450        Opcode::LD2R => 161,
2451        Opcode::LD3R => 162,
2452        Opcode::LD4R => 163,
2453        Opcode::FMADD => 164,
2454        Opcode::FMSUB => 165,
2455        Opcode::FNMADD => 166,
2456        Opcode::FNMSUB => 167,
2457        Opcode::SCVTF => 168,
2458        Opcode::UCVTF => 169,
2459        Opcode::FCVTZS => 170,
2460        Opcode::FCVTZU => 171,
2461        Opcode::FMOV => 172,
2462        Opcode::FABS => 173,
2463        Opcode::FNEG => 174,
2464        Opcode::FSQRT => 175,
2465        Opcode::FRINTN => 176,
2466        Opcode::FRINTP => 177,
2467        Opcode::FRINTM => 178,
2468        Opcode::FRINTZ => 179,
2469        Opcode::FRINTA => 180,
2470        Opcode::FRINTX => 181,
2471        Opcode::FRINTI => 182,
2472        Opcode::FRINT32Z => 183,
2473        Opcode::FRINT32X => 184,
2474        Opcode::FRINT64Z => 185,
2475        Opcode::FRINT64X => 186,
2476        Opcode::BFCVT => 187,
2477        Opcode::FCVT => 188,
2478        Opcode::FCMP => 189,
2479        Opcode::FCMPE => 190,
2480        Opcode::FMUL => 191,
2481        Opcode::FDIV => 192,
2482        Opcode::FADD => 193,
2483        Opcode::FSUB => 194,
2484        Opcode::FMAX => 195,
2485        Opcode::FMIN => 196,
2486        Opcode::FMAXNM => 197,
2487        Opcode::FMINNM => 198,
2488        Opcode::FNMUL => 199,
2489        Opcode::FCSEL => 200,
2490        Opcode::FCCMP => 201,
2491        Opcode::FCCMPE => 202,
2492        Opcode::FMULX => 203,
2493        Opcode::FMLSL => 204,
2494        Opcode::FMLAL => 205,
2495        Opcode::SQRDMLSH => 206,
2496        Opcode::UDOT => 207,
2497        Opcode::SQRDMLAH => 208,
2498        Opcode::UMULL => 209,
2499        Opcode::UMULL2 => 210,
2500        Opcode::UMLSL => 211,
2501        Opcode::UMLSL2 => 212,
2502        Opcode::MLS => 213,
2503        Opcode::UMLAL => 214,
2504        Opcode::UMLAL2 => 215,
2505        Opcode::MLA => 216,
2506        Opcode::SDOT => 217,
2507        Opcode::SQDMULH => 218,
2508        Opcode::SQDMULL => 219,
2509        Opcode::SQDMULL2 => 220,
2510        Opcode::SMULL => 221,
2511        Opcode::SMULL2 => 222,
2512        Opcode::MUL => 223,
2513        Opcode::SQDMLSL => 224,
2514        Opcode::SQDMLSL2 => 225,
2515        Opcode::SMLSL => 226,
2516        Opcode::SMLSL2 => 227,
2517        Opcode::SQDMLAL => 228,
2518        Opcode::SQDMLAL2 => 229,
2519        Opcode::SMLAL => 230,
2520        Opcode::SMLAL2 => 231,
2521        Opcode::SQRDMULH => 232,
2522        Opcode::FCMLA => 233,
2523        Opcode::SSHR => 234,
2524        Opcode::SSRA => 235,
2525        Opcode::SRSHR => 236,
2526        Opcode::SRSRA => 237,
2527        Opcode::SHL => 238,
2528        Opcode::SQSHL => 239,
2529        Opcode::SHRN => 240,
2530        Opcode::RSHRN => 241,
2531        Opcode::SQSHRN => 242,
2532        Opcode::SQRSHRN => 243,
2533        Opcode::SSHLL => 244,
2534        Opcode::USHR => 245,
2535        Opcode::USRA => 246,
2536        Opcode::URSHR => 247,
2537        Opcode::URSRA => 248,
2538        Opcode::SRI => 249,
2539        Opcode::SLI => 250,
2540        Opcode::SQSHLU => 251,
2541        Opcode::UQSHL => 252,
2542        Opcode::SQSHRUN => 253,
2543        Opcode::SQRSHRUN => 254,
2544        Opcode::UQSHRN => 255,
2545        Opcode::UQRSHRN => 256,
2546        Opcode::USHLL => 257,
2547        Opcode::MOVI => 258,
2548        Opcode::MVNI => 259,
2549        Opcode::SHADD => 260,
2550        Opcode::SQADD => 261,
2551        Opcode::SRHADD => 262,
2552        Opcode::SHSUB => 263,
2553        Opcode::SQSUB => 264,
2554        Opcode::CMGT => 265,
2555        Opcode::CMGE => 266,
2556        Opcode::SSHL => 267,
2557        Opcode::SRSHL => 268,
2558        Opcode::SQRSHL => 269,
2559        Opcode::SMAX => 270,
2560        Opcode::SMIN => 271,
2561        Opcode::SABD => 272,
2562        Opcode::SABA => 273,
2563        Opcode::CMTST => 274,
2564        Opcode::SMAXP => 275,
2565        Opcode::SMINP => 276,
2566        Opcode::ADDP => 277,
2567        Opcode::UHADD => 278,
2568        Opcode::UQADD => 279,
2569        Opcode::URHADD => 280,
2570        Opcode::UHSUB => 281,
2571        Opcode::UQSUB => 282,
2572        Opcode::CMHI => 283,
2573        Opcode::CMHS => 284,
2574        Opcode::USHL => 285,
2575        Opcode::URSHL => 286,
2576        Opcode::UQRSHL => 287,
2577        Opcode::UMAX => 288,
2578        Opcode::UMIN => 289,
2579        Opcode::UABD => 290,
2580        Opcode::UABA => 291,
2581        Opcode::CMEQ => 292,
2582        Opcode::PMUL => 293,
2583        Opcode::UMAXP => 294,
2584        Opcode::UMINP => 295,
2585        Opcode::FMLA => 296,
2586        Opcode::FCMEQ => 297,
2587        Opcode::FRECPS => 298,
2588        Opcode::BSL => 299,
2589        Opcode::BIT => 300,
2590        Opcode::BIF => 301,
2591        Opcode::FMAXNMP => 302,
2592        Opcode::FMINMNP => 303,
2593        Opcode::FADDP => 304,
2594        Opcode::FCMGE => 305,
2595        Opcode::FACGE => 306,
2596        Opcode::FMAXP => 307,
2597        Opcode::SADDL => 308,
2598        Opcode::SADDL2 => 309,
2599        Opcode::SADDW => 310,
2600        Opcode::SADDW2 => 311,
2601        Opcode::SSUBL => 312,
2602        Opcode::SSUBL2 => 313,
2603        Opcode::SSUBW => 314,
2604        Opcode::SSUBW2 => 315,
2605        Opcode::ADDHN => 316,
2606        Opcode::ADDHN2 => 317,
2607        Opcode::SABAL => 318,
2608        Opcode::SABAL2 => 319,
2609        Opcode::SUBHN => 320,
2610        Opcode::SUBHN2 => 321,
2611        Opcode::SABDL => 322,
2612        Opcode::SABDL2 => 323,
2613        Opcode::PMULL => 324,
2614        Opcode::PMULL2 => 325,
2615        Opcode::UADDL => 326,
2616        Opcode::UADDL2 => 327,
2617        Opcode::UADDW => 328,
2618        Opcode::UADDW2 => 329,
2619        Opcode::USUBL => 330,
2620        Opcode::USUBL2 => 331,
2621        Opcode::USUBW => 332,
2622        Opcode::USUBW2 => 333,
2623        Opcode::RADDHN => 334,
2624        Opcode::RADDHN2 => 335,
2625        Opcode::RSUBHN => 336,
2626        Opcode::RSUBHN2 => 337,
2627        Opcode::UABAL => 338,
2628        Opcode::UABAL2 => 339,
2629        Opcode::UABDL => 340,
2630        Opcode::UABDL2 => 341,
2631        Opcode::REV64 => 342,
2632        Opcode::SADDLP => 343,
2633        Opcode::SUQADD => 344,
2634        Opcode::CNT => 345,
2635        Opcode::SADALP => 346,
2636        Opcode::SQABS => 347,
2637        Opcode::CMLT => 348,
2638        Opcode::ABS => 349,
2639        Opcode::XTN => 350,
2640        Opcode::XTN2 => 351,
2641        Opcode::SQXTN => 352,
2642        Opcode::SQXTN2 => 353,
2643        Opcode::FCVTN => 354,
2644        Opcode::FCVTN2 => 355,
2645        Opcode::FCMGT => 356,
2646        Opcode::FCVTL => 357,
2647        Opcode::FCVTL2 => 358,
2648        Opcode::FCVTNS => 359,
2649        Opcode::FCVTPS => 360,
2650        Opcode::FCVTMS => 361,
2651        Opcode::FCVTAS => 362,
2652        Opcode::URECPE => 363,
2653        Opcode::FRECPE => 364,
2654        Opcode::UADDLP => 365,
2655        Opcode::USQADD => 366,
2656        Opcode::UADALP => 367,
2657        Opcode::SQNEG => 368,
2658        Opcode::CMLE => 369,
2659        Opcode::NEG => 370,
2660        Opcode::SQXTUN => 371,
2661        Opcode::SQXTUN2 => 372,
2662        Opcode::SHLL => 373,
2663        Opcode::SHLL2 => 374,
2664        Opcode::UQXTN => 375,
2665        Opcode::UQXTN2 => 376,
2666        Opcode::FCVTXN => 377,
2667        Opcode::FCVTXN2 => 378,
2668        Opcode::FCVTNU => 379,
2669        Opcode::FCVTMU => 380,
2670        Opcode::FCVTAU => 381,
2671        Opcode::INS => 382,
2672        Opcode::EXT => 383,
2673        Opcode::DUP => 384,
2674        Opcode::UZP1 => 385,
2675        Opcode::TRN1 => 386,
2676        Opcode::ZIP1 => 387,
2677        Opcode::UZP2 => 388,
2678        Opcode::TRN2 => 389,
2679        Opcode::ZIP2 => 390,
2680        Opcode::SMOV => 391,
2681        Opcode::UMOV => 392,
2682        Opcode::SQSHRN2 => 393,
2683        Opcode::SQRSHRN2 => 394,
2684        Opcode::SQSHRUN2 => 395,
2685        Opcode::UQSHRN2 => 396,
2686        Opcode::UQRSHRN2 => 397,
2687        Opcode::FMLS => 398,
2688        Opcode::FRECPX => 399,
2689        Opcode::FRSQRTE => 400,
2690        Opcode::FCVTPU => 401,
2691        Opcode::FCMLT => 402,
2692        Opcode::FCMLE => 403,
2693        Opcode::FMAXNMV => 404,
2694        Opcode::FMINNMV => 405,
2695        Opcode::FMAXV => 406,
2696        Opcode::FMINV => 407,
2697        Opcode::UADDLV => 408,
2698        Opcode::SADDLV => 409,
2699        Opcode::UMAXV => 410,
2700        Opcode::SMAXV => 411,
2701        Opcode::UMINV => 412,
2702        Opcode::SMINV => 413,
2703        Opcode::ADDV => 414,
2704        Opcode::FRSQRTS => 415,
2705        Opcode::FMINNMP => 416,
2706        Opcode::FMLAL2 => 417,
2707        Opcode::FMLSL2 => 418,
2708        Opcode::FABD => 419,
2709        Opcode::FACGT => 420,
2710        Opcode::FMINP => 421,
2711        Opcode::FJCVTZS => 422,
2712        Opcode::URSQRTE => 423,
2713        Opcode::PRFM => 424,
2714        Opcode::PRFUM => 425,
2715        Opcode::AESE => 426,
2716        Opcode::AESD => 427,
2717        Opcode::AESMC => 428,
2718        Opcode::AESIMC => 429,
2719        Opcode::SHA1H => 430,
2720        Opcode::SHA1SU1 => 431,
2721        Opcode::SHA256SU0 => 432,
2722        Opcode::SM3TT1A => 433,
2723        Opcode::SM3TT1B => 434,
2724        Opcode::SM3TT2A => 435,
2725        Opcode::SM3TT2B => 436,
2726        Opcode::SHA512H => 437,
2727        Opcode::SHA512H2 => 438,
2728        Opcode::SHA512SU1 => 439,
2729        Opcode::RAX1 => 440,
2730        Opcode::SM3PARTW1 => 441,
2731        Opcode::SM3PARTW2 => 442,
2732        Opcode::SM4EKEY => 443,
2733        Opcode::BCAX => 444,
2734        Opcode::SM3SS1 => 445,
2735        Opcode::SHA512SU0 => 446,
2736        Opcode::SM4E => 447,
2737        Opcode::EOR3 => 448,
2738        Opcode::XAR => 449,
2739        Opcode::LDRAA => 450,
2740        Opcode::LDRAB => 451,
2741        Opcode::LDAPR => 452,
2742        Opcode::LDAPRH => 453,
2743        Opcode::LDAPRB => 454,
2744        Opcode::SWP(_) => 455,
2745        Opcode::SWPB(_) => 456,
2746        Opcode::SWPH(_) => 457,
2747        Opcode::LDADDB(_) => 458,
2748        Opcode::LDCLRB(_) => 459,
2749        Opcode::LDEORB(_) => 460,
2750        Opcode::LDSETB(_) => 461,
2751        Opcode::LDSMAXB(_) => 462,
2752        Opcode::LDSMINB(_) => 463,
2753        Opcode::LDUMAXB(_) => 464,
2754        Opcode::LDUMINB(_) => 465,
2755        Opcode::LDADDH(_) => 466,
2756        Opcode::LDCLRH(_) => 467,
2757        Opcode::LDEORH(_) => 468,
2758        Opcode::LDSETH(_) => 469,
2759        Opcode::LDSMAXH(_) => 470,
2760        Opcode::LDSMINH(_) => 471,
2761        Opcode::LDUMAXH(_) => 472,
2762        Opcode::LDUMINH(_) => 473,
2763        Opcode::LDADD(_) => 474,
2764        Opcode::LDCLR(_) => 475,
2765        Opcode::LDEOR(_) => 476,
2766        Opcode::LDSET(_) => 477,
2767        Opcode::LDSMAX(_) => 478,
2768        Opcode::LDSMIN(_) => 479,
2769        Opcode::LDUMAX(_) => 480,
2770        Opcode::LDUMIN(_) => 481,
2771        Opcode::CAS(_) => 482,
2772        Opcode::CASH(_) => 483,
2773        Opcode::CASB(_) => 484,
2774        Opcode::CASP(_) => 485,
2775        Opcode::TBL => 486,
2776        Opcode::TBX => 487,
2777        Opcode::FCADD => 488,
2778        Opcode::LDGM => 489,
2779        Opcode::LDG => 490,
2780        Opcode::STGM => 491,
2781        Opcode::STZGM => 492,
2782        Opcode::STG => 493,
2783        Opcode::STZG => 494,
2784        Opcode::ST2G => 495,
2785        Opcode::STZ2G => 496,
2786        Opcode::LDAPUR => 497,
2787        Opcode::LDAPURB => 498,
2788        Opcode::LDAPURH => 499,
2789        Opcode::LDAPURSB => 500,
2790        Opcode::LDAPURSH => 501,
2791        Opcode::LDAPURSW => 502,
2792        Opcode::STLUR => 503,
2793        Opcode::STLURB => 504,
2794        Opcode::STLURH => 505,
2795        Opcode::SETF8 => 506,
2796        Opcode::SETF16 => 507,
2797        Opcode::RMIF => 508,
2798        Opcode::NOT => 509,
2799        Opcode::RSHRN2 => 510,
2800        Opcode::SQRSHRUN2 => 511,
2801        Opcode::USHLL2 => 512,
2802        Opcode::SSHLL2 => 513,
2803        Opcode::SHA1C => 514,
2804        Opcode::SHA1P => 515,
2805        Opcode::SHA1M => 516,
2806        Opcode::SHA1SU0 => 517,
2807        Opcode::SHA256H => 518,
2808        Opcode::SHA256H2 => 519,
2809        Opcode::SHA256SU1 => 520,
2810        Opcode::SHRN2 => 521,
2811        Opcode::BLRAA => 522,
2812        Opcode::BLRAAZ => 523,
2813        Opcode::BLRAB => 524,
2814        Opcode::BLRABZ => 525,
2815        Opcode::BRAA => 526,
2816        Opcode::BRAAZ => 527,
2817        Opcode::BRAB => 528,
2818        Opcode::BRABZ => 529,
2819        Opcode::RETAA => 530,
2820        Opcode::RETAB => 531,
2821        Opcode::ERETAA => 532,
2822        Opcode::ERETAB => 533,
2823        Opcode::PACIA => 534,
2824        Opcode::PACIB => 535,
2825        Opcode::PACDA => 536,
2826        Opcode::PACDB => 537,
2827        Opcode::AUTIA => 538,
2828        Opcode::AUTIB => 539,
2829        Opcode::AUTDA => 540,
2830        Opcode::AUTDB => 541,
2831        Opcode::PACIZA => 542,
2832        Opcode::PACIZB => 543,
2833        Opcode::PACDZA => 544,
2834        Opcode::PACDZB => 545,
2835        Opcode::AUTIZA => 546,
2836        Opcode::AUTIZB => 547,
2837        Opcode::AUTDZA => 548,
2838        Opcode::AUTDZB => 549,
2839        Opcode::XPACI => 550,
2840        Opcode::XPACD => 551,
2841        Opcode::PACGA => 552,
2842        Opcode::GMI => 553,
2843        Opcode::IRG => 554,
2844        Opcode::SUBP => 555,
2845        Opcode::SUBPS => 556,
2846    }
2847}