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");