master
   1case: Case = .lower,
   2mnemonic_operands_separator: []const u8 = " ",
   3operands_separator: []const u8 = ", ",
   4enable_aliases: bool = true,
   5
   6pub const Case = enum {
   7    lower,
   8    upper,
   9    pub fn convert(case: Case, c: u8) u8 {
  10        return switch (case) {
  11            .lower => std.ascii.toLower(c),
  12            .upper => std.ascii.toUpper(c),
  13        };
  14    }
  15};
  16
  17pub fn printInstruction(dis: Disassemble, inst: aarch64.encoding.Instruction, writer: *std.Io.Writer) std.Io.Writer.Error!void {
  18    unallocated: switch (inst.decode()) {
  19        .unallocated => break :unallocated,
  20        .reserved => |reserved| switch (reserved.decode()) {
  21            .unallocated => break :unallocated,
  22            .udf => |udf| return writer.print("{f}{s}#0x{x}", .{
  23                fmtCase(.udf, dis.case),
  24                dis.mnemonic_operands_separator,
  25                udf.imm16,
  26            }),
  27        },
  28        .sme => {},
  29        .sve => {},
  30        .data_processing_immediate => |data_processing_immediate| switch (data_processing_immediate.decode()) {
  31            .unallocated => break :unallocated,
  32            .pc_relative_addressing => |pc_relative_addressing| {
  33                const group = pc_relative_addressing.group;
  34                const imm = (@as(i33, group.immhi) << 2 | @as(i33, group.immlo) << 0) + @as(i33, switch (group.op) {
  35                    .adr => aarch64.encoding.Instruction.size,
  36                    .adrp => 0,
  37                });
  38                return writer.print("{f}{s}{f}{s}.{c}0x{x}", .{
  39                    fmtCase(group.op, dis.case),
  40                    dis.mnemonic_operands_separator,
  41                    group.Rd.decode(.{}).x().fmtCase(dis.case),
  42                    dis.operands_separator,
  43                    @as(u8, if (imm < 0) '-' else '+'),
  44                    switch (group.op) {
  45                        .adr => @abs(imm),
  46                        .adrp => @abs(imm) << 12,
  47                    },
  48                });
  49            },
  50            .add_subtract_immediate => |add_subtract_immediate| {
  51                const group = add_subtract_immediate.group;
  52                const op = group.op;
  53                const S = group.S;
  54                const sf = group.sf;
  55                const sh = group.sh;
  56                const imm12 = group.imm12;
  57                const Rn = group.Rn.decode(.{ .sp = true }).general(sf);
  58                const Rd = group.Rd.decode(.{ .sp = !S }).general(sf);
  59                const elide_shift = sh == .@"0";
  60                if (dis.enable_aliases and op == .add and S == false and elide_shift and imm12 == 0 and
  61                    (Rn.alias == .sp or Rd.alias == .sp)) try writer.print("{f}{s}{f}{s}{f}", .{
  62                    fmtCase(.mov, dis.case),
  63                    dis.mnemonic_operands_separator,
  64                    Rd.fmtCase(dis.case),
  65                    dis.operands_separator,
  66                    Rn.fmtCase(dis.case),
  67                }) else try writer.print("{f}{s}{s}{f}{s}{f}{s}#0x{x}", .{
  68                    fmtCase(op, dis.case),
  69                    if (S) "s" else "",
  70                    dis.mnemonic_operands_separator,
  71                    Rd.fmtCase(dis.case),
  72                    dis.operands_separator,
  73                    Rn.fmtCase(dis.case),
  74                    dis.operands_separator,
  75                    imm12,
  76                });
  77                return if (!elide_shift) writer.print("{s}{f} #{t}", .{
  78                    dis.operands_separator,
  79                    fmtCase(.lsl, dis.case),
  80                    sh,
  81                });
  82            },
  83            .add_subtract_immediate_with_tags => |add_subtract_immediate_with_tags| {
  84                const decoded = add_subtract_immediate_with_tags.decode();
  85                if (decoded == .unallocated) break :unallocated;
  86                const group = add_subtract_immediate_with_tags.group;
  87                return writer.print("{f}{s}{f}{s}{f}{s}#0x{x}{s}#0x{x}", .{
  88                    fmtCase(decoded, dis.case),
  89                    dis.mnemonic_operands_separator,
  90                    group.Rd.decode(.{ .sp = true }).x().fmtCase(dis.case),
  91                    dis.operands_separator,
  92                    group.Rn.decode(.{ .sp = true }).x().fmtCase(dis.case),
  93                    dis.operands_separator,
  94                    @as(u10, group.uimm6) << 4,
  95                    dis.operands_separator,
  96                    group.uimm4,
  97                });
  98            },
  99            .logical_immediate => |logical_immediate| {
 100                const decoded = logical_immediate.decode();
 101                if (decoded == .unallocated) break :unallocated;
 102                const group = logical_immediate.group;
 103                const sf = group.sf;
 104                const decoded_imm = group.imm.decodeImmediate(sf);
 105                const imm = switch (sf) {
 106                    .word => @as(i32, @bitCast(@as(u32, @intCast(decoded_imm)))),
 107                    .doubleword => @as(i64, @bitCast(decoded_imm)),
 108                };
 109                const Rn = group.Rn.decode(.{}).general(sf);
 110                const Rd = group.Rd.decode(.{ .sp = decoded != .ands }).general(sf);
 111                return if (dis.enable_aliases and decoded == .orr and Rn.alias == .zr and !group.imm.moveWidePreferred(sf)) writer.print("{f}{s}{f}{s}#{s}0x{x}", .{
 112                    fmtCase(.mov, dis.case),
 113                    dis.mnemonic_operands_separator,
 114                    Rd.fmtCase(dis.case),
 115                    dis.operands_separator,
 116                    if (imm < 0) "-" else "",
 117                    @abs(imm),
 118                }) else if (dis.enable_aliases and decoded == .ands and Rd.alias == .zr) writer.print("{f}{s}{f}{s}#{s}0x{x}", .{
 119                    fmtCase(.tst, dis.case),
 120                    dis.mnemonic_operands_separator,
 121                    Rn.fmtCase(dis.case),
 122                    dis.operands_separator,
 123                    if (imm < 0) "-" else "",
 124                    @abs(imm),
 125                }) else writer.print("{f}{s}{f}{s}{f}{s}#0x{x}", .{
 126                    fmtCase(decoded, dis.case),
 127                    dis.mnemonic_operands_separator,
 128                    Rd.fmtCase(dis.case),
 129                    dis.operands_separator,
 130                    Rn.fmtCase(dis.case),
 131                    dis.operands_separator,
 132                    decoded_imm,
 133                });
 134            },
 135            .move_wide_immediate => |move_wide_immediate| {
 136                const decoded = move_wide_immediate.decode();
 137                if (decoded == .unallocated) break :unallocated;
 138                const group = move_wide_immediate.group;
 139                const sf = group.sf;
 140                const hw = group.hw;
 141                const imm16 = group.imm16;
 142                const Rd = group.Rd.decode(.{}).general(sf);
 143                const elide_shift = hw == .@"0";
 144                if (dis.enable_aliases and switch (decoded) {
 145                    .unallocated => unreachable,
 146                    .movz => elide_shift or group.imm16 != 0,
 147                    .movn => (elide_shift or group.imm16 != 0) and switch (sf) {
 148                        .word => group.imm16 != std.math.maxInt(u16),
 149                        .doubleword => true,
 150                    },
 151                    .movk => false,
 152                }) {
 153                    const decoded_imm = switch (sf) {
 154                        .word => @as(i32, @bitCast(@as(u32, group.imm16) << @intCast(hw.int()))),
 155                        .doubleword => @as(i64, @bitCast(@as(u64, group.imm16) << hw.int())),
 156                    };
 157                    const imm = switch (decoded) {
 158                        .unallocated => unreachable,
 159                        .movz => decoded_imm,
 160                        .movn => ~decoded_imm,
 161                        .movk => unreachable,
 162                    };
 163                    return writer.print("{f}{s}{f}{s}#{s}0x{x}", .{
 164                        fmtCase(.mov, dis.case),
 165                        dis.mnemonic_operands_separator,
 166                        Rd.fmtCase(dis.case),
 167                        dis.operands_separator,
 168                        if (imm < 0) "-" else "",
 169                        @abs(imm),
 170                    });
 171                }
 172                try writer.print("{f}{s}{f}{s}#0x{x}", .{
 173                    fmtCase(decoded, dis.case),
 174                    dis.mnemonic_operands_separator,
 175                    Rd.fmtCase(dis.case),
 176                    dis.operands_separator,
 177                    imm16,
 178                });
 179                return if (!elide_shift) writer.print("{s}{f} #{t}", .{
 180                    dis.operands_separator,
 181                    fmtCase(.lsl, dis.case),
 182                    hw,
 183                });
 184            },
 185            .bitfield => |bitfield| {
 186                const decoded = bitfield.decode();
 187                if (decoded == .unallocated) break :unallocated;
 188                const group = bitfield.group;
 189                const sf = group.sf;
 190                const Rd = group.Rd.decode(.{}).general(sf);
 191                const Rn = group.Rn.decode(.{}).general(sf);
 192                return if (!dis.enable_aliases) writer.print("{f}{s}{f}{s}{f}{s}#{d}{s}#{d}", .{
 193                    fmtCase(decoded, dis.case),
 194                    dis.mnemonic_operands_separator,
 195                    Rd.fmtCase(dis.case),
 196                    dis.operands_separator,
 197                    Rn.fmtCase(dis.case),
 198                    dis.operands_separator,
 199                    group.imm.immr,
 200                    dis.operands_separator,
 201                    group.imm.imms,
 202                }) else if (group.imm.imms >= group.imm.immr) writer.print("{f}{s}{f}{s}{f}{s}#{d}{s}#{d}", .{
 203                    fmtCase(@as(enum { sbfx, bfxil, ubfx }, switch (decoded) {
 204                        .unallocated => unreachable,
 205                        .sbfm => .sbfx,
 206                        .bfm => .bfxil,
 207                        .ubfm => .ubfx,
 208                    }), dis.case),
 209                    dis.mnemonic_operands_separator,
 210                    Rd.fmtCase(dis.case),
 211                    dis.operands_separator,
 212                    Rn.fmtCase(dis.case),
 213                    dis.operands_separator,
 214                    group.imm.immr,
 215                    dis.operands_separator,
 216                    switch (sf) {
 217                        .word => @as(u6, group.imm.imms - group.imm.immr) + 1,
 218                        .doubleword => @as(u7, group.imm.imms - group.imm.immr) + 1,
 219                    },
 220                }) else {
 221                    const prefer_bfc = switch (decoded) {
 222                        .unallocated => unreachable,
 223                        .sbfm, .ubfm => false,
 224                        .bfm => Rn.alias == .zr,
 225                    };
 226                    try writer.print("{f}{s}{f}", .{
 227                        fmtCase(@as(enum { sbfiz, bfc, bfi, ubfiz }, switch (decoded) {
 228                            .unallocated => unreachable,
 229                            .sbfm => .sbfiz,
 230                            .bfm => if (prefer_bfc) .bfc else .bfi,
 231                            .ubfm => .ubfiz,
 232                        }), dis.case),
 233                        dis.mnemonic_operands_separator,
 234                        Rd.fmtCase(dis.case),
 235                    });
 236                    if (!prefer_bfc) try writer.print("{s}{f}", .{
 237                        dis.operands_separator,
 238                        Rn.fmtCase(dis.case),
 239                    });
 240                    try writer.print("{s}#{d}{s}#{d}", .{
 241                        dis.operands_separator,
 242                        switch (sf) {
 243                            .word => -%@as(u5, @intCast(group.imm.immr)),
 244                            .doubleword => -%@as(u6, @intCast(group.imm.immr)),
 245                        },
 246                        dis.operands_separator,
 247                        switch (sf) {
 248                            .word => @as(u6, group.imm.imms) + 1,
 249                            .doubleword => @as(u7, group.imm.imms) + 1,
 250                        },
 251                    });
 252                };
 253            },
 254            .extract => |extract| {
 255                const decoded = extract.decode();
 256                if (decoded == .unallocated) break :unallocated;
 257                const group = extract.group;
 258                const sf = group.sf;
 259                return writer.print("{f}{s}{f}{s}{f}{s}{f}{s}#{d}", .{
 260                    fmtCase(decoded, dis.case),
 261                    dis.mnemonic_operands_separator,
 262                    group.Rd.decode(.{}).general(sf).fmtCase(dis.case),
 263                    dis.operands_separator,
 264                    group.Rn.decode(.{}).general(sf).fmtCase(dis.case),
 265                    dis.operands_separator,
 266                    group.Rm.decode(.{}).general(sf).fmtCase(dis.case),
 267                    dis.operands_separator,
 268                    group.imms,
 269                });
 270            },
 271        },
 272        .branch_exception_generating_system => |branch_exception_generating_system| switch (branch_exception_generating_system.decode()) {
 273            .unallocated => break :unallocated,
 274            .conditional_branch_immediate => |conditional_branch_immediate| {
 275                const decoded = conditional_branch_immediate.decode();
 276                if (decoded == .unallocated) break :unallocated;
 277                const group = conditional_branch_immediate.group;
 278                const imm = @as(i21, group.imm19);
 279                return writer.print("{f}.{f}{s}.{c}0x{x}", .{
 280                    fmtCase(decoded, dis.case),
 281                    fmtCase(group.cond, dis.case),
 282                    dis.mnemonic_operands_separator,
 283                    @as(u8, if (imm < 0) '-' else '+'),
 284                    @abs(imm) << 2,
 285                });
 286            },
 287            .exception_generating => |exception_generating| {
 288                const decoded = exception_generating.decode();
 289                switch (decoded) {
 290                    .unallocated => break :unallocated,
 291                    .svc, .hvc, .smc, .brk, .hlt, .tcancel => {},
 292                    .dcps1, .dcps2, .dcps3 => switch (exception_generating.group.imm16) {
 293                        0 => return writer.print("{f}", .{fmtCase(decoded, dis.case)}),
 294                        else => {},
 295                    },
 296                }
 297                return switch (exception_generating.group.imm16) {
 298                    0 => writer.print("{f}{s}#0", .{
 299                        fmtCase(decoded, dis.case),
 300                        dis.mnemonic_operands_separator,
 301                    }),
 302                    else => writer.print("{f}{s}#0x{x}", .{
 303                        fmtCase(decoded, dis.case),
 304                        dis.mnemonic_operands_separator,
 305                        exception_generating.group.imm16,
 306                    }),
 307                };
 308            },
 309            .system_register_argument => {},
 310            .hints => |hints| switch (hints.decode()) {
 311                .hint => |hint| return writer.print("{f}{s}#0x{x}", .{
 312                    fmtCase(.hint, dis.case),
 313                    dis.mnemonic_operands_separator,
 314                    @as(u7, hint.CRm) << 3 | @as(u7, hint.op2) << 0,
 315                }),
 316                else => |decoded| return writer.print("{f}", .{fmtCase(decoded, dis.case)}),
 317            },
 318            .barriers => {},
 319            .pstate => |pstate| {
 320                const decoded = pstate.decode();
 321                if (decoded == .unallocated) break :unallocated;
 322                return writer.print("{f}", .{fmtCase(decoded, dis.case)});
 323            },
 324            .system_result => {},
 325            .system => {},
 326            .system_register_move => {},
 327            .unconditional_branch_register => |unconditional_branch_register| {
 328                const decoded = unconditional_branch_register.decode();
 329                if (decoded == .unallocated) break :unallocated;
 330                const group = unconditional_branch_register.group;
 331                const Rn = group.Rn.decode(.{}).x();
 332                try writer.print("{f}", .{fmtCase(decoded, dis.case)});
 333                return if (decoded != .ret or Rn.alias != .r30) try writer.print("{s}{f}", .{
 334                    dis.mnemonic_operands_separator,
 335                    Rn.fmtCase(dis.case),
 336                });
 337            },
 338            .unconditional_branch_immediate => |unconditional_branch_immediate| {
 339                const group = unconditional_branch_immediate.group;
 340                const imm = @as(i28, group.imm26);
 341                return writer.print("{f}{s}.{c}0x{x}", .{
 342                    fmtCase(group.op, dis.case),
 343                    dis.mnemonic_operands_separator,
 344                    @as(u8, if (imm < 0) '-' else '+'),
 345                    @abs(imm) << 2,
 346                });
 347            },
 348            .compare_branch_immediate => |compare_branch_immediate| {
 349                const group = compare_branch_immediate.group;
 350                const imm = @as(i21, group.imm19);
 351                return writer.print("{f}{s}{f}{s}.{c}0x{x}", .{
 352                    fmtCase(group.op, dis.case),
 353                    dis.mnemonic_operands_separator,
 354                    group.Rt.decode(.{}).general(group.sf).fmtCase(dis.case),
 355                    dis.operands_separator,
 356                    @as(u8, if (imm < 0) '-' else '+'),
 357                    @abs(imm) << 2,
 358                });
 359            },
 360            .test_branch_immediate => |test_branch_immediate| {
 361                const group = test_branch_immediate.group;
 362                const imm = @as(i16, group.imm14);
 363                return writer.print("{f}{s}{f}{s}#0x{d}{s}.{c}0x{x}", .{
 364                    fmtCase(group.op, dis.case),
 365                    dis.mnemonic_operands_separator,
 366                    group.Rt.decode(.{}).general(@enumFromInt(group.b5)).fmtCase(dis.case),
 367                    dis.operands_separator,
 368                    @as(u6, group.b5) << 5 |
 369                        @as(u6, group.b40) << 0,
 370                    dis.operands_separator,
 371                    @as(u8, if (imm < 0) '-' else '+'),
 372                    @abs(imm) << 2,
 373                });
 374            },
 375        },
 376        .load_store => |load_store| switch (load_store.decode()) {
 377            .unallocated => break :unallocated,
 378            .register_literal => {},
 379            .memory => {},
 380            .no_allocate_pair_offset => {},
 381            .register_pair_post_indexed => |register_pair_post_indexed| switch (register_pair_post_indexed.decode()) {
 382                .integer => |integer| {
 383                    const decoded = integer.decode();
 384                    if (decoded == .unallocated) break :unallocated;
 385                    const group = integer.group;
 386                    const sf: aarch64.encoding.Register.GeneralSize = @enumFromInt(group.opc >> 1);
 387                    return writer.print("{f}{s}{f}{s}{f}{s}[{f}]{s}#{s}0x{x}", .{
 388                        fmtCase(decoded, dis.case),
 389                        dis.mnemonic_operands_separator,
 390                        group.Rt.decode(.{}).general(sf).fmtCase(dis.case),
 391                        dis.operands_separator,
 392                        group.Rt2.decode(.{}).general(sf).fmtCase(dis.case),
 393                        dis.operands_separator,
 394                        group.Rn.decode(.{ .sp = true }).x().fmtCase(dis.case),
 395                        dis.operands_separator,
 396                        if (group.imm7 < 0) "-" else "",
 397                        @as(u10, @abs(group.imm7)) << (@as(u2, 2) + @intFromEnum(sf)),
 398                    });
 399                },
 400                .vector => |vector| {
 401                    const decoded = vector.decode();
 402                    if (decoded == .unallocated) break :unallocated;
 403                    const group = vector.group;
 404                    const vs = group.opc.decode();
 405                    return writer.print("{f}{s}{f}{s}{f}{s}[{f}]{s}#{s}0x{x}", .{
 406                        fmtCase(decoded, dis.case),
 407                        dis.mnemonic_operands_separator,
 408                        group.Rt.decode(.{ .V = true }).scalar(vs).fmtCase(dis.case),
 409                        dis.operands_separator,
 410                        group.Rt2.decode(.{ .V = true }).scalar(vs).fmtCase(dis.case),
 411                        dis.operands_separator,
 412                        group.Rn.decode(.{ .sp = true }).x().fmtCase(dis.case),
 413                        dis.operands_separator,
 414                        if (group.imm7 < 0) "-" else "",
 415                        @as(u11, @abs(group.imm7)) << (@as(u3, 2) + @intFromEnum(vs)),
 416                    });
 417                },
 418            },
 419            .register_pair_offset => |register_pair_offset| switch (register_pair_offset.decode()) {
 420                .integer => |integer| {
 421                    const decoded = integer.decode();
 422                    if (decoded == .unallocated) break :unallocated;
 423                    const group = integer.group;
 424                    const sf: aarch64.encoding.Register.GeneralSize = @enumFromInt(group.opc >> 1);
 425                    try writer.print("{f}{s}{f}{s}{f}{s}[{f}", .{
 426                        fmtCase(decoded, dis.case),
 427                        dis.mnemonic_operands_separator,
 428                        group.Rt.decode(.{}).general(sf).fmtCase(dis.case),
 429                        dis.operands_separator,
 430                        group.Rt2.decode(.{}).general(sf).fmtCase(dis.case),
 431                        dis.operands_separator,
 432                        group.Rn.decode(.{ .sp = true }).x().fmtCase(dis.case),
 433                    });
 434                    if (group.imm7 != 0) try writer.print("{s}#{s}0x{x}", .{
 435                        dis.operands_separator,
 436                        if (group.imm7 < 0) "-" else "",
 437                        @as(u10, @abs(group.imm7)) << (@as(u2, 2) + @intFromEnum(sf)),
 438                    });
 439                    return writer.writeByte(']');
 440                },
 441                .vector => |vector| {
 442                    const decoded = vector.decode();
 443                    if (decoded == .unallocated) break :unallocated;
 444                    const group = vector.group;
 445                    const vs = group.opc.decode();
 446                    try writer.print("{f}{s}{f}{s}{f}{s}[{f}", .{
 447                        fmtCase(decoded, dis.case),
 448                        dis.mnemonic_operands_separator,
 449                        group.Rt.decode(.{ .V = true }).scalar(vs).fmtCase(dis.case),
 450                        dis.operands_separator,
 451                        group.Rt2.decode(.{ .V = true }).scalar(vs).fmtCase(dis.case),
 452                        dis.operands_separator,
 453                        group.Rn.decode(.{ .sp = true }).x().fmtCase(dis.case),
 454                    });
 455                    if (group.imm7 != 0) try writer.print("{s}#{s}0x{x}", .{
 456                        dis.operands_separator,
 457                        if (group.imm7 < 0) "-" else "",
 458                        @as(u11, @abs(group.imm7)) << (@as(u3, 2) + @intFromEnum(vs)),
 459                    });
 460                    return writer.writeByte(']');
 461                },
 462            },
 463            .register_pair_pre_indexed => |register_pair_pre_indexed| switch (register_pair_pre_indexed.decode()) {
 464                .integer => |integer| {
 465                    const decoded = integer.decode();
 466                    if (decoded == .unallocated) break :unallocated;
 467                    const group = integer.group;
 468                    const sf: aarch64.encoding.Register.GeneralSize = @enumFromInt(group.opc >> 1);
 469                    return writer.print("{f}{s}{f}{s}{f}{s}[{f}{s}#{s}0x{x}]!", .{
 470                        fmtCase(decoded, dis.case),
 471                        dis.mnemonic_operands_separator,
 472                        group.Rt.decode(.{}).general(sf).fmtCase(dis.case),
 473                        dis.operands_separator,
 474                        group.Rt2.decode(.{}).general(sf).fmtCase(dis.case),
 475                        dis.operands_separator,
 476                        group.Rn.decode(.{ .sp = true }).x().fmtCase(dis.case),
 477                        dis.operands_separator,
 478                        if (group.imm7 < 0) "-" else "",
 479                        @as(u10, @abs(group.imm7)) << (@as(u2, 2) + @intFromEnum(sf)),
 480                    });
 481                },
 482                .vector => |vector| {
 483                    const decoded = vector.decode();
 484                    if (decoded == .unallocated) break :unallocated;
 485                    const group = vector.group;
 486                    const vs = group.opc.decode();
 487                    return writer.print("{f}{s}{f}{s}{f}{s}[{f}{s}#{s}0x{x}]!", .{
 488                        fmtCase(decoded, dis.case),
 489                        dis.mnemonic_operands_separator,
 490                        group.Rt.decode(.{ .V = true }).scalar(vs).fmtCase(dis.case),
 491                        dis.operands_separator,
 492                        group.Rt2.decode(.{ .V = true }).scalar(vs).fmtCase(dis.case),
 493                        dis.operands_separator,
 494                        group.Rn.decode(.{ .sp = true }).x().fmtCase(dis.case),
 495                        dis.operands_separator,
 496                        if (group.imm7 < 0) "-" else "",
 497                        @as(u11, @abs(group.imm7)) << (@as(u3, 2) + @intFromEnum(vs)),
 498                    });
 499                },
 500            },
 501            .register_unscaled_immediate => {},
 502            .register_immediate_post_indexed => |register_immediate_post_indexed| switch (register_immediate_post_indexed.decode()) {
 503                .integer => |integer| {
 504                    const decoded = integer.decode();
 505                    const sf: aarch64.encoding.Register.GeneralSize = switch (decoded) {
 506                        .unallocated => break :unallocated,
 507                        .strb, .ldrb, .strh, .ldrh => .word,
 508                        inline .ldrsb, .ldrsh => |encoded| switch (encoded.opc0) {
 509                            0b0 => .doubleword,
 510                            0b1 => .word,
 511                        },
 512                        .ldrsw => .doubleword,
 513                        inline .str, .ldr => |encoded| encoded.sf,
 514                    };
 515                    const group = integer.group;
 516                    return writer.print("{f}{s}{f}{s}[{f}]{s}#{s}0x{x}", .{
 517                        fmtCase(decoded, dis.case),
 518                        dis.mnemonic_operands_separator,
 519                        group.Rt.decode(.{}).general(sf).fmtCase(dis.case),
 520                        dis.operands_separator,
 521                        group.Rn.decode(.{ .sp = true }).x().fmtCase(dis.case),
 522                        dis.operands_separator,
 523                        if (group.imm9 < 0) "-" else "",
 524                        @abs(group.imm9),
 525                    });
 526                },
 527                .vector => {},
 528            },
 529            .register_unprivileged => {},
 530            .register_immediate_pre_indexed => |register_immediate_pre_indexed| switch (register_immediate_pre_indexed.decode()) {
 531                .integer => |integer| {
 532                    const decoded = integer.decode();
 533                    const sf: aarch64.encoding.Register.GeneralSize = switch (decoded) {
 534                        .unallocated => break :unallocated,
 535                        inline .ldrsb, .ldrsh => |encoded| switch (encoded.opc0) {
 536                            0b0 => .doubleword,
 537                            0b1 => .word,
 538                        },
 539                        .strb, .ldrb, .strh, .ldrh => .word,
 540                        .ldrsw => .doubleword,
 541                        inline .str, .ldr => |encoded| encoded.sf,
 542                    };
 543                    const group = integer.group;
 544                    return writer.print("{f}{s}{f}{s}[{f}{s}#{s}0x{x}]!", .{
 545                        fmtCase(decoded, dis.case),
 546                        dis.mnemonic_operands_separator,
 547                        group.Rt.decode(.{}).general(sf).fmtCase(dis.case),
 548                        dis.operands_separator,
 549                        group.Rn.decode(.{ .sp = true }).x().fmtCase(dis.case),
 550                        dis.operands_separator,
 551                        if (group.imm9 < 0) "-" else "",
 552                        @abs(group.imm9),
 553                    });
 554                },
 555                .vector => |vector| {
 556                    const decoded = vector.decode();
 557                    if (decoded == .unallocated) break :unallocated;
 558                    const group = vector.group;
 559                    return writer.print("{f}{s}{f}{s}[{f}{s}#{s}0x{x}]!", .{
 560                        fmtCase(decoded, dis.case),
 561                        dis.mnemonic_operands_separator,
 562                        group.Rt.decode(.{ .V = true }).scalar(group.opc1.decode(group.size)).fmtCase(dis.case),
 563                        dis.operands_separator,
 564                        group.Rn.decode(.{ .sp = true }).x().fmtCase(dis.case),
 565                        dis.operands_separator,
 566                        if (group.imm9 < 0) "-" else "",
 567                        @abs(group.imm9),
 568                    });
 569                },
 570            },
 571            .register_register_offset => |register_register_offset| switch (register_register_offset.decode()) {
 572                .integer => |integer| {
 573                    const decoded = integer.decode();
 574                    const sf: aarch64.encoding.Register.GeneralSize = switch (decoded) {
 575                        .unallocated, .prfm => break :unallocated,
 576                        .strb, .ldrb, .strh, .ldrh => .word,
 577                        inline .ldrsb, .ldrsh => |encoded| switch (encoded.opc0) {
 578                            0b0 => .doubleword,
 579                            0b1 => .word,
 580                        },
 581                        .ldrsw => .doubleword,
 582                        inline .str, .ldr => |encoded| encoded.sf,
 583                    };
 584                    const group = integer.group;
 585                    try writer.print("{f}{s}{f}{s}[{f}{s}{f}", .{
 586                        fmtCase(decoded, dis.case),
 587                        dis.mnemonic_operands_separator,
 588                        group.Rt.decode(.{}).general(sf).fmtCase(dis.case),
 589                        dis.operands_separator,
 590                        group.Rn.decode(.{ .sp = true }).x().fmtCase(dis.case),
 591                        dis.operands_separator,
 592                        group.Rm.decode(.{}).general(group.option.sf()).fmtCase(dis.case),
 593                    });
 594                    if (group.option != .lsl or group.S) {
 595                        try writer.print("{s}{f}", .{
 596                            dis.operands_separator,
 597                            fmtCase(group.option, dis.case),
 598                        });
 599                        if (group.S) try writer.print(" #{d}", .{
 600                            @intFromEnum(group.size),
 601                        });
 602                    }
 603                    return writer.writeByte(']');
 604                },
 605                .vector => {},
 606            },
 607            .register_unsigned_immediate => |register_unsigned_immediate| switch (register_unsigned_immediate.decode()) {
 608                .integer => |integer| {
 609                    const decoded = integer.decode();
 610                    const sf: aarch64.encoding.Register.GeneralSize = switch (decoded) {
 611                        .unallocated, .prfm => break :unallocated,
 612                        .strb, .ldrb, .strh, .ldrh => .word,
 613                        inline .ldrsb, .ldrsh => |encoded| switch (encoded.opc0) {
 614                            0b0 => .doubleword,
 615                            0b1 => .word,
 616                        },
 617                        .ldrsw => .doubleword,
 618                        inline .str, .ldr => |encoded| encoded.sf,
 619                    };
 620                    const group = integer.group;
 621                    try writer.print("{f}{s}{f}{s}[{f}", .{
 622                        fmtCase(decoded, dis.case),
 623                        dis.mnemonic_operands_separator,
 624                        group.Rt.decode(.{}).general(sf).fmtCase(dis.case),
 625                        dis.operands_separator,
 626                        group.Rn.decode(.{ .sp = true }).x().fmtCase(dis.case),
 627                    });
 628                    if (group.imm12 > 0) try writer.print("{s}#0x{x}", .{
 629                        dis.operands_separator,
 630                        @as(u15, group.imm12) << @intFromEnum(group.size),
 631                    });
 632                    return writer.writeByte(']');
 633                },
 634                .vector => {},
 635            },
 636        },
 637        .data_processing_register => |data_processing_register| switch (data_processing_register.decode()) {
 638            .unallocated => break :unallocated,
 639            .data_processing_two_source => |data_processing_two_source| {
 640                const decoded = data_processing_two_source.decode();
 641                if (decoded == .unallocated) break :unallocated;
 642                const group = data_processing_two_source.group;
 643                const sf = group.sf;
 644                return writer.print("{f}{s}{f}{s}{f}{s}{f}", .{
 645                    if (dis.enable_aliases) fmtCase(@as(enum { udiv, sdiv, lsl, lsr, asr, ror }, switch (decoded) {
 646                        .unallocated => unreachable,
 647                        .udiv => .udiv,
 648                        .sdiv => .sdiv,
 649                        .lslv => .lsl,
 650                        .lsrv => .lsr,
 651                        .asrv => .asr,
 652                        .rorv => .ror,
 653                    }), dis.case) else fmtCase(decoded, dis.case),
 654                    dis.mnemonic_operands_separator,
 655                    group.Rd.decode(.{}).general(sf).fmtCase(dis.case),
 656                    dis.operands_separator,
 657                    group.Rn.decode(.{}).general(sf).fmtCase(dis.case),
 658                    dis.operands_separator,
 659                    group.Rm.decode(.{}).general(sf).fmtCase(dis.case),
 660                });
 661            },
 662            .data_processing_one_source => |data_processing_one_source| {
 663                const decoded = data_processing_one_source.decode();
 664                if (decoded == .unallocated) break :unallocated;
 665                const group = data_processing_one_source.group;
 666                const sf = group.sf;
 667                return writer.print("{f}{s}{f}{s}{f}", .{
 668                    fmtCase(decoded, dis.case),
 669                    dis.mnemonic_operands_separator,
 670                    group.Rd.decode(.{}).general(sf).fmtCase(dis.case),
 671                    dis.operands_separator,
 672                    group.Rn.decode(.{}).general(sf).fmtCase(dis.case),
 673                });
 674            },
 675            .logical_shifted_register => |logical_shifted_register| {
 676                const decoded = logical_shifted_register.decode();
 677                if (decoded == .unallocated) break :unallocated;
 678                const group = logical_shifted_register.group;
 679                const sf = group.sf;
 680                const shift = group.shift;
 681                const Rm = group.Rm.decode(.{}).general(sf);
 682                const amount = group.imm6;
 683                const Rn = group.Rn.decode(.{}).general(sf);
 684                const Rd = group.Rd.decode(.{}).general(sf);
 685                const elide_shift = shift == .lsl and amount == 0;
 686                if (dis.enable_aliases and switch (decoded) {
 687                    else => false,
 688                    .orr => elide_shift,
 689                    .orn => true,
 690                } and Rn.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{
 691                    fmtCase(@as(enum { mov, mvn }, switch (decoded) {
 692                        else => unreachable,
 693                        .orr => .mov,
 694                        .orn => .mvn,
 695                    }), dis.case),
 696                    dis.mnemonic_operands_separator,
 697                    Rd.fmtCase(dis.case),
 698                    dis.operands_separator,
 699                    Rm.fmtCase(dis.case),
 700                }) else if (dis.enable_aliases and decoded == .ands and Rd.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{
 701                    fmtCase(.tst, dis.case),
 702                    dis.mnemonic_operands_separator,
 703                    Rn.fmtCase(dis.case),
 704                    dis.operands_separator,
 705                    Rm.fmtCase(dis.case),
 706                }) else try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{
 707                    fmtCase(decoded, dis.case),
 708                    dis.mnemonic_operands_separator,
 709                    Rd.fmtCase(dis.case),
 710                    dis.operands_separator,
 711                    Rn.fmtCase(dis.case),
 712                    dis.operands_separator,
 713                    Rm.fmtCase(dis.case),
 714                });
 715                return if (!elide_shift) writer.print("{s}{f} #{d}", .{
 716                    dis.operands_separator,
 717                    fmtCase(shift, dis.case),
 718                    amount,
 719                });
 720            },
 721            .add_subtract_shifted_register => |add_subtract_shifted_register| {
 722                const decoded = add_subtract_shifted_register.decode();
 723                if (decoded == .unallocated) break :unallocated;
 724                const group = add_subtract_shifted_register.group;
 725                const sf = group.sf;
 726                const shift = group.shift;
 727                const Rm = group.Rm.decode(.{}).general(sf);
 728                const imm6 = group.imm6;
 729                const Rn = group.Rn.decode(.{}).general(sf);
 730                const Rd = group.Rd.decode(.{}).general(sf);
 731                if (dis.enable_aliases and group.S and Rd.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{
 732                    fmtCase(@as(enum { cmn, cmp }, switch (group.op) {
 733                        .add => .cmn,
 734                        .sub => .cmp,
 735                    }), dis.case),
 736                    dis.mnemonic_operands_separator,
 737                    Rn.fmtCase(dis.case),
 738                    dis.operands_separator,
 739                    Rm.fmtCase(dis.case),
 740                }) else if (dis.enable_aliases and group.op == .sub and Rn.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{
 741                    fmtCase(@as(enum { neg, negs }, switch (group.S) {
 742                        false => .neg,
 743                        true => .negs,
 744                    }), dis.case),
 745                    dis.mnemonic_operands_separator,
 746                    Rd.fmtCase(dis.case),
 747                    dis.operands_separator,
 748                    Rm.fmtCase(dis.case),
 749                }) else try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{
 750                    fmtCase(decoded, dis.case),
 751                    dis.mnemonic_operands_separator,
 752                    Rd.fmtCase(dis.case),
 753                    dis.operands_separator,
 754                    Rn.fmtCase(dis.case),
 755                    dis.operands_separator,
 756                    Rm.fmtCase(dis.case),
 757                });
 758                return if (shift != .lsl or imm6 != 0) return writer.print("{s}{f} #{d}", .{
 759                    dis.operands_separator,
 760                    fmtCase(shift, dis.case),
 761                    imm6,
 762                });
 763            },
 764            .add_subtract_extended_register => |add_subtract_extended_register| {
 765                const decoded = add_subtract_extended_register.decode();
 766                if (decoded == .unallocated) break :unallocated;
 767                const group = add_subtract_extended_register.group;
 768                const sf = group.sf;
 769                const Rm = group.Rm.decode(.{}).general(switch (sf) {
 770                    .word => .word,
 771                    .doubleword => group.option.sf(),
 772                });
 773                const Rn = group.Rn.decode(.{ .sp = true }).general(sf);
 774                const Rd = group.Rd.decode(.{ .sp = !group.S }).general(sf);
 775                const prefer_lsl = (Rd.alias == .sp or Rn.alias == .sp) and group.option == @as(
 776                    aarch64.encoding.Instruction.DataProcessingRegister.AddSubtractExtendedRegister.Option,
 777                    switch (sf) {
 778                        .word => .uxtw,
 779                        .doubleword => .uxtx,
 780                    },
 781                );
 782                if (dis.enable_aliases and group.S and Rd.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{
 783                    fmtCase(@as(enum { cmn, cmp }, switch (group.op) {
 784                        .add => .cmn,
 785                        .sub => .cmp,
 786                    }), dis.case),
 787                    dis.mnemonic_operands_separator,
 788                    Rn.fmtCase(dis.case),
 789                    dis.operands_separator,
 790                    Rm.fmtCase(dis.case),
 791                }) else try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{
 792                    fmtCase(decoded, dis.case),
 793                    dis.mnemonic_operands_separator,
 794                    Rd.fmtCase(dis.case),
 795                    dis.operands_separator,
 796                    Rn.fmtCase(dis.case),
 797                    dis.operands_separator,
 798                    Rm.fmtCase(dis.case),
 799                });
 800                return if (!prefer_lsl or group.imm3 != 0) {
 801                    try writer.print("{s}{f}", .{
 802                        dis.operands_separator,
 803                        if (prefer_lsl) fmtCase(.lsl, dis.case) else fmtCase(group.option, dis.case),
 804                    });
 805                    if (group.imm3 != 0) try writer.print(" #{d}", .{group.imm3});
 806                };
 807            },
 808            .add_subtract_with_carry => |add_subtract_with_carry| {
 809                const decoded = add_subtract_with_carry.decode();
 810                const group = add_subtract_with_carry.group;
 811                const sf = group.sf;
 812                const Rm = group.Rm.decode(.{}).general(sf);
 813                const Rn = group.Rn.decode(.{}).general(sf);
 814                const Rd = group.Rd.decode(.{}).general(sf);
 815                return if (dis.enable_aliases and group.op == .sbc and Rn.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{
 816                    fmtCase(@as(enum { ngc, ngcs }, switch (group.S) {
 817                        false => .ngc,
 818                        true => .ngcs,
 819                    }), dis.case),
 820                    dis.mnemonic_operands_separator,
 821                    Rd.fmtCase(dis.case),
 822                    dis.operands_separator,
 823                    Rm.fmtCase(dis.case),
 824                }) else try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{
 825                    fmtCase(decoded, dis.case),
 826                    dis.mnemonic_operands_separator,
 827                    Rd.fmtCase(dis.case),
 828                    dis.operands_separator,
 829                    Rn.fmtCase(dis.case),
 830                    dis.operands_separator,
 831                    Rm.fmtCase(dis.case),
 832                });
 833            },
 834            .rotate_right_into_flags => {},
 835            .evaluate_into_flags => {},
 836            .conditional_compare_register => |conditional_compare_register| {
 837                const group = conditional_compare_register.group;
 838                const sf = group.sf;
 839                return writer.print("{f}{s}{f}{s}{f}{s}#0x{x}{s}{f}", .{
 840                    fmtCase(group.op, dis.case),
 841                    dis.mnemonic_operands_separator,
 842                    group.Rn.decode(.{}).general(sf).fmtCase(dis.case),
 843                    dis.operands_separator,
 844                    group.Rm.decode(.{}).general(sf).fmtCase(dis.case),
 845                    dis.operands_separator,
 846                    @as(u4, @bitCast(group.nzcv)),
 847                    dis.operands_separator,
 848                    fmtCase(group.cond, dis.case),
 849                });
 850            },
 851            .conditional_compare_immediate => |conditional_compare_immediate| {
 852                const group = conditional_compare_immediate.group;
 853                const sf = group.sf;
 854                return writer.print("{f}{s}{f}{s}#0x{x}{s}#0x{x}{s}{f}", .{
 855                    fmtCase(group.op, dis.case),
 856                    dis.mnemonic_operands_separator,
 857                    group.Rn.decode(.{}).general(sf).fmtCase(dis.case),
 858                    dis.operands_separator,
 859                    group.imm5,
 860                    dis.operands_separator,
 861                    @as(u4, @bitCast(group.nzcv)),
 862                    dis.operands_separator,
 863                    fmtCase(group.cond, dis.case),
 864                });
 865            },
 866            .conditional_select => |conditional_select| {
 867                const decoded = conditional_select.decode();
 868                if (decoded == .unallocated) break :unallocated;
 869                const group = conditional_select.group;
 870                const sf = group.sf;
 871                const Rm = group.Rm.decode(.{}).general(sf);
 872                const cond = group.cond;
 873                const Rn = group.Rn.decode(.{}).general(sf);
 874                const Rd = group.Rd.decode(.{}).general(sf);
 875                return if (dis.enable_aliases and group.op != group.op2 and Rm.alias == .zr and cond != .al and cond != .nv and Rn.alias == Rm.alias) writer.print("{f}{s}{f}{s}{f}", .{
 876                    fmtCase(@as(enum { cset, csetm }, switch (decoded) {
 877                        else => unreachable,
 878                        .csinc => .cset,
 879                        .csinv => .csetm,
 880                    }), dis.case),
 881                    dis.mnemonic_operands_separator,
 882                    Rd.fmtCase(dis.case),
 883                    dis.operands_separator,
 884                    fmtCase(cond.invert(), dis.case),
 885                }) else if (dis.enable_aliases and decoded != .csel and cond != .al and cond != .nv and Rn.alias == Rm.alias) writer.print("{f}{s}{f}{s}{f}{s}{f}", .{
 886                    fmtCase(@as(enum { cinc, cinv, cneg }, switch (decoded) {
 887                        else => unreachable,
 888                        .csinc => .cinc,
 889                        .csinv => .cinv,
 890                        .csneg => .cneg,
 891                    }), dis.case),
 892                    dis.mnemonic_operands_separator,
 893                    Rd.fmtCase(dis.case),
 894                    dis.operands_separator,
 895                    Rn.fmtCase(dis.case),
 896                    dis.operands_separator,
 897                    fmtCase(cond.invert(), dis.case),
 898                }) else writer.print("{f}{s}{f}{s}{f}{s}{f}{s}{f}", .{
 899                    fmtCase(decoded, dis.case),
 900                    dis.mnemonic_operands_separator,
 901                    Rd.fmtCase(dis.case),
 902                    dis.operands_separator,
 903                    Rn.fmtCase(dis.case),
 904                    dis.operands_separator,
 905                    Rm.fmtCase(dis.case),
 906                    dis.operands_separator,
 907                    fmtCase(cond, dis.case),
 908                });
 909            },
 910            .data_processing_three_source => |data_processing_three_source| {
 911                const decoded = data_processing_three_source.decode();
 912                const group = data_processing_three_source.group;
 913                const sf = group.sf;
 914                const operand_sf = switch (decoded) {
 915                    .unallocated => break :unallocated,
 916                    .madd, .msub, .smulh, .umulh => sf,
 917                    .smaddl, .smsubl, .umaddl, .umsubl => .word,
 918                };
 919                const Ra = group.Ra.decode(.{}).general(sf);
 920                const elide_addend = dis.enable_aliases and Ra.alias == .zr;
 921                try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{
 922                    if (elide_addend) fmtCase(@as(enum {
 923                        mul,
 924                        mneg,
 925                        smull,
 926                        smnegl,
 927                        smulh,
 928                        umull,
 929                        umnegl,
 930                        umulh,
 931                    }, switch (decoded) {
 932                        .unallocated => unreachable,
 933                        .madd => .mul,
 934                        .msub => .mneg,
 935                        .smaddl => .smull,
 936                        .smsubl => .smnegl,
 937                        .smulh => .smulh,
 938                        .umaddl => .umull,
 939                        .umsubl => .umnegl,
 940                        .umulh => .umulh,
 941                    }), dis.case) else fmtCase(decoded, dis.case),
 942                    dis.mnemonic_operands_separator,
 943                    group.Rd.decode(.{}).general(sf).fmtCase(dis.case),
 944                    dis.operands_separator,
 945                    group.Rn.decode(.{}).general(operand_sf).fmtCase(dis.case),
 946                    dis.operands_separator,
 947                    group.Rm.decode(.{}).general(operand_sf).fmtCase(dis.case),
 948                });
 949                return if (!elide_addend) switch (decoded) {
 950                    .unallocated => unreachable,
 951                    .madd, .msub, .smaddl, .smsubl, .umaddl, .umsubl => writer.print("{s}{f}", .{
 952                        dis.operands_separator,
 953                        Ra.fmtCase(dis.case),
 954                    }),
 955                    .smulh, .umulh => {},
 956                };
 957            },
 958        },
 959        .data_processing_vector => |data_processing_vector| switch (data_processing_vector.decode()) {
 960            .unallocated => break :unallocated,
 961            .simd_scalar_copy => |simd_scalar_copy| {
 962                const decoded = simd_scalar_copy.decode();
 963                if (decoded == .unallocated) break :unallocated;
 964                const group = simd_scalar_copy.group;
 965                const elem_size = @ctz(group.imm5);
 966                return writer.print("{f}{s}{f}{s}{f}", .{
 967                    if (dis.enable_aliases and decoded == .dup)
 968                        fmtCase(.mov, dis.case)
 969                    else
 970                        fmtCase(decoded, dis.case),
 971                    dis.mnemonic_operands_separator,
 972                    group.Rd.decode(.{ .V = true }).scalar(@enumFromInt(elem_size)).fmtCase(dis.case),
 973                    dis.operands_separator,
 974                    group.Rn.decode(.{ .V = true }).element(
 975                        @enumFromInt(elem_size),
 976                        @intCast(group.imm5 >> (elem_size + 1)),
 977                    ).fmtCase(dis.case),
 978                });
 979            },
 980            .simd_scalar_two_register_miscellaneous_fp16 => |simd_scalar_two_register_miscellaneous_fp16| {
 981                const decoded = simd_scalar_two_register_miscellaneous_fp16.decode();
 982                if (decoded == .unallocated) break :unallocated;
 983                const group = simd_scalar_two_register_miscellaneous_fp16.group;
 984                try writer.print("{f}{s}{f}{s}{f}", .{
 985                    fmtCase(decoded, dis.case),
 986                    dis.mnemonic_operands_separator,
 987                    group.Rd.decode(.{ .V = true }).h().fmtCase(dis.case),
 988                    dis.operands_separator,
 989                    group.Rn.decode(.{ .V = true }).h().fmtCase(dis.case),
 990                });
 991                return switch (decoded) {
 992                    .unallocated => unreachable,
 993                    else => {},
 994                    .fcmgt,
 995                    .fcmeq,
 996                    .fcmlt,
 997                    .fcmge,
 998                    .fcmle,
 999                    => writer.print("{s}#0.0", .{dis.operands_separator}),
1000                };
1001            },
1002            .simd_scalar_two_register_miscellaneous => |simd_scalar_two_register_miscellaneous| {
1003                const decoded = simd_scalar_two_register_miscellaneous.decode();
1004                const group = simd_scalar_two_register_miscellaneous.group;
1005                const elem_size = switch (decoded) {
1006                    .unallocated => break :unallocated,
1007                    inline .fcvtns,
1008                    .fcvtms,
1009                    .fcvtas,
1010                    .scvtf,
1011                    .fcvtps,
1012                    .fcvtzs,
1013                    .fcvtxn,
1014                    .fcvtnu,
1015                    .fcvtmu,
1016                    .fcvtau,
1017                    .ucvtf,
1018                    .fcvtpu,
1019                    .fcvtzu,
1020                    => |f| f.sz.toScalarSize(),
1021                    else => group.size.toScalarSize(),
1022                };
1023                try writer.print("{f}{s}{f}{s}{f}", .{
1024                    fmtCase(decoded, dis.case),
1025                    dis.mnemonic_operands_separator,
1026                    group.Rd.decode(.{ .V = true }).scalar(elem_size).fmtCase(dis.case),
1027                    dis.operands_separator,
1028                    group.Rn.decode(.{ .V = true }).scalar(switch (decoded) {
1029                        .unallocated => unreachable,
1030                        else => elem_size,
1031                        .sqxtn => elem_size.w(),
1032                    }).fmtCase(dis.case),
1033                });
1034                return switch (decoded) {
1035                    .unallocated => unreachable,
1036                    else => {},
1037                    .cmgt,
1038                    .cmeq,
1039                    .cmlt,
1040                    .cmge,
1041                    .cmle,
1042                    => writer.print("{s}#0", .{dis.operands_separator}),
1043                    .fcmgt,
1044                    .fcmeq,
1045                    .fcmlt,
1046                    .fcmge,
1047                    .fcmle,
1048                    => writer.print("{s}#0.0", .{dis.operands_separator}),
1049                };
1050            },
1051            .simd_scalar_pairwise => {},
1052            .simd_copy => |simd_copy| {
1053                const decoded = simd_copy.decode();
1054                if (decoded == .unallocated) break :unallocated;
1055                const group = simd_copy.group;
1056                const elem_size = @ctz(group.imm5);
1057                return writer.print("{f}{s}{f}{s}{f}", .{
1058                    if (dis.enable_aliases and switch (decoded) {
1059                        .unallocated => unreachable,
1060                        .dup, .smov => false,
1061                        .umov => elem_size >= 2,
1062                        .ins => true,
1063                    }) fmtCase(.mov, dis.case) else fmtCase(decoded, dis.case),
1064                    dis.mnemonic_operands_separator,
1065                    switch (decoded) {
1066                        .unallocated => unreachable,
1067                        .dup => |dup| group.Rd.decode(.{ .V = true }).vector(.wrap(.{
1068                            .size = dup.Q,
1069                            .elem_size = @enumFromInt(elem_size),
1070                        })),
1071                        inline .smov, .umov => |mov| group.Rd.decode(.{}).general(mov.Q),
1072                        .ins => group.Rd.decode(.{ .V = true }).element(
1073                            @enumFromInt(elem_size),
1074                            @intCast(group.imm5 >> (elem_size + 1)),
1075                        ),
1076                    }.fmtCase(dis.case),
1077                    dis.operands_separator,
1078                    switch (decoded) {
1079                        .unallocated => unreachable,
1080                        .dup => |dup| switch (dup.imm4) {
1081                            .element => group.Rn.decode(.{ .V = true }).element(
1082                                @enumFromInt(elem_size),
1083                                @intCast(group.imm5 >> (elem_size + 1)),
1084                            ),
1085                            .general => group.Rn.decode(.{}).general(switch (elem_size) {
1086                                0...2 => .word,
1087                                3 => .doubleword,
1088                                else => unreachable,
1089                            }),
1090                            _ => unreachable,
1091                        },
1092                        .smov, .umov => group.Rn.decode(.{ .V = true }).element(
1093                            @enumFromInt(elem_size),
1094                            @intCast(group.imm5 >> (elem_size + 1)),
1095                        ),
1096                        .ins => |ins| switch (ins.op) {
1097                            .element => group.Rn.decode(.{ .V = true }).element(
1098                                @enumFromInt(elem_size),
1099                                @intCast(group.imm4 >> @intCast(elem_size)),
1100                            ),
1101                            .general => group.Rn.decode(.{}).general(switch (elem_size) {
1102                                0...2 => .word,
1103                                3 => .doubleword,
1104                                else => unreachable,
1105                            }),
1106                        },
1107                    }.fmtCase(dis.case),
1108                });
1109            },
1110            .simd_two_register_miscellaneous_fp16 => |simd_two_register_miscellaneous_fp16| {
1111                const decoded = simd_two_register_miscellaneous_fp16.decode();
1112                if (decoded == .unallocated) break :unallocated;
1113                const group = simd_two_register_miscellaneous_fp16.group;
1114                const arrangement: aarch64.encoding.Register.Arrangement = .wrap(.{
1115                    .size = group.Q,
1116                    .elem_size = .half,
1117                });
1118                try writer.print("{f}{s}{f}{s}{f}", .{
1119                    fmtCase(decoded, dis.case),
1120                    dis.mnemonic_operands_separator,
1121                    group.Rd.decode(.{ .V = true }).vector(arrangement).fmtCase(dis.case),
1122                    dis.operands_separator,
1123                    group.Rn.decode(.{ .V = true }).vector(arrangement).fmtCase(dis.case),
1124                });
1125                return switch (decoded) {
1126                    .unallocated => unreachable,
1127                    else => {},
1128                    .fcmgt,
1129                    .fcmeq,
1130                    .fcmlt,
1131                    .fcmge,
1132                    .fcmle,
1133                    => writer.print("{s}#0.0", .{dis.operands_separator}),
1134                };
1135            },
1136            .simd_two_register_miscellaneous => |simd_two_register_miscellaneous| {
1137                const decoded = simd_two_register_miscellaneous.decode();
1138                const group = simd_two_register_miscellaneous.group;
1139                const elem_size = switch (decoded) {
1140                    .unallocated => break :unallocated,
1141                    inline .frintn,
1142                    .frintm,
1143                    .fcvtns,
1144                    .fcvtms,
1145                    .fcvtas,
1146                    .scvtf,
1147                    .frintp,
1148                    .frintz,
1149                    .fcvtps,
1150                    .fcvtzs,
1151                    .fcvtxn,
1152                    .frinta,
1153                    .frintx,
1154                    .fcvtnu,
1155                    .fcvtmu,
1156                    .fcvtau,
1157                    .ucvtf,
1158                    .frinti,
1159                    .fcvtpu,
1160                    .fcvtzu,
1161                    => |f| f.sz.toSize(),
1162                    else => group.size,
1163                };
1164                const arrangement: aarch64.encoding.Register.Arrangement = .wrap(.{
1165                    .size = group.Q,
1166                    .elem_size = elem_size,
1167                });
1168                try writer.print("{f}{s}{s}{f}{s}{f}", .{
1169                    fmtCase(decoded, dis.case),
1170                    switch (decoded) {
1171                        .unallocated => unreachable,
1172                        else => "",
1173                        .sqxtn => switch (group.Q) {
1174                            .double => "",
1175                            .quad => "2",
1176                        },
1177                    },
1178                    dis.mnemonic_operands_separator,
1179                    group.Rd.decode(.{ .V = true }).vector(arrangement).fmtCase(dis.case),
1180                    dis.operands_separator,
1181                    group.Rn.decode(.{ .V = true }).vector(switch (decoded) {
1182                        .unallocated => unreachable,
1183                        else => arrangement,
1184                        .sqxtn => .wrap(.{
1185                            .size = .quad,
1186                            .elem_size = elem_size.w(),
1187                        }),
1188                    }).fmtCase(dis.case),
1189                });
1190                return switch (decoded) {
1191                    .unallocated => unreachable,
1192                    else => {},
1193                    .cmgt,
1194                    .cmeq,
1195                    .cmlt,
1196                    .cmge,
1197                    .cmle,
1198                    => writer.print("{s}#0", .{dis.operands_separator}),
1199                    .fcmgt,
1200                    .fcmeq,
1201                    .fcmlt,
1202                    .fcmge,
1203                    .fcmle,
1204                    => writer.print("{s}#0.0", .{dis.operands_separator}),
1205                };
1206            },
1207            .simd_across_lanes => |simd_across_lanes| {
1208                const decoded = simd_across_lanes.decode();
1209                if (decoded == .unallocated) break :unallocated;
1210                const group = simd_across_lanes.group;
1211                const arrangement: aarch64.encoding.Register.Arrangement = .wrap(.{
1212                    .size = group.Q,
1213                    .elem_size = group.size,
1214                });
1215                return writer.print("{f}{s}{f}{s}{f}", .{
1216                    fmtCase(decoded, dis.case),
1217                    dis.mnemonic_operands_separator,
1218                    group.Rd.decode(.{ .V = true }).scalar(group.size.toScalarSize()).fmtCase(dis.case),
1219                    dis.operands_separator,
1220                    group.Rn.decode(.{ .V = true }).vector(arrangement).fmtCase(dis.case),
1221                });
1222            },
1223            .simd_three_same => |simd_three_same| {
1224                const decoded = simd_three_same.decode();
1225                if (decoded == .unallocated) break :unallocated;
1226                const group = simd_three_same.group;
1227                const arrangement: aarch64.encoding.Register.Arrangement = .wrap(.{
1228                    .size = group.Q,
1229                    .elem_size = switch (decoded) {
1230                        .unallocated => break :unallocated,
1231                        .addp => group.size,
1232                        .@"and", .bic, .orr, .orn, .eor, .bsl, .bit, .bif => .byte,
1233                    },
1234                });
1235                const Rd = group.Rd.decode(.{ .V = true }).vector(arrangement);
1236                const Rn = group.Rn.decode(.{ .V = true }).vector(arrangement);
1237                const Rm = group.Rm.decode(.{ .V = true }).vector(arrangement);
1238                return if (dis.enable_aliases and decoded == .orr and Rm.alias == Rn.alias) try writer.print("{f}{s}{f}{s}{f}", .{
1239                    fmtCase(.mov, dis.case),
1240                    dis.mnemonic_operands_separator,
1241                    Rd.fmtCase(dis.case),
1242                    dis.operands_separator,
1243                    Rn.fmtCase(dis.case),
1244                }) else try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{
1245                    fmtCase(decoded, dis.case),
1246                    dis.mnemonic_operands_separator,
1247                    Rd.fmtCase(dis.case),
1248                    dis.operands_separator,
1249                    Rn.fmtCase(dis.case),
1250                    dis.operands_separator,
1251                    Rm.fmtCase(dis.case),
1252                });
1253            },
1254            .simd_modified_immediate => |simd_modified_immediate| {
1255                const decoded = simd_modified_immediate.decode();
1256                if (decoded == .unallocated) break :unallocated;
1257                const group = simd_modified_immediate.group;
1258                const DataProcessingVector = aarch64.encoding.Instruction.DataProcessingVector;
1259                try writer.print("{f}{s}{f}", .{
1260                    fmtCase(decoded, dis.case),
1261                    dis.mnemonic_operands_separator,
1262                    group.Rd.decode(.{ .V = true }).vector(.wrap(.{
1263                        .size = group.Q,
1264                        .elem_size = switch (group.o2) {
1265                            0b1 => .half,
1266                            0b0 => DataProcessingVector.Sz.toSize(@enumFromInt(group.op)),
1267                        },
1268                    })).fmtCase(dis.case),
1269                });
1270                return switch (decoded) {
1271                    .unallocated => unreachable,
1272                    .fmov => {
1273                        const imm = DataProcessingVector.FloatImmediate.Fmov.Imm8.fromModified(.{
1274                            .imm5 = group.imm5,
1275                            .imm3 = group.imm3,
1276                        }).decode();
1277                        try writer.print("{s}#{d}{s}", .{
1278                            dis.operands_separator,
1279                            @as(f32, imm),
1280                            if (imm == @trunc(imm)) ".0" else "",
1281                        });
1282                    },
1283                };
1284            },
1285            .convert_float_fixed => {},
1286            .convert_float_integer => |convert_float_integer| {
1287                const decoded = convert_float_integer.decode();
1288                if (decoded == .unallocated) break :unallocated;
1289                const group = convert_float_integer.group;
1290                const direction: enum { float_to_integer, integer_to_float } = switch (group.opcode) {
1291                    0b000, 0b001, 0b100, 0b101, 0b110 => .float_to_integer,
1292                    0b010, 0b011, 0b111 => .integer_to_float,
1293                };
1294                return writer.print("{f}{s}{f}{s}{f}", .{
1295                    fmtCase(decoded, dis.case),
1296                    dis.mnemonic_operands_separator,
1297                    @as(aarch64.encoding.Register, switch (direction) {
1298                        .float_to_integer => group.Rd.decode(.{}).general(group.sf),
1299                        .integer_to_float => switch (group.ptype) {
1300                            .single, .double, .half => group.Rd.decode(.{ .V = true }).scalar(group.ptype.toScalarSize()),
1301                            .quad => group.Rd.decode(.{ .V = true }).@"d[]"(@intCast(group.rmode)),
1302                        },
1303                    }).fmtCase(dis.case),
1304                    dis.operands_separator,
1305                    @as(aarch64.encoding.Register, switch (direction) {
1306                        .float_to_integer => switch (group.ptype) {
1307                            .single, .double, .half => group.Rn.decode(.{ .V = true }).scalar(group.ptype.toScalarSize()),
1308                            .quad => group.Rn.decode(.{ .V = true }).@"d[]"(@intCast(group.rmode)),
1309                        },
1310                        .integer_to_float => group.Rn.decode(.{}).general(group.sf),
1311                    }).fmtCase(dis.case),
1312                });
1313            },
1314            .float_data_processing_one_source => |float_data_processing_one_source| {
1315                const decoded = float_data_processing_one_source.decode();
1316                if (decoded == .unallocated) break :unallocated;
1317                const group = float_data_processing_one_source.group;
1318                return writer.print("{f}{s}{f}{s}{f}", .{
1319                    fmtCase(decoded, dis.case),
1320                    dis.mnemonic_operands_separator,
1321                    group.Rd.decode(.{ .V = true }).scalar(group.ptype.toScalarSize()).fmtCase(dis.case),
1322                    dis.operands_separator,
1323                    group.Rn.decode(.{ .V = true }).scalar(group.ptype.toScalarSize()).fmtCase(dis.case),
1324                });
1325            },
1326            .float_compare => {},
1327            .float_immediate => |float_immediate| {
1328                const decoded = float_immediate.decode();
1329                const group = float_immediate.group;
1330                const imm = switch (decoded) {
1331                    .unallocated => break :unallocated,
1332                    .fmov => |fmov| fmov.imm8.decode(),
1333                };
1334                return writer.print("{f}{s}{f}{s}#{d}{s}", .{
1335                    fmtCase(decoded, dis.case),
1336                    dis.mnemonic_operands_separator,
1337                    group.Rd.decode(.{ .V = true }).scalar(group.ptype.toScalarSize()).fmtCase(dis.case),
1338                    dis.operands_separator,
1339                    @as(f32, imm),
1340                    if (imm == @trunc(imm)) ".0" else "",
1341                });
1342            },
1343            .float_conditional_compare => {},
1344            .float_data_processing_two_source => {},
1345            .float_conditional_select => {},
1346            .float_data_processing_three_source => {},
1347        },
1348    }
1349    return writer.print(".{f}{s}0x{x:0>8}", .{
1350        fmtCase(.word, dis.case),
1351        dis.mnemonic_operands_separator,
1352        @as(aarch64.encoding.Instruction.Backing, @bitCast(inst)),
1353    });
1354}
1355
1356fn fmtCase(tag: anytype, case: Case) struct {
1357    tag: []const u8,
1358    case: Case,
1359    pub fn format(data: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void {
1360        for (data.tag) |c| try writer.writeByte(data.case.convert(c));
1361    }
1362} {
1363    return .{ .tag = @tagName(tag), .case = case };
1364}
1365
1366pub const RegisterFormatter = struct {
1367    reg: aarch64.encoding.Register,
1368    case: Case,
1369    pub fn format(data: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void {
1370        switch (data.reg.format) {
1371            .alias => try writer.print("{f}", .{fmtCase(data.reg.alias, data.case)}),
1372            .general => |size| switch (data.reg.alias) {
1373                else => unreachable,
1374                .r0,
1375                .r1,
1376                .r2,
1377                .r3,
1378                .r4,
1379                .r5,
1380                .r6,
1381                .r7,
1382                .r8,
1383                .r9,
1384                .r10,
1385                .r11,
1386                .r12,
1387                .r13,
1388                .r14,
1389                .r15,
1390                .r16,
1391                .r17,
1392                .r18,
1393                .r19,
1394                .r20,
1395                .r21,
1396                .r22,
1397                .r23,
1398                .r24,
1399                .r25,
1400                .r26,
1401                .r27,
1402                .r28,
1403                .r29,
1404                .r30,
1405                => |alias| try writer.print("{c}{d}", .{
1406                    data.case.convert(size.prefix()),
1407                    @intFromEnum(alias.encode(.{})),
1408                }),
1409                .zr => try writer.print("{c}{f}", .{
1410                    data.case.convert(size.prefix()),
1411                    fmtCase(data.reg.alias, data.case),
1412                }),
1413                .sp => try writer.print("{s}{f}", .{
1414                    switch (size) {
1415                        .word => &.{data.case.convert('w')},
1416                        .doubleword => "",
1417                    },
1418                    fmtCase(data.reg.alias, data.case),
1419                }),
1420            },
1421            .scalar => |size| try writer.print("{c}{d}", .{
1422                data.case.convert(size.prefix()),
1423                @intFromEnum(data.reg.alias.encode(.{ .V = true })),
1424            }),
1425            .vector => |arrangement| try writer.print("{f}.{f}", .{
1426                fmtCase(data.reg.alias, data.case),
1427                fmtCase(arrangement, data.case),
1428            }),
1429            .element => |element| try writer.print("{f}.{c}[{d}]", .{
1430                fmtCase(data.reg.alias, data.case),
1431                data.case.convert(element.size.prefix()),
1432                element.index,
1433            }),
1434            .scalable => try writer.print("{c}{d}", .{
1435                data.case.convert('z'),
1436                @intFromEnum(data.reg.alias.encode(.{ .V = true })),
1437            }),
1438        }
1439    }
1440};
1441
1442const aarch64 = @import("../aarch64.zig");
1443const Disassemble = @This();
1444const std = @import("std");