| 1 | case: Case = .lower, |
| 2 | mnemonic_operands_separator: []const u8 = " ", |
| 3 | operands_separator: []const u8 = ", ", |
| 4 | enable_aliases: bool = true, |
| 5 | |
| 6 | pub 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 | |
| 17 | pub 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(@fromBackingInt(@intCast(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 = @fromBackingInt(@intCast(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) + @backingInt(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) + @backingInt(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 = @fromBackingInt(@intCast(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) + @backingInt(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) + @backingInt(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 = @fromBackingInt(@intCast(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) + @backingInt(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) + @backingInt(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 | @backingInt(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) << @backingInt(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(@fromBackingInt(@intCast(elem_size))).fmtCase(dis.case), |
| 973 | dis.operands_separator, |
| 974 | group.Rn.decode(.{ .V = true }).element( |
| 975 | @fromBackingInt(@intCast(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 = @fromBackingInt(@intCast(elem_size)), |
| 1070 | })), |
| 1071 | inline .smov, .umov => |mov| group.Rd.decode(.{}).general(mov.Q), |
| 1072 | .ins => group.Rd.decode(.{ .V = true }).element( |
| 1073 | @fromBackingInt(@intCast(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 | @fromBackingInt(@intCast(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 | @fromBackingInt(@intCast(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 | @fromBackingInt(@intCast(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(@fromBackingInt(@intCast(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 | |
| 1356 | fn 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 | |
| 1366 | pub 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 | @backingInt(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 | @backingInt(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 | @backingInt(data.reg.alias.encode(.{ .V = true })), |
| 1437 | }), |
| 1438 | } |
| 1439 | } |
| 1440 | }; |
| 1441 | |
| 1442 | const aarch64 = @import("../aarch64.zig"); |
| 1443 | const Disassemble = @This(); |
| 1444 | const std = @import("std"); |