authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-06-18 10:59:09-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-22 19:43:47-07:00
log5060ab99c94dd8afc8b84e74fe4d050c88cdfc0a
treecbf778a4b590aee34366bb5fc00091d5d60c2d72
parenta023b9b22b6593ebd5a86736a4a9955840d1bfa1

aarch64: add new from scratch self-hosted backend


167 files changed, 28209 insertions(+), 3729 deletions(-)

CMakeLists.txt+8
......@@ -550,6 +550,14 @@ set(ZIG_STAGE2_SOURCES
550550 src/clang_options.zig
551551 src/clang_options_data.zig
552552 src/codegen.zig
553 src/codegen/aarch64.zig
554 src/codegen/aarch64/abi.zig
555 src/codegen/aarch64/Assemble.zig
556 src/codegen/aarch64/Disassemble.zig
557 src/codegen/aarch64/encoding.zig
558 src/codegen/aarch64/instructions.zon
559 src/codegen/aarch64/Mir.zig
560 src/codegen/aarch64/Select.zig
553561 src/codegen/c.zig
554562 src/codegen/c/Type.zig
555563 src/codegen/llvm.zig
lib/compiler/test_runner.zig+19-20
......@@ -16,6 +16,7 @@ var stdin_buffer: [4096]u8 = undefined;
1616var stdout_buffer: [4096]u8 = undefined;
1717
1818const crippled = switch (builtin.zig_backend) {
19 .stage2_aarch64,
1920 .stage2_powerpc,
2021 .stage2_riscv64,
2122 => true,
......@@ -287,13 +288,14 @@ pub fn log(
287288/// work-in-progress backends can handle it.
288289pub fn mainSimple() anyerror!void {
289290 @disableInstrumentation();
290 // is the backend capable of printing to stderr?
291 const enable_print = switch (builtin.zig_backend) {
291 // is the backend capable of calling `std.fs.File.writeAll`?
292 const enable_write = switch (builtin.zig_backend) {
293 .stage2_aarch64, .stage2_riscv64 => true,
292294 else => false,
293295 };
294 // is the backend capable of using std.fmt.format to print a summary at the end?
295 const print_summary = switch (builtin.zig_backend) {
296 .stage2_riscv64 => true,
296 // is the backend capable of calling `std.Io.Writer.print`?
297 const enable_print = switch (builtin.zig_backend) {
298 .stage2_aarch64, .stage2_riscv64 => true,
297299 else => false,
298300 };
299301
......@@ -302,34 +304,31 @@ pub fn mainSimple() anyerror!void {
302304 var failed: u64 = 0;
303305
304306 // we don't want to bring in File and Writer if the backend doesn't support it
305 const stderr = if (comptime enable_print) std.fs.File.stderr() else {};
307 const stdout = if (enable_write) std.fs.File.stdout() else {};
306308
307309 for (builtin.test_functions) |test_fn| {
310 if (enable_write) {
311 stdout.writeAll(test_fn.name) catch {};
312 stdout.writeAll("... ") catch {};
313 }
308314 if (test_fn.func()) |_| {
309 if (enable_print) {
310 stderr.writeAll(test_fn.name) catch {};
311 stderr.writeAll("... ") catch {};
312 stderr.writeAll("PASS\n") catch {};
313 }
315 if (enable_write) stdout.writeAll("PASS\n") catch {};
314316 } else |err| {
315 if (enable_print) {
316 stderr.writeAll(test_fn.name) catch {};
317 stderr.writeAll("... ") catch {};
318 }
319317 if (err != error.SkipZigTest) {
320 if (enable_print) stderr.writeAll("FAIL\n") catch {};
318 if (enable_write) stdout.writeAll("FAIL\n") catch {};
321319 failed += 1;
322 if (!enable_print) return err;
320 if (!enable_write) return err;
323321 continue;
324322 }
325 if (enable_print) stderr.writeAll("SKIP\n") catch {};
323 if (enable_write) stdout.writeAll("SKIP\n") catch {};
326324 skipped += 1;
327325 continue;
328326 }
329327 passed += 1;
330328 }
331 if (enable_print and print_summary) {
332 stderr.deprecatedWriter().print("{} passed, {} skipped, {} failed\n", .{ passed, skipped, failed }) catch {};
329 if (enable_print) {
330 var stdout_writer = stdout.writer(&.{});
331 stdout_writer.interface.print("{} passed, {} skipped, {} failed\n", .{ passed, skipped, failed }) catch {};
333332 }
334333 if (failed != 0) std.process.exit(1);
335334}
lib/compiler_rt.zig+3-3
......@@ -240,7 +240,7 @@ comptime {
240240 _ = @import("compiler_rt/udivmodti4.zig");
241241
242242 // extra
243 _ = @import("compiler_rt/os_version_check.zig");
243 if (builtin.zig_backend != .stage2_aarch64) _ = @import("compiler_rt/os_version_check.zig");
244244 _ = @import("compiler_rt/emutls.zig");
245245 _ = @import("compiler_rt/arm.zig");
246246 _ = @import("compiler_rt/aulldiv.zig");
......@@ -249,12 +249,12 @@ comptime {
249249 _ = @import("compiler_rt/hexagon.zig");
250250
251251 if (@import("builtin").object_format != .c) {
252 _ = @import("compiler_rt/atomics.zig");
252 if (builtin.zig_backend != .stage2_aarch64) _ = @import("compiler_rt/atomics.zig");
253253 _ = @import("compiler_rt/stack_probe.zig");
254254
255255 // macOS has these functions inside libSystem.
256256 if (builtin.cpu.arch.isAARCH64() and !builtin.os.tag.isDarwin()) {
257 _ = @import("compiler_rt/aarch64_outline_atomics.zig");
257 if (builtin.zig_backend != .stage2_aarch64) _ = @import("compiler_rt/aarch64_outline_atomics.zig");
258258 }
259259
260260 _ = @import("compiler_rt/memcpy.zig");
lib/compiler_rt/addo.zig+1-3
......@@ -1,6 +1,4 @@
11const std = @import("std");
2const builtin = @import("builtin");
3const is_test = builtin.is_test;
42const common = @import("./common.zig");
53pub const panic = @import("common.zig").panic;
64
......@@ -16,7 +14,7 @@ comptime {
1614// - addoXi4_generic as default
1715
1816inline fn addoXi4_generic(comptime ST: type, a: ST, b: ST, overflow: *c_int) ST {
19 @setRuntimeSafety(builtin.is_test);
17 @setRuntimeSafety(common.test_safety);
2018 overflow.* = 0;
2119 const sum: ST = a +% b;
2220 // Hackers Delight: section Overflow Detection, subsection Signed Add/Subtract
lib/compiler_rt/addoti4_test.zig+3
......@@ -1,4 +1,5 @@
11const addv = @import("addo.zig");
2const builtin = @import("builtin");
23const std = @import("std");
34const testing = std.testing;
45const math = std.math;
......@@ -23,6 +24,8 @@ fn simple_addoti4(a: i128, b: i128, overflow: *c_int) i128 {
2324}
2425
2526test "addoti4" {
27 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
28
2629 const min: i128 = math.minInt(i128);
2730 const max: i128 = math.maxInt(i128);
2831 var i: i128 = 1;
lib/compiler_rt/clear_cache.zig+4-10
......@@ -97,8 +97,7 @@ fn clear_cache(start: usize, end: usize) callconv(.c) void {
9797 .nbytes = end - start,
9898 .whichcache = 3, // ICACHE | DCACHE
9999 };
100 asm volatile (
101 \\ syscall
100 asm volatile ("syscall"
102101 :
103102 : [_] "{$2}" (165), // nr = SYS_sysarch
104103 [_] "{$4}" (0), // op = MIPS_CACHEFLUSH
......@@ -116,11 +115,8 @@ fn clear_cache(start: usize, end: usize) callconv(.c) void {
116115 } else if (arm64 and !apple) {
117116 // Get Cache Type Info.
118117 // TODO memoize this?
119 var ctr_el0: u64 = 0;
120 asm volatile (
121 \\mrs %[x], ctr_el0
122 \\
123 : [x] "=r" (ctr_el0),
118 const ctr_el0 = asm volatile ("mrs %[ctr_el0], ctr_el0"
119 : [ctr_el0] "=r" (-> u64),
124120 );
125121 // The DC and IC instructions must use 64-bit registers so we don't use
126122 // uintptr_t in case this runs in an IPL32 environment.
......@@ -187,9 +183,7 @@ fn clear_cache(start: usize, end: usize) callconv(.c) void {
187183 exportIt();
188184 } else if (os == .linux and loongarch) {
189185 // See: https://github.com/llvm/llvm-project/blob/cf54cae26b65fc3201eff7200ffb9b0c9e8f9a13/compiler-rt/lib/builtins/clear_cache.c#L94-L95
190 asm volatile (
191 \\ ibar 0
192 );
186 asm volatile ("ibar 0");
193187 exportIt();
194188 }
195189
lib/compiler_rt/cmp.zig-1
......@@ -1,6 +1,5 @@
11const std = @import("std");
22const builtin = @import("builtin");
3const is_test = builtin.is_test;
43const common = @import("common.zig");
54
65pub const panic = common.panic;
lib/compiler_rt/common.zig+6-1
......@@ -102,9 +102,14 @@ pub const gnu_f16_abi = switch (builtin.cpu.arch) {
102102
103103pub const want_sparc_abi = builtin.cpu.arch.isSPARC();
104104
105pub const test_safety = switch (builtin.zig_backend) {
106 .stage2_aarch64 => false,
107 else => builtin.is_test,
108};
109
105110// Avoid dragging in the runtime safety mechanisms into this .o file, unless
106111// we're trying to test compiler-rt.
107pub const panic = if (builtin.is_test) std.debug.FullPanic(std.debug.defaultPanic) else std.debug.no_panic;
112pub const panic = if (test_safety) std.debug.FullPanic(std.debug.defaultPanic) else std.debug.no_panic;
108113
109114/// This seems to mostly correspond to `clang::TargetInfo::HasFloat16`.
110115pub fn F16T(comptime OtherType: type) type {
lib/compiler_rt/comparedf2_test.zig-1
......@@ -4,7 +4,6 @@
44
55const std = @import("std");
66const builtin = @import("builtin");
7const is_test = builtin.is_test;
87
98const __eqdf2 = @import("./cmpdf2.zig").__eqdf2;
109const __ledf2 = @import("./cmpdf2.zig").__ledf2;
lib/compiler_rt/comparesf2_test.zig-1
......@@ -4,7 +4,6 @@
44
55const std = @import("std");
66const builtin = @import("builtin");
7const is_test = builtin.is_test;
87
98const __eqsf2 = @import("./cmpsf2.zig").__eqsf2;
109const __lesf2 = @import("./cmpsf2.zig").__lesf2;
lib/compiler_rt/count0bits.zig-1
......@@ -1,6 +1,5 @@
11const std = @import("std");
22const builtin = @import("builtin");
3const is_test = builtin.is_test;
43const common = @import("common.zig");
54
65pub const panic = common.panic;
lib/compiler_rt/divdf3.zig-1
......@@ -5,7 +5,6 @@
55const std = @import("std");
66const builtin = @import("builtin");
77const arch = builtin.cpu.arch;
8const is_test = builtin.is_test;
98const common = @import("common.zig");
109
1110const normalize = common.normalize;
lib/compiler_rt/divmodei4.zig+2-2
......@@ -34,7 +34,7 @@ fn divmod(q: ?[]u32, r: ?[]u32, u: []u32, v: []u32) !void {
3434}
3535
3636pub fn __divei4(q_p: [*]u8, u_p: [*]u8, v_p: [*]u8, bits: usize) callconv(.c) void {
37 @setRuntimeSafety(builtin.is_test);
37 @setRuntimeSafety(common.test_safety);
3838 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
3939 const q: []u32 = @ptrCast(@alignCast(q_p[0..byte_size]));
4040 const u: []u32 = @ptrCast(@alignCast(u_p[0..byte_size]));
......@@ -43,7 +43,7 @@ pub fn __divei4(q_p: [*]u8, u_p: [*]u8, v_p: [*]u8, bits: usize) callconv(.c) vo
4343}
4444
4545pub fn __modei4(r_p: [*]u8, u_p: [*]u8, v_p: [*]u8, bits: usize) callconv(.c) void {
46 @setRuntimeSafety(builtin.is_test);
46 @setRuntimeSafety(common.test_safety);
4747 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
4848 const r: []u32 = @ptrCast(@alignCast(r_p[0..byte_size]));
4949 const u: []u32 = @ptrCast(@alignCast(u_p[0..byte_size]));
lib/compiler_rt/fixint_test.zig-1
......@@ -1,4 +1,3 @@
1const is_test = @import("builtin").is_test;
21const std = @import("std");
32const math = std.math;
43const testing = std.testing;
lib/compiler_rt/int.zig-1
......@@ -6,7 +6,6 @@ const testing = std.testing;
66const maxInt = std.math.maxInt;
77const minInt = std.math.minInt;
88const arch = builtin.cpu.arch;
9const is_test = builtin.is_test;
109const common = @import("common.zig");
1110const udivmod = @import("udivmod.zig").udivmod;
1211const __divti3 = @import("divti3.zig").__divti3;
lib/compiler_rt/memcpy.zig+3-1
......@@ -11,7 +11,7 @@ comptime {
1111 .visibility = common.visibility,
1212 };
1313
14 if (builtin.mode == .ReleaseSmall)
14 if (builtin.mode == .ReleaseSmall or builtin.zig_backend == .stage2_aarch64)
1515 @export(&memcpySmall, export_options)
1616 else
1717 @export(&memcpyFast, export_options);
......@@ -195,6 +195,8 @@ inline fn copyRange4(
195195}
196196
197197test "memcpy" {
198 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
199
198200 const S = struct {
199201 fn testFunc(comptime copy_func: anytype) !void {
200202 const max_len = 1024;
lib/compiler_rt/memmove.zig+9-7
......@@ -14,7 +14,7 @@ comptime {
1414 .visibility = common.visibility,
1515 };
1616
17 if (builtin.mode == .ReleaseSmall)
17 if (builtin.mode == .ReleaseSmall or builtin.zig_backend == .stage2_aarch64)
1818 @export(&memmoveSmall, export_options)
1919 else
2020 @export(&memmoveFast, export_options);
......@@ -39,7 +39,7 @@ fn memmoveSmall(opt_dest: ?[*]u8, opt_src: ?[*]const u8, len: usize) callconv(.c
3939}
4040
4141fn memmoveFast(dest: ?[*]u8, src: ?[*]u8, len: usize) callconv(.c) ?[*]u8 {
42 @setRuntimeSafety(builtin.is_test);
42 @setRuntimeSafety(common.test_safety);
4343 const small_limit = @max(2 * @sizeOf(Element), @sizeOf(Element));
4444
4545 if (copySmallLength(small_limit, dest.?, src.?, len)) return dest;
......@@ -79,7 +79,7 @@ inline fn copyLessThan16(
7979 src: [*]const u8,
8080 len: usize,
8181) void {
82 @setRuntimeSafety(builtin.is_test);
82 @setRuntimeSafety(common.test_safety);
8383 if (len < 4) {
8484 if (len == 0) return;
8585 const b = len / 2;
......@@ -100,7 +100,7 @@ inline fn copy16ToSmallLimit(
100100 src: [*]const u8,
101101 len: usize,
102102) bool {
103 @setRuntimeSafety(builtin.is_test);
103 @setRuntimeSafety(common.test_safety);
104104 inline for (2..(std.math.log2(small_limit) + 1) / 2 + 1) |p| {
105105 const limit = 1 << (2 * p);
106106 if (len < limit) {
......@@ -119,7 +119,7 @@ inline fn copyRange4(
119119 src: [*]const u8,
120120 len: usize,
121121) void {
122 @setRuntimeSafety(builtin.is_test);
122 @setRuntimeSafety(common.test_safety);
123123 comptime assert(std.math.isPowerOfTwo(copy_len));
124124 assert(len >= copy_len);
125125 assert(len < 4 * copy_len);
......@@ -147,7 +147,7 @@ inline fn copyForwards(
147147 src: [*]const u8,
148148 len: usize,
149149) void {
150 @setRuntimeSafety(builtin.is_test);
150 @setRuntimeSafety(common.test_safety);
151151 assert(len >= 2 * @sizeOf(Element));
152152
153153 const head = src[0..@sizeOf(Element)].*;
......@@ -181,7 +181,7 @@ inline fn copyBlocks(
181181 src: anytype,
182182 max_bytes: usize,
183183) void {
184 @setRuntimeSafety(builtin.is_test);
184 @setRuntimeSafety(common.test_safety);
185185
186186 const T = @typeInfo(@TypeOf(dest)).pointer.child;
187187 comptime assert(T == @typeInfo(@TypeOf(src)).pointer.child);
......@@ -217,6 +217,8 @@ inline fn copyBackwards(
217217}
218218
219219test memmoveFast {
220 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
221
220222 const max_len = 1024;
221223 var buffer: [max_len + @alignOf(Element) - 1]u8 = undefined;
222224 for (&buffer, 0..) |*b, i| {
lib/compiler_rt/mulf3.zig+2-2
......@@ -6,7 +6,7 @@ const common = @import("./common.zig");
66/// Ported from:
77/// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/lib/builtins/fp_mul_impl.inc
88pub inline fn mulf3(comptime T: type, a: T, b: T) T {
9 @setRuntimeSafety(builtin.is_test);
9 @setRuntimeSafety(common.test_safety);
1010 const typeWidth = @typeInfo(T).float.bits;
1111 const significandBits = math.floatMantissaBits(T);
1212 const fractionalBits = math.floatFractionalBits(T);
......@@ -163,7 +163,7 @@ pub inline fn mulf3(comptime T: type, a: T, b: T) T {
163163///
164164/// This is analogous to an shr version of `@shlWithOverflow`
165165fn wideShrWithTruncation(comptime Z: type, hi: *Z, lo: *Z, count: u32) bool {
166 @setRuntimeSafety(builtin.is_test);
166 @setRuntimeSafety(common.test_safety);
167167 const typeWidth = @typeInfo(Z).int.bits;
168168 var inexact = false;
169169 if (count < typeWidth) {
lib/compiler_rt/rem_pio2_large.zig+1-1
......@@ -251,7 +251,7 @@ const PIo2 = [_]f64{
251251/// compiler will convert from decimal to binary accurately enough
252252/// to produce the hexadecimal values shown.
253253///
254pub fn rem_pio2_large(x: []f64, y: []f64, e0: i32, nx: i32, prec: usize) i32 {
254pub fn rem_pio2_large(x: []const f64, y: []f64, e0: i32, nx: i32, prec: usize) i32 {
255255 var jz: i32 = undefined;
256256 var jx: i32 = undefined;
257257 var jv: i32 = undefined;
lib/compiler_rt/stack_probe.zig-1
......@@ -4,7 +4,6 @@ const common = @import("common.zig");
44const os_tag = builtin.os.tag;
55const arch = builtin.cpu.arch;
66const abi = builtin.abi;
7const is_test = builtin.is_test;
87
98pub const panic = common.panic;
109
lib/compiler_rt/suboti4_test.zig+3
......@@ -1,4 +1,5 @@
11const subo = @import("subo.zig");
2const builtin = @import("builtin");
23const std = @import("std");
34const testing = std.testing;
45const math = std.math;
......@@ -27,6 +28,8 @@ pub fn simple_suboti4(a: i128, b: i128, overflow: *c_int) i128 {
2728}
2829
2930test "suboti3" {
31 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
32
3033 const min: i128 = math.minInt(i128);
3134 const max: i128 = math.maxInt(i128);
3235 var i: i128 = 1;
lib/compiler_rt/udivmod.zig+5-5
......@@ -1,8 +1,8 @@
11const std = @import("std");
22const builtin = @import("builtin");
3const is_test = builtin.is_test;
43const Log2Int = std.math.Log2Int;
5const HalveInt = @import("common.zig").HalveInt;
4const common = @import("common.zig");
5const HalveInt = common.HalveInt;
66
77const lo = switch (builtin.cpu.arch.endian()) {
88 .big => 1,
......@@ -14,7 +14,7 @@ const hi = 1 - lo;
1414// Returns U / v_ and sets r = U % v_.
1515fn divwide_generic(comptime T: type, _u1: T, _u0: T, v_: T, r: *T) T {
1616 const HalfT = HalveInt(T, false).HalfT;
17 @setRuntimeSafety(is_test);
17 @setRuntimeSafety(common.test_safety);
1818 var v = v_;
1919
2020 const b = @as(T, 1) << (@bitSizeOf(T) / 2);
......@@ -70,7 +70,7 @@ fn divwide_generic(comptime T: type, _u1: T, _u0: T, v_: T, r: *T) T {
7070}
7171
7272fn divwide(comptime T: type, _u1: T, _u0: T, v: T, r: *T) T {
73 @setRuntimeSafety(is_test);
73 @setRuntimeSafety(common.test_safety);
7474 if (T == u64 and builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag != .windows) {
7575 var rem: T = undefined;
7676 const quo = asm (
......@@ -90,7 +90,7 @@ fn divwide(comptime T: type, _u1: T, _u0: T, v: T, r: *T) T {
9090
9191// Returns a_ / b_ and sets maybe_rem = a_ % b.
9292pub fn udivmod(comptime T: type, a_: T, b_: T, maybe_rem: ?*T) T {
93 @setRuntimeSafety(is_test);
93 @setRuntimeSafety(common.test_safety);
9494 const HalfT = HalveInt(T, false).HalfT;
9595 const SignedT = std.meta.Int(.signed, @bitSizeOf(T));
9696
lib/compiler_rt/udivmodei4.zig+3-2
......@@ -113,7 +113,7 @@ pub fn divmod(q: ?[]u32, r: ?[]u32, u: []const u32, v: []const u32) !void {
113113}
114114
115115pub fn __udivei4(q_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, bits: usize) callconv(.c) void {
116 @setRuntimeSafety(builtin.is_test);
116 @setRuntimeSafety(common.test_safety);
117117 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
118118 const q: []u32 = @ptrCast(@alignCast(q_p[0..byte_size]));
119119 const u: []const u32 = @ptrCast(@alignCast(u_p[0..byte_size]));
......@@ -122,7 +122,7 @@ pub fn __udivei4(q_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, bits: usize) ca
122122}
123123
124124pub fn __umodei4(r_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, bits: usize) callconv(.c) void {
125 @setRuntimeSafety(builtin.is_test);
125 @setRuntimeSafety(common.test_safety);
126126 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
127127 const r: []u32 = @ptrCast(@alignCast(r_p[0..byte_size]));
128128 const u: []const u32 = @ptrCast(@alignCast(u_p[0..byte_size]));
......@@ -131,6 +131,7 @@ pub fn __umodei4(r_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, bits: usize) ca
131131}
132132
133133test "__udivei4/__umodei4" {
134 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
134135 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
135136 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
136137
lib/std/Io/Writer.zig+4
......@@ -2239,6 +2239,10 @@ pub const Discarding = struct {
22392239
22402240 pub fn sendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize {
22412241 if (File.Handle == void) return error.Unimplemented;
2242 switch (builtin.zig_backend) {
2243 else => {},
2244 .stage2_aarch64 => return error.Unimplemented,
2245 }
22422246 const d: *Discarding = @alignCast(@fieldParentPtr("writer", w));
22432247 d.count += w.end;
22442248 w.end = 0;
lib/std/Progress.zig+4-1
......@@ -408,6 +408,9 @@ pub const have_ipc = switch (builtin.os.tag) {
408408const noop_impl = builtin.single_threaded or switch (builtin.os.tag) {
409409 .wasi, .freestanding => true,
410410 else => false,
411} or switch (builtin.zig_backend) {
412 .stage2_aarch64 => true,
413 else => false,
411414};
412415
413416/// Initializes a global Progress instance.
......@@ -754,7 +757,7 @@ fn appendTreeSymbol(symbol: TreeSymbol, buf: []u8, start_i: usize) usize {
754757}
755758
756759fn clearWrittenWithEscapeCodes() anyerror!void {
757 if (!global_progress.need_clear) return;
760 if (noop_impl or !global_progress.need_clear) return;
758761
759762 global_progress.need_clear = false;
760763 try write(clear);
lib/std/builtin.zig+5-2
......@@ -772,7 +772,7 @@ pub const Endian = enum {
772772
773773/// This data structure is used by the Zig language code generation and
774774/// therefore must be kept in sync with the compiler implementation.
775pub const Signedness = enum {
775pub const Signedness = enum(u1) {
776776 signed,
777777 unsigned,
778778};
......@@ -894,7 +894,10 @@ pub const VaList = switch (builtin.cpu.arch) {
894894 .aarch64, .aarch64_be => switch (builtin.os.tag) {
895895 .windows => *u8,
896896 .ios, .macos, .tvos, .watchos, .visionos => *u8,
897 else => @compileError("disabled due to miscompilations"), // VaListAarch64,
897 else => switch (builtin.zig_backend) {
898 .stage2_aarch64 => VaListAarch64,
899 else => @compileError("disabled due to miscompilations"),
900 },
898901 },
899902 .arm, .armeb, .thumb, .thumbeb => switch (builtin.os.tag) {
900903 .ios, .macos, .tvos, .watchos, .visionos => *u8,
lib/std/elf.zig+1-1
......@@ -2001,7 +2001,7 @@ pub const R_AARCH64 = enum(u32) {
20012001 TLSLE_LDST64_TPREL_LO12 = 558,
20022002 /// Likewise; no check.
20032003 TLSLE_LDST64_TPREL_LO12_NC = 559,
2004 /// PC-rel. load immediate 20:2.
2004 /// PC-rel. load immediate 20:2.
20052005 TLSDESC_LD_PREL19 = 560,
20062006 /// PC-rel. ADR immediate 20:0.
20072007 TLSDESC_ADR_PREL21 = 561,
lib/std/fs/File.zig+4-1
......@@ -1554,7 +1554,10 @@ pub const Writer = struct {
15541554 return .{
15551555 .vtable = &.{
15561556 .drain = drain,
1557 .sendFile = sendFile,
1557 .sendFile = switch (builtin.zig_backend) {
1558 else => sendFile,
1559 .stage2_aarch64 => std.io.Writer.unimplementedSendFile,
1560 },
15581561 },
15591562 .buffer = buffer,
15601563 };
lib/std/math.zig+55-38
......@@ -45,6 +45,7 @@ pub const rad_per_deg = 0.017453292519943295769236907684886127134428718885417254
4545/// 180.0/pi
4646pub const deg_per_rad = 57.295779513082320876798154814105170332405472466564321549160243861;
4747
48pub const Sign = enum(u1) { positive, negative };
4849pub const FloatRepr = float.FloatRepr;
4950pub const floatExponentBits = float.floatExponentBits;
5051pub const floatMantissaBits = float.floatMantissaBits;
......@@ -594,27 +595,30 @@ pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T {
594595/// Shifts left. Overflowed bits are truncated.
595596/// A negative shift amount results in a right shift.
596597pub fn shl(comptime T: type, a: T, shift_amt: anytype) T {
598 const is_shl = shift_amt >= 0;
597599 const abs_shift_amt = @abs(shift_amt);
598
599 const casted_shift_amt = blk: {
600 if (@typeInfo(T) == .vector) {
601 const C = @typeInfo(T).vector.child;
602 const len = @typeInfo(T).vector.len;
603 if (abs_shift_amt >= @typeInfo(C).int.bits) return @splat(0);
604 break :blk @as(@Vector(len, Log2Int(C)), @splat(@as(Log2Int(C), @intCast(abs_shift_amt))));
605 } else {
606 if (abs_shift_amt >= @typeInfo(T).int.bits) return 0;
607 break :blk @as(Log2Int(T), @intCast(abs_shift_amt));
608 }
600 const casted_shift_amt = casted_shift_amt: switch (@typeInfo(T)) {
601 .int => |info| {
602 if (abs_shift_amt < info.bits) break :casted_shift_amt @as(
603 Log2Int(T),
604 @intCast(abs_shift_amt),
605 );
606 if (info.signedness == .unsigned or is_shl) return 0;
607 return a >> (info.bits - 1);
608 },
609 .vector => |info| {
610 const Child = info.child;
611 const child_info = @typeInfo(Child).int;
612 if (abs_shift_amt < child_info.bits) break :casted_shift_amt @as(
613 @Vector(info.len, Log2Int(Child)),
614 @splat(@as(Log2Int(Child), @intCast(abs_shift_amt))),
615 );
616 if (child_info.signedness == .unsigned or is_shl) return @splat(0);
617 return a >> @splat(child_info.bits - 1);
618 },
619 else => comptime unreachable,
609620 };
610
611 if (@TypeOf(shift_amt) == comptime_int or @typeInfo(@TypeOf(shift_amt)).int.signedness == .signed) {
612 if (shift_amt < 0) {
613 return a >> casted_shift_amt;
614 }
615 }
616
617 return a << casted_shift_amt;
621 return if (is_shl) a << casted_shift_amt else a >> casted_shift_amt;
618622}
619623
620624test shl {
......@@ -629,32 +633,40 @@ test shl {
629633 try testing.expect(shl(@Vector(1, u32), @Vector(1, u32){42}, @as(usize, 1))[0] == @as(u32, 42) << 1);
630634 try testing.expect(shl(@Vector(1, u32), @Vector(1, u32){42}, @as(isize, -1))[0] == @as(u32, 42) >> 1);
631635 try testing.expect(shl(@Vector(1, u32), @Vector(1, u32){42}, 33)[0] == 0);
636
637 try testing.expect(shl(i8, -1, -100) == -1);
638 try testing.expect(shl(i8, -1, 100) == 0);
639 try testing.expect(@reduce(.And, shl(@Vector(2, i8), .{ -1, 1 }, -100) == @Vector(2, i8){ -1, 0 }));
640 try testing.expect(@reduce(.And, shl(@Vector(2, i8), .{ -1, 1 }, 100) == @Vector(2, i8){ 0, 0 }));
632641}
633642
634643/// Shifts right. Overflowed bits are truncated.
635644/// A negative shift amount results in a left shift.
636645pub fn shr(comptime T: type, a: T, shift_amt: anytype) T {
646 const is_shl = shift_amt < 0;
637647 const abs_shift_amt = @abs(shift_amt);
638
639 const casted_shift_amt = blk: {
640 if (@typeInfo(T) == .vector) {
641 const C = @typeInfo(T).vector.child;
642 const len = @typeInfo(T).vector.len;
643 if (abs_shift_amt >= @typeInfo(C).int.bits) return @splat(0);
644 break :blk @as(@Vector(len, Log2Int(C)), @splat(@as(Log2Int(C), @intCast(abs_shift_amt))));
645 } else {
646 if (abs_shift_amt >= @typeInfo(T).int.bits) return 0;
647 break :blk @as(Log2Int(T), @intCast(abs_shift_amt));
648 }
648 const casted_shift_amt = casted_shift_amt: switch (@typeInfo(T)) {
649 .int => |info| {
650 if (abs_shift_amt < info.bits) break :casted_shift_amt @as(
651 Log2Int(T),
652 @intCast(abs_shift_amt),
653 );
654 if (info.signedness == .unsigned or is_shl) return 0;
655 return a >> (info.bits - 1);
656 },
657 .vector => |info| {
658 const Child = info.child;
659 const child_info = @typeInfo(Child).int;
660 if (abs_shift_amt < child_info.bits) break :casted_shift_amt @as(
661 @Vector(info.len, Log2Int(Child)),
662 @splat(@as(Log2Int(Child), @intCast(abs_shift_amt))),
663 );
664 if (child_info.signedness == .unsigned or is_shl) return @splat(0);
665 return a >> @splat(child_info.bits - 1);
666 },
667 else => comptime unreachable,
649668 };
650
651 if (@TypeOf(shift_amt) == comptime_int or @typeInfo(@TypeOf(shift_amt)).int.signedness == .signed) {
652 if (shift_amt < 0) {
653 return a << casted_shift_amt;
654 }
655 }
656
657 return a >> casted_shift_amt;
669 return if (is_shl) a << casted_shift_amt else a >> casted_shift_amt;
658670}
659671
660672test shr {
......@@ -669,6 +681,11 @@ test shr {
669681 try testing.expect(shr(@Vector(1, u32), @Vector(1, u32){42}, @as(usize, 1))[0] == @as(u32, 42) >> 1);
670682 try testing.expect(shr(@Vector(1, u32), @Vector(1, u32){42}, @as(isize, -1))[0] == @as(u32, 42) << 1);
671683 try testing.expect(shr(@Vector(1, u32), @Vector(1, u32){42}, 33)[0] == 0);
684
685 try testing.expect(shr(i8, -1, -100) == 0);
686 try testing.expect(shr(i8, -1, 100) == -1);
687 try testing.expect(@reduce(.And, shr(@Vector(2, i8), .{ -1, 1 }, -100) == @Vector(2, i8){ 0, 0 }));
688 try testing.expect(@reduce(.And, shr(@Vector(2, i8), .{ -1, 1 }, 100) == @Vector(2, i8){ -1, 0 }));
672689}
673690
674691/// Rotates right. Only unsigned values can be rotated. Negative shift
lib/std/math/big/int_test.zig-1
......@@ -2774,7 +2774,6 @@ test "bitNotWrap more than two limbs" {
27742774 // This test requires int sizes greater than 128 bits.
27752775 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
27762776 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
2777 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
27782777 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
27792778 // LLVM: unexpected runtime library name: __umodei4
27802779 if (builtin.zig_backend == .stage2_llvm and comptime builtin.target.cpu.arch.isWasm()) return error.SkipZigTest; // TODO
lib/std/math/float.zig+2-4
......@@ -4,8 +4,6 @@ const assert = std.debug.assert;
44const expect = std.testing.expect;
55const expectEqual = std.testing.expectEqual;
66
7pub const Sign = enum(u1) { positive, negative };
8
97pub fn FloatRepr(comptime Float: type) type {
108 const fractional_bits = floatFractionalBits(Float);
119 const exponent_bits = floatExponentBits(Float);
......@@ -14,7 +12,7 @@ pub fn FloatRepr(comptime Float: type) type {
1412
1513 mantissa: StoredMantissa,
1614 exponent: BiasedExponent,
17 sign: Sign,
15 sign: std.math.Sign,
1816
1917 pub const StoredMantissa = @Type(.{ .int = .{
2018 .signedness = .unsigned,
......@@ -69,7 +67,7 @@ pub fn FloatRepr(comptime Float: type) type {
6967
7068 /// This currently truncates denormal values, which needs to be fixed before this can be used to
7169 /// produce a rounded value.
72 pub fn reconstruct(normalized: Normalized, sign: Sign) Float {
70 pub fn reconstruct(normalized: Normalized, sign: std.math.Sign) Float {
7371 if (normalized.exponent > BiasedExponent.max_normal.unbias()) return @bitCast(Repr{
7472 .mantissa = 0,
7573 .exponent = .infinite,
lib/std/math/log10.zig-1
......@@ -132,7 +132,6 @@ inline fn less_than_5(x: u32) u32 {
132132test log10_int {
133133 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
134134 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
136135 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
137136 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
138137 if (builtin.zig_backend == .stage2_llvm and comptime builtin.target.cpu.arch.isWasm()) return error.SkipZigTest; // TODO
lib/std/mem.zig+4-3
......@@ -676,6 +676,7 @@ test lessThan {
676676
677677const eqlBytes_allowed = switch (builtin.zig_backend) {
678678 // These backends don't support vectors yet.
679 .stage2_aarch64,
679680 .stage2_powerpc,
680681 .stage2_riscv64,
681682 => false,
......@@ -4482,7 +4483,7 @@ pub fn doNotOptimizeAway(val: anytype) void {
44824483 );
44834484 asm volatile (""
44844485 :
4485 : [val2] "r" (val2),
4486 : [_] "r" (val2),
44864487 );
44874488 } else doNotOptimizeAway(&val);
44884489 },
......@@ -4490,7 +4491,7 @@ pub fn doNotOptimizeAway(val: anytype) void {
44904491 if ((t.float.bits == 32 or t.float.bits == 64) and builtin.zig_backend != .stage2_c) {
44914492 asm volatile (""
44924493 :
4493 : [val] "rm" (val),
4494 : [_] "rm" (val),
44944495 );
44954496 } else doNotOptimizeAway(&val);
44964497 },
......@@ -4500,7 +4501,7 @@ pub fn doNotOptimizeAway(val: anytype) void {
45004501 } else {
45014502 asm volatile (""
45024503 :
4503 : [val] "m" (val),
4504 : [_] "m" (val),
45044505 : .{ .memory = true });
45054506 }
45064507 },
lib/std/os/linux.zig-1
......@@ -503,7 +503,6 @@ pub var elf_aux_maybe: ?[*]std.elf.Auxv = null;
503503/// Whether an external or internal getauxval implementation is used.
504504const extern_getauxval = switch (builtin.zig_backend) {
505505 // Calling extern functions is not yet supported with these backends
506 .stage2_aarch64,
507506 .stage2_arm,
508507 .stage2_powerpc,
509508 .stage2_riscv64,
lib/std/start.zig+5-54
......@@ -101,17 +101,11 @@ comptime {
101101// Simplified start code for stage2 until it supports more language features ///
102102
103103fn main2() callconv(.c) c_int {
104 root.main();
105 return 0;
104 return callMain();
106105}
107106
108107fn _start2() callconv(.withStackAlign(.c, 1)) noreturn {
109 callMain2();
110}
111
112fn callMain2() noreturn {
113 root.main();
114 exit2(0);
108 std.posix.exit(callMain());
115109}
116110
117111fn spirvMain2() callconv(.kernel) void {
......@@ -119,51 +113,7 @@ fn spirvMain2() callconv(.kernel) void {
119113}
120114
121115fn wWinMainCRTStartup2() callconv(.c) noreturn {
122 root.main();
123 exit2(0);
124}
125
126fn exit2(code: usize) noreturn {
127 switch (native_os) {
128 .linux => switch (builtin.cpu.arch) {
129 .x86_64 => {
130 asm volatile ("syscall"
131 :
132 : [number] "{rax}" (231),
133 [arg1] "{rdi}" (code),
134 : .{ .rcx = true, .r11 = true, .memory = true });
135 },
136 .arm => {
137 asm volatile ("svc #0"
138 :
139 : [number] "{r7}" (1),
140 [arg1] "{r0}" (code),
141 : .{ .memory = true });
142 },
143 .aarch64 => {
144 asm volatile ("svc #0"
145 :
146 : [number] "{x8}" (93),
147 [arg1] "{x0}" (code),
148 : .{ .memory = true });
149 },
150 .sparc64 => {
151 asm volatile ("ta 0x6d"
152 :
153 : [number] "{g1}" (1),
154 [arg1] "{o0}" (code),
155 : .{ .o0 = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o6 = true, .o7 = true, .memory = true });
156 },
157 else => @compileError("TODO"),
158 },
159 // exits(0)
160 .plan9 => std.os.plan9.exits(null),
161 .windows => {
162 std.os.windows.ntdll.RtlExitUserProcess(@truncate(code));
163 },
164 else => @compileError("TODO"),
165 }
166 unreachable;
116 std.posix.exit(callMain());
167117}
168118
169119////////////////////////////////////////////////////////////////////////////////
......@@ -676,10 +626,11 @@ pub inline fn callMain() u8 {
676626
677627 const result = root.main() catch |err| {
678628 switch (builtin.zig_backend) {
629 .stage2_aarch64,
679630 .stage2_powerpc,
680631 .stage2_riscv64,
681632 => {
682 std.debug.print("error: failed with error\n", .{});
633 _ = std.posix.write(std.posix.STDERR_FILENO, "error: failed with error\n") catch {};
683634 return 1;
684635 },
685636 else => {},
lib/std/testing.zig+1
......@@ -33,6 +33,7 @@ pub var log_level = std.log.Level.warn;
3333
3434// Disable printing in tests for simple backends.
3535pub const backend_can_print = switch (builtin.zig_backend) {
36 .stage2_aarch64,
3637 .stage2_powerpc,
3738 .stage2_riscv64,
3839 .stage2_spirv,
src/Compilation.zig+1-1
......@@ -1850,7 +1850,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
18501850 // approach, since the ubsan runtime uses quite a lot of the standard library
18511851 // and this reduces unnecessary bloat.
18521852 const ubsan_rt_strat: RtStrat = s: {
1853 const can_build_ubsan_rt = target_util.canBuildLibUbsanRt(target);
1853 const can_build_ubsan_rt = target_util.canBuildLibUbsanRt(target, use_llvm, build_options.have_llvm);
18541854 const want_ubsan_rt = options.want_ubsan_rt orelse (can_build_ubsan_rt and any_sanitize_c == .full and is_exe_or_dyn_lib);
18551855 if (!want_ubsan_rt) break :s .none;
18561856 if (options.skip_linker_dependencies) break :s .none;
src/InternPool.zig+10-4
......@@ -7556,12 +7556,18 @@ fn extraFuncCoerced(ip: *const InternPool, extra: Local.Extra, extra_index: u32)
75567556fn indexToKeyBigInt(ip: *const InternPool, tid: Zcu.PerThread.Id, limb_index: u32, positive: bool) Key {
75577557 const limbs_items = ip.getLocalShared(tid).getLimbs().view().items(.@"0");
75587558 const int: Int = @bitCast(limbs_items[limb_index..][0..Int.limbs_items_len].*);
7559 const big_int: BigIntConst = .{
7560 .limbs = limbs_items[limb_index + Int.limbs_items_len ..][0..int.limbs_len],
7561 .positive = positive,
7562 };
75597563 return .{ .int = .{
75607564 .ty = int.ty,
7561 .storage = .{ .big_int = .{
7562 .limbs = limbs_items[limb_index + Int.limbs_items_len ..][0..int.limbs_len],
7563 .positive = positive,
7564 } },
7565 .storage = if (big_int.toInt(u64)) |x|
7566 .{ .u64 = x }
7567 else |_| if (big_int.toInt(i64)) |x|
7568 .{ .i64 = x }
7569 else |_|
7570 .{ .big_int = big_int },
75657571 } };
75667572}
75677573
src/Sema.zig+5-4
......@@ -16522,7 +16522,7 @@ fn zirAsm(
1652216522 break :empty try sema.structInitEmpty(block, clobbers_ty, src, src);
1652316523 } else try sema.resolveInst(extra.data.clobbers); // Already coerced by AstGen.
1652416524 const clobbers_val = try sema.resolveConstDefinedValue(block, src, clobbers, .{ .simple = .clobber });
16525 needed_capacity += (asm_source.len + 3) / 4;
16525 needed_capacity += asm_source.len / 4 + 1;
1652616526
1652716527 const gpa = sema.gpa;
1652816528 try sema.air_extra.ensureUnusedCapacity(gpa, needed_capacity);
......@@ -16562,7 +16562,8 @@ fn zirAsm(
1656216562 {
1656316563 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
1656416564 @memcpy(buffer[0..asm_source.len], asm_source);
16565 sema.air_extra.items.len += (asm_source.len + 3) / 4;
16565 buffer[asm_source.len] = 0;
16566 sema.air_extra.items.len += asm_source.len / 4 + 1;
1656616567 }
1656716568 return asm_air;
1656816569}
......@@ -24846,7 +24847,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
2484624847 },
2484724848 .@"packed" => {
2484824849 const byte_offset = std.math.divExact(u32, @abs(@as(i32, actual_parent_ptr_info.packed_offset.bit_offset) +
24849 (if (zcu.typeToStruct(parent_ty)) |struct_obj| pt.structPackedFieldBitOffset(struct_obj, field_index) else 0) -
24850 (if (zcu.typeToStruct(parent_ty)) |struct_obj| zcu.structPackedFieldBitOffset(struct_obj, field_index) else 0) -
2485024851 actual_field_ptr_info.packed_offset.bit_offset), 8) catch
2485124852 return sema.fail(block, inst_src, "pointer bit-offset mismatch", .{});
2485224853 actual_parent_ptr_info.flags.alignment = actual_field_ptr_info.flags.alignment.minStrict(if (byte_offset > 0)
......@@ -24873,7 +24874,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
2487324874 // Logic lifted from type computation above - I'm just assuming it's correct.
2487424875 // `catch unreachable` since error case handled above.
2487524876 const byte_offset = std.math.divExact(u32, @abs(@as(i32, actual_parent_ptr_info.packed_offset.bit_offset) +
24876 pt.structPackedFieldBitOffset(zcu.typeToStruct(parent_ty).?, field_index) -
24877 zcu.structPackedFieldBitOffset(zcu.typeToStruct(parent_ty).?, field_index) -
2487724878 actual_field_ptr_info.packed_offset.bit_offset), 8) catch unreachable;
2487824879 const parent_ptr_val = try sema.ptrSubtract(block, field_ptr_src, field_ptr_val, byte_offset, actual_parent_ptr_ty);
2487924880 break :result Air.internedToRef(parent_ptr_val.toIntern());
src/Type.zig+1-1
......@@ -4166,7 +4166,7 @@ pub const generic_poison: Type = .{ .ip_index = .generic_poison_type };
41664166pub fn smallestUnsignedBits(max: u64) u16 {
41674167 return switch (max) {
41684168 0 => 0,
4169 else => 1 + std.math.log2_int(u64, max),
4169 else => @as(u16, 1) + std.math.log2_int(u64, max),
41704170 };
41714171}
41724172
src/Zcu.zig+24-5
......@@ -3891,6 +3891,29 @@ pub fn typeToPackedStruct(zcu: *const Zcu, ty: Type) ?InternPool.LoadedStructTyp
38913891 return s;
38923892}
38933893
3894/// https://github.com/ziglang/zig/issues/17178 explored storing these bit offsets
3895/// into the packed struct InternPool data rather than computing this on the
3896/// fly, however it was found to perform worse when measured on real world
3897/// projects.
3898pub fn structPackedFieldBitOffset(
3899 zcu: *Zcu,
3900 struct_type: InternPool.LoadedStructType,
3901 field_index: u32,
3902) u16 {
3903 const ip = &zcu.intern_pool;
3904 assert(struct_type.layout == .@"packed");
3905 assert(struct_type.haveLayout(ip));
3906 var bit_sum: u64 = 0;
3907 for (0..struct_type.field_types.len) |i| {
3908 if (i == field_index) {
3909 return @intCast(bit_sum);
3910 }
3911 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
3912 bit_sum += field_ty.bitSize(zcu);
3913 }
3914 unreachable; // index out of bounds
3915}
3916
38943917pub fn typeToUnion(zcu: *const Zcu, ty: Type) ?InternPool.LoadedUnionType {
38953918 if (ty.ip_index == .none) return null;
38963919 const ip = &zcu.intern_pool;
......@@ -4436,11 +4459,7 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu
44364459 else => false,
44374460 },
44384461 .stage2_aarch64 => switch (cc) {
4439 .aarch64_aapcs,
4440 .aarch64_aapcs_darwin,
4441 .aarch64_aapcs_win,
4442 => |opts| opts.incoming_stack_alignment == null,
4443 .naked => true,
4462 .aarch64_aapcs, .aarch64_aapcs_darwin, .naked => true,
44444463 else => false,
44454464 },
44464465 .stage2_x86 => switch (cc) {
src/Zcu/PerThread.zig+7-28
......@@ -3737,30 +3737,6 @@ pub fn intBitsForValue(pt: Zcu.PerThread, val: Value, sign: bool) u16 {
37373737 }
37383738}
37393739
3740/// https://github.com/ziglang/zig/issues/17178 explored storing these bit offsets
3741/// into the packed struct InternPool data rather than computing this on the
3742/// fly, however it was found to perform worse when measured on real world
3743/// projects.
3744pub fn structPackedFieldBitOffset(
3745 pt: Zcu.PerThread,
3746 struct_type: InternPool.LoadedStructType,
3747 field_index: u32,
3748) u16 {
3749 const zcu = pt.zcu;
3750 const ip = &zcu.intern_pool;
3751 assert(struct_type.layout == .@"packed");
3752 assert(struct_type.haveLayout(ip));
3753 var bit_sum: u64 = 0;
3754 for (0..struct_type.field_types.len) |i| {
3755 if (i == field_index) {
3756 return @intCast(bit_sum);
3757 }
3758 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
3759 bit_sum += field_ty.bitSize(zcu);
3760 }
3761 unreachable; // index out of bounds
3762}
3763
37643740pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Error!Type {
37653741 const zcu = pt.zcu;
37663742 const ip = &zcu.intern_pool;
......@@ -4381,8 +4357,11 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e
43814357 try air.legalize(pt, features);
43824358 }
43834359
4384 var liveness: Air.Liveness = try .analyze(zcu, air.*, ip);
4385 defer liveness.deinit(gpa);
4360 var liveness: ?Air.Liveness = if (codegen.wantsLiveness(pt, nav))
4361 try .analyze(zcu, air.*, ip)
4362 else
4363 null;
4364 defer if (liveness) |*l| l.deinit(gpa);
43864365
43874366 if (build_options.enable_debug_extensions and comp.verbose_air) {
43884367 const stderr = std.debug.lockStderrWriter(&.{});
......@@ -4392,12 +4371,12 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e
43924371 stderr.print("# End Function AIR: {f}\n\n", .{fqn.fmt(ip)}) catch {};
43934372 }
43944373
4395 if (std.debug.runtime_safety) {
4374 if (std.debug.runtime_safety) verify_liveness: {
43964375 var verify: Air.Liveness.Verify = .{
43974376 .gpa = gpa,
43984377 .zcu = zcu,
43994378 .air = air.*,
4400 .liveness = liveness,
4379 .liveness = liveness orelse break :verify_liveness,
44014380 .intern_pool = ip,
44024381 };
44034382 defer verify.deinit();
src/arch/aarch64/bits.zig deleted-2063
......@@ -1,2063 +0,0 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const testing = std.testing;
5
6/// Disjoint sets of registers. Every register must belong to
7/// exactly one register class.
8pub const RegisterClass = enum {
9 general_purpose,
10 stack_pointer,
11 floating_point,
12};
13
14/// Registers in the AArch64 instruction set
15pub const Register = enum(u8) {
16 // zig fmt: off
17 // 64-bit general-purpose registers
18 x0, x1, x2, x3, x4, x5, x6, x7,
19 x8, x9, x10, x11, x12, x13, x14, x15,
20 x16, x17, x18, x19, x20, x21, x22, x23,
21 x24, x25, x26, x27, x28, x29, x30, xzr,
22
23 // 32-bit general-purpose registers
24 w0, w1, w2, w3, w4, w5, w6, w7,
25 w8, w9, w10, w11, w12, w13, w14, w15,
26 w16, w17, w18, w19, w20, w21, w22, w23,
27 w24, w25, w26, w27, w28, w29, w30, wzr,
28
29 // Stack pointer
30 sp, wsp,
31
32 // 128-bit floating-point registers
33 q0, q1, q2, q3, q4, q5, q6, q7,
34 q8, q9, q10, q11, q12, q13, q14, q15,
35 q16, q17, q18, q19, q20, q21, q22, q23,
36 q24, q25, q26, q27, q28, q29, q30, q31,
37
38 // 64-bit floating-point registers
39 d0, d1, d2, d3, d4, d5, d6, d7,
40 d8, d9, d10, d11, d12, d13, d14, d15,
41 d16, d17, d18, d19, d20, d21, d22, d23,
42 d24, d25, d26, d27, d28, d29, d30, d31,
43
44 // 32-bit floating-point registers
45 s0, s1, s2, s3, s4, s5, s6, s7,
46 s8, s9, s10, s11, s12, s13, s14, s15,
47 s16, s17, s18, s19, s20, s21, s22, s23,
48 s24, s25, s26, s27, s28, s29, s30, s31,
49
50 // 16-bit floating-point registers
51 h0, h1, h2, h3, h4, h5, h6, h7,
52 h8, h9, h10, h11, h12, h13, h14, h15,
53 h16, h17, h18, h19, h20, h21, h22, h23,
54 h24, h25, h26, h27, h28, h29, h30, h31,
55
56 // 8-bit floating-point registers
57 b0, b1, b2, b3, b4, b5, b6, b7,
58 b8, b9, b10, b11, b12, b13, b14, b15,
59 b16, b17, b18, b19, b20, b21, b22, b23,
60 b24, b25, b26, b27, b28, b29, b30, b31,
61 // zig fmt: on
62
63 pub fn class(self: Register) RegisterClass {
64 return switch (@intFromEnum(self)) {
65 @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => .general_purpose,
66 @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => .general_purpose,
67
68 @intFromEnum(Register.sp) => .stack_pointer,
69 @intFromEnum(Register.wsp) => .stack_pointer,
70
71 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => .floating_point,
72 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => .floating_point,
73 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => .floating_point,
74 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => .floating_point,
75 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => .floating_point,
76 else => unreachable,
77 };
78 }
79
80 pub fn id(self: Register) u6 {
81 return switch (@intFromEnum(self)) {
82 @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.x0))),
83 @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.w0))),
84
85 @intFromEnum(Register.sp) => 32,
86 @intFromEnum(Register.wsp) => 32,
87
88 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.q0) + 33)),
89 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.d0) + 33)),
90 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.s0) + 33)),
91 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.h0) + 33)),
92 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.b0) + 33)),
93 else => unreachable,
94 };
95 }
96
97 pub fn enc(self: Register) u5 {
98 return switch (@intFromEnum(self)) {
99 @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.x0))),
100 @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.w0))),
101
102 @intFromEnum(Register.sp) => 31,
103 @intFromEnum(Register.wsp) => 31,
104
105 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.q0))),
106 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.d0))),
107 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.s0))),
108 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.h0))),
109 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.b0))),
110 else => unreachable,
111 };
112 }
113
114 /// Returns the bit-width of the register.
115 pub fn size(self: Register) u8 {
116 return switch (@intFromEnum(self)) {
117 @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => 64,
118 @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => 32,
119
120 @intFromEnum(Register.sp) => 64,
121 @intFromEnum(Register.wsp) => 32,
122
123 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => 128,
124 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => 64,
125 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => 32,
126 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => 16,
127 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => 8,
128 else => unreachable,
129 };
130 }
131
132 /// Convert from a general-purpose register to its 64 bit alias.
133 pub fn toX(self: Register) Register {
134 return switch (@intFromEnum(self)) {
135 @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => @as(
136 Register,
137 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.x0) + @intFromEnum(Register.x0)),
138 ),
139 @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => @as(
140 Register,
141 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.w0) + @intFromEnum(Register.x0)),
142 ),
143 else => unreachable,
144 };
145 }
146
147 /// Convert from a general-purpose register to its 32 bit alias.
148 pub fn toW(self: Register) Register {
149 return switch (@intFromEnum(self)) {
150 @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => @as(
151 Register,
152 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.x0) + @intFromEnum(Register.w0)),
153 ),
154 @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => @as(
155 Register,
156 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.w0) + @intFromEnum(Register.w0)),
157 ),
158 else => unreachable,
159 };
160 }
161
162 /// Convert from a floating-point register to its 128 bit alias.
163 pub fn toQ(self: Register) Register {
164 return switch (@intFromEnum(self)) {
165 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(
166 Register,
167 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.q0)),
168 ),
169 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(
170 Register,
171 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.q0)),
172 ),
173 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(
174 Register,
175 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.q0)),
176 ),
177 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(
178 Register,
179 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.q0)),
180 ),
181 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(
182 Register,
183 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.q0)),
184 ),
185 else => unreachable,
186 };
187 }
188
189 /// Convert from a floating-point register to its 64 bit alias.
190 pub fn toD(self: Register) Register {
191 return switch (@intFromEnum(self)) {
192 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(
193 Register,
194 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.d0)),
195 ),
196 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(
197 Register,
198 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.d0)),
199 ),
200 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(
201 Register,
202 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.d0)),
203 ),
204 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(
205 Register,
206 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.d0)),
207 ),
208 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(
209 Register,
210 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.d0)),
211 ),
212 else => unreachable,
213 };
214 }
215
216 /// Convert from a floating-point register to its 32 bit alias.
217 pub fn toS(self: Register) Register {
218 return switch (@intFromEnum(self)) {
219 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(
220 Register,
221 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.s0)),
222 ),
223 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(
224 Register,
225 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.s0)),
226 ),
227 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(
228 Register,
229 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.s0)),
230 ),
231 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(
232 Register,
233 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.s0)),
234 ),
235 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(
236 Register,
237 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.s0)),
238 ),
239 else => unreachable,
240 };
241 }
242
243 /// Convert from a floating-point register to its 16 bit alias.
244 pub fn toH(self: Register) Register {
245 return switch (@intFromEnum(self)) {
246 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(
247 Register,
248 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.h0)),
249 ),
250 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(
251 Register,
252 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.h0)),
253 ),
254 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(
255 Register,
256 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.h0)),
257 ),
258 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(
259 Register,
260 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.h0)),
261 ),
262 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(
263 Register,
264 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.h0)),
265 ),
266 else => unreachable,
267 };
268 }
269
270 /// Convert from a floating-point register to its 8 bit alias.
271 pub fn toB(self: Register) Register {
272 return switch (@intFromEnum(self)) {
273 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(
274 Register,
275 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.b0)),
276 ),
277 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(
278 Register,
279 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.b0)),
280 ),
281 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(
282 Register,
283 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.b0)),
284 ),
285 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(
286 Register,
287 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.b0)),
288 ),
289 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(
290 Register,
291 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.b0)),
292 ),
293 else => unreachable,
294 };
295 }
296
297 pub fn dwarfNum(self: Register) u5 {
298 return self.enc();
299 }
300};
301
302test "Register.enc" {
303 try testing.expectEqual(@as(u5, 0), Register.x0.enc());
304 try testing.expectEqual(@as(u5, 0), Register.w0.enc());
305
306 try testing.expectEqual(@as(u5, 31), Register.xzr.enc());
307 try testing.expectEqual(@as(u5, 31), Register.wzr.enc());
308
309 try testing.expectEqual(@as(u5, 31), Register.sp.enc());
310 try testing.expectEqual(@as(u5, 31), Register.sp.enc());
311}
312
313test "Register.size" {
314 try testing.expectEqual(@as(u8, 64), Register.x19.size());
315 try testing.expectEqual(@as(u8, 32), Register.w3.size());
316}
317
318test "Register.toX/toW" {
319 try testing.expectEqual(Register.x0, Register.w0.toX());
320 try testing.expectEqual(Register.x0, Register.x0.toX());
321
322 try testing.expectEqual(Register.w3, Register.w3.toW());
323 try testing.expectEqual(Register.w3, Register.x3.toW());
324}
325
326/// Represents an instruction in the AArch64 instruction set
327pub const Instruction = union(enum) {
328 move_wide_immediate: packed struct {
329 rd: u5,
330 imm16: u16,
331 hw: u2,
332 fixed: u6 = 0b100101,
333 opc: u2,
334 sf: u1,
335 },
336 pc_relative_address: packed struct {
337 rd: u5,
338 immhi: u19,
339 fixed: u5 = 0b10000,
340 immlo: u2,
341 op: u1,
342 },
343 load_store_register: packed struct {
344 rt: u5,
345 rn: u5,
346 offset: u12,
347 opc: u2,
348 op1: u2,
349 v: u1,
350 fixed: u3 = 0b111,
351 size: u2,
352 },
353 load_store_register_pair: packed struct {
354 rt1: u5,
355 rn: u5,
356 rt2: u5,
357 imm7: u7,
358 load: u1,
359 encoding: u2,
360 fixed: u5 = 0b101_0_0,
361 opc: u2,
362 },
363 load_literal: packed struct {
364 rt: u5,
365 imm19: u19,
366 fixed: u6 = 0b011_0_00,
367 opc: u2,
368 },
369 exception_generation: packed struct {
370 ll: u2,
371 op2: u3,
372 imm16: u16,
373 opc: u3,
374 fixed: u8 = 0b1101_0100,
375 },
376 unconditional_branch_register: packed struct {
377 op4: u5,
378 rn: u5,
379 op3: u6,
380 op2: u5,
381 opc: u4,
382 fixed: u7 = 0b1101_011,
383 },
384 unconditional_branch_immediate: packed struct {
385 imm26: u26,
386 fixed: u5 = 0b00101,
387 op: u1,
388 },
389 no_operation: packed struct {
390 fixed: u32 = 0b1101010100_0_00_011_0010_0000_000_11111,
391 },
392 logical_shifted_register: packed struct {
393 rd: u5,
394 rn: u5,
395 imm6: u6,
396 rm: u5,
397 n: u1,
398 shift: u2,
399 fixed: u5 = 0b01010,
400 opc: u2,
401 sf: u1,
402 },
403 add_subtract_immediate: packed struct {
404 rd: u5,
405 rn: u5,
406 imm12: u12,
407 sh: u1,
408 fixed: u6 = 0b100010,
409 s: u1,
410 op: u1,
411 sf: u1,
412 },
413 logical_immediate: packed struct {
414 rd: u5,
415 rn: u5,
416 imms: u6,
417 immr: u6,
418 n: u1,
419 fixed: u6 = 0b100100,
420 opc: u2,
421 sf: u1,
422 },
423 bitfield: packed struct {
424 rd: u5,
425 rn: u5,
426 imms: u6,
427 immr: u6,
428 n: u1,
429 fixed: u6 = 0b100110,
430 opc: u2,
431 sf: u1,
432 },
433 add_subtract_shifted_register: packed struct {
434 rd: u5,
435 rn: u5,
436 imm6: u6,
437 rm: u5,
438 fixed_1: u1 = 0b0,
439 shift: u2,
440 fixed_2: u5 = 0b01011,
441 s: u1,
442 op: u1,
443 sf: u1,
444 },
445 add_subtract_extended_register: packed struct {
446 rd: u5,
447 rn: u5,
448 imm3: u3,
449 option: u3,
450 rm: u5,
451 fixed: u8 = 0b01011_00_1,
452 s: u1,
453 op: u1,
454 sf: u1,
455 },
456 conditional_branch: struct {
457 cond: u4,
458 o0: u1,
459 imm19: u19,
460 o1: u1,
461 fixed: u7 = 0b0101010,
462 },
463 compare_and_branch: struct {
464 rt: u5,
465 imm19: u19,
466 op: u1,
467 fixed: u6 = 0b011010,
468 sf: u1,
469 },
470 conditional_select: struct {
471 rd: u5,
472 rn: u5,
473 op2: u2,
474 cond: u4,
475 rm: u5,
476 fixed: u8 = 0b11010100,
477 s: u1,
478 op: u1,
479 sf: u1,
480 },
481 data_processing_3_source: packed struct {
482 rd: u5,
483 rn: u5,
484 ra: u5,
485 o0: u1,
486 rm: u5,
487 op31: u3,
488 fixed: u5 = 0b11011,
489 op54: u2,
490 sf: u1,
491 },
492 data_processing_2_source: packed struct {
493 rd: u5,
494 rn: u5,
495 opcode: u6,
496 rm: u5,
497 fixed_1: u8 = 0b11010110,
498 s: u1,
499 fixed_2: u1 = 0b0,
500 sf: u1,
501 },
502
503 pub const Condition = enum(u4) {
504 /// Integer: Equal
505 /// Floating point: Equal
506 eq,
507 /// Integer: Not equal
508 /// Floating point: Not equal or unordered
509 ne,
510 /// Integer: Carry set
511 /// Floating point: Greater than, equal, or unordered
512 cs,
513 /// Integer: Carry clear
514 /// Floating point: Less than
515 cc,
516 /// Integer: Minus, negative
517 /// Floating point: Less than
518 mi,
519 /// Integer: Plus, positive or zero
520 /// Floating point: Greater than, equal, or unordered
521 pl,
522 /// Integer: Overflow
523 /// Floating point: Unordered
524 vs,
525 /// Integer: No overflow
526 /// Floating point: Ordered
527 vc,
528 /// Integer: Unsigned higher
529 /// Floating point: Greater than, or unordered
530 hi,
531 /// Integer: Unsigned lower or same
532 /// Floating point: Less than or equal
533 ls,
534 /// Integer: Signed greater than or equal
535 /// Floating point: Greater than or equal
536 ge,
537 /// Integer: Signed less than
538 /// Floating point: Less than, or unordered
539 lt,
540 /// Integer: Signed greater than
541 /// Floating point: Greater than
542 gt,
543 /// Integer: Signed less than or equal
544 /// Floating point: Less than, equal, or unordered
545 le,
546 /// Integer: Always
547 /// Floating point: Always
548 al,
549 /// Integer: Always
550 /// Floating point: Always
551 nv,
552
553 /// Converts a std.math.CompareOperator into a condition flag,
554 /// i.e. returns the condition that is true iff the result of the
555 /// comparison is true. Assumes signed comparison
556 pub fn fromCompareOperatorSigned(op: std.math.CompareOperator) Condition {
557 return switch (op) {
558 .gte => .ge,
559 .gt => .gt,
560 .neq => .ne,
561 .lt => .lt,
562 .lte => .le,
563 .eq => .eq,
564 };
565 }
566
567 /// Converts a std.math.CompareOperator into a condition flag,
568 /// i.e. returns the condition that is true iff the result of the
569 /// comparison is true. Assumes unsigned comparison
570 pub fn fromCompareOperatorUnsigned(op: std.math.CompareOperator) Condition {
571 return switch (op) {
572 .gte => .cs,
573 .gt => .hi,
574 .neq => .ne,
575 .lt => .cc,
576 .lte => .ls,
577 .eq => .eq,
578 };
579 }
580
581 /// Returns the condition which is true iff the given condition is
582 /// false (if such a condition exists)
583 pub fn negate(cond: Condition) Condition {
584 return switch (cond) {
585 .eq => .ne,
586 .ne => .eq,
587 .cs => .cc,
588 .cc => .cs,
589 .mi => .pl,
590 .pl => .mi,
591 .vs => .vc,
592 .vc => .vs,
593 .hi => .ls,
594 .ls => .hi,
595 .ge => .lt,
596 .lt => .ge,
597 .gt => .le,
598 .le => .gt,
599 .al => unreachable,
600 .nv => unreachable,
601 };
602 }
603 };
604
605 pub fn toU32(self: Instruction) u32 {
606 return switch (self) {
607 .move_wide_immediate => |v| @as(u32, @bitCast(v)),
608 .pc_relative_address => |v| @as(u32, @bitCast(v)),
609 .load_store_register => |v| @as(u32, @bitCast(v)),
610 .load_store_register_pair => |v| @as(u32, @bitCast(v)),
611 .load_literal => |v| @as(u32, @bitCast(v)),
612 .exception_generation => |v| @as(u32, @bitCast(v)),
613 .unconditional_branch_register => |v| @as(u32, @bitCast(v)),
614 .unconditional_branch_immediate => |v| @as(u32, @bitCast(v)),
615 .no_operation => |v| @as(u32, @bitCast(v)),
616 .logical_shifted_register => |v| @as(u32, @bitCast(v)),
617 .add_subtract_immediate => |v| @as(u32, @bitCast(v)),
618 .logical_immediate => |v| @as(u32, @bitCast(v)),
619 .bitfield => |v| @as(u32, @bitCast(v)),
620 .add_subtract_shifted_register => |v| @as(u32, @bitCast(v)),
621 .add_subtract_extended_register => |v| @as(u32, @bitCast(v)),
622 // TODO once packed structs work, this can be refactored
623 .conditional_branch => |v| @as(u32, v.cond) | (@as(u32, v.o0) << 4) | (@as(u32, v.imm19) << 5) | (@as(u32, v.o1) << 24) | (@as(u32, v.fixed) << 25),
624 .compare_and_branch => |v| @as(u32, v.rt) | (@as(u32, v.imm19) << 5) | (@as(u32, v.op) << 24) | (@as(u32, v.fixed) << 25) | (@as(u32, v.sf) << 31),
625 .conditional_select => |v| @as(u32, v.rd) | @as(u32, v.rn) << 5 | @as(u32, v.op2) << 10 | @as(u32, v.cond) << 12 | @as(u32, v.rm) << 16 | @as(u32, v.fixed) << 21 | @as(u32, v.s) << 29 | @as(u32, v.op) << 30 | @as(u32, v.sf) << 31,
626 .data_processing_3_source => |v| @as(u32, @bitCast(v)),
627 .data_processing_2_source => |v| @as(u32, @bitCast(v)),
628 };
629 }
630
631 fn moveWideImmediate(
632 opc: u2,
633 rd: Register,
634 imm16: u16,
635 shift: u6,
636 ) Instruction {
637 assert(shift % 16 == 0);
638 assert(!(rd.size() == 32 and shift > 16));
639 assert(!(rd.size() == 64 and shift > 48));
640
641 return Instruction{
642 .move_wide_immediate = .{
643 .rd = rd.enc(),
644 .imm16 = imm16,
645 .hw = @as(u2, @intCast(shift / 16)),
646 .opc = opc,
647 .sf = switch (rd.size()) {
648 32 => 0,
649 64 => 1,
650 else => unreachable, // unexpected register size
651 },
652 },
653 };
654 }
655
656 fn pcRelativeAddress(rd: Register, imm21: i21, op: u1) Instruction {
657 assert(rd.size() == 64);
658 const imm21_u = @as(u21, @bitCast(imm21));
659 return Instruction{
660 .pc_relative_address = .{
661 .rd = rd.enc(),
662 .immlo = @as(u2, @truncate(imm21_u)),
663 .immhi = @as(u19, @truncate(imm21_u >> 2)),
664 .op = op,
665 },
666 };
667 }
668
669 pub const LoadStoreOffsetImmediate = union(enum) {
670 post_index: i9,
671 pre_index: i9,
672 unsigned: u12,
673 };
674
675 pub const LoadStoreOffsetRegister = struct {
676 rm: u5,
677 shift: union(enum) {
678 uxtw: u2,
679 lsl: u2,
680 sxtw: u2,
681 sxtx: u2,
682 },
683 };
684
685 /// Represents the offset operand of a load or store instruction.
686 /// Data can be loaded from memory with either an immediate offset
687 /// or an offset that is stored in some register.
688 pub const LoadStoreOffset = union(enum) {
689 immediate: LoadStoreOffsetImmediate,
690 register: LoadStoreOffsetRegister,
691
692 pub const none = LoadStoreOffset{
693 .immediate = .{ .unsigned = 0 },
694 };
695
696 pub fn toU12(self: LoadStoreOffset) u12 {
697 return switch (self) {
698 .immediate => |imm_type| switch (imm_type) {
699 .post_index => |v| (@as(u12, @intCast(@as(u9, @bitCast(v)))) << 2) + 1,
700 .pre_index => |v| (@as(u12, @intCast(@as(u9, @bitCast(v)))) << 2) + 3,
701 .unsigned => |v| v,
702 },
703 .register => |r| switch (r.shift) {
704 .uxtw => |v| (@as(u12, @intCast(r.rm)) << 6) + (@as(u12, @intCast(v)) << 2) + 16 + 2050,
705 .lsl => |v| (@as(u12, @intCast(r.rm)) << 6) + (@as(u12, @intCast(v)) << 2) + 24 + 2050,
706 .sxtw => |v| (@as(u12, @intCast(r.rm)) << 6) + (@as(u12, @intCast(v)) << 2) + 48 + 2050,
707 .sxtx => |v| (@as(u12, @intCast(r.rm)) << 6) + (@as(u12, @intCast(v)) << 2) + 56 + 2050,
708 },
709 };
710 }
711
712 pub fn imm(offset: u12) LoadStoreOffset {
713 return .{
714 .immediate = .{ .unsigned = offset },
715 };
716 }
717
718 pub fn imm_post_index(offset: i9) LoadStoreOffset {
719 return .{
720 .immediate = .{ .post_index = offset },
721 };
722 }
723
724 pub fn imm_pre_index(offset: i9) LoadStoreOffset {
725 return .{
726 .immediate = .{ .pre_index = offset },
727 };
728 }
729
730 pub fn reg(rm: Register) LoadStoreOffset {
731 return .{
732 .register = .{
733 .rm = rm.enc(),
734 .shift = .{
735 .lsl = 0,
736 },
737 },
738 };
739 }
740
741 pub fn reg_uxtw(rm: Register, shift: u2) LoadStoreOffset {
742 assert(rm.size() == 32 and (shift == 0 or shift == 2));
743 return .{
744 .register = .{
745 .rm = rm.enc(),
746 .shift = .{
747 .uxtw = shift,
748 },
749 },
750 };
751 }
752
753 pub fn reg_lsl(rm: Register, shift: u2) LoadStoreOffset {
754 assert(rm.size() == 64 and (shift == 0 or shift == 3));
755 return .{
756 .register = .{
757 .rm = rm.enc(),
758 .shift = .{
759 .lsl = shift,
760 },
761 },
762 };
763 }
764
765 pub fn reg_sxtw(rm: Register, shift: u2) LoadStoreOffset {
766 assert(rm.size() == 32 and (shift == 0 or shift == 2));
767 return .{
768 .register = .{
769 .rm = rm.enc(),
770 .shift = .{
771 .sxtw = shift,
772 },
773 },
774 };
775 }
776
777 pub fn reg_sxtx(rm: Register, shift: u2) LoadStoreOffset {
778 assert(rm.size() == 64 and (shift == 0 or shift == 3));
779 return .{
780 .register = .{
781 .rm = rm.enc(),
782 .shift = .{
783 .sxtx = shift,
784 },
785 },
786 };
787 }
788 };
789
790 /// Which kind of load/store to perform
791 const LoadStoreVariant = enum {
792 /// 32 bits or 64 bits
793 str,
794 /// 8 bits, zero-extended
795 strb,
796 /// 16 bits, zero-extended
797 strh,
798 /// 32 bits or 64 bits
799 ldr,
800 /// 8 bits, zero-extended
801 ldrb,
802 /// 16 bits, zero-extended
803 ldrh,
804 /// 8 bits, sign extended
805 ldrsb,
806 /// 16 bits, sign extended
807 ldrsh,
808 /// 32 bits, sign extended
809 ldrsw,
810 };
811
812 fn loadStoreRegister(
813 rt: Register,
814 rn: Register,
815 offset: LoadStoreOffset,
816 variant: LoadStoreVariant,
817 ) Instruction {
818 assert(rn.size() == 64);
819 assert(rn.id() != Register.xzr.id());
820
821 const off = offset.toU12();
822
823 const op1: u2 = blk: {
824 switch (offset) {
825 .immediate => |imm| switch (imm) {
826 .unsigned => break :blk 0b01,
827 else => {},
828 },
829 else => {},
830 }
831 break :blk 0b00;
832 };
833
834 const opc: u2 = blk: {
835 switch (variant) {
836 .ldr, .ldrh, .ldrb => break :blk 0b01,
837 .str, .strh, .strb => break :blk 0b00,
838 .ldrsb,
839 .ldrsh,
840 => switch (rt.size()) {
841 32 => break :blk 0b11,
842 64 => break :blk 0b10,
843 else => unreachable, // unexpected register size
844 },
845 .ldrsw => break :blk 0b10,
846 }
847 };
848
849 const size: u2 = blk: {
850 switch (variant) {
851 .ldr, .str => switch (rt.size()) {
852 32 => break :blk 0b10,
853 64 => break :blk 0b11,
854 else => unreachable, // unexpected register size
855 },
856 .ldrsw => break :blk 0b10,
857 .ldrh, .ldrsh, .strh => break :blk 0b01,
858 .ldrb, .ldrsb, .strb => break :blk 0b00,
859 }
860 };
861
862 return Instruction{
863 .load_store_register = .{
864 .rt = rt.enc(),
865 .rn = rn.enc(),
866 .offset = off,
867 .opc = opc,
868 .op1 = op1,
869 .v = 0,
870 .size = size,
871 },
872 };
873 }
874
875 fn loadStoreRegisterPair(
876 rt1: Register,
877 rt2: Register,
878 rn: Register,
879 offset: i9,
880 encoding: u2,
881 load: bool,
882 ) Instruction {
883 assert(rn.size() == 64);
884 assert(rn.id() != Register.xzr.id());
885
886 switch (rt1.size()) {
887 32 => {
888 assert(-256 <= offset and offset <= 252);
889 const imm7 = @as(u7, @truncate(@as(u9, @bitCast(offset >> 2))));
890 return Instruction{
891 .load_store_register_pair = .{
892 .rt1 = rt1.enc(),
893 .rn = rn.enc(),
894 .rt2 = rt2.enc(),
895 .imm7 = imm7,
896 .load = @intFromBool(load),
897 .encoding = encoding,
898 .opc = 0b00,
899 },
900 };
901 },
902 64 => {
903 assert(-512 <= offset and offset <= 504);
904 const imm7 = @as(u7, @truncate(@as(u9, @bitCast(offset >> 3))));
905 return Instruction{
906 .load_store_register_pair = .{
907 .rt1 = rt1.enc(),
908 .rn = rn.enc(),
909 .rt2 = rt2.enc(),
910 .imm7 = imm7,
911 .load = @intFromBool(load),
912 .encoding = encoding,
913 .opc = 0b10,
914 },
915 };
916 },
917 else => unreachable, // unexpected register size
918 }
919 }
920
921 fn loadLiteral(rt: Register, imm19: u19) Instruction {
922 return Instruction{
923 .load_literal = .{
924 .rt = rt.enc(),
925 .imm19 = imm19,
926 .opc = switch (rt.size()) {
927 32 => 0b00,
928 64 => 0b01,
929 else => unreachable, // unexpected register size
930 },
931 },
932 };
933 }
934
935 fn exceptionGeneration(
936 opc: u3,
937 op2: u3,
938 ll: u2,
939 imm16: u16,
940 ) Instruction {
941 return Instruction{
942 .exception_generation = .{
943 .ll = ll,
944 .op2 = op2,
945 .imm16 = imm16,
946 .opc = opc,
947 },
948 };
949 }
950
951 fn unconditionalBranchRegister(
952 opc: u4,
953 op2: u5,
954 op3: u6,
955 rn: Register,
956 op4: u5,
957 ) Instruction {
958 assert(rn.size() == 64);
959
960 return Instruction{
961 .unconditional_branch_register = .{
962 .op4 = op4,
963 .rn = rn.enc(),
964 .op3 = op3,
965 .op2 = op2,
966 .opc = opc,
967 },
968 };
969 }
970
971 fn unconditionalBranchImmediate(
972 op: u1,
973 offset: i28,
974 ) Instruction {
975 return Instruction{
976 .unconditional_branch_immediate = .{
977 .imm26 = @as(u26, @bitCast(@as(i26, @intCast(offset >> 2)))),
978 .op = op,
979 },
980 };
981 }
982
983 pub const LogicalShiftedRegisterShift = enum(u2) { lsl, lsr, asr, ror };
984
985 fn logicalShiftedRegister(
986 opc: u2,
987 n: u1,
988 rd: Register,
989 rn: Register,
990 rm: Register,
991 shift: LogicalShiftedRegisterShift,
992 amount: u6,
993 ) Instruction {
994 assert(rd.size() == rn.size());
995 assert(rd.size() == rm.size());
996 if (rd.size() == 32) assert(amount < 32);
997
998 return Instruction{
999 .logical_shifted_register = .{
1000 .rd = rd.enc(),
1001 .rn = rn.enc(),
1002 .imm6 = amount,
1003 .rm = rm.enc(),
1004 .n = n,
1005 .shift = @intFromEnum(shift),
1006 .opc = opc,
1007 .sf = switch (rd.size()) {
1008 32 => 0b0,
1009 64 => 0b1,
1010 else => unreachable,
1011 },
1012 },
1013 };
1014 }
1015
1016 fn addSubtractImmediate(
1017 op: u1,
1018 s: u1,
1019 rd: Register,
1020 rn: Register,
1021 imm12: u12,
1022 shift: bool,
1023 ) Instruction {
1024 assert(rd.size() == rn.size());
1025 assert(rn.id() != Register.xzr.id());
1026
1027 return Instruction{
1028 .add_subtract_immediate = .{
1029 .rd = rd.enc(),
1030 .rn = rn.enc(),
1031 .imm12 = imm12,
1032 .sh = @intFromBool(shift),
1033 .s = s,
1034 .op = op,
1035 .sf = switch (rd.size()) {
1036 32 => 0b0,
1037 64 => 0b1,
1038 else => unreachable, // unexpected register size
1039 },
1040 },
1041 };
1042 }
1043
1044 fn logicalImmediate(
1045 opc: u2,
1046 rd: Register,
1047 rn: Register,
1048 imms: u6,
1049 immr: u6,
1050 n: u1,
1051 ) Instruction {
1052 assert(rd.size() == rn.size());
1053 assert(!(rd.size() == 32 and n != 0));
1054
1055 return Instruction{
1056 .logical_immediate = .{
1057 .rd = rd.enc(),
1058 .rn = rn.enc(),
1059 .imms = imms,
1060 .immr = immr,
1061 .n = n,
1062 .opc = opc,
1063 .sf = switch (rd.size()) {
1064 32 => 0b0,
1065 64 => 0b1,
1066 else => unreachable, // unexpected register size
1067 },
1068 },
1069 };
1070 }
1071
1072 fn initBitfield(
1073 opc: u2,
1074 n: u1,
1075 rd: Register,
1076 rn: Register,
1077 immr: u6,
1078 imms: u6,
1079 ) Instruction {
1080 assert(rd.size() == rn.size());
1081 assert(!(rd.size() == 64 and n != 1));
1082 assert(!(rd.size() == 32 and (n != 0 or immr >> 5 != 0 or immr >> 5 != 0)));
1083
1084 return Instruction{
1085 .bitfield = .{
1086 .rd = rd.enc(),
1087 .rn = rn.enc(),
1088 .imms = imms,
1089 .immr = immr,
1090 .n = n,
1091 .opc = opc,
1092 .sf = switch (rd.size()) {
1093 32 => 0b0,
1094 64 => 0b1,
1095 else => unreachable, // unexpected register size
1096 },
1097 },
1098 };
1099 }
1100
1101 pub const AddSubtractShiftedRegisterShift = enum(u2) { lsl, lsr, asr, _ };
1102
1103 fn addSubtractShiftedRegister(
1104 op: u1,
1105 s: u1,
1106 shift: AddSubtractShiftedRegisterShift,
1107 rd: Register,
1108 rn: Register,
1109 rm: Register,
1110 imm6: u6,
1111 ) Instruction {
1112 assert(rd.size() == rn.size());
1113 assert(rd.size() == rm.size());
1114
1115 return Instruction{
1116 .add_subtract_shifted_register = .{
1117 .rd = rd.enc(),
1118 .rn = rn.enc(),
1119 .imm6 = imm6,
1120 .rm = rm.enc(),
1121 .shift = @intFromEnum(shift),
1122 .s = s,
1123 .op = op,
1124 .sf = switch (rd.size()) {
1125 32 => 0b0,
1126 64 => 0b1,
1127 else => unreachable, // unexpected register size
1128 },
1129 },
1130 };
1131 }
1132
1133 pub const AddSubtractExtendedRegisterOption = enum(u3) {
1134 uxtb,
1135 uxth,
1136 uxtw,
1137 uxtx, // serves also as lsl
1138 sxtb,
1139 sxth,
1140 sxtw,
1141 sxtx,
1142 };
1143
1144 fn addSubtractExtendedRegister(
1145 op: u1,
1146 s: u1,
1147 rd: Register,
1148 rn: Register,
1149 rm: Register,
1150 extend: AddSubtractExtendedRegisterOption,
1151 imm3: u3,
1152 ) Instruction {
1153 return Instruction{
1154 .add_subtract_extended_register = .{
1155 .rd = rd.enc(),
1156 .rn = rn.enc(),
1157 .imm3 = imm3,
1158 .option = @intFromEnum(extend),
1159 .rm = rm.enc(),
1160 .s = s,
1161 .op = op,
1162 .sf = switch (rd.size()) {
1163 32 => 0b0,
1164 64 => 0b1,
1165 else => unreachable, // unexpected register size
1166 },
1167 },
1168 };
1169 }
1170
1171 fn conditionalBranch(
1172 o0: u1,
1173 o1: u1,
1174 cond: Condition,
1175 offset: i21,
1176 ) Instruction {
1177 assert(offset & 0b11 == 0b00);
1178
1179 return Instruction{
1180 .conditional_branch = .{
1181 .cond = @intFromEnum(cond),
1182 .o0 = o0,
1183 .imm19 = @as(u19, @bitCast(@as(i19, @intCast(offset >> 2)))),
1184 .o1 = o1,
1185 },
1186 };
1187 }
1188
1189 fn compareAndBranch(
1190 op: u1,
1191 rt: Register,
1192 offset: i21,
1193 ) Instruction {
1194 assert(offset & 0b11 == 0b00);
1195
1196 return Instruction{
1197 .compare_and_branch = .{
1198 .rt = rt.enc(),
1199 .imm19 = @as(u19, @bitCast(@as(i19, @intCast(offset >> 2)))),
1200 .op = op,
1201 .sf = switch (rt.size()) {
1202 32 => 0b0,
1203 64 => 0b1,
1204 else => unreachable, // unexpected register size
1205 },
1206 },
1207 };
1208 }
1209
1210 fn conditionalSelect(
1211 op2: u2,
1212 op: u1,
1213 s: u1,
1214 rd: Register,
1215 rn: Register,
1216 rm: Register,
1217 cond: Condition,
1218 ) Instruction {
1219 assert(rd.size() == rn.size());
1220 assert(rd.size() == rm.size());
1221
1222 return Instruction{
1223 .conditional_select = .{
1224 .rd = rd.enc(),
1225 .rn = rn.enc(),
1226 .op2 = op2,
1227 .cond = @intFromEnum(cond),
1228 .rm = rm.enc(),
1229 .s = s,
1230 .op = op,
1231 .sf = switch (rd.size()) {
1232 32 => 0b0,
1233 64 => 0b1,
1234 else => unreachable, // unexpected register size
1235 },
1236 },
1237 };
1238 }
1239
1240 fn dataProcessing3Source(
1241 op54: u2,
1242 op31: u3,
1243 o0: u1,
1244 rd: Register,
1245 rn: Register,
1246 rm: Register,
1247 ra: Register,
1248 ) Instruction {
1249 return Instruction{
1250 .data_processing_3_source = .{
1251 .rd = rd.enc(),
1252 .rn = rn.enc(),
1253 .ra = ra.enc(),
1254 .o0 = o0,
1255 .rm = rm.enc(),
1256 .op31 = op31,
1257 .op54 = op54,
1258 .sf = switch (rd.size()) {
1259 32 => 0b0,
1260 64 => 0b1,
1261 else => unreachable, // unexpected register size
1262 },
1263 },
1264 };
1265 }
1266
1267 fn dataProcessing2Source(
1268 s: u1,
1269 opcode: u6,
1270 rd: Register,
1271 rn: Register,
1272 rm: Register,
1273 ) Instruction {
1274 assert(rd.size() == rn.size());
1275 assert(rd.size() == rm.size());
1276
1277 return Instruction{
1278 .data_processing_2_source = .{
1279 .rd = rd.enc(),
1280 .rn = rn.enc(),
1281 .opcode = opcode,
1282 .rm = rm.enc(),
1283 .s = s,
1284 .sf = switch (rd.size()) {
1285 32 => 0b0,
1286 64 => 0b1,
1287 else => unreachable, // unexpected register size
1288 },
1289 },
1290 };
1291 }
1292
1293 // Helper functions for assembly syntax functions
1294
1295 // Move wide (immediate)
1296
1297 pub fn movn(rd: Register, imm16: u16, shift: u6) Instruction {
1298 return moveWideImmediate(0b00, rd, imm16, shift);
1299 }
1300
1301 pub fn movz(rd: Register, imm16: u16, shift: u6) Instruction {
1302 return moveWideImmediate(0b10, rd, imm16, shift);
1303 }
1304
1305 pub fn movk(rd: Register, imm16: u16, shift: u6) Instruction {
1306 return moveWideImmediate(0b11, rd, imm16, shift);
1307 }
1308
1309 // PC relative address
1310
1311 pub fn adr(rd: Register, imm21: i21) Instruction {
1312 return pcRelativeAddress(rd, imm21, 0b0);
1313 }
1314
1315 pub fn adrp(rd: Register, imm21: i21) Instruction {
1316 return pcRelativeAddress(rd, imm21, 0b1);
1317 }
1318
1319 // Load or store register
1320
1321 pub fn ldrLiteral(rt: Register, literal: u19) Instruction {
1322 return loadLiteral(rt, literal);
1323 }
1324
1325 pub fn ldr(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1326 return loadStoreRegister(rt, rn, offset, .ldr);
1327 }
1328
1329 pub fn ldrh(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1330 return loadStoreRegister(rt, rn, offset, .ldrh);
1331 }
1332
1333 pub fn ldrb(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1334 return loadStoreRegister(rt, rn, offset, .ldrb);
1335 }
1336
1337 pub fn ldrsb(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1338 return loadStoreRegister(rt, rn, offset, .ldrsb);
1339 }
1340
1341 pub fn ldrsh(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1342 return loadStoreRegister(rt, rn, offset, .ldrsh);
1343 }
1344
1345 pub fn ldrsw(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1346 return loadStoreRegister(rt, rn, offset, .ldrsw);
1347 }
1348
1349 pub fn str(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1350 return loadStoreRegister(rt, rn, offset, .str);
1351 }
1352
1353 pub fn strh(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1354 return loadStoreRegister(rt, rn, offset, .strh);
1355 }
1356
1357 pub fn strb(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1358 return loadStoreRegister(rt, rn, offset, .strb);
1359 }
1360
1361 // Load or store pair of registers
1362
1363 pub const LoadStorePairOffset = struct {
1364 encoding: enum(u2) {
1365 post_index = 0b01,
1366 signed = 0b10,
1367 pre_index = 0b11,
1368 },
1369 offset: i9,
1370
1371 pub fn none() LoadStorePairOffset {
1372 return .{ .encoding = .signed, .offset = 0 };
1373 }
1374
1375 pub fn post_index(imm: i9) LoadStorePairOffset {
1376 return .{ .encoding = .post_index, .offset = imm };
1377 }
1378
1379 pub fn pre_index(imm: i9) LoadStorePairOffset {
1380 return .{ .encoding = .pre_index, .offset = imm };
1381 }
1382
1383 pub fn signed(imm: i9) LoadStorePairOffset {
1384 return .{ .encoding = .signed, .offset = imm };
1385 }
1386 };
1387
1388 pub fn ldp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction {
1389 return loadStoreRegisterPair(rt1, rt2, rn, offset.offset, @intFromEnum(offset.encoding), true);
1390 }
1391
1392 pub fn ldnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction {
1393 return loadStoreRegisterPair(rt1, rt2, rn, offset, 0, true);
1394 }
1395
1396 pub fn stp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction {
1397 return loadStoreRegisterPair(rt1, rt2, rn, offset.offset, @intFromEnum(offset.encoding), false);
1398 }
1399
1400 pub fn stnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction {
1401 return loadStoreRegisterPair(rt1, rt2, rn, offset, 0, false);
1402 }
1403
1404 // Exception generation
1405
1406 pub fn svc(imm16: u16) Instruction {
1407 return exceptionGeneration(0b000, 0b000, 0b01, imm16);
1408 }
1409
1410 pub fn hvc(imm16: u16) Instruction {
1411 return exceptionGeneration(0b000, 0b000, 0b10, imm16);
1412 }
1413
1414 pub fn smc(imm16: u16) Instruction {
1415 return exceptionGeneration(0b000, 0b000, 0b11, imm16);
1416 }
1417
1418 pub fn brk(imm16: u16) Instruction {
1419 return exceptionGeneration(0b001, 0b000, 0b00, imm16);
1420 }
1421
1422 pub fn hlt(imm16: u16) Instruction {
1423 return exceptionGeneration(0b010, 0b000, 0b00, imm16);
1424 }
1425
1426 // Unconditional branch (register)
1427
1428 pub fn br(rn: Register) Instruction {
1429 return unconditionalBranchRegister(0b0000, 0b11111, 0b000000, rn, 0b00000);
1430 }
1431
1432 pub fn blr(rn: Register) Instruction {
1433 return unconditionalBranchRegister(0b0001, 0b11111, 0b000000, rn, 0b00000);
1434 }
1435
1436 pub fn ret(rn: ?Register) Instruction {
1437 return unconditionalBranchRegister(0b0010, 0b11111, 0b000000, rn orelse .x30, 0b00000);
1438 }
1439
1440 // Unconditional branch (immediate)
1441
1442 pub fn b(offset: i28) Instruction {
1443 return unconditionalBranchImmediate(0, offset);
1444 }
1445
1446 pub fn bl(offset: i28) Instruction {
1447 return unconditionalBranchImmediate(1, offset);
1448 }
1449
1450 // Nop
1451
1452 pub fn nop() Instruction {
1453 return Instruction{ .no_operation = .{} };
1454 }
1455
1456 // Logical (shifted register)
1457
1458 pub fn andShiftedRegister(
1459 rd: Register,
1460 rn: Register,
1461 rm: Register,
1462 shift: LogicalShiftedRegisterShift,
1463 amount: u6,
1464 ) Instruction {
1465 return logicalShiftedRegister(0b00, 0b0, rd, rn, rm, shift, amount);
1466 }
1467
1468 pub fn bicShiftedRegister(
1469 rd: Register,
1470 rn: Register,
1471 rm: Register,
1472 shift: LogicalShiftedRegisterShift,
1473 amount: u6,
1474 ) Instruction {
1475 return logicalShiftedRegister(0b00, 0b1, rd, rn, rm, shift, amount);
1476 }
1477
1478 pub fn orrShiftedRegister(
1479 rd: Register,
1480 rn: Register,
1481 rm: Register,
1482 shift: LogicalShiftedRegisterShift,
1483 amount: u6,
1484 ) Instruction {
1485 return logicalShiftedRegister(0b01, 0b0, rd, rn, rm, shift, amount);
1486 }
1487
1488 pub fn ornShiftedRegister(
1489 rd: Register,
1490 rn: Register,
1491 rm: Register,
1492 shift: LogicalShiftedRegisterShift,
1493 amount: u6,
1494 ) Instruction {
1495 return logicalShiftedRegister(0b01, 0b1, rd, rn, rm, shift, amount);
1496 }
1497
1498 pub fn eorShiftedRegister(
1499 rd: Register,
1500 rn: Register,
1501 rm: Register,
1502 shift: LogicalShiftedRegisterShift,
1503 amount: u6,
1504 ) Instruction {
1505 return logicalShiftedRegister(0b10, 0b0, rd, rn, rm, shift, amount);
1506 }
1507
1508 pub fn eonShiftedRegister(
1509 rd: Register,
1510 rn: Register,
1511 rm: Register,
1512 shift: LogicalShiftedRegisterShift,
1513 amount: u6,
1514 ) Instruction {
1515 return logicalShiftedRegister(0b10, 0b1, rd, rn, rm, shift, amount);
1516 }
1517
1518 pub fn andsShiftedRegister(
1519 rd: Register,
1520 rn: Register,
1521 rm: Register,
1522 shift: LogicalShiftedRegisterShift,
1523 amount: u6,
1524 ) Instruction {
1525 return logicalShiftedRegister(0b11, 0b0, rd, rn, rm, shift, amount);
1526 }
1527
1528 pub fn bicsShiftedRegister(
1529 rd: Register,
1530 rn: Register,
1531 rm: Register,
1532 shift: LogicalShiftedRegisterShift,
1533 amount: u6,
1534 ) Instruction {
1535 return logicalShiftedRegister(0b11, 0b1, rd, rn, rm, shift, amount);
1536 }
1537
1538 // Add/subtract (immediate)
1539
1540 pub fn add(rd: Register, rn: Register, imm: u12, shift: bool) Instruction {
1541 return addSubtractImmediate(0b0, 0b0, rd, rn, imm, shift);
1542 }
1543
1544 pub fn adds(rd: Register, rn: Register, imm: u12, shift: bool) Instruction {
1545 return addSubtractImmediate(0b0, 0b1, rd, rn, imm, shift);
1546 }
1547
1548 pub fn sub(rd: Register, rn: Register, imm: u12, shift: bool) Instruction {
1549 return addSubtractImmediate(0b1, 0b0, rd, rn, imm, shift);
1550 }
1551
1552 pub fn subs(rd: Register, rn: Register, imm: u12, shift: bool) Instruction {
1553 return addSubtractImmediate(0b1, 0b1, rd, rn, imm, shift);
1554 }
1555
1556 // Logical (immediate)
1557
1558 pub fn andImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction {
1559 return logicalImmediate(0b00, rd, rn, imms, immr, n);
1560 }
1561
1562 pub fn orrImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction {
1563 return logicalImmediate(0b01, rd, rn, imms, immr, n);
1564 }
1565
1566 pub fn eorImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction {
1567 return logicalImmediate(0b10, rd, rn, imms, immr, n);
1568 }
1569
1570 pub fn andsImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction {
1571 return logicalImmediate(0b11, rd, rn, imms, immr, n);
1572 }
1573
1574 // Bitfield
1575
1576 pub fn sbfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction {
1577 const n: u1 = switch (rd.size()) {
1578 32 => 0b0,
1579 64 => 0b1,
1580 else => unreachable, // unexpected register size
1581 };
1582 return initBitfield(0b00, n, rd, rn, immr, imms);
1583 }
1584
1585 pub fn bfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction {
1586 const n: u1 = switch (rd.size()) {
1587 32 => 0b0,
1588 64 => 0b1,
1589 else => unreachable, // unexpected register size
1590 };
1591 return initBitfield(0b01, n, rd, rn, immr, imms);
1592 }
1593
1594 pub fn ubfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction {
1595 const n: u1 = switch (rd.size()) {
1596 32 => 0b0,
1597 64 => 0b1,
1598 else => unreachable, // unexpected register size
1599 };
1600 return initBitfield(0b10, n, rd, rn, immr, imms);
1601 }
1602
1603 pub fn asrImmediate(rd: Register, rn: Register, shift: u6) Instruction {
1604 const imms = @as(u6, @intCast(rd.size() - 1));
1605 return sbfm(rd, rn, shift, imms);
1606 }
1607
1608 pub fn sbfx(rd: Register, rn: Register, lsb: u6, width: u7) Instruction {
1609 return sbfm(rd, rn, lsb, @as(u6, @intCast(lsb + width - 1)));
1610 }
1611
1612 pub fn sxtb(rd: Register, rn: Register) Instruction {
1613 return sbfm(rd, rn, 0, 7);
1614 }
1615
1616 pub fn sxth(rd: Register, rn: Register) Instruction {
1617 return sbfm(rd, rn, 0, 15);
1618 }
1619
1620 pub fn sxtw(rd: Register, rn: Register) Instruction {
1621 assert(rd.size() == 64);
1622 return sbfm(rd, rn, 0, 31);
1623 }
1624
1625 pub fn lslImmediate(rd: Register, rn: Register, shift: u6) Instruction {
1626 const size = @as(u6, @intCast(rd.size() - 1));
1627 return ubfm(rd, rn, size - shift + 1, size - shift);
1628 }
1629
1630 pub fn lsrImmediate(rd: Register, rn: Register, shift: u6) Instruction {
1631 const imms = @as(u6, @intCast(rd.size() - 1));
1632 return ubfm(rd, rn, shift, imms);
1633 }
1634
1635 pub fn ubfx(rd: Register, rn: Register, lsb: u6, width: u7) Instruction {
1636 return ubfm(rd, rn, lsb, @as(u6, @intCast(lsb + width - 1)));
1637 }
1638
1639 pub fn uxtb(rd: Register, rn: Register) Instruction {
1640 return ubfm(rd, rn, 0, 7);
1641 }
1642
1643 pub fn uxth(rd: Register, rn: Register) Instruction {
1644 return ubfm(rd, rn, 0, 15);
1645 }
1646
1647 // Add/subtract (shifted register)
1648
1649 pub fn addShiftedRegister(
1650 rd: Register,
1651 rn: Register,
1652 rm: Register,
1653 shift: AddSubtractShiftedRegisterShift,
1654 imm6: u6,
1655 ) Instruction {
1656 return addSubtractShiftedRegister(0b0, 0b0, shift, rd, rn, rm, imm6);
1657 }
1658
1659 pub fn addsShiftedRegister(
1660 rd: Register,
1661 rn: Register,
1662 rm: Register,
1663 shift: AddSubtractShiftedRegisterShift,
1664 imm6: u6,
1665 ) Instruction {
1666 return addSubtractShiftedRegister(0b0, 0b1, shift, rd, rn, rm, imm6);
1667 }
1668
1669 pub fn subShiftedRegister(
1670 rd: Register,
1671 rn: Register,
1672 rm: Register,
1673 shift: AddSubtractShiftedRegisterShift,
1674 imm6: u6,
1675 ) Instruction {
1676 return addSubtractShiftedRegister(0b1, 0b0, shift, rd, rn, rm, imm6);
1677 }
1678
1679 pub fn subsShiftedRegister(
1680 rd: Register,
1681 rn: Register,
1682 rm: Register,
1683 shift: AddSubtractShiftedRegisterShift,
1684 imm6: u6,
1685 ) Instruction {
1686 return addSubtractShiftedRegister(0b1, 0b1, shift, rd, rn, rm, imm6);
1687 }
1688
1689 // Add/subtract (extended register)
1690
1691 pub fn addExtendedRegister(
1692 rd: Register,
1693 rn: Register,
1694 rm: Register,
1695 extend: AddSubtractExtendedRegisterOption,
1696 imm3: u3,
1697 ) Instruction {
1698 return addSubtractExtendedRegister(0b0, 0b0, rd, rn, rm, extend, imm3);
1699 }
1700
1701 pub fn addsExtendedRegister(
1702 rd: Register,
1703 rn: Register,
1704 rm: Register,
1705 extend: AddSubtractExtendedRegisterOption,
1706 imm3: u3,
1707 ) Instruction {
1708 return addSubtractExtendedRegister(0b0, 0b1, rd, rn, rm, extend, imm3);
1709 }
1710
1711 pub fn subExtendedRegister(
1712 rd: Register,
1713 rn: Register,
1714 rm: Register,
1715 extend: AddSubtractExtendedRegisterOption,
1716 imm3: u3,
1717 ) Instruction {
1718 return addSubtractExtendedRegister(0b1, 0b0, rd, rn, rm, extend, imm3);
1719 }
1720
1721 pub fn subsExtendedRegister(
1722 rd: Register,
1723 rn: Register,
1724 rm: Register,
1725 extend: AddSubtractExtendedRegisterOption,
1726 imm3: u3,
1727 ) Instruction {
1728 return addSubtractExtendedRegister(0b1, 0b1, rd, rn, rm, extend, imm3);
1729 }
1730
1731 // Conditional branch
1732
1733 pub fn bCond(cond: Condition, offset: i21) Instruction {
1734 return conditionalBranch(0b0, 0b0, cond, offset);
1735 }
1736
1737 // Compare and branch
1738
1739 pub fn cbz(rt: Register, offset: i21) Instruction {
1740 return compareAndBranch(0b0, rt, offset);
1741 }
1742
1743 pub fn cbnz(rt: Register, offset: i21) Instruction {
1744 return compareAndBranch(0b1, rt, offset);
1745 }
1746
1747 // Conditional select
1748
1749 pub fn csel(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction {
1750 return conditionalSelect(0b00, 0b0, 0b0, rd, rn, rm, cond);
1751 }
1752
1753 pub fn csinc(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction {
1754 return conditionalSelect(0b01, 0b0, 0b0, rd, rn, rm, cond);
1755 }
1756
1757 pub fn csinv(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction {
1758 return conditionalSelect(0b00, 0b1, 0b0, rd, rn, rm, cond);
1759 }
1760
1761 pub fn csneg(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction {
1762 return conditionalSelect(0b01, 0b1, 0b0, rd, rn, rm, cond);
1763 }
1764
1765 // Data processing (3 source)
1766
1767 pub fn madd(rd: Register, rn: Register, rm: Register, ra: Register) Instruction {
1768 return dataProcessing3Source(0b00, 0b000, 0b0, rd, rn, rm, ra);
1769 }
1770
1771 pub fn smaddl(rd: Register, rn: Register, rm: Register, ra: Register) Instruction {
1772 assert(rd.size() == 64 and rn.size() == 32 and rm.size() == 32 and ra.size() == 64);
1773 return dataProcessing3Source(0b00, 0b001, 0b0, rd, rn, rm, ra);
1774 }
1775
1776 pub fn umaddl(rd: Register, rn: Register, rm: Register, ra: Register) Instruction {
1777 assert(rd.size() == 64 and rn.size() == 32 and rm.size() == 32 and ra.size() == 64);
1778 return dataProcessing3Source(0b00, 0b101, 0b0, rd, rn, rm, ra);
1779 }
1780
1781 pub fn msub(rd: Register, rn: Register, rm: Register, ra: Register) Instruction {
1782 return dataProcessing3Source(0b00, 0b000, 0b1, rd, rn, rm, ra);
1783 }
1784
1785 pub fn mul(rd: Register, rn: Register, rm: Register) Instruction {
1786 return madd(rd, rn, rm, .xzr);
1787 }
1788
1789 pub fn smull(rd: Register, rn: Register, rm: Register) Instruction {
1790 return smaddl(rd, rn, rm, .xzr);
1791 }
1792
1793 pub fn smulh(rd: Register, rn: Register, rm: Register) Instruction {
1794 assert(rd.size() == 64);
1795 return dataProcessing3Source(0b00, 0b010, 0b0, rd, rn, rm, .xzr);
1796 }
1797
1798 pub fn umull(rd: Register, rn: Register, rm: Register) Instruction {
1799 return umaddl(rd, rn, rm, .xzr);
1800 }
1801
1802 pub fn umulh(rd: Register, rn: Register, rm: Register) Instruction {
1803 assert(rd.size() == 64);
1804 return dataProcessing3Source(0b00, 0b110, 0b0, rd, rn, rm, .xzr);
1805 }
1806
1807 pub fn mneg(rd: Register, rn: Register, rm: Register) Instruction {
1808 return msub(rd, rn, rm, .xzr);
1809 }
1810
1811 // Data processing (2 source)
1812
1813 pub fn udiv(rd: Register, rn: Register, rm: Register) Instruction {
1814 return dataProcessing2Source(0b0, 0b000010, rd, rn, rm);
1815 }
1816
1817 pub fn sdiv(rd: Register, rn: Register, rm: Register) Instruction {
1818 return dataProcessing2Source(0b0, 0b000011, rd, rn, rm);
1819 }
1820
1821 pub fn lslv(rd: Register, rn: Register, rm: Register) Instruction {
1822 return dataProcessing2Source(0b0, 0b001000, rd, rn, rm);
1823 }
1824
1825 pub fn lsrv(rd: Register, rn: Register, rm: Register) Instruction {
1826 return dataProcessing2Source(0b0, 0b001001, rd, rn, rm);
1827 }
1828
1829 pub fn asrv(rd: Register, rn: Register, rm: Register) Instruction {
1830 return dataProcessing2Source(0b0, 0b001010, rd, rn, rm);
1831 }
1832
1833 pub const asrRegister = asrv;
1834 pub const lslRegister = lslv;
1835 pub const lsrRegister = lsrv;
1836};
1837
1838test {
1839 testing.refAllDecls(@This());
1840}
1841
1842test "serialize instructions" {
1843 const Testcase = struct {
1844 inst: Instruction,
1845 expected: u32,
1846 };
1847
1848 const testcases = [_]Testcase{
1849 .{ // orr x0, xzr, x1
1850 .inst = Instruction.orrShiftedRegister(.x0, .xzr, .x1, .lsl, 0),
1851 .expected = 0b1_01_01010_00_0_00001_000000_11111_00000,
1852 },
1853 .{ // orn x0, xzr, x1
1854 .inst = Instruction.ornShiftedRegister(.x0, .xzr, .x1, .lsl, 0),
1855 .expected = 0b1_01_01010_00_1_00001_000000_11111_00000,
1856 },
1857 .{ // movz x1, #4
1858 .inst = Instruction.movz(.x1, 4, 0),
1859 .expected = 0b1_10_100101_00_0000000000000100_00001,
1860 },
1861 .{ // movz x1, #4, lsl 16
1862 .inst = Instruction.movz(.x1, 4, 16),
1863 .expected = 0b1_10_100101_01_0000000000000100_00001,
1864 },
1865 .{ // movz x1, #4, lsl 32
1866 .inst = Instruction.movz(.x1, 4, 32),
1867 .expected = 0b1_10_100101_10_0000000000000100_00001,
1868 },
1869 .{ // movz x1, #4, lsl 48
1870 .inst = Instruction.movz(.x1, 4, 48),
1871 .expected = 0b1_10_100101_11_0000000000000100_00001,
1872 },
1873 .{ // movz w1, #4
1874 .inst = Instruction.movz(.w1, 4, 0),
1875 .expected = 0b0_10_100101_00_0000000000000100_00001,
1876 },
1877 .{ // movz w1, #4, lsl 16
1878 .inst = Instruction.movz(.w1, 4, 16),
1879 .expected = 0b0_10_100101_01_0000000000000100_00001,
1880 },
1881 .{ // svc #0
1882 .inst = Instruction.svc(0),
1883 .expected = 0b1101_0100_000_0000000000000000_00001,
1884 },
1885 .{ // svc #0x80 ; typical on Darwin
1886 .inst = Instruction.svc(0x80),
1887 .expected = 0b1101_0100_000_0000000010000000_00001,
1888 },
1889 .{ // ret
1890 .inst = Instruction.ret(null),
1891 .expected = 0b1101_011_00_10_11111_0000_00_11110_00000,
1892 },
1893 .{ // bl #0x10
1894 .inst = Instruction.bl(0x10),
1895 .expected = 0b1_00101_00_0000_0000_0000_0000_0000_0100,
1896 },
1897 .{ // ldr x2, [x1]
1898 .inst = Instruction.ldr(.x2, .x1, Instruction.LoadStoreOffset.none),
1899 .expected = 0b11_111_0_01_01_000000000000_00001_00010,
1900 },
1901 .{ // ldr x2, [x1, #1]!
1902 .inst = Instruction.ldr(.x2, .x1, Instruction.LoadStoreOffset.imm_pre_index(1)),
1903 .expected = 0b11_111_0_00_01_0_000000001_11_00001_00010,
1904 },
1905 .{ // ldr x2, [x1], #-1
1906 .inst = Instruction.ldr(.x2, .x1, Instruction.LoadStoreOffset.imm_post_index(-1)),
1907 .expected = 0b11_111_0_00_01_0_111111111_01_00001_00010,
1908 },
1909 .{ // ldr x2, [x1], (x3)
1910 .inst = Instruction.ldr(.x2, .x1, Instruction.LoadStoreOffset.reg(.x3)),
1911 .expected = 0b11_111_0_00_01_1_00011_011_0_10_00001_00010,
1912 },
1913 .{ // ldr x2, label
1914 .inst = Instruction.ldrLiteral(.x2, 0x1),
1915 .expected = 0b01_011_0_00_0000000000000000001_00010,
1916 },
1917 .{ // ldrh x7, [x4], #0xaa
1918 .inst = Instruction.ldrh(.x7, .x4, Instruction.LoadStoreOffset.imm_post_index(0xaa)),
1919 .expected = 0b01_111_0_00_01_0_010101010_01_00100_00111,
1920 },
1921 .{ // ldrb x9, [x15, #0xff]!
1922 .inst = Instruction.ldrb(.x9, .x15, Instruction.LoadStoreOffset.imm_pre_index(0xff)),
1923 .expected = 0b00_111_0_00_01_0_011111111_11_01111_01001,
1924 },
1925 .{ // str x2, [x1]
1926 .inst = Instruction.str(.x2, .x1, Instruction.LoadStoreOffset.none),
1927 .expected = 0b11_111_0_01_00_000000000000_00001_00010,
1928 },
1929 .{ // str x2, [x1], (x3)
1930 .inst = Instruction.str(.x2, .x1, Instruction.LoadStoreOffset.reg(.x3)),
1931 .expected = 0b11_111_0_00_00_1_00011_011_0_10_00001_00010,
1932 },
1933 .{ // strh w0, [x1]
1934 .inst = Instruction.strh(.w0, .x1, Instruction.LoadStoreOffset.none),
1935 .expected = 0b01_111_0_01_00_000000000000_00001_00000,
1936 },
1937 .{ // strb w8, [x9]
1938 .inst = Instruction.strb(.w8, .x9, Instruction.LoadStoreOffset.none),
1939 .expected = 0b00_111_0_01_00_000000000000_01001_01000,
1940 },
1941 .{ // adr x2, #0x8
1942 .inst = Instruction.adr(.x2, 0x8),
1943 .expected = 0b0_00_10000_0000000000000000010_00010,
1944 },
1945 .{ // adr x2, -#0x8
1946 .inst = Instruction.adr(.x2, -0x8),
1947 .expected = 0b0_00_10000_1111111111111111110_00010,
1948 },
1949 .{ // adrp x2, #0x8
1950 .inst = Instruction.adrp(.x2, 0x8),
1951 .expected = 0b1_00_10000_0000000000000000010_00010,
1952 },
1953 .{ // adrp x2, -#0x8
1954 .inst = Instruction.adrp(.x2, -0x8),
1955 .expected = 0b1_00_10000_1111111111111111110_00010,
1956 },
1957 .{ // stp x1, x2, [sp, #8]
1958 .inst = Instruction.stp(.x1, .x2, .sp, Instruction.LoadStorePairOffset.signed(8)),
1959 .expected = 0b10_101_0_010_0_0000001_00010_11111_00001,
1960 },
1961 .{ // ldp x1, x2, [sp, #8]
1962 .inst = Instruction.ldp(.x1, .x2, .sp, Instruction.LoadStorePairOffset.signed(8)),
1963 .expected = 0b10_101_0_010_1_0000001_00010_11111_00001,
1964 },
1965 .{ // stp x1, x2, [sp, #-16]!
1966 .inst = Instruction.stp(.x1, .x2, .sp, Instruction.LoadStorePairOffset.pre_index(-16)),
1967 .expected = 0b10_101_0_011_0_1111110_00010_11111_00001,
1968 },
1969 .{ // ldp x1, x2, [sp], #16
1970 .inst = Instruction.ldp(.x1, .x2, .sp, Instruction.LoadStorePairOffset.post_index(16)),
1971 .expected = 0b10_101_0_001_1_0000010_00010_11111_00001,
1972 },
1973 .{ // and x0, x4, x2
1974 .inst = Instruction.andShiftedRegister(.x0, .x4, .x2, .lsl, 0),
1975 .expected = 0b1_00_01010_00_0_00010_000000_00100_00000,
1976 },
1977 .{ // and x0, x4, x2, lsl #0x8
1978 .inst = Instruction.andShiftedRegister(.x0, .x4, .x2, .lsl, 0x8),
1979 .expected = 0b1_00_01010_00_0_00010_001000_00100_00000,
1980 },
1981 .{ // add x0, x10, #10
1982 .inst = Instruction.add(.x0, .x10, 10, false),
1983 .expected = 0b1_0_0_100010_0_0000_0000_1010_01010_00000,
1984 },
1985 .{ // subs x0, x5, #11, lsl #12
1986 .inst = Instruction.subs(.x0, .x5, 11, true),
1987 .expected = 0b1_1_1_100010_1_0000_0000_1011_00101_00000,
1988 },
1989 .{ // b.hi #-4
1990 .inst = Instruction.bCond(.hi, -4),
1991 .expected = 0b0101010_0_1111111111111111111_0_1000,
1992 },
1993 .{ // cbz x10, #40
1994 .inst = Instruction.cbz(.x10, 40),
1995 .expected = 0b1_011010_0_0000000000000001010_01010,
1996 },
1997 .{ // add x0, x1, x2, lsl #5
1998 .inst = Instruction.addShiftedRegister(.x0, .x1, .x2, .lsl, 5),
1999 .expected = 0b1_0_0_01011_00_0_00010_000101_00001_00000,
2000 },
2001 .{ // csinc x1, x2, x4, eq
2002 .inst = Instruction.csinc(.x1, .x2, .x4, .eq),
2003 .expected = 0b1_0_0_11010100_00100_0000_0_1_00010_00001,
2004 },
2005 .{ // mul x1, x4, x9
2006 .inst = Instruction.mul(.x1, .x4, .x9),
2007 .expected = 0b1_00_11011_000_01001_0_11111_00100_00001,
2008 },
2009 .{ // eor x3, x5, #1
2010 .inst = Instruction.eorImmediate(.x3, .x5, 0b000000, 0b000000, 0b1),
2011 .expected = 0b1_10_100100_1_000000_000000_00101_00011,
2012 },
2013 .{ // lslv x6, x9, x10
2014 .inst = Instruction.lslv(.x6, .x9, .x10),
2015 .expected = 0b1_0_0_11010110_01010_0010_00_01001_00110,
2016 },
2017 .{ // lsl x4, x2, #42
2018 .inst = Instruction.lslImmediate(.x4, .x2, 42),
2019 .expected = 0b1_10_100110_1_010110_010101_00010_00100,
2020 },
2021 .{ // lsl x4, x2, #63
2022 .inst = Instruction.lslImmediate(.x4, .x2, 63),
2023 .expected = 0b1_10_100110_1_000001_000000_00010_00100,
2024 },
2025 .{ // lsr x4, x2, #42
2026 .inst = Instruction.lsrImmediate(.x4, .x2, 42),
2027 .expected = 0b1_10_100110_1_101010_111111_00010_00100,
2028 },
2029 .{ // lsr x4, x2, #63
2030 .inst = Instruction.lsrImmediate(.x4, .x2, 63),
2031 .expected = 0b1_10_100110_1_111111_111111_00010_00100,
2032 },
2033 .{ // umull x0, w0, w1
2034 .inst = Instruction.umull(.x0, .w0, .w1),
2035 .expected = 0b1_00_11011_1_01_00001_0_11111_00000_00000,
2036 },
2037 .{ // smull x0, w0, w1
2038 .inst = Instruction.smull(.x0, .w0, .w1),
2039 .expected = 0b1_00_11011_0_01_00001_0_11111_00000_00000,
2040 },
2041 .{ // tst x0, #0xffffffff00000000
2042 .inst = Instruction.andsImmediate(.xzr, .x0, 0b011111, 0b100000, 0b1),
2043 .expected = 0b1_11_100100_1_100000_011111_00000_11111,
2044 },
2045 .{ // umulh x0, x1, x2
2046 .inst = Instruction.umulh(.x0, .x1, .x2),
2047 .expected = 0b1_00_11011_1_10_00010_0_11111_00001_00000,
2048 },
2049 .{ // smulh x0, x1, x2
2050 .inst = Instruction.smulh(.x0, .x1, .x2),
2051 .expected = 0b1_00_11011_0_10_00010_0_11111_00001_00000,
2052 },
2053 .{ // adds x0, x1, x2, sxtx
2054 .inst = Instruction.addsExtendedRegister(.x0, .x1, .x2, .sxtx, 0),
2055 .expected = 0b1_0_1_01011_00_1_00010_111_000_00001_00000,
2056 },
2057 };
2058
2059 for (testcases) |case| {
2060 const actual = case.inst.toU32();
2061 try testing.expectEqual(case.expected, actual);
2062 }
2063}
src/arch/riscv64/CodeGen.zig+5-5
......@@ -744,7 +744,7 @@ pub fn generate(
744744 src_loc: Zcu.LazySrcLoc,
745745 func_index: InternPool.Index,
746746 air: *const Air,
747 liveness: *const Air.Liveness,
747 liveness: *const ?Air.Liveness,
748748) CodeGenError!Mir {
749749 const zcu = pt.zcu;
750750 const gpa = zcu.gpa;
......@@ -767,7 +767,7 @@ pub fn generate(
767767 .pt = pt,
768768 .mod = mod,
769769 .bin_file = bin_file,
770 .liveness = liveness.*,
770 .liveness = liveness.*.?,
771771 .target = &mod.resolved_target.result,
772772 .owner = .{ .nav_index = func.owner_nav },
773773 .args = undefined, // populated after `resolveCallingConventionValues`
......@@ -4584,7 +4584,7 @@ fn structFieldPtr(func: *Func, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
45844584 const field_offset: i32 = switch (container_ty.containerLayout(zcu)) {
45854585 .auto, .@"extern" => @intCast(container_ty.structFieldOffset(index, zcu)),
45864586 .@"packed" => @divExact(@as(i32, ptr_container_ty.ptrInfo(zcu).packed_offset.bit_offset) +
4587 (if (zcu.typeToStruct(container_ty)) |struct_obj| pt.structPackedFieldBitOffset(struct_obj, index) else 0) -
4587 (if (zcu.typeToStruct(container_ty)) |struct_obj| zcu.structPackedFieldBitOffset(struct_obj, index) else 0) -
45884588 ptr_field_ty.ptrInfo(zcu).packed_offset.bit_offset, 8),
45894589 };
45904590
......@@ -4615,7 +4615,7 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void {
46154615 const field_off: u32 = switch (struct_ty.containerLayout(zcu)) {
46164616 .auto, .@"extern" => @intCast(struct_ty.structFieldOffset(index, zcu) * 8),
46174617 .@"packed" => if (zcu.typeToStruct(struct_ty)) |struct_type|
4618 pt.structPackedFieldBitOffset(struct_type, index)
4618 zcu.structPackedFieldBitOffset(struct_type, index)
46194619 else
46204620 0,
46214621 };
......@@ -8059,7 +8059,7 @@ fn airAggregateInit(func: *Func, inst: Air.Inst.Index) !void {
80598059
80608060 const elem_abi_size: u32 = @intCast(elem_ty.abiSize(zcu));
80618061 const elem_abi_bits = elem_abi_size * 8;
8062 const elem_off = pt.structPackedFieldBitOffset(struct_obj, elem_i);
8062 const elem_off = zcu.structPackedFieldBitOffset(struct_obj, elem_i);
80638063 const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size);
80648064 const elem_bit_off = elem_off % elem_abi_bits;
80658065 const elem_mcv = try func.resolveInst(elem);
src/arch/sparc64/CodeGen.zig+2-2
......@@ -267,7 +267,7 @@ pub fn generate(
267267 src_loc: Zcu.LazySrcLoc,
268268 func_index: InternPool.Index,
269269 air: *const Air,
270 liveness: *const Air.Liveness,
270 liveness: *const ?Air.Liveness,
271271) CodeGenError!Mir {
272272 const zcu = pt.zcu;
273273 const gpa = zcu.gpa;
......@@ -288,7 +288,7 @@ pub fn generate(
288288 .gpa = gpa,
289289 .pt = pt,
290290 .air = air.*,
291 .liveness = liveness.*,
291 .liveness = liveness.*.?,
292292 .target = target,
293293 .bin_file = lf,
294294 .func_index = func_index,
src/arch/wasm/CodeGen.zig+5-5
......@@ -1173,7 +1173,7 @@ pub fn generate(
11731173 src_loc: Zcu.LazySrcLoc,
11741174 func_index: InternPool.Index,
11751175 air: *const Air,
1176 liveness: *const Air.Liveness,
1176 liveness: *const ?Air.Liveness,
11771177) Error!Mir {
11781178 _ = src_loc;
11791179 _ = bin_file;
......@@ -1194,7 +1194,7 @@ pub fn generate(
11941194 .gpa = gpa,
11951195 .pt = pt,
11961196 .air = air.*,
1197 .liveness = liveness.*,
1197 .liveness = liveness.*.?,
11981198 .owner_nav = cg.owner_nav,
11991199 .target = target,
12001200 .ptr_size = switch (target.cpu.arch) {
......@@ -3776,7 +3776,7 @@ fn structFieldPtr(
37763776 break :offset @as(u32, 0);
37773777 }
37783778 const struct_type = zcu.typeToStruct(struct_ty).?;
3779 break :offset @divExact(pt.structPackedFieldBitOffset(struct_type, index) + struct_ptr_ty_info.packed_offset.bit_offset, 8);
3779 break :offset @divExact(zcu.structPackedFieldBitOffset(struct_type, index) + struct_ptr_ty_info.packed_offset.bit_offset, 8);
37803780 },
37813781 .@"union" => 0,
37823782 else => unreachable,
......@@ -3812,7 +3812,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
38123812 .@"packed" => switch (struct_ty.zigTypeTag(zcu)) {
38133813 .@"struct" => result: {
38143814 const packed_struct = zcu.typeToPackedStruct(struct_ty).?;
3815 const offset = pt.structPackedFieldBitOffset(packed_struct, field_index);
3815 const offset = zcu.structPackedFieldBitOffset(packed_struct, field_index);
38163816 const backing_ty = Type.fromInterned(packed_struct.backingIntTypeUnordered(ip));
38173817 const host_bits = backing_ty.intInfo(zcu).bits;
38183818
......@@ -5696,7 +5696,7 @@ fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
56965696 .auto, .@"extern" => parent_ty.structFieldOffset(field_index, zcu),
56975697 .@"packed" => offset: {
56985698 const parent_ptr_offset = parent_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset;
5699 const field_offset = if (zcu.typeToStruct(parent_ty)) |loaded_struct| pt.structPackedFieldBitOffset(loaded_struct, field_index) else 0;
5699 const field_offset = if (zcu.typeToStruct(parent_ty)) |loaded_struct| zcu.structPackedFieldBitOffset(loaded_struct, field_index) else 0;
57005700 const field_ptr_offset = field_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset;
57015701 break :offset @divExact(parent_ptr_offset + field_offset - field_ptr_offset, 8);
57025702 },
src/arch/x86_64/CodeGen.zig+20-31
......@@ -878,7 +878,7 @@ pub fn generate(
878878 src_loc: Zcu.LazySrcLoc,
879879 func_index: InternPool.Index,
880880 air: *const Air,
881 liveness: *const Air.Liveness,
881 liveness: *const ?Air.Liveness,
882882) codegen.CodeGenError!Mir {
883883 _ = bin_file;
884884 const zcu = pt.zcu;
......@@ -894,7 +894,7 @@ pub fn generate(
894894 .gpa = gpa,
895895 .pt = pt,
896896 .air = air.*,
897 .liveness = liveness.*,
897 .liveness = liveness.*.?,
898898 .target = &mod.resolved_target.result,
899899 .mod = mod,
900900 .owner = .{ .nav_index = func.owner_nav },
......@@ -100674,11 +100674,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
100674100674 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
100675100675 const struct_field = cg.air.extraData(Air.StructField, ty_pl.payload).data;
100676100676 var ops = try cg.tempsFromOperands(inst, .{struct_field.struct_operand});
100677 try ops[0].toOffset(cg.fieldOffset(
100677 try ops[0].toOffset(@intCast(codegen.fieldOffset(
100678100678 cg.typeOf(struct_field.struct_operand),
100679100679 ty_pl.ty.toType(),
100680100680 struct_field.field_index,
100681 ), cg);
100681 zcu,
100682 )), cg);
100682100683 try ops[0].finish(inst, &.{struct_field.struct_operand}, &ops, cg);
100683100684 },
100684100685 .struct_field_ptr_index_0,
......@@ -100688,7 +100689,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
100688100689 => |air_tag| {
100689100690 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
100690100691 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
100691 try ops[0].toOffset(cg.fieldOffset(
100692 try ops[0].toOffset(@intCast(codegen.fieldOffset(
100692100693 cg.typeOf(ty_op.operand),
100693100694 ty_op.ty.toType(),
100694100695 switch (air_tag) {
......@@ -100698,7 +100699,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
100698100699 .struct_field_ptr_index_2 => 2,
100699100700 .struct_field_ptr_index_3 => 3,
100700100701 },
100701 ), cg);
100702 zcu,
100703 )), cg);
100702100704 try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
100703100705 },
100704100706 .struct_field_val => {
......@@ -168108,11 +168110,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
168108168110 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
168109168111 const field_parent_ptr = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
168110168112 var ops = try cg.tempsFromOperands(inst, .{field_parent_ptr.field_ptr});
168111 try ops[0].toOffset(-cg.fieldOffset(
168113 try ops[0].toOffset(-@as(i32, @intCast(codegen.fieldOffset(
168112168114 ty_pl.ty.toType(),
168113168115 cg.typeOf(field_parent_ptr.field_ptr),
168114168116 field_parent_ptr.field_index,
168115 ), cg);
168117 zcu,
168118 ))), cg);
168116168119 try ops[0].finish(inst, &.{field_parent_ptr.field_ptr}, &ops, cg);
168117168120 },
168118168121 .wasm_memory_size, .wasm_memory_grow => unreachable,
......@@ -174809,18 +174812,6 @@ fn airStore(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void {
174809174812 return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none });
174810174813}
174811174814
174812fn fieldOffset(self: *CodeGen, ptr_agg_ty: Type, ptr_field_ty: Type, field_index: u32) i32 {
174813 const pt = self.pt;
174814 const zcu = pt.zcu;
174815 const agg_ty = ptr_agg_ty.childType(zcu);
174816 return switch (agg_ty.containerLayout(zcu)) {
174817 .auto, .@"extern" => @intCast(agg_ty.structFieldOffset(field_index, zcu)),
174818 .@"packed" => @divExact(@as(i32, ptr_agg_ty.ptrInfo(zcu).packed_offset.bit_offset) +
174819 (if (zcu.typeToStruct(agg_ty)) |loaded_struct| pt.structPackedFieldBitOffset(loaded_struct, field_index) else 0) -
174820 ptr_field_ty.ptrInfo(zcu).packed_offset.bit_offset, 8),
174821 };
174822}
174823
174824174815fn genUnOp(self: *CodeGen, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: Air.Inst.Ref) !MCValue {
174825174816 const pt = self.pt;
174826174817 const zcu = pt.zcu;
......@@ -184575,7 +184566,7 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void {
184575184566 }
184576184567 const elem_abi_size: u32 = @intCast(elem_ty.abiSize(zcu));
184577184568 const elem_abi_bits = elem_abi_size * 8;
184578 const elem_off = pt.structPackedFieldBitOffset(loaded_struct, elem_i);
184569 const elem_off = zcu.structPackedFieldBitOffset(loaded_struct, elem_i);
184579184570 const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size);
184580184571 const elem_bit_off = elem_off % elem_abi_bits;
184581184572 const elem_mcv = try self.resolveInst(elem);
......@@ -185625,21 +185616,19 @@ fn resolveCallingConventionValues(
185625185616fn fail(cg: *CodeGen, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {
185626185617 @branchHint(.cold);
185627185618 const zcu = cg.pt.zcu;
185628 switch (cg.owner) {
185629 .nav_index => |i| return zcu.codegenFail(i, format, args),
185630 .lazy_sym => |s| return zcu.codegenFailType(s.ty, format, args),
185631 }
185632 return error.CodegenFail;
185619 return switch (cg.owner) {
185620 .nav_index => |i| zcu.codegenFail(i, format, args),
185621 .lazy_sym => |s| zcu.codegenFailType(s.ty, format, args),
185622 };
185633185623}
185634185624
185635185625fn failMsg(cg: *CodeGen, msg: *Zcu.ErrorMsg) error{ OutOfMemory, CodegenFail } {
185636185626 @branchHint(.cold);
185637185627 const zcu = cg.pt.zcu;
185638 switch (cg.owner) {
185639 .nav_index => |i| return zcu.codegenFailMsg(i, msg),
185640 .lazy_sym => |s| return zcu.codegenFailTypeMsg(s.ty, msg),
185641 }
185642 return error.CodegenFail;
185628 return switch (cg.owner) {
185629 .nav_index => |i| zcu.codegenFailMsg(i, msg),
185630 .lazy_sym => |s| zcu.codegenFailTypeMsg(s.ty, msg),
185631 };
185643185632}
185644185633
185645185634fn parseRegName(name: []const u8) ?Register {
src/codegen.zig+43-8
......@@ -22,6 +22,8 @@ const Zir = std.zig.Zir;
2222const Alignment = InternPool.Alignment;
2323const dev = @import("dev.zig");
2424
25pub const aarch64 = @import("codegen/aarch64.zig");
26
2527pub const CodeGenError = GenerateSymbolError || error{
2628 /// Indicates the error is already stored in Zcu `failed_codegen`.
2729 CodegenFail,
......@@ -48,7 +50,7 @@ fn devFeatureForBackend(backend: std.builtin.CompilerBackend) dev.Feature {
4850fn importBackend(comptime backend: std.builtin.CompilerBackend) type {
4951 return switch (backend) {
5052 .other, .stage1 => unreachable,
51 .stage2_aarch64 => unreachable,
53 .stage2_aarch64 => aarch64,
5254 .stage2_arm => unreachable,
5355 .stage2_c => @import("codegen/c.zig"),
5456 .stage2_llvm => @import("codegen/llvm.zig"),
......@@ -71,6 +73,7 @@ pub fn legalizeFeatures(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) ?*co
7173 .stage2_c,
7274 .stage2_wasm,
7375 .stage2_x86_64,
76 .stage2_aarch64,
7477 .stage2_x86,
7578 .stage2_riscv64,
7679 .stage2_sparc64,
......@@ -82,10 +85,20 @@ pub fn legalizeFeatures(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) ?*co
8285 }
8386}
8487
88pub fn wantsLiveness(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) bool {
89 const zcu = pt.zcu;
90 const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;
91 return switch (target_util.zigBackend(target, zcu.comp.config.use_llvm)) {
92 else => true,
93 .stage2_aarch64 => false,
94 };
95}
96
8597/// Every code generation backend has a different MIR representation. However, we want to pass
8698/// MIR from codegen to the linker *regardless* of which backend is in use. So, we use this: a
8799/// union of all MIR types. The active tag is known from the backend in use; see `AnyMir.tag`.
88100pub const AnyMir = union {
101 aarch64: @import("codegen/aarch64/Mir.zig"),
89102 riscv64: @import("arch/riscv64/Mir.zig"),
90103 sparc64: @import("arch/sparc64/Mir.zig"),
91104 x86_64: @import("arch/x86_64/Mir.zig"),
......@@ -95,7 +108,6 @@ pub const AnyMir = union {
95108 pub inline fn tag(comptime backend: std.builtin.CompilerBackend) []const u8 {
96109 return switch (backend) {
97110 .stage2_aarch64 => "aarch64",
98 .stage2_arm => "arm",
99111 .stage2_riscv64 => "riscv64",
100112 .stage2_sparc64 => "sparc64",
101113 .stage2_x86_64 => "x86_64",
......@@ -110,7 +122,8 @@ pub const AnyMir = union {
110122 const backend = target_util.zigBackend(&zcu.root_mod.resolved_target.result, zcu.comp.config.use_llvm);
111123 switch (backend) {
112124 else => unreachable,
113 inline .stage2_riscv64,
125 inline .stage2_aarch64,
126 .stage2_riscv64,
114127 .stage2_sparc64,
115128 .stage2_x86_64,
116129 .stage2_wasm,
......@@ -131,14 +144,15 @@ pub fn generateFunction(
131144 src_loc: Zcu.LazySrcLoc,
132145 func_index: InternPool.Index,
133146 air: *const Air,
134 liveness: *const Air.Liveness,
147 liveness: *const ?Air.Liveness,
135148) CodeGenError!AnyMir {
136149 const zcu = pt.zcu;
137150 const func = zcu.funcInfo(func_index);
138151 const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result;
139152 switch (target_util.zigBackend(target, false)) {
140153 else => unreachable,
141 inline .stage2_riscv64,
154 inline .stage2_aarch64,
155 .stage2_riscv64,
142156 .stage2_sparc64,
143157 .stage2_x86_64,
144158 .stage2_wasm,
......@@ -173,7 +187,8 @@ pub fn emitFunction(
173187 const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result;
174188 switch (target_util.zigBackend(target, zcu.comp.config.use_llvm)) {
175189 else => unreachable,
176 inline .stage2_riscv64,
190 inline .stage2_aarch64,
191 .stage2_riscv64,
177192 .stage2_sparc64,
178193 .stage2_x86_64,
179194 => |backend| {
......@@ -420,7 +435,7 @@ pub fn generateSymbol(
420435 const int_tag_ty = ty.intTagType(zcu);
421436 try generateSymbol(bin_file, pt, src_loc, try pt.getCoerced(Value.fromInterned(enum_tag.int), int_tag_ty), code, reloc_parent);
422437 },
423 .float => |float| switch (float.storage) {
438 .float => |float| storage: switch (float.storage) {
424439 .f16 => |f16_val| writeFloat(f16, f16_val, target, endian, try code.addManyAsArray(gpa, 2)),
425440 .f32 => |f32_val| writeFloat(f32, f32_val, target, endian, try code.addManyAsArray(gpa, 4)),
426441 .f64 => |f64_val| writeFloat(f64, f64_val, target, endian, try code.addManyAsArray(gpa, 8)),
......@@ -429,7 +444,13 @@ pub fn generateSymbol(
429444 const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow;
430445 try code.appendNTimes(gpa, 0, abi_size - 10);
431446 },
432 .f128 => |f128_val| writeFloat(f128, f128_val, target, endian, try code.addManyAsArray(gpa, 16)),
447 .f128 => |f128_val| switch (Type.fromInterned(float.ty).floatBits(target)) {
448 else => unreachable,
449 16 => continue :storage .{ .f16 = @floatCast(f128_val) },
450 32 => continue :storage .{ .f32 = @floatCast(f128_val) },
451 64 => continue :storage .{ .f64 = @floatCast(f128_val) },
452 128 => writeFloat(f128, f128_val, target, endian, try code.addManyAsArray(gpa, 16)),
453 },
433454 },
434455 .ptr => try lowerPtr(bin_file, pt, src_loc, val.toIntern(), code, reloc_parent, 0),
435456 .slice => |slice| {
......@@ -1218,3 +1239,17 @@ pub fn errUnionErrorOffset(payload_ty: Type, zcu: *Zcu) u64 {
12181239 return 0;
12191240 }
12201241}
1242
1243pub fn fieldOffset(ptr_agg_ty: Type, ptr_field_ty: Type, field_index: u32, zcu: *Zcu) u64 {
1244 const agg_ty = ptr_agg_ty.childType(zcu);
1245 return switch (agg_ty.containerLayout(zcu)) {
1246 .auto, .@"extern" => agg_ty.structFieldOffset(field_index, zcu),
1247 .@"packed" => @divExact(@as(u64, ptr_agg_ty.ptrInfo(zcu).packed_offset.bit_offset) +
1248 (if (zcu.typeToPackedStruct(agg_ty)) |loaded_struct| zcu.structPackedFieldBitOffset(loaded_struct, field_index) else 0) -
1249 ptr_field_ty.ptrInfo(zcu).packed_offset.bit_offset, 8),
1250 };
1251}
1252
1253test {
1254 _ = aarch64;
1255}
src/codegen/aarch64.zig created+194
......@@ -0,0 +1,194 @@
1pub const abi = @import("aarch64/abi.zig");
2pub const Assemble = @import("aarch64/Assemble.zig");
3pub const Disassemble = @import("aarch64/Disassemble.zig");
4pub const encoding = @import("aarch64/encoding.zig");
5pub const Mir = @import("aarch64/Mir.zig");
6pub const Select = @import("aarch64/Select.zig");
7
8pub fn legalizeFeatures(_: *const std.Target) ?*Air.Legalize.Features {
9 return null;
10}
11
12pub fn generate(
13 _: *link.File,
14 pt: Zcu.PerThread,
15 _: Zcu.LazySrcLoc,
16 func_index: InternPool.Index,
17 air: *const Air,
18 liveness: *const ?Air.Liveness,
19) !Mir {
20 const zcu = pt.zcu;
21 const gpa = zcu.gpa;
22 const func = zcu.funcInfo(func_index);
23 const func_type = zcu.intern_pool.indexToKey(func.ty).func_type;
24 assert(liveness.* == null);
25
26 const mod = zcu.navFileScope(func.owner_nav).mod.?;
27 var isel: Select = .{
28 .pt = pt,
29 .target = &mod.resolved_target.result,
30 .air = air.*,
31 .nav_index = zcu.funcInfo(func_index).owner_nav,
32
33 .def_order = .empty,
34 .blocks = .empty,
35 .loops = .empty,
36 .active_loops = .empty,
37 .loop_live = .{
38 .set = .empty,
39 .list = .empty,
40 },
41 .dom_start = 0,
42 .dom_len = 0,
43 .dom = .empty,
44
45 .saved_registers = comptime .initEmpty(),
46 .instructions = .empty,
47 .literals = .empty,
48 .nav_relocs = .empty,
49 .uav_relocs = .empty,
50 .global_relocs = .empty,
51 .literal_relocs = .empty,
52
53 .returns = false,
54 .va_list = undefined,
55 .stack_size = 0,
56 .stack_align = .@"16",
57
58 .live_registers = comptime .initFill(.free),
59 .live_values = .empty,
60 .values = .empty,
61 };
62 defer isel.deinit();
63
64 const air_main_body = air.getMainBody();
65 var param_it: Select.CallAbiIterator = .init;
66 const air_args = for (air_main_body, 0..) |air_inst_index, body_index| {
67 if (air.instructions.items(.tag)[@intFromEnum(air_inst_index)] != .arg) break air_main_body[0..body_index];
68 const param_ty = air.instructions.items(.data)[@intFromEnum(air_inst_index)].arg.ty.toType();
69 const param_vi = try param_it.param(&isel, param_ty);
70 tracking_log.debug("${d} <- %{d}", .{ @intFromEnum(param_vi.?), @intFromEnum(air_inst_index) });
71 try isel.live_values.putNoClobber(gpa, air_inst_index, param_vi.?);
72 } else unreachable;
73
74 const saved_gra_start = if (mod.strip) param_it.ngrn else Select.CallAbiIterator.ngrn_start;
75 const saved_gra_end = if (func_type.is_var_args) Select.CallAbiIterator.ngrn_end else param_it.ngrn;
76 const saved_gra_len = @intFromEnum(saved_gra_end) - @intFromEnum(saved_gra_start);
77
78 const saved_vra_start = if (mod.strip) param_it.nsrn else Select.CallAbiIterator.nsrn_start;
79 const saved_vra_end = if (func_type.is_var_args) Select.CallAbiIterator.nsrn_end else param_it.nsrn;
80 const saved_vra_len = @intFromEnum(saved_vra_end) - @intFromEnum(saved_vra_start);
81
82 const frame_record = 2;
83 const named_stack_args: Select.Value.Indirect = .{
84 .base = .fp,
85 .offset = 8 * std.mem.alignForward(u7, frame_record + saved_gra_len, 2),
86 };
87 isel.va_list = .{
88 .__stack = named_stack_args.withOffset(param_it.nsaa),
89 .__gr_top = named_stack_args,
90 .__vr_top = .{ .base = .fp, .offset = 0 },
91 };
92
93 // translate arg locations from caller-based to callee-based
94 for (air_args) |air_inst_index| {
95 assert(air.instructions.items(.tag)[@intFromEnum(air_inst_index)] == .arg);
96 const arg_vi = isel.live_values.get(air_inst_index).?;
97 const passed_vi = switch (arg_vi.parent(&isel)) {
98 .unallocated, .stack_slot => arg_vi,
99 .value, .constant => unreachable,
100 .address => |address_vi| address_vi,
101 };
102 switch (passed_vi.parent(&isel)) {
103 .unallocated => if (!mod.strip) {
104 var part_it = arg_vi.parts(&isel);
105 const first_passed_part_vi = part_it.next() orelse passed_vi;
106 const hint_ra = first_passed_part_vi.hint(&isel).?;
107 passed_vi.setParent(&isel, .{ .stack_slot = if (hint_ra.isVector())
108 isel.va_list.__vr_top.withOffset(@as(i8, -16) *
109 (@intFromEnum(saved_vra_end) - @intFromEnum(hint_ra)))
110 else
111 isel.va_list.__gr_top.withOffset(@as(i8, -8) *
112 (@intFromEnum(saved_gra_end) - @intFromEnum(hint_ra))) });
113 },
114 .stack_slot => |stack_slot| {
115 assert(stack_slot.base == .sp);
116 passed_vi.setParent(&isel, .{
117 .stack_slot = named_stack_args.withOffset(stack_slot.offset),
118 });
119 },
120 .address, .value, .constant => unreachable,
121 }
122 }
123
124 ret: {
125 var ret_it: Select.CallAbiIterator = .init;
126 const ret_vi = try ret_it.ret(&isel, .fromInterned(func_type.return_type)) orelse break :ret;
127 tracking_log.debug("${d} <- %main", .{@intFromEnum(ret_vi)});
128 try isel.live_values.putNoClobber(gpa, Select.Block.main, ret_vi);
129 }
130
131 assert(!(try isel.blocks.getOrPut(gpa, Select.Block.main)).found_existing);
132 try isel.analyze(air_main_body);
133 try isel.finishAnalysis();
134 isel.verify(false);
135
136 isel.blocks.values()[0] = .{
137 .live_registers = isel.live_registers,
138 .target_label = @intCast(isel.instructions.items.len),
139 };
140 try isel.body(air_main_body);
141 if (isel.live_values.fetchRemove(Select.Block.main)) |ret_vi| {
142 switch (ret_vi.value.parent(&isel)) {
143 .unallocated, .stack_slot => {},
144 .value, .constant => unreachable,
145 .address => |address_vi| try address_vi.liveIn(
146 &isel,
147 address_vi.hint(&isel).?,
148 comptime &.initFill(.free),
149 ),
150 }
151 ret_vi.value.deref(&isel);
152 }
153 isel.verify(true);
154
155 const prologue = isel.instructions.items.len;
156 const epilogue = try isel.layout(
157 param_it,
158 func_type.is_var_args,
159 saved_gra_len,
160 saved_vra_len,
161 mod,
162 );
163
164 const instructions = try isel.instructions.toOwnedSlice(gpa);
165 var mir: Mir = .{
166 .prologue = instructions[prologue..epilogue],
167 .body = instructions[0..prologue],
168 .epilogue = instructions[epilogue..],
169 .literals = &.{},
170 .nav_relocs = &.{},
171 .uav_relocs = &.{},
172 .global_relocs = &.{},
173 .literal_relocs = &.{},
174 };
175 errdefer mir.deinit(gpa);
176 mir.literals = try isel.literals.toOwnedSlice(gpa);
177 mir.nav_relocs = try isel.nav_relocs.toOwnedSlice(gpa);
178 mir.uav_relocs = try isel.uav_relocs.toOwnedSlice(gpa);
179 mir.global_relocs = try isel.global_relocs.toOwnedSlice(gpa);
180 mir.literal_relocs = try isel.literal_relocs.toOwnedSlice(gpa);
181 return mir;
182}
183
184test {
185 _ = Assemble;
186}
187
188const Air = @import("../Air.zig");
189const assert = std.debug.assert;
190const InternPool = @import("../InternPool.zig");
191const link = @import("../link.zig");
192const std = @import("std");
193const tracking_log = std.log.scoped(.tracking);
194const Zcu = @import("../Zcu.zig");
src/codegen/aarch64/Assemble.zig created+1653
......@@ -0,0 +1,1653 @@
1source: [*:0]const u8,
2operands: std.StringHashMapUnmanaged(Operand),
3
4pub const Operand = union(enum) {
5 register: aarch64.encoding.Register,
6};
7
8pub fn nextInstruction(as: *Assemble) !?Instruction {
9 @setEvalBranchQuota(37_000);
10 comptime var ct_token_buf: [token_buf_len]u8 = undefined;
11 var token_buf: [token_buf_len]u8 = undefined;
12 const original_source = while (true) {
13 const original_source = as.source;
14 const source_token = try as.nextToken(&token_buf, .{});
15 if (source_token.len == 0) return null;
16 if (source_token[0] != '\n') break original_source;
17 };
18 log.debug(
19 \\.
20 \\=========================
21 \\= Assembling "{f}"
22 \\=========================
23 \\
24 , .{std.zig.fmtString(std.mem.span(original_source))});
25 inline for (instructions) |instruction| {
26 next_pattern: {
27 as.source = original_source;
28 var symbols: Symbols: {
29 const symbols = @typeInfo(@TypeOf(instruction.symbols)).@"struct".fields;
30 var symbol_fields: [symbols.len]std.builtin.Type.StructField = undefined;
31 for (&symbol_fields, symbols) |*symbol_field, symbol| symbol_field.* = .{
32 .name = symbol.name,
33 .type = zonCast(SymbolSpec, @field(instruction.symbols, symbol.name), .{}).Storage(),
34 .default_value_ptr = null,
35 .is_comptime = false,
36 .alignment = 0,
37 };
38 break :Symbols @Type(.{ .@"struct" = .{
39 .layout = .auto,
40 .fields = &symbol_fields,
41 .decls = &.{},
42 .is_tuple = false,
43 } });
44 } = undefined;
45 comptime var pattern_as: Assemble = .{ .source = instruction.pattern, .operands = undefined };
46 inline while (true) {
47 const pattern_token = comptime pattern_as.nextToken(&ct_token_buf, .{ .placeholders = true }) catch |err|
48 @compileError(@errorName(err) ++ " while parsing '" ++ instruction.pattern ++ "'");
49 const source_token = try as.nextToken(&token_buf, .{ .operands = true });
50 log.debug("\"{f}\" -> \"{f}\"", .{
51 std.zig.fmtString(pattern_token),
52 std.zig.fmtString(source_token),
53 });
54 if (pattern_token.len == 0) {
55 if (source_token.len > 0 and source_token[0] != '\n') break :next_pattern;
56 const encode = @field(Instruction, @tagName(instruction.encode[0]));
57 const Encode = @TypeOf(encode);
58 var args: std.meta.ArgsTuple(Encode) = undefined;
59 inline for (&args, @typeInfo(Encode).@"fn".params, 1..instruction.encode.len) |*arg, param, encode_index|
60 arg.* = zonCast(param.type.?, instruction.encode[encode_index], symbols);
61 return @call(.auto, encode, args);
62 } else if (pattern_token[0] == '<') {
63 const symbol_name = comptime pattern_token[1 .. std.mem.indexOfScalarPos(u8, pattern_token, 1, '|') orelse
64 pattern_token.len - 1];
65 const symbol = &@field(symbols, symbol_name);
66 symbol.* = zonCast(SymbolSpec, @field(instruction.symbols, symbol_name), .{}).parse(source_token) orelse break :next_pattern;
67 log.debug("{s} = {any}", .{ symbol_name, symbol.* });
68 } else if (!std.ascii.eqlIgnoreCase(pattern_token, source_token)) break :next_pattern;
69 }
70 }
71 log.debug("'{s}' not matched...", .{instruction.pattern});
72 }
73 as.source = original_source;
74 log.debug("Nothing matched!\n", .{});
75 return error.InvalidSyntax;
76}
77
78fn zonCast(comptime Result: type, zon_value: anytype, symbols: anytype) Result {
79 const ZonValue = @TypeOf(zon_value);
80 const Symbols = @TypeOf(symbols);
81 switch (@typeInfo(ZonValue)) {
82 .void, .bool, .int, .float, .pointer, .comptime_float, .comptime_int, .@"enum" => return zon_value,
83 .@"struct" => |zon_struct| switch (@typeInfo(Result)) {
84 .@"struct" => |result_struct| {
85 comptime var used_zon_fields = 0;
86 var result: Result = undefined;
87 inline for (result_struct.fields) |result_field| @field(result, result_field.name) = if (@hasField(ZonValue, result_field.name)) result: {
88 used_zon_fields += 1;
89 break :result zonCast(@FieldType(Result, result_field.name), @field(zon_value, result_field.name), symbols);
90 } else result_field.defaultValue() orelse @compileError(std.fmt.comptimePrint("missing zon field '{s}': {} <- {any}", .{ result_field.name, Result, zon_value }));
91 if (used_zon_fields != zon_struct.fields.len) @compileError(std.fmt.comptimePrint("unused zon field: {} <- {any}", .{ Result, zon_value }));
92 return result;
93 },
94 .@"union" => {
95 if (zon_struct.fields.len != 1) @compileError(std.fmt.comptimePrint("{} <- {any}", .{ Result, zon_value }));
96 const field_name = zon_struct.fields[0].name;
97 return @unionInit(
98 Result,
99 field_name,
100 zonCast(@FieldType(Result, field_name), @field(zon_value, field_name), symbols),
101 );
102 },
103 else => @compileError(std.fmt.comptimePrint("unsupported zon type: {} <- {any}", .{ Result, zon_value })),
104 },
105 .enum_literal => if (@hasField(Symbols, @tagName(zon_value))) {
106 const symbol = @field(symbols, @tagName(zon_value));
107 const Symbol = @TypeOf(symbol);
108 switch (@typeInfo(Result)) {
109 .@"enum" => switch (@typeInfo(Symbol)) {
110 .int => |symbol_int| {
111 var buf: [
112 std.fmt.count("{d}", .{switch (symbol_int.signedness) {
113 .signed => std.math.minInt(Symbol),
114 .unsigned => std.math.maxInt(Symbol),
115 }})
116 ]u8 = undefined;
117 return std.meta.stringToEnum(Result, std.fmt.bufPrint(&buf, "{d}", .{symbol}) catch unreachable).?;
118 },
119 else => return symbol,
120 },
121 else => return symbol,
122 }
123 } else return if (@hasDecl(Result, @tagName(zon_value))) @field(Result, @tagName(zon_value)) else zon_value,
124 else => @compileError(std.fmt.comptimePrint("unsupported zon type: {} <- {any}", .{ Result, zon_value })),
125 }
126}
127
128const token_buf_len = "v31.b[15]".len;
129fn nextToken(as: *Assemble, buf: *[token_buf_len]u8, comptime opts: struct {
130 operands: bool = false,
131 placeholders: bool = false,
132}) ![]const u8 {
133 const invalid_syntax: u8 = 1;
134 while (true) c: switch (as.source[0]) {
135 0 => return as.source[0..0],
136 '\t', '\n' + 1...'\r', ' ' => as.source = as.source[1..],
137 '\n', '!', '#', ',', '[', ']' => {
138 defer as.source = as.source[1..];
139 return as.source[0..1];
140 },
141 '%' => if (opts.operands) {
142 if (as.source[1] != '[') continue :c invalid_syntax;
143 const name_start: usize = 2;
144 var index = name_start;
145 while (switch (as.source[index]) {
146 else => true,
147 ':', ']' => false,
148 }) index += 1;
149 const operand = as.operands.get(as.source[name_start..index]) orelse continue :c invalid_syntax;
150 const modifier = modifier: switch (as.source[index]) {
151 else => unreachable,
152 ':' => {
153 index += 1;
154 const modifier_start = index;
155 while (switch (as.source[index]) {
156 else => true,
157 ']' => false,
158 }) index += 1;
159 break :modifier as.source[modifier_start..index];
160 },
161 ']' => "",
162 };
163 assert(as.source[index] == ']');
164 const modified_operand: Operand = if (std.mem.eql(u8, modifier, ""))
165 operand
166 else if (std.mem.eql(u8, modifier, "w")) switch (operand) {
167 .register => |reg| .{ .register = reg.alias.w() },
168 } else if (std.mem.eql(u8, modifier, "x")) switch (operand) {
169 .register => |reg| .{ .register = reg.alias.x() },
170 } else if (std.mem.eql(u8, modifier, "b")) switch (operand) {
171 .register => |reg| .{ .register = reg.alias.b() },
172 } else if (std.mem.eql(u8, modifier, "h")) switch (operand) {
173 .register => |reg| .{ .register = reg.alias.h() },
174 } else if (std.mem.eql(u8, modifier, "s")) switch (operand) {
175 .register => |reg| .{ .register = reg.alias.s() },
176 } else if (std.mem.eql(u8, modifier, "d")) switch (operand) {
177 .register => |reg| .{ .register = reg.alias.d() },
178 } else if (std.mem.eql(u8, modifier, "q")) switch (operand) {
179 .register => |reg| .{ .register = reg.alias.q() },
180 } else if (std.mem.eql(u8, modifier, "Z")) switch (operand) {
181 .register => |reg| .{ .register = reg.alias.z() },
182 } else continue :c invalid_syntax;
183 switch (modified_operand) {
184 .register => |reg| {
185 as.source = as.source[index + 1 ..];
186 return std.fmt.bufPrint(buf, "{f}", .{reg.fmt()}) catch unreachable;
187 },
188 }
189 } else continue :c invalid_syntax,
190 '-', '0'...'9', 'A'...'Z', '_', 'a'...'z' => {
191 var index: usize = 1;
192 while (switch (as.source[index]) {
193 '0'...'9', 'A'...'Z', '_', 'a'...'z' => true,
194 else => false,
195 }) index += 1;
196 defer as.source = as.source[index..];
197 return as.source[0..index];
198 },
199 '<' => if (opts.placeholders) {
200 var index: usize = 1;
201 while (switch (as.source[index]) {
202 0 => return error.UnterminatedPlaceholder,
203 '>' => false,
204 else => true,
205 }) index += 1;
206 defer as.source = as.source[index + 1 ..];
207 return as.source[0 .. index + 1];
208 } else continue :c invalid_syntax,
209 else => {
210 if (!@inComptime()) log.debug("invalid token \"{f}\"", .{std.zig.fmtString(std.mem.span(as.source))});
211 return error.InvalidSyntax;
212 },
213 };
214}
215
216const SymbolSpec = union(enum) {
217 reg: struct { format: aarch64.encoding.Register.Format, allow_sp: bool = false },
218 imm: struct {
219 type: std.builtin.Type.Int,
220 multiple_of: comptime_int = 1,
221 max_valid: ?comptime_int = null,
222 },
223 extend: struct { size: aarch64.encoding.Register.IntegerSize },
224 shift: struct { allow_ror: bool = true },
225 barrier: struct { only_sy: bool = false },
226
227 fn Storage(comptime spec: SymbolSpec) type {
228 return switch (spec) {
229 .reg => aarch64.encoding.Register,
230 .imm => |imm| @Type(.{ .int = imm.type }),
231 .extend => Instruction.DataProcessingRegister.AddSubtractExtendedRegister.Option,
232 .shift => Instruction.DataProcessingRegister.Shift.Op,
233 .barrier => Instruction.BranchExceptionGeneratingSystem.Barriers.Option,
234 };
235 }
236
237 fn parse(comptime spec: SymbolSpec, token: []const u8) ?Storage(spec) {
238 const Result = Storage(spec);
239 switch (spec) {
240 .reg => |reg_spec| {
241 var buf: [token_buf_len]u8 = undefined;
242 const reg = Result.parse(std.ascii.lowerString(&buf, token[0..@min(token.len, buf.len)])) orelse {
243 log.debug("invalid register: \"{f}\"", .{std.zig.fmtString(token)});
244 return null;
245 };
246 if (reg.format.integer != reg_spec.format.integer) {
247 log.debug("invalid register size: \"{f}\"", .{std.zig.fmtString(token)});
248 return null;
249 }
250 if (reg.alias == if (reg_spec.allow_sp) .zr else .sp) {
251 log.debug("invalid register usage: \"{f}\"", .{std.zig.fmtString(token)});
252 return null;
253 }
254 return reg;
255 },
256 .imm => |imm_spec| {
257 const imm = std.fmt.parseInt(Result, token, 0) catch {
258 log.debug("invalid immediate: \"{f}\"", .{std.zig.fmtString(token)});
259 return null;
260 };
261 if (@rem(imm, imm_spec.multiple_of) != 0) {
262 log.debug("invalid immediate usage: \"{f}\"", .{std.zig.fmtString(token)});
263 return null;
264 }
265 if (imm_spec.max_valid) |max_valid| if (imm > max_valid) {
266 log.debug("out of range immediate: \"{f}\"", .{std.zig.fmtString(token)});
267 return null;
268 };
269 return imm;
270 },
271 .extend => |extend_spec| {
272 const Option = Instruction.DataProcessingRegister.AddSubtractExtendedRegister.Option;
273 var buf: [
274 max_len: {
275 var max_len = 0;
276 for (@typeInfo(Option).@"enum".fields) |field| max_len = @max(max_len, field.name.len);
277 break :max_len max_len;
278 } + 1
279 ]u8 = undefined;
280 const extend = std.meta.stringToEnum(Option, std.ascii.lowerString(
281 &buf,
282 token[0..@min(token.len, buf.len)],
283 )) orelse {
284 log.debug("invalid extend: \"{f}\"", .{std.zig.fmtString(token)});
285 return null;
286 };
287 if (extend.sf() != extend_spec.size) {
288 log.debug("invalid extend: \"{f}\"", .{std.zig.fmtString(token)});
289 return null;
290 }
291 return extend;
292 },
293 .shift => |shift_spec| {
294 const ShiftOp = Instruction.DataProcessingRegister.Shift.Op;
295 var buf: [
296 max_len: {
297 var max_len = 0;
298 for (@typeInfo(ShiftOp).@"enum".fields) |field| max_len = @max(max_len, field.name.len);
299 break :max_len max_len;
300 } + 1
301 ]u8 = undefined;
302 const shift = std.meta.stringToEnum(ShiftOp, std.ascii.lowerString(
303 &buf,
304 token[0..@min(token.len, buf.len)],
305 )) orelse {
306 log.debug("invalid shift: \"{f}\"", .{std.zig.fmtString(token)});
307 return null;
308 };
309 if (!shift_spec.allow_ror and shift == .ror) {
310 log.debug("invalid shift usage: \"{f}\"", .{std.zig.fmtString(token)});
311 return null;
312 }
313 return shift;
314 },
315 .barrier => |barrier_spec| {
316 const Option = Instruction.BranchExceptionGeneratingSystem.Barriers.Option;
317 var buf: [
318 max_len: {
319 var max_len = 0;
320 for (@typeInfo(Option).@"enum".fields) |field| max_len = @max(max_len, field.name.len);
321 break :max_len max_len;
322 } + 1
323 ]u8 = undefined;
324 const barrier = std.meta.stringToEnum(Option, std.ascii.lowerString(
325 &buf,
326 token[0..@min(token.len, buf.len)],
327 )) orelse {
328 log.debug("invalid barrier: \"{f}\"", .{std.zig.fmtString(token)});
329 return null;
330 };
331 if (barrier_spec.only_sy and barrier != .sy) {
332 log.debug("invalid barrier: \"{f}\"", .{std.zig.fmtString(token)});
333 return null;
334 }
335 return barrier;
336 },
337 }
338 }
339};
340
341test "add sub" {
342 var as: Assemble = .{
343 .source =
344 \\ add w0, w0, w1
345 \\ add w2, w3, w4
346 \\ add wsp, w5, w6
347 \\ add w7, wsp, w8
348 \\ add wsp, wsp, w9
349 \\ add w10, w10, wzr
350 \\ add w11, w12, wzr
351 \\ add wsp, w13, wzr
352 \\ add w14, wsp, wzr
353 \\ add wsp, wsp, wzr
354 \\
355 \\ add x0, x0, x1
356 \\ add x2, x3, x4
357 \\ add sp, x5, x6
358 \\ add x7, sp, x8
359 \\ add sp, sp, x9
360 \\ add x10, x10, xzr
361 \\ add x11, x12, xzr
362 \\ add sp, x13, xzr
363 \\ add x14, sp, xzr
364 \\ add sp, sp, xzr
365 \\
366 \\ add w0, w0, w1
367 \\ add w2, w3, w4, uxtb #0
368 \\ add wsp, w5, w6, uxth #1
369 \\ add w7, wsp, w8, uxtw #0
370 \\ add wsp, wsp, w9, uxtw #2
371 \\ add w10, w10, wzr, uxtw #3
372 \\ add w11, w12, wzr, sxtb #4
373 \\ add wsp, w13, wzr, sxth #0
374 \\ add w14, wsp, wzr, sxtw #1
375 \\ add wsp, wsp, wzr, sxtw #2
376 \\
377 \\ add x0, x0, x1
378 \\ add x2, x3, w4, uxtb #0
379 \\ add sp, x5, w6, uxth #1
380 \\ add x7, sp, w8, uxtw #2
381 \\ add sp, sp, x9, uxtx #0
382 \\ add x10, x10, xzr, uxtx #3
383 \\ add x11, x12, wzr, sxtb #4
384 \\ add sp, x13, wzr, sxth #0
385 \\ add x14, sp, wzr, sxtw #1
386 \\ add sp, sp, xzr, sxtx #2
387 \\
388 \\ add w0, w0, #0
389 \\ add w0, w1, #1, lsl #0
390 \\ add wsp, w2, #2, lsl #12
391 \\ add w3, wsp, #3, lsl #0
392 \\ add wsp, wsp, #4095, lsl #12
393 \\ add w0, w1, #0
394 \\ add w2, w3, #0, lsl #0
395 \\ add w4, wsp, #0
396 \\ add w5, wsp, #0, lsl #0
397 \\ add wsp, w6, #0
398 \\ add wsp, w7, #0, lsl #0
399 \\ add wsp, wsp, #0
400 \\ add wsp, wsp, #0, lsl #0
401 \\
402 \\ add x0, x0, #0
403 \\ add x0, x1, #1, lsl #0
404 \\ add sp, x2, #2, lsl #12
405 \\ add x3, sp, #3, lsl #0
406 \\ add sp, sp, #4095, lsl #12
407 \\ add x0, x1, #0
408 \\ add x2, x3, #0, lsl #0
409 \\ add x4, sp, #0
410 \\ add x5, sp, #0, lsl #0
411 \\ add sp, x6, #0
412 \\ add sp, x7, #0, lsl #0
413 \\ add sp, sp, #0
414 \\ add sp, sp, #0, lsl #0
415 \\
416 \\ add w0, w0, w0
417 \\ add w1, w1, w2, lsl #0
418 \\ add w3, w4, w5, lsl #1
419 \\ add w6, w6, wzr, lsl #31
420 \\ add w7, wzr, w8, lsr #0
421 \\ add w9, wzr, wzr, lsr #30
422 \\ add wzr, w10, w11, lsr #31
423 \\ add wzr, w12, wzr, asr #0x0
424 \\ add wzr, wzr, w13, asr #0x10
425 \\ add wzr, wzr, wzr, asr #0x1f
426 \\
427 \\ add x0, x0, x0
428 \\ add x1, x1, x2, lsl #0
429 \\ add x3, x4, x5, lsl #1
430 \\ add x6, x6, xzr, lsl #63
431 \\ add x7, xzr, x8, lsr #0
432 \\ add x9, xzr, xzr, lsr #62
433 \\ add xzr, x10, x11, lsr #63
434 \\ add xzr, x12, xzr, asr #0x0
435 \\ add xzr, xzr, x13, asr #0x1F
436 \\ add xzr, xzr, xzr, asr #0x3f
437 \\
438 \\ sub w0, w0, w1
439 \\ sub w2, w3, w4
440 \\ sub wsp, w5, w6
441 \\ sub w7, wsp, w8
442 \\ sub wsp, wsp, w9
443 \\ sub w10, w10, wzr
444 \\ sub w11, w12, wzr
445 \\ sub wsp, w13, wzr
446 \\ sub w14, wsp, wzr
447 \\ sub wsp, wsp, wzr
448 \\
449 \\ sub x0, x0, x1
450 \\ sub x2, x3, x4
451 \\ sub sp, x5, x6
452 \\ sub x7, sp, x8
453 \\ sub sp, sp, x9
454 \\ sub x10, x10, xzr
455 \\ sub x11, x12, xzr
456 \\ sub sp, x13, xzr
457 \\ sub x14, sp, xzr
458 \\ sub sp, sp, xzr
459 \\
460 \\ sub w0, w0, w1
461 \\ sub w2, w3, w4, uxtb #0
462 \\ sub wsp, w5, w6, uxth #1
463 \\ sub w7, wsp, w8, uxtw #0
464 \\ sub wsp, wsp, w9, uxtw #2
465 \\ sub w10, w10, wzr, uxtw #3
466 \\ sub w11, w12, wzr, sxtb #4
467 \\ sub wsp, w13, wzr, sxth #0
468 \\ sub w14, wsp, wzr, sxtw #1
469 \\ sub wsp, wsp, wzr, sxtw #2
470 \\
471 \\ sub x0, x0, x1
472 \\ sub x2, x3, w4, uxtb #0
473 \\ sub sp, x5, w6, uxth #1
474 \\ sub x7, sp, w8, uxtw #2
475 \\ sub sp, sp, x9, uxtx #0
476 \\ sub x10, x10, xzr, uxtx #3
477 \\ sub x11, x12, wzr, sxtb #4
478 \\ sub sp, x13, wzr, sxth #0
479 \\ sub x14, sp, wzr, sxtw #1
480 \\ sub sp, sp, xzr, sxtx #2
481 \\
482 \\ sub w0, w0, #0
483 \\ sub w0, w1, #1, lsl #0
484 \\ sub wsp, w2, #2, lsl #12
485 \\ sub w3, wsp, #3, lsl #0
486 \\ sub wsp, wsp, #4095, lsl #12
487 \\ sub w0, w1, #0
488 \\ sub w2, w3, #0, lsl #0
489 \\ sub w4, wsp, #0
490 \\ sub w5, wsp, #0, lsl #0
491 \\ sub wsp, w6, #0
492 \\ sub wsp, w7, #0, lsl #0
493 \\ sub wsp, wsp, #0
494 \\ sub wsp, wsp, #0, lsl #0
495 \\
496 \\ sub x0, x0, #0
497 \\ sub x0, x1, #1, lsl #0
498 \\ sub sp, x2, #2, lsl #12
499 \\ sub x3, sp, #3, lsl #0
500 \\ sub sp, sp, #4095, lsl #12
501 \\ sub x0, x1, #0
502 \\ sub x2, x3, #0, lsl #0
503 \\ sub x4, sp, #0
504 \\ sub x5, sp, #0, lsl #0
505 \\ sub sp, x6, #0
506 \\ sub sp, x7, #0, lsl #0
507 \\ sub sp, sp, #0
508 \\ sub sp, sp, #0, lsl #0
509 \\
510 \\ sub w0, w0, w0
511 \\ sub w1, w1, w2, lsl #0
512 \\ sub w3, w4, w5, lsl #1
513 \\ sub w6, w6, wzr, lsl #31
514 \\ sub w7, wzr, w8, lsr #0
515 \\ sub w9, wzr, wzr, lsr #30
516 \\ sub wzr, w10, w11, lsr #31
517 \\ sub wzr, w12, wzr, asr #0x0
518 \\ sub wzr, wzr, w13, asr #0x10
519 \\ sub wzr, wzr, wzr, asr #0x1f
520 \\
521 \\ sub x0, x0, x0
522 \\ sub x1, x1, x2, lsl #0
523 \\ sub x3, x4, x5, lsl #1
524 \\ sub x6, x6, xzr, lsl #63
525 \\ sub x7, xzr, x8, lsr #0
526 \\ sub x9, xzr, xzr, lsr #62
527 \\ sub xzr, x10, x11, lsr #63
528 \\ sub xzr, x12, xzr, asr #0x0
529 \\ sub xzr, xzr, x13, asr #0x1F
530 \\ sub xzr, xzr, xzr, asr #0x3f
531 \\
532 \\ neg w0, w0
533 \\ neg w1, w2, lsl #0
534 \\ neg w3, wzr, lsl #7
535 \\ neg wzr, w4, lsr #14
536 \\ neg wzr, wzr, asr #21
537 \\
538 \\ neg x0, x0
539 \\ neg x1, x2, lsl #0
540 \\ neg x3, xzr, lsl #11
541 \\ neg xzr, x4, lsr #22
542 \\ neg xzr, xzr, asr #33
543 ,
544 .operands = .empty,
545 };
546
547 try std.testing.expectFmt("add w0, w0, w1", "{f}", .{(try as.nextInstruction()).?});
548 try std.testing.expectFmt("add w2, w3, w4", "{f}", .{(try as.nextInstruction()).?});
549 try std.testing.expectFmt("add wsp, w5, w6", "{f}", .{(try as.nextInstruction()).?});
550 try std.testing.expectFmt("add w7, wsp, w8", "{f}", .{(try as.nextInstruction()).?});
551 try std.testing.expectFmt("add wsp, wsp, w9", "{f}", .{(try as.nextInstruction()).?});
552 try std.testing.expectFmt("add w10, w10, wzr", "{f}", .{(try as.nextInstruction()).?});
553 try std.testing.expectFmt("add w11, w12, wzr", "{f}", .{(try as.nextInstruction()).?});
554 try std.testing.expectFmt("add wsp, w13, wzr", "{f}", .{(try as.nextInstruction()).?});
555 try std.testing.expectFmt("add w14, wsp, wzr", "{f}", .{(try as.nextInstruction()).?});
556 try std.testing.expectFmt("add wsp, wsp, wzr", "{f}", .{(try as.nextInstruction()).?});
557
558 try std.testing.expectFmt("add x0, x0, x1", "{f}", .{(try as.nextInstruction()).?});
559 try std.testing.expectFmt("add x2, x3, x4", "{f}", .{(try as.nextInstruction()).?});
560 try std.testing.expectFmt("add sp, x5, x6", "{f}", .{(try as.nextInstruction()).?});
561 try std.testing.expectFmt("add x7, sp, x8", "{f}", .{(try as.nextInstruction()).?});
562 try std.testing.expectFmt("add sp, sp, x9", "{f}", .{(try as.nextInstruction()).?});
563 try std.testing.expectFmt("add x10, x10, xzr", "{f}", .{(try as.nextInstruction()).?});
564 try std.testing.expectFmt("add x11, x12, xzr", "{f}", .{(try as.nextInstruction()).?});
565 try std.testing.expectFmt("add sp, x13, xzr", "{f}", .{(try as.nextInstruction()).?});
566 try std.testing.expectFmt("add x14, sp, xzr", "{f}", .{(try as.nextInstruction()).?});
567 try std.testing.expectFmt("add sp, sp, xzr", "{f}", .{(try as.nextInstruction()).?});
568
569 try std.testing.expectFmt("add w0, w0, w1", "{f}", .{(try as.nextInstruction()).?});
570 try std.testing.expectFmt("add w2, w3, w4, uxtb #0", "{f}", .{(try as.nextInstruction()).?});
571 try std.testing.expectFmt("add wsp, w5, w6, uxth #1", "{f}", .{(try as.nextInstruction()).?});
572 try std.testing.expectFmt("add w7, wsp, w8", "{f}", .{(try as.nextInstruction()).?});
573 try std.testing.expectFmt("add wsp, wsp, w9, uxtw #2", "{f}", .{(try as.nextInstruction()).?});
574 try std.testing.expectFmt("add w10, w10, wzr, uxtw #3", "{f}", .{(try as.nextInstruction()).?});
575 try std.testing.expectFmt("add w11, w12, wzr, sxtb #4", "{f}", .{(try as.nextInstruction()).?});
576 try std.testing.expectFmt("add wsp, w13, wzr, sxth #0", "{f}", .{(try as.nextInstruction()).?});
577 try std.testing.expectFmt("add w14, wsp, wzr, sxtw #1", "{f}", .{(try as.nextInstruction()).?});
578 try std.testing.expectFmt("add wsp, wsp, wzr, sxtw #2", "{f}", .{(try as.nextInstruction()).?});
579
580 try std.testing.expectFmt("add x0, x0, x1", "{f}", .{(try as.nextInstruction()).?});
581 try std.testing.expectFmt("add x2, x3, w4, uxtb #0", "{f}", .{(try as.nextInstruction()).?});
582 try std.testing.expectFmt("add sp, x5, w6, uxth #1", "{f}", .{(try as.nextInstruction()).?});
583 try std.testing.expectFmt("add x7, sp, w8, uxtw #2", "{f}", .{(try as.nextInstruction()).?});
584 try std.testing.expectFmt("add sp, sp, x9", "{f}", .{(try as.nextInstruction()).?});
585 try std.testing.expectFmt("add x10, x10, xzr, uxtx #3", "{f}", .{(try as.nextInstruction()).?});
586 try std.testing.expectFmt("add x11, x12, wzr, sxtb #4", "{f}", .{(try as.nextInstruction()).?});
587 try std.testing.expectFmt("add sp, x13, wzr, sxth #0", "{f}", .{(try as.nextInstruction()).?});
588 try std.testing.expectFmt("add x14, sp, wzr, sxtw #1", "{f}", .{(try as.nextInstruction()).?});
589 try std.testing.expectFmt("add sp, sp, xzr, sxtx #2", "{f}", .{(try as.nextInstruction()).?});
590
591 try std.testing.expectFmt("add w0, w0, #0x0", "{f}", .{(try as.nextInstruction()).?});
592 try std.testing.expectFmt("add w0, w1, #0x1", "{f}", .{(try as.nextInstruction()).?});
593 try std.testing.expectFmt("add wsp, w2, #0x2, lsl #12", "{f}", .{(try as.nextInstruction()).?});
594 try std.testing.expectFmt("add w3, wsp, #0x3", "{f}", .{(try as.nextInstruction()).?});
595 try std.testing.expectFmt("add wsp, wsp, #0xfff, lsl #12", "{f}", .{(try as.nextInstruction()).?});
596 try std.testing.expectFmt("add w0, w1, #0x0", "{f}", .{(try as.nextInstruction()).?});
597 try std.testing.expectFmt("add w2, w3, #0x0", "{f}", .{(try as.nextInstruction()).?});
598 try std.testing.expectFmt("mov w4, wsp", "{f}", .{(try as.nextInstruction()).?});
599 try std.testing.expectFmt("mov w5, wsp", "{f}", .{(try as.nextInstruction()).?});
600 try std.testing.expectFmt("mov wsp, w6", "{f}", .{(try as.nextInstruction()).?});
601 try std.testing.expectFmt("mov wsp, w7", "{f}", .{(try as.nextInstruction()).?});
602 try std.testing.expectFmt("mov wsp, wsp", "{f}", .{(try as.nextInstruction()).?});
603 try std.testing.expectFmt("mov wsp, wsp", "{f}", .{(try as.nextInstruction()).?});
604
605 try std.testing.expectFmt("add x0, x0, #0x0", "{f}", .{(try as.nextInstruction()).?});
606 try std.testing.expectFmt("add x0, x1, #0x1", "{f}", .{(try as.nextInstruction()).?});
607 try std.testing.expectFmt("add sp, x2, #0x2, lsl #12", "{f}", .{(try as.nextInstruction()).?});
608 try std.testing.expectFmt("add x3, sp, #0x3", "{f}", .{(try as.nextInstruction()).?});
609 try std.testing.expectFmt("add sp, sp, #0xfff, lsl #12", "{f}", .{(try as.nextInstruction()).?});
610 try std.testing.expectFmt("add x0, x1, #0x0", "{f}", .{(try as.nextInstruction()).?});
611 try std.testing.expectFmt("add x2, x3, #0x0", "{f}", .{(try as.nextInstruction()).?});
612 try std.testing.expectFmt("mov x4, sp", "{f}", .{(try as.nextInstruction()).?});
613 try std.testing.expectFmt("mov x5, sp", "{f}", .{(try as.nextInstruction()).?});
614 try std.testing.expectFmt("mov sp, x6", "{f}", .{(try as.nextInstruction()).?});
615 try std.testing.expectFmt("mov sp, x7", "{f}", .{(try as.nextInstruction()).?});
616 try std.testing.expectFmt("mov sp, sp", "{f}", .{(try as.nextInstruction()).?});
617 try std.testing.expectFmt("mov sp, sp", "{f}", .{(try as.nextInstruction()).?});
618
619 try std.testing.expectFmt("add w0, w0, w0", "{f}", .{(try as.nextInstruction()).?});
620 try std.testing.expectFmt("add w1, w1, w2", "{f}", .{(try as.nextInstruction()).?});
621 try std.testing.expectFmt("add w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
622 try std.testing.expectFmt("add w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?});
623 try std.testing.expectFmt("add w7, wzr, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
624 try std.testing.expectFmt("add w9, wzr, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?});
625 try std.testing.expectFmt("add wzr, w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?});
626 try std.testing.expectFmt("add wzr, w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
627 try std.testing.expectFmt("add wzr, wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?});
628 try std.testing.expectFmt("add wzr, wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?});
629
630 try std.testing.expectFmt("add x0, x0, x0", "{f}", .{(try as.nextInstruction()).?});
631 try std.testing.expectFmt("add x1, x1, x2", "{f}", .{(try as.nextInstruction()).?});
632 try std.testing.expectFmt("add x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
633 try std.testing.expectFmt("add x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?});
634 try std.testing.expectFmt("add x7, xzr, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
635 try std.testing.expectFmt("add x9, xzr, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?});
636 try std.testing.expectFmt("add xzr, x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?});
637 try std.testing.expectFmt("add xzr, x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
638 try std.testing.expectFmt("add xzr, xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?});
639 try std.testing.expectFmt("add xzr, xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?});
640
641 try std.testing.expectFmt("sub w0, w0, w1", "{f}", .{(try as.nextInstruction()).?});
642 try std.testing.expectFmt("sub w2, w3, w4", "{f}", .{(try as.nextInstruction()).?});
643 try std.testing.expectFmt("sub wsp, w5, w6", "{f}", .{(try as.nextInstruction()).?});
644 try std.testing.expectFmt("sub w7, wsp, w8", "{f}", .{(try as.nextInstruction()).?});
645 try std.testing.expectFmt("sub wsp, wsp, w9", "{f}", .{(try as.nextInstruction()).?});
646 try std.testing.expectFmt("sub w10, w10, wzr", "{f}", .{(try as.nextInstruction()).?});
647 try std.testing.expectFmt("sub w11, w12, wzr", "{f}", .{(try as.nextInstruction()).?});
648 try std.testing.expectFmt("sub wsp, w13, wzr", "{f}", .{(try as.nextInstruction()).?});
649 try std.testing.expectFmt("sub w14, wsp, wzr", "{f}", .{(try as.nextInstruction()).?});
650 try std.testing.expectFmt("sub wsp, wsp, wzr", "{f}", .{(try as.nextInstruction()).?});
651
652 try std.testing.expectFmt("sub x0, x0, x1", "{f}", .{(try as.nextInstruction()).?});
653 try std.testing.expectFmt("sub x2, x3, x4", "{f}", .{(try as.nextInstruction()).?});
654 try std.testing.expectFmt("sub sp, x5, x6", "{f}", .{(try as.nextInstruction()).?});
655 try std.testing.expectFmt("sub x7, sp, x8", "{f}", .{(try as.nextInstruction()).?});
656 try std.testing.expectFmt("sub sp, sp, x9", "{f}", .{(try as.nextInstruction()).?});
657 try std.testing.expectFmt("sub x10, x10, xzr", "{f}", .{(try as.nextInstruction()).?});
658 try std.testing.expectFmt("sub x11, x12, xzr", "{f}", .{(try as.nextInstruction()).?});
659 try std.testing.expectFmt("sub sp, x13, xzr", "{f}", .{(try as.nextInstruction()).?});
660 try std.testing.expectFmt("sub x14, sp, xzr", "{f}", .{(try as.nextInstruction()).?});
661 try std.testing.expectFmt("sub sp, sp, xzr", "{f}", .{(try as.nextInstruction()).?});
662
663 try std.testing.expectFmt("sub w0, w0, w1", "{f}", .{(try as.nextInstruction()).?});
664 try std.testing.expectFmt("sub w2, w3, w4, uxtb #0", "{f}", .{(try as.nextInstruction()).?});
665 try std.testing.expectFmt("sub wsp, w5, w6, uxth #1", "{f}", .{(try as.nextInstruction()).?});
666 try std.testing.expectFmt("sub w7, wsp, w8", "{f}", .{(try as.nextInstruction()).?});
667 try std.testing.expectFmt("sub wsp, wsp, w9, uxtw #2", "{f}", .{(try as.nextInstruction()).?});
668 try std.testing.expectFmt("sub w10, w10, wzr, uxtw #3", "{f}", .{(try as.nextInstruction()).?});
669 try std.testing.expectFmt("sub w11, w12, wzr, sxtb #4", "{f}", .{(try as.nextInstruction()).?});
670 try std.testing.expectFmt("sub wsp, w13, wzr, sxth #0", "{f}", .{(try as.nextInstruction()).?});
671 try std.testing.expectFmt("sub w14, wsp, wzr, sxtw #1", "{f}", .{(try as.nextInstruction()).?});
672 try std.testing.expectFmt("sub wsp, wsp, wzr, sxtw #2", "{f}", .{(try as.nextInstruction()).?});
673
674 try std.testing.expectFmt("sub x0, x0, x1", "{f}", .{(try as.nextInstruction()).?});
675 try std.testing.expectFmt("sub x2, x3, w4, uxtb #0", "{f}", .{(try as.nextInstruction()).?});
676 try std.testing.expectFmt("sub sp, x5, w6, uxth #1", "{f}", .{(try as.nextInstruction()).?});
677 try std.testing.expectFmt("sub x7, sp, w8, uxtw #2", "{f}", .{(try as.nextInstruction()).?});
678 try std.testing.expectFmt("sub sp, sp, x9", "{f}", .{(try as.nextInstruction()).?});
679 try std.testing.expectFmt("sub x10, x10, xzr, uxtx #3", "{f}", .{(try as.nextInstruction()).?});
680 try std.testing.expectFmt("sub x11, x12, wzr, sxtb #4", "{f}", .{(try as.nextInstruction()).?});
681 try std.testing.expectFmt("sub sp, x13, wzr, sxth #0", "{f}", .{(try as.nextInstruction()).?});
682 try std.testing.expectFmt("sub x14, sp, wzr, sxtw #1", "{f}", .{(try as.nextInstruction()).?});
683 try std.testing.expectFmt("sub sp, sp, xzr, sxtx #2", "{f}", .{(try as.nextInstruction()).?});
684
685 try std.testing.expectFmt("sub w0, w0, #0x0", "{f}", .{(try as.nextInstruction()).?});
686 try std.testing.expectFmt("sub w0, w1, #0x1", "{f}", .{(try as.nextInstruction()).?});
687 try std.testing.expectFmt("sub wsp, w2, #0x2, lsl #12", "{f}", .{(try as.nextInstruction()).?});
688 try std.testing.expectFmt("sub w3, wsp, #0x3", "{f}", .{(try as.nextInstruction()).?});
689 try std.testing.expectFmt("sub wsp, wsp, #0xfff, lsl #12", "{f}", .{(try as.nextInstruction()).?});
690 try std.testing.expectFmt("sub w0, w1, #0x0", "{f}", .{(try as.nextInstruction()).?});
691 try std.testing.expectFmt("sub w2, w3, #0x0", "{f}", .{(try as.nextInstruction()).?});
692 try std.testing.expectFmt("sub w4, wsp, #0x0", "{f}", .{(try as.nextInstruction()).?});
693 try std.testing.expectFmt("sub w5, wsp, #0x0", "{f}", .{(try as.nextInstruction()).?});
694 try std.testing.expectFmt("sub wsp, w6, #0x0", "{f}", .{(try as.nextInstruction()).?});
695 try std.testing.expectFmt("sub wsp, w7, #0x0", "{f}", .{(try as.nextInstruction()).?});
696 try std.testing.expectFmt("sub wsp, wsp, #0x0", "{f}", .{(try as.nextInstruction()).?});
697 try std.testing.expectFmt("sub wsp, wsp, #0x0", "{f}", .{(try as.nextInstruction()).?});
698
699 try std.testing.expectFmt("sub x0, x0, #0x0", "{f}", .{(try as.nextInstruction()).?});
700 try std.testing.expectFmt("sub x0, x1, #0x1", "{f}", .{(try as.nextInstruction()).?});
701 try std.testing.expectFmt("sub sp, x2, #0x2, lsl #12", "{f}", .{(try as.nextInstruction()).?});
702 try std.testing.expectFmt("sub x3, sp, #0x3", "{f}", .{(try as.nextInstruction()).?});
703 try std.testing.expectFmt("sub sp, sp, #0xfff, lsl #12", "{f}", .{(try as.nextInstruction()).?});
704 try std.testing.expectFmt("sub x0, x1, #0x0", "{f}", .{(try as.nextInstruction()).?});
705 try std.testing.expectFmt("sub x2, x3, #0x0", "{f}", .{(try as.nextInstruction()).?});
706 try std.testing.expectFmt("sub x4, sp, #0x0", "{f}", .{(try as.nextInstruction()).?});
707 try std.testing.expectFmt("sub x5, sp, #0x0", "{f}", .{(try as.nextInstruction()).?});
708 try std.testing.expectFmt("sub sp, x6, #0x0", "{f}", .{(try as.nextInstruction()).?});
709 try std.testing.expectFmt("sub sp, x7, #0x0", "{f}", .{(try as.nextInstruction()).?});
710 try std.testing.expectFmt("sub sp, sp, #0x0", "{f}", .{(try as.nextInstruction()).?});
711 try std.testing.expectFmt("sub sp, sp, #0x0", "{f}", .{(try as.nextInstruction()).?});
712
713 try std.testing.expectFmt("sub w0, w0, w0", "{f}", .{(try as.nextInstruction()).?});
714 try std.testing.expectFmt("sub w1, w1, w2", "{f}", .{(try as.nextInstruction()).?});
715 try std.testing.expectFmt("sub w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
716 try std.testing.expectFmt("sub w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?});
717 try std.testing.expectFmt("neg w7, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
718 try std.testing.expectFmt("neg w9, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?});
719 try std.testing.expectFmt("sub wzr, w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?});
720 try std.testing.expectFmt("sub wzr, w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
721 try std.testing.expectFmt("neg wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?});
722 try std.testing.expectFmt("neg wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?});
723
724 try std.testing.expectFmt("sub x0, x0, x0", "{f}", .{(try as.nextInstruction()).?});
725 try std.testing.expectFmt("sub x1, x1, x2", "{f}", .{(try as.nextInstruction()).?});
726 try std.testing.expectFmt("sub x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
727 try std.testing.expectFmt("sub x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?});
728 try std.testing.expectFmt("neg x7, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
729 try std.testing.expectFmt("neg x9, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?});
730 try std.testing.expectFmt("sub xzr, x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?});
731 try std.testing.expectFmt("sub xzr, x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
732 try std.testing.expectFmt("neg xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?});
733 try std.testing.expectFmt("neg xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?});
734
735 try std.testing.expectFmt("neg w0, w0", "{f}", .{(try as.nextInstruction()).?});
736 try std.testing.expectFmt("neg w1, w2", "{f}", .{(try as.nextInstruction()).?});
737 try std.testing.expectFmt("neg w3, wzr, lsl #7", "{f}", .{(try as.nextInstruction()).?});
738 try std.testing.expectFmt("neg wzr, w4, lsr #14", "{f}", .{(try as.nextInstruction()).?});
739 try std.testing.expectFmt("neg wzr, wzr, asr #21", "{f}", .{(try as.nextInstruction()).?});
740
741 try std.testing.expectFmt("neg x0, x0", "{f}", .{(try as.nextInstruction()).?});
742 try std.testing.expectFmt("neg x1, x2", "{f}", .{(try as.nextInstruction()).?});
743 try std.testing.expectFmt("neg x3, xzr, lsl #11", "{f}", .{(try as.nextInstruction()).?});
744 try std.testing.expectFmt("neg xzr, x4, lsr #22", "{f}", .{(try as.nextInstruction()).?});
745 try std.testing.expectFmt("neg xzr, xzr, asr #33", "{f}", .{(try as.nextInstruction()).?});
746
747 try std.testing.expect(null == try as.nextInstruction());
748}
749test "bitfield" {
750 var as: Assemble = .{
751 .source =
752 \\sbfm w0, w0, #0, #31
753 \\sbfm w0, w0, #31, #0
754 \\
755 \\sbfm x0, x0, #0, #63
756 \\sbfm x0, x0, #63, #0
757 \\
758 \\bfm w0, w0, #0, #31
759 \\bfm w0, w0, #31, #0
760 \\
761 \\bfm x0, x0, #0, #63
762 \\bfm x0, x0, #63, #0
763 \\
764 \\ubfm w0, w0, #0, #31
765 \\ubfm w0, w0, #31, #0
766 \\
767 \\ubfm x0, x0, #0, #63
768 \\ubfm x0, x0, #63, #0
769 ,
770 .operands = .empty,
771 };
772
773 try std.testing.expectFmt("sbfm w0, w0, #0, #31", "{f}", .{(try as.nextInstruction()).?});
774 try std.testing.expectFmt("sbfm w0, w0, #31, #0", "{f}", .{(try as.nextInstruction()).?});
775
776 try std.testing.expectFmt("sbfm x0, x0, #0, #63", "{f}", .{(try as.nextInstruction()).?});
777 try std.testing.expectFmt("sbfm x0, x0, #63, #0", "{f}", .{(try as.nextInstruction()).?});
778
779 try std.testing.expectFmt("bfm w0, w0, #0, #31", "{f}", .{(try as.nextInstruction()).?});
780 try std.testing.expectFmt("bfm w0, w0, #31, #0", "{f}", .{(try as.nextInstruction()).?});
781
782 try std.testing.expectFmt("bfm x0, x0, #0, #63", "{f}", .{(try as.nextInstruction()).?});
783 try std.testing.expectFmt("bfm x0, x0, #63, #0", "{f}", .{(try as.nextInstruction()).?});
784
785 try std.testing.expectFmt("ubfm w0, w0, #0, #31", "{f}", .{(try as.nextInstruction()).?});
786 try std.testing.expectFmt("ubfm w0, w0, #31, #0", "{f}", .{(try as.nextInstruction()).?});
787
788 try std.testing.expectFmt("ubfm x0, x0, #0, #63", "{f}", .{(try as.nextInstruction()).?});
789 try std.testing.expectFmt("ubfm x0, x0, #63, #0", "{f}", .{(try as.nextInstruction()).?});
790
791 try std.testing.expect(null == try as.nextInstruction());
792}
793test "branch register" {
794 var as: Assemble = .{
795 .source =
796 \\ret
797 \\br x30
798 \\blr x30
799 \\ret x30
800 \\br x29
801 \\blr x29
802 \\ret x29
803 \\br x2
804 \\blr x1
805 \\ret x0
806 ,
807 .operands = .empty,
808 };
809
810 try std.testing.expectFmt("ret", "{f}", .{(try as.nextInstruction()).?});
811 try std.testing.expectFmt("br x30", "{f}", .{(try as.nextInstruction()).?});
812 try std.testing.expectFmt("blr x30", "{f}", .{(try as.nextInstruction()).?});
813 try std.testing.expectFmt("ret", "{f}", .{(try as.nextInstruction()).?});
814 try std.testing.expectFmt("br x29", "{f}", .{(try as.nextInstruction()).?});
815 try std.testing.expectFmt("blr x29", "{f}", .{(try as.nextInstruction()).?});
816 try std.testing.expectFmt("ret x29", "{f}", .{(try as.nextInstruction()).?});
817 try std.testing.expectFmt("br x2", "{f}", .{(try as.nextInstruction()).?});
818 try std.testing.expectFmt("blr x1", "{f}", .{(try as.nextInstruction()).?});
819 try std.testing.expectFmt("ret x0", "{f}", .{(try as.nextInstruction()).?});
820
821 try std.testing.expect(null == try as.nextInstruction());
822}
823test "exception generating" {
824 var as: Assemble = .{
825 .source =
826 \\SVC #0
827 \\HVC #0x1
828 \\SMC #0o15
829 \\BRK #42
830 \\HLT #0x42
831 \\TCANCEL #123
832 \\DCPS1 #1234
833 \\DCPS2 #12345
834 \\DCPS3 #65535
835 \\DCPS3 #0x0
836 \\DCPS2 #0
837 \\DCPS1
838 ,
839 .operands = .empty,
840 };
841
842 try std.testing.expectFmt("svc #0", "{f}", .{(try as.nextInstruction()).?});
843 try std.testing.expectFmt("hvc #0x1", "{f}", .{(try as.nextInstruction()).?});
844 try std.testing.expectFmt("smc #0xd", "{f}", .{(try as.nextInstruction()).?});
845 try std.testing.expectFmt("brk #0x2a", "{f}", .{(try as.nextInstruction()).?});
846 try std.testing.expectFmt("hlt #0x42", "{f}", .{(try as.nextInstruction()).?});
847 try std.testing.expectFmt("tcancel #0x7b", "{f}", .{(try as.nextInstruction()).?});
848 try std.testing.expectFmt("dcps1 #0x4d2", "{f}", .{(try as.nextInstruction()).?});
849 try std.testing.expectFmt("dcps2 #0x3039", "{f}", .{(try as.nextInstruction()).?});
850 try std.testing.expectFmt("dcps3 #0xffff", "{f}", .{(try as.nextInstruction()).?});
851 try std.testing.expectFmt("dcps3", "{f}", .{(try as.nextInstruction()).?});
852 try std.testing.expectFmt("dcps2", "{f}", .{(try as.nextInstruction()).?});
853 try std.testing.expectFmt("dcps1", "{f}", .{(try as.nextInstruction()).?});
854
855 try std.testing.expect(null == try as.nextInstruction());
856}
857test "extract" {
858 var as: Assemble = .{
859 .source =
860 \\extr W0, W1, W2, #0
861 \\extr W3, W3, W4, #1
862 \\extr W5, W5, W5, #31
863 \\
864 \\extr X0, X1, X2, #0
865 \\extr X3, X3, X4, #1
866 \\extr X5, X5, X5, #63
867 ,
868 .operands = .empty,
869 };
870
871 try std.testing.expectFmt("extr w0, w1, w2, #0", "{f}", .{(try as.nextInstruction()).?});
872 try std.testing.expectFmt("extr w3, w3, w4, #1", "{f}", .{(try as.nextInstruction()).?});
873 try std.testing.expectFmt("extr w5, w5, w5, #31", "{f}", .{(try as.nextInstruction()).?});
874
875 try std.testing.expectFmt("extr x0, x1, x2, #0", "{f}", .{(try as.nextInstruction()).?});
876 try std.testing.expectFmt("extr x3, x3, x4, #1", "{f}", .{(try as.nextInstruction()).?});
877 try std.testing.expectFmt("extr x5, x5, x5, #63", "{f}", .{(try as.nextInstruction()).?});
878
879 try std.testing.expect(null == try as.nextInstruction());
880}
881test "hints" {
882 var as: Assemble = .{
883 .source =
884 \\NOP
885 \\hint #0
886 \\YiElD
887 \\Hint #0x1
888 \\WfE
889 \\hInt #02
890 \\wFi
891 \\hiNt #0b11
892 \\sEv
893 \\hinT #4
894 \\sevl
895 \\HINT #0b101
896 \\hint #0x7F
897 ,
898 .operands = .empty,
899 };
900
901 try std.testing.expectFmt("nop", "{f}", .{(try as.nextInstruction()).?});
902 try std.testing.expectFmt("nop", "{f}", .{(try as.nextInstruction()).?});
903 try std.testing.expectFmt("yield", "{f}", .{(try as.nextInstruction()).?});
904 try std.testing.expectFmt("yield", "{f}", .{(try as.nextInstruction()).?});
905 try std.testing.expectFmt("wfe", "{f}", .{(try as.nextInstruction()).?});
906 try std.testing.expectFmt("wfe", "{f}", .{(try as.nextInstruction()).?});
907 try std.testing.expectFmt("wfi", "{f}", .{(try as.nextInstruction()).?});
908 try std.testing.expectFmt("wfi", "{f}", .{(try as.nextInstruction()).?});
909 try std.testing.expectFmt("sev", "{f}", .{(try as.nextInstruction()).?});
910 try std.testing.expectFmt("sev", "{f}", .{(try as.nextInstruction()).?});
911 try std.testing.expectFmt("sevl", "{f}", .{(try as.nextInstruction()).?});
912 try std.testing.expectFmt("sevl", "{f}", .{(try as.nextInstruction()).?});
913 try std.testing.expectFmt("hint #0x7f", "{f}", .{(try as.nextInstruction()).?});
914
915 try std.testing.expect(null == try as.nextInstruction());
916}
917test "load store" {
918 var as: Assemble = .{
919 .source =
920 \\ LDP w0, w1, [x2], #-256
921 \\ LDP w3, w4, [x5], #0
922 \\ LDP w6, w7, [sp], #252
923 \\ LDP w0, w1, [x2, #-0x100]!
924 \\ LDP w3, w4, [x5, #0]!
925 \\ LDP w6, w7, [sp, #0xfc]!
926 \\ LDP w0, w1, [x2, #-256]
927 \\ LDP w3, w4, [x5]
928 \\ LDP w6, w7, [x8, #0]
929 \\ LDP w9, w10, [sp, #252]
930 \\
931 \\ LDP x0, x1, [x2], #-512
932 \\ LDP x3, x4, [x5], #0
933 \\ LDP x6, x7, [sp], #504
934 \\ LDP x0, x1, [x2, #-0x200]!
935 \\ LDP x3, x4, [x5, #0]!
936 \\ LDP x6, x7, [sp, #0x1f8]!
937 \\ LDP x0, x1, [x2, #-512]
938 \\ LDP x3, x4, [x5]
939 \\ LDP x6, x7, [x8, #0]
940 \\ LDP x9, x10, [sp, #504]
941 \\
942 \\ LDR w0, [x1], #-256
943 \\ LDR w2, [x3], #0
944 \\ LDR w4, [sp], #255
945 \\ LDR w0, [x1, #-0x100]!
946 \\ LDR w2, [x3, #0]!
947 \\ LDR w4, [sp, #0xff]!
948 \\ LDR w0, [x1, #0]
949 \\ LDR w2, [x3]
950 \\ LDR w4, [sp, #16380]
951 \\
952 \\ LDR x0, [x1], #-256
953 \\ LDR x2, [x3], #0
954 \\ LDR x4, [sp], #255
955 \\ LDR x0, [x1, #-0x100]!
956 \\ LDR x2, [x3, #0]!
957 \\ LDR x4, [sp, #0xff]!
958 \\ LDR x0, [x1, #0]
959 \\ LDR x2, [x3]
960 \\ LDR x4, [sp, #32760]
961 \\
962 \\ STP w0, w1, [x2], #-256
963 \\ STP w3, w4, [x5], #0
964 \\ STP w6, w7, [sp], #252
965 \\ STP w0, w1, [x2, #-0x100]!
966 \\ STP w3, w4, [x5, #0]!
967 \\ STP w6, w7, [sp, #0xfc]!
968 \\ STP w0, w1, [x2, #-256]
969 \\ STP w3, w4, [x5]
970 \\ STP w6, w7, [x8, #0]
971 \\ STP w9, w10, [sp, #252]
972 \\
973 \\ STP x0, x1, [x2], #-512
974 \\ STP x3, x4, [x5], #0
975 \\ STP x6, x7, [sp], #504
976 \\ STP x0, x1, [x2, #-0x200]!
977 \\ STP x3, x4, [x5, #0]!
978 \\ STP x6, x7, [sp, #0x1f8]!
979 \\ STP x0, x1, [x2, #-512]
980 \\ STP x3, x4, [x5]
981 \\ STP x6, x7, [x8, #0]
982 \\ STP x9, x10, [sp, #504]
983 \\
984 \\ STR w0, [x1], #-256
985 \\ STR w2, [x3], #0
986 \\ STR w4, [sp], #255
987 \\ STR w0, [x1, #-0x100]!
988 \\ STR w2, [x3, #0]!
989 \\ STR w4, [sp, #0xff]!
990 \\ STR w0, [x1, #0]
991 \\ STR w2, [x3]
992 \\ STR w4, [sp, #16380]
993 \\
994 \\ STR x0, [x1], #-256
995 \\ STR x2, [x3], #0
996 \\ STR x4, [sp], #255
997 \\ STR x0, [x1, #-0x100]!
998 \\ STR x2, [x3, #0]!
999 \\ STR x4, [sp, #0xff]!
1000 \\ STR x0, [x1, #0]
1001 \\ STR x2, [x3]
1002 \\ STR x4, [sp, #32760]
1003 ,
1004 .operands = .empty,
1005 };
1006
1007 try std.testing.expectFmt("ldp w0, w1, [x2], #-0x100", "{f}", .{(try as.nextInstruction()).?});
1008 try std.testing.expectFmt("ldp w3, w4, [x5], #0x0", "{f}", .{(try as.nextInstruction()).?});
1009 try std.testing.expectFmt("ldp w6, w7, [sp], #0xfc", "{f}", .{(try as.nextInstruction()).?});
1010 try std.testing.expectFmt("ldp w0, w1, [x2, #-0x100]!", "{f}", .{(try as.nextInstruction()).?});
1011 try std.testing.expectFmt("ldp w3, w4, [x5, #0x0]!", "{f}", .{(try as.nextInstruction()).?});
1012 try std.testing.expectFmt("ldp w6, w7, [sp, #0xfc]!", "{f}", .{(try as.nextInstruction()).?});
1013 try std.testing.expectFmt("ldp w0, w1, [x2, #-0x100]", "{f}", .{(try as.nextInstruction()).?});
1014 try std.testing.expectFmt("ldp w3, w4, [x5]", "{f}", .{(try as.nextInstruction()).?});
1015 try std.testing.expectFmt("ldp w6, w7, [x8]", "{f}", .{(try as.nextInstruction()).?});
1016 try std.testing.expectFmt("ldp w9, w10, [sp, #0xfc]", "{f}", .{(try as.nextInstruction()).?});
1017
1018 try std.testing.expectFmt("ldp x0, x1, [x2], #-0x200", "{f}", .{(try as.nextInstruction()).?});
1019 try std.testing.expectFmt("ldp x3, x4, [x5], #0x0", "{f}", .{(try as.nextInstruction()).?});
1020 try std.testing.expectFmt("ldp x6, x7, [sp], #0x1f8", "{f}", .{(try as.nextInstruction()).?});
1021 try std.testing.expectFmt("ldp x0, x1, [x2, #-0x200]!", "{f}", .{(try as.nextInstruction()).?});
1022 try std.testing.expectFmt("ldp x3, x4, [x5, #0x0]!", "{f}", .{(try as.nextInstruction()).?});
1023 try std.testing.expectFmt("ldp x6, x7, [sp, #0x1f8]!", "{f}", .{(try as.nextInstruction()).?});
1024 try std.testing.expectFmt("ldp x0, x1, [x2, #-0x200]", "{f}", .{(try as.nextInstruction()).?});
1025 try std.testing.expectFmt("ldp x3, x4, [x5]", "{f}", .{(try as.nextInstruction()).?});
1026 try std.testing.expectFmt("ldp x6, x7, [x8]", "{f}", .{(try as.nextInstruction()).?});
1027 try std.testing.expectFmt("ldp x9, x10, [sp, #0x1f8]", "{f}", .{(try as.nextInstruction()).?});
1028
1029 try std.testing.expectFmt("ldr w0, [x1], #-0x100", "{f}", .{(try as.nextInstruction()).?});
1030 try std.testing.expectFmt("ldr w2, [x3], #0x0", "{f}", .{(try as.nextInstruction()).?});
1031 try std.testing.expectFmt("ldr w4, [sp], #0xff", "{f}", .{(try as.nextInstruction()).?});
1032 try std.testing.expectFmt("ldr w0, [x1, #-0x100]!", "{f}", .{(try as.nextInstruction()).?});
1033 try std.testing.expectFmt("ldr w2, [x3, #0x0]!", "{f}", .{(try as.nextInstruction()).?});
1034 try std.testing.expectFmt("ldr w4, [sp, #0xff]!", "{f}", .{(try as.nextInstruction()).?});
1035 try std.testing.expectFmt("ldr w0, [x1]", "{f}", .{(try as.nextInstruction()).?});
1036 try std.testing.expectFmt("ldr w2, [x3]", "{f}", .{(try as.nextInstruction()).?});
1037 try std.testing.expectFmt("ldr w4, [sp, #0x3ffc]", "{f}", .{(try as.nextInstruction()).?});
1038
1039 try std.testing.expectFmt("ldr x0, [x1], #-0x100", "{f}", .{(try as.nextInstruction()).?});
1040 try std.testing.expectFmt("ldr x2, [x3], #0x0", "{f}", .{(try as.nextInstruction()).?});
1041 try std.testing.expectFmt("ldr x4, [sp], #0xff", "{f}", .{(try as.nextInstruction()).?});
1042 try std.testing.expectFmt("ldr x0, [x1, #-0x100]!", "{f}", .{(try as.nextInstruction()).?});
1043 try std.testing.expectFmt("ldr x2, [x3, #0x0]!", "{f}", .{(try as.nextInstruction()).?});
1044 try std.testing.expectFmt("ldr x4, [sp, #0xff]!", "{f}", .{(try as.nextInstruction()).?});
1045 try std.testing.expectFmt("ldr x0, [x1]", "{f}", .{(try as.nextInstruction()).?});
1046 try std.testing.expectFmt("ldr x2, [x3]", "{f}", .{(try as.nextInstruction()).?});
1047 try std.testing.expectFmt("ldr x4, [sp, #0x7ff8]", "{f}", .{(try as.nextInstruction()).?});
1048
1049 try std.testing.expectFmt("stp w0, w1, [x2], #-0x100", "{f}", .{(try as.nextInstruction()).?});
1050 try std.testing.expectFmt("stp w3, w4, [x5], #0x0", "{f}", .{(try as.nextInstruction()).?});
1051 try std.testing.expectFmt("stp w6, w7, [sp], #0xfc", "{f}", .{(try as.nextInstruction()).?});
1052 try std.testing.expectFmt("stp w0, w1, [x2, #-0x100]!", "{f}", .{(try as.nextInstruction()).?});
1053 try std.testing.expectFmt("stp w3, w4, [x5, #0x0]!", "{f}", .{(try as.nextInstruction()).?});
1054 try std.testing.expectFmt("stp w6, w7, [sp, #0xfc]!", "{f}", .{(try as.nextInstruction()).?});
1055 try std.testing.expectFmt("stp w0, w1, [x2, #-0x100]", "{f}", .{(try as.nextInstruction()).?});
1056 try std.testing.expectFmt("stp w3, w4, [x5]", "{f}", .{(try as.nextInstruction()).?});
1057 try std.testing.expectFmt("stp w6, w7, [x8]", "{f}", .{(try as.nextInstruction()).?});
1058 try std.testing.expectFmt("stp w9, w10, [sp, #0xfc]", "{f}", .{(try as.nextInstruction()).?});
1059
1060 try std.testing.expectFmt("stp x0, x1, [x2], #-0x200", "{f}", .{(try as.nextInstruction()).?});
1061 try std.testing.expectFmt("stp x3, x4, [x5], #0x0", "{f}", .{(try as.nextInstruction()).?});
1062 try std.testing.expectFmt("stp x6, x7, [sp], #0x1f8", "{f}", .{(try as.nextInstruction()).?});
1063 try std.testing.expectFmt("stp x0, x1, [x2, #-0x200]!", "{f}", .{(try as.nextInstruction()).?});
1064 try std.testing.expectFmt("stp x3, x4, [x5, #0x0]!", "{f}", .{(try as.nextInstruction()).?});
1065 try std.testing.expectFmt("stp x6, x7, [sp, #0x1f8]!", "{f}", .{(try as.nextInstruction()).?});
1066 try std.testing.expectFmt("stp x0, x1, [x2, #-0x200]", "{f}", .{(try as.nextInstruction()).?});
1067 try std.testing.expectFmt("stp x3, x4, [x5]", "{f}", .{(try as.nextInstruction()).?});
1068 try std.testing.expectFmt("stp x6, x7, [x8]", "{f}", .{(try as.nextInstruction()).?});
1069 try std.testing.expectFmt("stp x9, x10, [sp, #0x1f8]", "{f}", .{(try as.nextInstruction()).?});
1070
1071 try std.testing.expectFmt("str w0, [x1], #-0x100", "{f}", .{(try as.nextInstruction()).?});
1072 try std.testing.expectFmt("str w2, [x3], #0x0", "{f}", .{(try as.nextInstruction()).?});
1073 try std.testing.expectFmt("str w4, [sp], #0xff", "{f}", .{(try as.nextInstruction()).?});
1074 try std.testing.expectFmt("str w0, [x1, #-0x100]!", "{f}", .{(try as.nextInstruction()).?});
1075 try std.testing.expectFmt("str w2, [x3, #0x0]!", "{f}", .{(try as.nextInstruction()).?});
1076 try std.testing.expectFmt("str w4, [sp, #0xff]!", "{f}", .{(try as.nextInstruction()).?});
1077 try std.testing.expectFmt("str w0, [x1]", "{f}", .{(try as.nextInstruction()).?});
1078 try std.testing.expectFmt("str w2, [x3]", "{f}", .{(try as.nextInstruction()).?});
1079 try std.testing.expectFmt("str w4, [sp, #0x3ffc]", "{f}", .{(try as.nextInstruction()).?});
1080
1081 try std.testing.expectFmt("str x0, [x1], #-0x100", "{f}", .{(try as.nextInstruction()).?});
1082 try std.testing.expectFmt("str x2, [x3], #0x0", "{f}", .{(try as.nextInstruction()).?});
1083 try std.testing.expectFmt("str x4, [sp], #0xff", "{f}", .{(try as.nextInstruction()).?});
1084 try std.testing.expectFmt("str x0, [x1, #-0x100]!", "{f}", .{(try as.nextInstruction()).?});
1085 try std.testing.expectFmt("str x2, [x3, #0x0]!", "{f}", .{(try as.nextInstruction()).?});
1086 try std.testing.expectFmt("str x4, [sp, #0xff]!", "{f}", .{(try as.nextInstruction()).?});
1087 try std.testing.expectFmt("str x0, [x1]", "{f}", .{(try as.nextInstruction()).?});
1088 try std.testing.expectFmt("str x2, [x3]", "{f}", .{(try as.nextInstruction()).?});
1089 try std.testing.expectFmt("str x4, [sp, #0x7ff8]", "{f}", .{(try as.nextInstruction()).?});
1090
1091 try std.testing.expect(null == try as.nextInstruction());
1092}
1093test "logical" {
1094 var as: Assemble = .{
1095 .source =
1096 \\ and w0, w0, w0
1097 \\ and w1, w1, w2, lsl #0
1098 \\ and w3, w4, w5, lsl #1
1099 \\ and w6, w6, wzr, lsl #31
1100 \\ and w7, wzr, w8, lsr #0
1101 \\ and w9, wzr, wzr, lsr #30
1102 \\ and wzr, w10, w11, lsr #31
1103 \\ and wzr, w12, wzr, asr #0x0
1104 \\ and wzr, wzr, w13, asr #0x10
1105 \\ and wzr, wzr, wzr, asr #0x1f
1106 \\ and w0, w0, wzr
1107 \\ and w1, w2, wzr, lsl #0
1108 \\ and w3, wzr, w3
1109 \\ and w4, wzr, w5, lsl #0
1110 \\ and w6, wzr, wzr
1111 \\ and w7, wzr, wzr, lsl #0
1112 \\ and wzr, w8, wzr
1113 \\ and wzr, w9, wzr, lsl #0
1114 \\ and wzr, wzr, w10
1115 \\ and wzr, wzr, w11, lsl #0
1116 \\ and wzr, wzr, wzr
1117 \\ and wzr, wzr, wzr, lsl #0
1118 \\
1119 \\ and x0, x0, x0
1120 \\ and x1, x1, x2, lsl #0
1121 \\ and x3, x4, x5, lsl #1
1122 \\ and x6, x6, xzr, lsl #63
1123 \\ and x7, xzr, x8, lsr #0
1124 \\ and x9, xzr, xzr, lsr #62
1125 \\ and xzr, x10, x11, lsr #63
1126 \\ and xzr, x12, xzr, asr #0x0
1127 \\ and xzr, xzr, x13, asr #0x1F
1128 \\ and xzr, xzr, xzr, asr #0x3f
1129 \\ and x0, x0, xzr
1130 \\ and x1, x2, xzr, lsl #0
1131 \\ and x3, xzr, x3
1132 \\ and x4, xzr, x5, lsl #0
1133 \\ and x6, xzr, xzr
1134 \\ and x7, xzr, xzr, lsl #0
1135 \\ and xzr, x8, xzr
1136 \\ and xzr, x9, xzr, lsl #0
1137 \\ and xzr, xzr, x10
1138 \\ and xzr, xzr, x11, lsl #0
1139 \\ and xzr, xzr, xzr
1140 \\ and xzr, xzr, xzr, lsl #0
1141 \\
1142 \\ orr w0, w0, w0
1143 \\ orr w1, w1, w2, lsl #0
1144 \\ orr w3, w4, w5, lsl #1
1145 \\ orr w6, w6, wzr, lsl #31
1146 \\ orr w7, wzr, w8, lsr #0
1147 \\ orr w9, wzr, wzr, lsr #30
1148 \\ orr wzr, w10, w11, lsr #31
1149 \\ orr wzr, w12, wzr, asr #0x0
1150 \\ orr wzr, wzr, w13, asr #0x10
1151 \\ orr wzr, wzr, wzr, asr #0x1f
1152 \\ orr w0, w0, wzr
1153 \\ orr w1, w2, wzr, lsl #0
1154 \\ orr w3, wzr, w3
1155 \\ orr w4, wzr, w5, lsl #0
1156 \\ orr w6, wzr, wzr
1157 \\ orr w7, wzr, wzr, lsl #0
1158 \\ orr wzr, w8, wzr
1159 \\ orr wzr, w9, wzr, lsl #0
1160 \\ orr wzr, wzr, w10
1161 \\ orr wzr, wzr, w11, lsl #0
1162 \\ orr wzr, wzr, wzr
1163 \\ orr wzr, wzr, wzr, lsl #0
1164 \\
1165 \\ orr x0, x0, x0
1166 \\ orr x1, x1, x2, lsl #0
1167 \\ orr x3, x4, x5, lsl #1
1168 \\ orr x6, x6, xzr, lsl #63
1169 \\ orr x7, xzr, x8, lsr #0
1170 \\ orr x9, xzr, xzr, lsr #62
1171 \\ orr xzr, x10, x11, lsr #63
1172 \\ orr xzr, x12, xzr, asr #0x0
1173 \\ orr xzr, xzr, x13, asr #0x1F
1174 \\ orr xzr, xzr, xzr, asr #0x3f
1175 \\ orr x0, x0, xzr
1176 \\ orr x1, x2, xzr, lsl #0
1177 \\ orr x3, xzr, x3
1178 \\ orr x4, xzr, x5, lsl #0
1179 \\ orr x6, xzr, xzr
1180 \\ orr x7, xzr, xzr, lsl #0
1181 \\ orr xzr, x8, xzr
1182 \\ orr xzr, x9, xzr, lsl #0
1183 \\ orr xzr, xzr, x10
1184 \\ orr xzr, xzr, x11, lsl #0
1185 \\ orr xzr, xzr, xzr
1186 \\ orr xzr, xzr, xzr, lsl #0
1187 \\
1188 \\ eor w0, w0, w0
1189 \\ eor w1, w1, w2, lsl #0
1190 \\ eor w3, w4, w5, lsl #1
1191 \\ eor w6, w6, wzr, lsl #31
1192 \\ eor w7, wzr, w8, lsr #0
1193 \\ eor w9, wzr, wzr, lsr #30
1194 \\ eor wzr, w10, w11, lsr #31
1195 \\ eor wzr, w12, wzr, asr #0x0
1196 \\ eor wzr, wzr, w13, asr #0x10
1197 \\ eor wzr, wzr, wzr, asr #0x1f
1198 \\ eor w0, w0, wzr
1199 \\ eor w1, w2, wzr, lsl #0
1200 \\ eor w3, wzr, w3
1201 \\ eor w4, wzr, w5, lsl #0
1202 \\ eor w6, wzr, wzr
1203 \\ eor w7, wzr, wzr, lsl #0
1204 \\ eor wzr, w8, wzr
1205 \\ eor wzr, w9, wzr, lsl #0
1206 \\ eor wzr, wzr, w10
1207 \\ eor wzr, wzr, w11, lsl #0
1208 \\ eor wzr, wzr, wzr
1209 \\ eor wzr, wzr, wzr, lsl #0
1210 \\
1211 \\ eor x0, x0, x0
1212 \\ eor x1, x1, x2, lsl #0
1213 \\ eor x3, x4, x5, lsl #1
1214 \\ eor x6, x6, xzr, lsl #63
1215 \\ eor x7, xzr, x8, lsr #0
1216 \\ eor x9, xzr, xzr, lsr #62
1217 \\ eor xzr, x10, x11, lsr #63
1218 \\ eor xzr, x12, xzr, asr #0x0
1219 \\ eor xzr, xzr, x13, asr #0x1F
1220 \\ eor xzr, xzr, xzr, asr #0x3f
1221 \\ eor x0, x0, xzr
1222 \\ eor x1, x2, xzr, lsl #0
1223 \\ eor x3, xzr, x3
1224 \\ eor x4, xzr, x5, lsl #0
1225 \\ eor x6, xzr, xzr
1226 \\ eor x7, xzr, xzr, lsl #0
1227 \\ eor xzr, x8, xzr
1228 \\ eor xzr, x9, xzr, lsl #0
1229 \\ eor xzr, xzr, x10
1230 \\ eor xzr, xzr, x11, lsl #0
1231 \\ eor xzr, xzr, xzr
1232 \\ eor xzr, xzr, xzr, lsl #0
1233 \\
1234 \\ ands w0, w0, w0
1235 \\ ands w1, w1, w2, lsl #0
1236 \\ ands w3, w4, w5, lsl #1
1237 \\ ands w6, w6, wzr, lsl #31
1238 \\ ands w7, wzr, w8, lsr #0
1239 \\ ands w9, wzr, wzr, lsr #30
1240 \\ ands wzr, w10, w11, lsr #31
1241 \\ ands wzr, w12, wzr, asr #0x0
1242 \\ ands wzr, wzr, w13, asr #0x10
1243 \\ ands wzr, wzr, wzr, asr #0x1f
1244 \\ ands w0, w0, wzr
1245 \\ ands w1, w2, wzr, lsl #0
1246 \\ ands w3, wzr, w3
1247 \\ ands w4, wzr, w5, lsl #0
1248 \\ ands w6, wzr, wzr
1249 \\ ands w7, wzr, wzr, lsl #0
1250 \\ ands wzr, w8, wzr
1251 \\ ands wzr, w9, wzr, lsl #0
1252 \\ ands wzr, wzr, w10
1253 \\ ands wzr, wzr, w11, lsl #0
1254 \\ ands wzr, wzr, wzr
1255 \\ ands wzr, wzr, wzr, lsl #0
1256 \\
1257 \\ ands x0, x0, x0
1258 \\ ands x1, x1, x2, lsl #0
1259 \\ ands x3, x4, x5, lsl #1
1260 \\ ands x6, x6, xzr, lsl #63
1261 \\ ands x7, xzr, x8, lsr #0
1262 \\ ands x9, xzr, xzr, lsr #62
1263 \\ ands xzr, x10, x11, lsr #63
1264 \\ ands xzr, x12, xzr, asr #0x0
1265 \\ ands xzr, xzr, x13, asr #0x1F
1266 \\ ands xzr, xzr, xzr, asr #0x3f
1267 \\ ands x0, x0, xzr
1268 \\ ands x1, x2, xzr, lsl #0
1269 \\ ands x3, xzr, x3
1270 \\ ands x4, xzr, x5, lsl #0
1271 \\ ands x6, xzr, xzr
1272 \\ ands x7, xzr, xzr, lsl #0
1273 \\ ands xzr, x8, xzr
1274 \\ ands xzr, x9, xzr, lsl #0
1275 \\ ands xzr, xzr, x10
1276 \\ ands xzr, xzr, x11, lsl #0
1277 \\ ands xzr, xzr, xzr
1278 \\ ands xzr, xzr, xzr, lsl #0
1279 ,
1280 .operands = .empty,
1281 };
1282
1283 try std.testing.expectFmt("and w0, w0, w0", "{f}", .{(try as.nextInstruction()).?});
1284 try std.testing.expectFmt("and w1, w1, w2", "{f}", .{(try as.nextInstruction()).?});
1285 try std.testing.expectFmt("and w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
1286 try std.testing.expectFmt("and w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?});
1287 try std.testing.expectFmt("and w7, wzr, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
1288 try std.testing.expectFmt("and w9, wzr, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?});
1289 try std.testing.expectFmt("and wzr, w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?});
1290 try std.testing.expectFmt("and wzr, w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
1291 try std.testing.expectFmt("and wzr, wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?});
1292 try std.testing.expectFmt("and wzr, wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?});
1293 try std.testing.expectFmt("and w0, w0, wzr", "{f}", .{(try as.nextInstruction()).?});
1294 try std.testing.expectFmt("and w1, w2, wzr", "{f}", .{(try as.nextInstruction()).?});
1295 try std.testing.expectFmt("and w3, wzr, w3", "{f}", .{(try as.nextInstruction()).?});
1296 try std.testing.expectFmt("and w4, wzr, w5", "{f}", .{(try as.nextInstruction()).?});
1297 try std.testing.expectFmt("and w6, wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1298 try std.testing.expectFmt("and w7, wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1299 try std.testing.expectFmt("and wzr, w8, wzr", "{f}", .{(try as.nextInstruction()).?});
1300 try std.testing.expectFmt("and wzr, w9, wzr", "{f}", .{(try as.nextInstruction()).?});
1301 try std.testing.expectFmt("and wzr, wzr, w10", "{f}", .{(try as.nextInstruction()).?});
1302 try std.testing.expectFmt("and wzr, wzr, w11", "{f}", .{(try as.nextInstruction()).?});
1303 try std.testing.expectFmt("and wzr, wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1304 try std.testing.expectFmt("and wzr, wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1305
1306 try std.testing.expectFmt("and x0, x0, x0", "{f}", .{(try as.nextInstruction()).?});
1307 try std.testing.expectFmt("and x1, x1, x2", "{f}", .{(try as.nextInstruction()).?});
1308 try std.testing.expectFmt("and x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
1309 try std.testing.expectFmt("and x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?});
1310 try std.testing.expectFmt("and x7, xzr, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
1311 try std.testing.expectFmt("and x9, xzr, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?});
1312 try std.testing.expectFmt("and xzr, x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?});
1313 try std.testing.expectFmt("and xzr, x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
1314 try std.testing.expectFmt("and xzr, xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?});
1315 try std.testing.expectFmt("and xzr, xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?});
1316 try std.testing.expectFmt("and x0, x0, xzr", "{f}", .{(try as.nextInstruction()).?});
1317 try std.testing.expectFmt("and x1, x2, xzr", "{f}", .{(try as.nextInstruction()).?});
1318 try std.testing.expectFmt("and x3, xzr, x3", "{f}", .{(try as.nextInstruction()).?});
1319 try std.testing.expectFmt("and x4, xzr, x5", "{f}", .{(try as.nextInstruction()).?});
1320 try std.testing.expectFmt("and x6, xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1321 try std.testing.expectFmt("and x7, xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1322 try std.testing.expectFmt("and xzr, x8, xzr", "{f}", .{(try as.nextInstruction()).?});
1323 try std.testing.expectFmt("and xzr, x9, xzr", "{f}", .{(try as.nextInstruction()).?});
1324 try std.testing.expectFmt("and xzr, xzr, x10", "{f}", .{(try as.nextInstruction()).?});
1325 try std.testing.expectFmt("and xzr, xzr, x11", "{f}", .{(try as.nextInstruction()).?});
1326 try std.testing.expectFmt("and xzr, xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1327 try std.testing.expectFmt("and xzr, xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1328
1329 try std.testing.expectFmt("orr w0, w0, w0", "{f}", .{(try as.nextInstruction()).?});
1330 try std.testing.expectFmt("orr w1, w1, w2", "{f}", .{(try as.nextInstruction()).?});
1331 try std.testing.expectFmt("orr w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
1332 try std.testing.expectFmt("orr w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?});
1333 try std.testing.expectFmt("orr w7, wzr, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
1334 try std.testing.expectFmt("orr w9, wzr, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?});
1335 try std.testing.expectFmt("orr wzr, w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?});
1336 try std.testing.expectFmt("orr wzr, w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
1337 try std.testing.expectFmt("orr wzr, wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?});
1338 try std.testing.expectFmt("orr wzr, wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?});
1339 try std.testing.expectFmt("orr w0, w0, wzr", "{f}", .{(try as.nextInstruction()).?});
1340 try std.testing.expectFmt("orr w1, w2, wzr", "{f}", .{(try as.nextInstruction()).?});
1341 try std.testing.expectFmt("mov w3, w3", "{f}", .{(try as.nextInstruction()).?});
1342 try std.testing.expectFmt("mov w4, w5", "{f}", .{(try as.nextInstruction()).?});
1343 try std.testing.expectFmt("mov w6, wzr", "{f}", .{(try as.nextInstruction()).?});
1344 try std.testing.expectFmt("mov w7, wzr", "{f}", .{(try as.nextInstruction()).?});
1345 try std.testing.expectFmt("orr wzr, w8, wzr", "{f}", .{(try as.nextInstruction()).?});
1346 try std.testing.expectFmt("orr wzr, w9, wzr", "{f}", .{(try as.nextInstruction()).?});
1347 try std.testing.expectFmt("mov wzr, w10", "{f}", .{(try as.nextInstruction()).?});
1348 try std.testing.expectFmt("mov wzr, w11", "{f}", .{(try as.nextInstruction()).?});
1349 try std.testing.expectFmt("mov wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1350 try std.testing.expectFmt("mov wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1351
1352 try std.testing.expectFmt("orr x0, x0, x0", "{f}", .{(try as.nextInstruction()).?});
1353 try std.testing.expectFmt("orr x1, x1, x2", "{f}", .{(try as.nextInstruction()).?});
1354 try std.testing.expectFmt("orr x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
1355 try std.testing.expectFmt("orr x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?});
1356 try std.testing.expectFmt("orr x7, xzr, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
1357 try std.testing.expectFmt("orr x9, xzr, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?});
1358 try std.testing.expectFmt("orr xzr, x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?});
1359 try std.testing.expectFmt("orr xzr, x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
1360 try std.testing.expectFmt("orr xzr, xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?});
1361 try std.testing.expectFmt("orr xzr, xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?});
1362 try std.testing.expectFmt("orr x0, x0, xzr", "{f}", .{(try as.nextInstruction()).?});
1363 try std.testing.expectFmt("orr x1, x2, xzr", "{f}", .{(try as.nextInstruction()).?});
1364 try std.testing.expectFmt("mov x3, x3", "{f}", .{(try as.nextInstruction()).?});
1365 try std.testing.expectFmt("mov x4, x5", "{f}", .{(try as.nextInstruction()).?});
1366 try std.testing.expectFmt("mov x6, xzr", "{f}", .{(try as.nextInstruction()).?});
1367 try std.testing.expectFmt("mov x7, xzr", "{f}", .{(try as.nextInstruction()).?});
1368 try std.testing.expectFmt("orr xzr, x8, xzr", "{f}", .{(try as.nextInstruction()).?});
1369 try std.testing.expectFmt("orr xzr, x9, xzr", "{f}", .{(try as.nextInstruction()).?});
1370 try std.testing.expectFmt("mov xzr, x10", "{f}", .{(try as.nextInstruction()).?});
1371 try std.testing.expectFmt("mov xzr, x11", "{f}", .{(try as.nextInstruction()).?});
1372 try std.testing.expectFmt("mov xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1373 try std.testing.expectFmt("mov xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1374
1375 try std.testing.expectFmt("eor w0, w0, w0", "{f}", .{(try as.nextInstruction()).?});
1376 try std.testing.expectFmt("eor w1, w1, w2", "{f}", .{(try as.nextInstruction()).?});
1377 try std.testing.expectFmt("eor w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
1378 try std.testing.expectFmt("eor w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?});
1379 try std.testing.expectFmt("eor w7, wzr, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
1380 try std.testing.expectFmt("eor w9, wzr, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?});
1381 try std.testing.expectFmt("eor wzr, w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?});
1382 try std.testing.expectFmt("eor wzr, w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
1383 try std.testing.expectFmt("eor wzr, wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?});
1384 try std.testing.expectFmt("eor wzr, wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?});
1385 try std.testing.expectFmt("eor w0, w0, wzr", "{f}", .{(try as.nextInstruction()).?});
1386 try std.testing.expectFmt("eor w1, w2, wzr", "{f}", .{(try as.nextInstruction()).?});
1387 try std.testing.expectFmt("eor w3, wzr, w3", "{f}", .{(try as.nextInstruction()).?});
1388 try std.testing.expectFmt("eor w4, wzr, w5", "{f}", .{(try as.nextInstruction()).?});
1389 try std.testing.expectFmt("eor w6, wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1390 try std.testing.expectFmt("eor w7, wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1391 try std.testing.expectFmt("eor wzr, w8, wzr", "{f}", .{(try as.nextInstruction()).?});
1392 try std.testing.expectFmt("eor wzr, w9, wzr", "{f}", .{(try as.nextInstruction()).?});
1393 try std.testing.expectFmt("eor wzr, wzr, w10", "{f}", .{(try as.nextInstruction()).?});
1394 try std.testing.expectFmt("eor wzr, wzr, w11", "{f}", .{(try as.nextInstruction()).?});
1395 try std.testing.expectFmt("eor wzr, wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1396 try std.testing.expectFmt("eor wzr, wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1397
1398 try std.testing.expectFmt("eor x0, x0, x0", "{f}", .{(try as.nextInstruction()).?});
1399 try std.testing.expectFmt("eor x1, x1, x2", "{f}", .{(try as.nextInstruction()).?});
1400 try std.testing.expectFmt("eor x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
1401 try std.testing.expectFmt("eor x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?});
1402 try std.testing.expectFmt("eor x7, xzr, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
1403 try std.testing.expectFmt("eor x9, xzr, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?});
1404 try std.testing.expectFmt("eor xzr, x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?});
1405 try std.testing.expectFmt("eor xzr, x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
1406 try std.testing.expectFmt("eor xzr, xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?});
1407 try std.testing.expectFmt("eor xzr, xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?});
1408 try std.testing.expectFmt("eor x0, x0, xzr", "{f}", .{(try as.nextInstruction()).?});
1409 try std.testing.expectFmt("eor x1, x2, xzr", "{f}", .{(try as.nextInstruction()).?});
1410 try std.testing.expectFmt("eor x3, xzr, x3", "{f}", .{(try as.nextInstruction()).?});
1411 try std.testing.expectFmt("eor x4, xzr, x5", "{f}", .{(try as.nextInstruction()).?});
1412 try std.testing.expectFmt("eor x6, xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1413 try std.testing.expectFmt("eor x7, xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1414 try std.testing.expectFmt("eor xzr, x8, xzr", "{f}", .{(try as.nextInstruction()).?});
1415 try std.testing.expectFmt("eor xzr, x9, xzr", "{f}", .{(try as.nextInstruction()).?});
1416 try std.testing.expectFmt("eor xzr, xzr, x10", "{f}", .{(try as.nextInstruction()).?});
1417 try std.testing.expectFmt("eor xzr, xzr, x11", "{f}", .{(try as.nextInstruction()).?});
1418 try std.testing.expectFmt("eor xzr, xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1419 try std.testing.expectFmt("eor xzr, xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1420
1421 try std.testing.expectFmt("ands w0, w0, w0", "{f}", .{(try as.nextInstruction()).?});
1422 try std.testing.expectFmt("ands w1, w1, w2", "{f}", .{(try as.nextInstruction()).?});
1423 try std.testing.expectFmt("ands w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
1424 try std.testing.expectFmt("ands w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?});
1425 try std.testing.expectFmt("ands w7, wzr, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
1426 try std.testing.expectFmt("ands w9, wzr, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?});
1427 try std.testing.expectFmt("tst w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?});
1428 try std.testing.expectFmt("tst w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
1429 try std.testing.expectFmt("tst wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?});
1430 try std.testing.expectFmt("tst wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?});
1431 try std.testing.expectFmt("ands w0, w0, wzr", "{f}", .{(try as.nextInstruction()).?});
1432 try std.testing.expectFmt("ands w1, w2, wzr", "{f}", .{(try as.nextInstruction()).?});
1433 try std.testing.expectFmt("ands w3, wzr, w3", "{f}", .{(try as.nextInstruction()).?});
1434 try std.testing.expectFmt("ands w4, wzr, w5", "{f}", .{(try as.nextInstruction()).?});
1435 try std.testing.expectFmt("ands w6, wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1436 try std.testing.expectFmt("ands w7, wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1437 try std.testing.expectFmt("tst w8, wzr", "{f}", .{(try as.nextInstruction()).?});
1438 try std.testing.expectFmt("tst w9, wzr", "{f}", .{(try as.nextInstruction()).?});
1439 try std.testing.expectFmt("tst wzr, w10", "{f}", .{(try as.nextInstruction()).?});
1440 try std.testing.expectFmt("tst wzr, w11", "{f}", .{(try as.nextInstruction()).?});
1441 try std.testing.expectFmt("tst wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1442 try std.testing.expectFmt("tst wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1443
1444 try std.testing.expectFmt("ands x0, x0, x0", "{f}", .{(try as.nextInstruction()).?});
1445 try std.testing.expectFmt("ands x1, x1, x2", "{f}", .{(try as.nextInstruction()).?});
1446 try std.testing.expectFmt("ands x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
1447 try std.testing.expectFmt("ands x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?});
1448 try std.testing.expectFmt("ands x7, xzr, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
1449 try std.testing.expectFmt("ands x9, xzr, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?});
1450 try std.testing.expectFmt("tst x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?});
1451 try std.testing.expectFmt("tst x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
1452 try std.testing.expectFmt("tst xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?});
1453 try std.testing.expectFmt("tst xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?});
1454 try std.testing.expectFmt("ands x0, x0, xzr", "{f}", .{(try as.nextInstruction()).?});
1455 try std.testing.expectFmt("ands x1, x2, xzr", "{f}", .{(try as.nextInstruction()).?});
1456 try std.testing.expectFmt("ands x3, xzr, x3", "{f}", .{(try as.nextInstruction()).?});
1457 try std.testing.expectFmt("ands x4, xzr, x5", "{f}", .{(try as.nextInstruction()).?});
1458 try std.testing.expectFmt("ands x6, xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1459 try std.testing.expectFmt("ands x7, xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1460 try std.testing.expectFmt("tst x8, xzr", "{f}", .{(try as.nextInstruction()).?});
1461 try std.testing.expectFmt("tst x9, xzr", "{f}", .{(try as.nextInstruction()).?});
1462 try std.testing.expectFmt("tst xzr, x10", "{f}", .{(try as.nextInstruction()).?});
1463 try std.testing.expectFmt("tst xzr, x11", "{f}", .{(try as.nextInstruction()).?});
1464 try std.testing.expectFmt("tst xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1465 try std.testing.expectFmt("tst xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1466
1467 try std.testing.expect(null == try as.nextInstruction());
1468}
1469test "mov" {
1470 var as: Assemble = .{
1471 .source =
1472 \\MOV W0, #0
1473 \\MOV WZR, #0xffff
1474 \\
1475 \\MOV X0, #0
1476 \\MOV XZR, #0xffff
1477 \\
1478 \\MOV W0, WSP
1479 \\MOV WSP, W1
1480 \\MOV WSP, WSP
1481 \\MOV X0, SP
1482 \\MOV SP, X1
1483 \\MOV SP, SP
1484 \\
1485 \\MOV W0, W0
1486 \\MOV W1, W2
1487 \\MOV W3, WZR
1488 \\MOV WZR, W4
1489 \\MOV WZR, WZR
1490 \\MOV X0, X0
1491 \\MOV X1, X2
1492 \\MOV X3, XZR
1493 \\MOV XZR, X4
1494 \\MOV XZR, XZR
1495 \\
1496 \\MOVK W0, #0
1497 \\MOVK W1, #1, lsl #0
1498 \\MOVK W2, #2, lsl #16
1499 \\MOVK X3, #3
1500 \\MOVK X4, #4, lsl #0x00
1501 \\MOVK X5, #5, lsl #0x10
1502 \\MOVK X6, #6, lsl #0x20
1503 \\MOVK X7, #7, lsl #0x30
1504 \\
1505 \\MOVN W0, #8
1506 \\MOVN W1, #9, lsl #0
1507 \\MOVN W2, #10, lsl #16
1508 \\MOVN X3, #11
1509 \\MOVN X4, #12, lsl #0x00
1510 \\MOVN X5, #13, lsl #0x10
1511 \\MOVN X6, #14, lsl #0x20
1512 \\MOVN X7, #15, lsl #0x30
1513 \\
1514 \\MOVN WZR, #0, lsl #0
1515 \\MOVN WZR, #0, lsl #16
1516 \\MOVN XZR, #0, lsl #0
1517 \\MOVN XZR, #0, lsl #16
1518 \\MOVN XZR, #0, lsl #32
1519 \\MOVN XZR, #0, lsl #48
1520 \\
1521 \\MOVN WZR, #0xffff, lsl #0
1522 \\MOVN WZR, #0xffff, lsl #16
1523 \\MOVN XZR, #0xffff, lsl #0
1524 \\MOVN XZR, #0xffff, lsl #16
1525 \\MOVN XZR, #0xffff, lsl #32
1526 \\MOVN XZR, #0xffff, lsl #48
1527 \\
1528 \\MOVZ W0, #16
1529 \\MOVZ W1, #17, lsl #0
1530 \\MOVZ W2, #18, lsl #16
1531 \\MOVZ X3, #19
1532 \\MOVZ X4, #20, lsl #0x00
1533 \\MOVZ X5, #21, lsl #0x10
1534 \\MOVZ X6, #22, lsl #0x20
1535 \\MOVZ X7, #23, lsl #0x30
1536 \\
1537 \\MOVZ WZR, #0, lsl #0
1538 \\MOVZ WZR, #0, lsl #16
1539 \\MOVZ XZR, #0, lsl #0
1540 \\MOVZ XZR, #0, lsl #16
1541 \\MOVZ XZR, #0, lsl #32
1542 \\MOVZ XZR, #0, lsl #48
1543 \\
1544 \\MOVZ WZR, #0xffff, lsl #0
1545 \\MOVZ WZR, #0xffff, lsl #16
1546 \\MOVZ XZR, #0xffff, lsl #0
1547 \\MOVZ XZR, #0xffff, lsl #16
1548 \\MOVZ XZR, #0xffff, lsl #32
1549 \\MOVZ XZR, #0xffff, lsl #48
1550 ,
1551 .operands = .empty,
1552 };
1553
1554 try std.testing.expectFmt("mov w0, #0x0", "{f}", .{(try as.nextInstruction()).?});
1555 try std.testing.expectFmt("mov wzr, #0xffff", "{f}", .{(try as.nextInstruction()).?});
1556 try std.testing.expectFmt("mov x0, #0x0", "{f}", .{(try as.nextInstruction()).?});
1557 try std.testing.expectFmt("mov xzr, #0xffff", "{f}", .{(try as.nextInstruction()).?});
1558
1559 try std.testing.expectFmt("mov w0, wsp", "{f}", .{(try as.nextInstruction()).?});
1560 try std.testing.expectFmt("mov wsp, w1", "{f}", .{(try as.nextInstruction()).?});
1561 try std.testing.expectFmt("mov wsp, wsp", "{f}", .{(try as.nextInstruction()).?});
1562 try std.testing.expectFmt("mov x0, sp", "{f}", .{(try as.nextInstruction()).?});
1563 try std.testing.expectFmt("mov sp, x1", "{f}", .{(try as.nextInstruction()).?});
1564 try std.testing.expectFmt("mov sp, sp", "{f}", .{(try as.nextInstruction()).?});
1565
1566 try std.testing.expectFmt("mov w0, w0", "{f}", .{(try as.nextInstruction()).?});
1567 try std.testing.expectFmt("mov w1, w2", "{f}", .{(try as.nextInstruction()).?});
1568 try std.testing.expectFmt("mov w3, wzr", "{f}", .{(try as.nextInstruction()).?});
1569 try std.testing.expectFmt("mov wzr, w4", "{f}", .{(try as.nextInstruction()).?});
1570 try std.testing.expectFmt("mov wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1571 try std.testing.expectFmt("mov x0, x0", "{f}", .{(try as.nextInstruction()).?});
1572 try std.testing.expectFmt("mov x1, x2", "{f}", .{(try as.nextInstruction()).?});
1573 try std.testing.expectFmt("mov x3, xzr", "{f}", .{(try as.nextInstruction()).?});
1574 try std.testing.expectFmt("mov xzr, x4", "{f}", .{(try as.nextInstruction()).?});
1575 try std.testing.expectFmt("mov xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1576
1577 try std.testing.expectFmt("movk w0, #0x0", "{f}", .{(try as.nextInstruction()).?});
1578 try std.testing.expectFmt("movk w1, #0x1", "{f}", .{(try as.nextInstruction()).?});
1579 try std.testing.expectFmt("movk w2, #0x2, lsl #16", "{f}", .{(try as.nextInstruction()).?});
1580 try std.testing.expectFmt("movk x3, #0x3", "{f}", .{(try as.nextInstruction()).?});
1581 try std.testing.expectFmt("movk x4, #0x4", "{f}", .{(try as.nextInstruction()).?});
1582 try std.testing.expectFmt("movk x5, #0x5, lsl #16", "{f}", .{(try as.nextInstruction()).?});
1583 try std.testing.expectFmt("movk x6, #0x6, lsl #32", "{f}", .{(try as.nextInstruction()).?});
1584 try std.testing.expectFmt("movk x7, #0x7, lsl #48", "{f}", .{(try as.nextInstruction()).?});
1585
1586 try std.testing.expectFmt("mov w0, #-0x9", "{f}", .{(try as.nextInstruction()).?});
1587 try std.testing.expectFmt("mov w1, #-0xa", "{f}", .{(try as.nextInstruction()).?});
1588 try std.testing.expectFmt("mov w2, #-0xa0001", "{f}", .{(try as.nextInstruction()).?});
1589 try std.testing.expectFmt("mov x3, #-0xc", "{f}", .{(try as.nextInstruction()).?});
1590 try std.testing.expectFmt("mov x4, #-0xd", "{f}", .{(try as.nextInstruction()).?});
1591 try std.testing.expectFmt("mov x5, #-0xd0001", "{f}", .{(try as.nextInstruction()).?});
1592 try std.testing.expectFmt("mov x6, #-0xe00000001", "{f}", .{(try as.nextInstruction()).?});
1593 try std.testing.expectFmt("mov x7, #-0xf000000000001", "{f}", .{(try as.nextInstruction()).?});
1594
1595 try std.testing.expectFmt("mov wzr, #-0x1", "{f}", .{(try as.nextInstruction()).?});
1596 try std.testing.expectFmt("movn wzr, #0x0, lsl #16", "{f}", .{(try as.nextInstruction()).?});
1597 try std.testing.expectFmt("mov xzr, #-0x1", "{f}", .{(try as.nextInstruction()).?});
1598 try std.testing.expectFmt("movn xzr, #0x0, lsl #16", "{f}", .{(try as.nextInstruction()).?});
1599 try std.testing.expectFmt("movn xzr, #0x0, lsl #32", "{f}", .{(try as.nextInstruction()).?});
1600 try std.testing.expectFmt("movn xzr, #0x0, lsl #48", "{f}", .{(try as.nextInstruction()).?});
1601
1602 try std.testing.expectFmt("movn wzr, #0xffff", "{f}", .{(try as.nextInstruction()).?});
1603 try std.testing.expectFmt("movn wzr, #0xffff, lsl #16", "{f}", .{(try as.nextInstruction()).?});
1604 try std.testing.expectFmt("mov xzr, #-0x10000", "{f}", .{(try as.nextInstruction()).?});
1605 try std.testing.expectFmt("mov xzr, #-0xffff0001", "{f}", .{(try as.nextInstruction()).?});
1606 try std.testing.expectFmt("mov xzr, #-0xffff00000001", "{f}", .{(try as.nextInstruction()).?});
1607 try std.testing.expectFmt("mov xzr, #0xffffffffffff", "{f}", .{(try as.nextInstruction()).?});
1608
1609 try std.testing.expectFmt("mov w0, #0x10", "{f}", .{(try as.nextInstruction()).?});
1610 try std.testing.expectFmt("mov w1, #0x11", "{f}", .{(try as.nextInstruction()).?});
1611 try std.testing.expectFmt("mov w2, #0x120000", "{f}", .{(try as.nextInstruction()).?});
1612 try std.testing.expectFmt("mov x3, #0x13", "{f}", .{(try as.nextInstruction()).?});
1613 try std.testing.expectFmt("mov x4, #0x14", "{f}", .{(try as.nextInstruction()).?});
1614 try std.testing.expectFmt("mov x5, #0x150000", "{f}", .{(try as.nextInstruction()).?});
1615 try std.testing.expectFmt("mov x6, #0x1600000000", "{f}", .{(try as.nextInstruction()).?});
1616 try std.testing.expectFmt("mov x7, #0x17000000000000", "{f}", .{(try as.nextInstruction()).?});
1617
1618 try std.testing.expectFmt("mov wzr, #0x0", "{f}", .{(try as.nextInstruction()).?});
1619 try std.testing.expectFmt("movz wzr, #0x0, lsl #16", "{f}", .{(try as.nextInstruction()).?});
1620 try std.testing.expectFmt("mov xzr, #0x0", "{f}", .{(try as.nextInstruction()).?});
1621 try std.testing.expectFmt("movz xzr, #0x0, lsl #16", "{f}", .{(try as.nextInstruction()).?});
1622 try std.testing.expectFmt("movz xzr, #0x0, lsl #32", "{f}", .{(try as.nextInstruction()).?});
1623 try std.testing.expectFmt("movz xzr, #0x0, lsl #48", "{f}", .{(try as.nextInstruction()).?});
1624
1625 try std.testing.expectFmt("mov wzr, #0xffff", "{f}", .{(try as.nextInstruction()).?});
1626 try std.testing.expectFmt("mov wzr, #-0x10000", "{f}", .{(try as.nextInstruction()).?});
1627 try std.testing.expectFmt("mov xzr, #0xffff", "{f}", .{(try as.nextInstruction()).?});
1628 try std.testing.expectFmt("mov xzr, #0xffff0000", "{f}", .{(try as.nextInstruction()).?});
1629 try std.testing.expectFmt("mov xzr, #0xffff00000000", "{f}", .{(try as.nextInstruction()).?});
1630 try std.testing.expectFmt("mov xzr, #-0x1000000000000", "{f}", .{(try as.nextInstruction()).?});
1631
1632 try std.testing.expect(null == try as.nextInstruction());
1633}
1634test "reserved" {
1635 var as: Assemble = .{
1636 .source = "\n\nudf #0x0\n\t\n\tudf\t#01234\n \nudf#65535",
1637 .operands = .empty,
1638 };
1639
1640 try std.testing.expectFmt("udf #0x0", "{f}", .{(try as.nextInstruction()).?});
1641 try std.testing.expectFmt("udf #0x4d2", "{f}", .{(try as.nextInstruction()).?});
1642 try std.testing.expectFmt("udf #0xffff", "{f}", .{(try as.nextInstruction()).?});
1643
1644 try std.testing.expect(null == try as.nextInstruction());
1645}
1646
1647const aarch64 = @import("../aarch64.zig");
1648const Assemble = @This();
1649const assert = std.debug.assert;
1650const Instruction = aarch64.encoding.Instruction;
1651const instructions = @import("instructions.zon");
1652const std = @import("std");
1653const log = std.log.scoped(.@"asm");
src/codegen/aarch64/Disassemble.zig created+905
......@@ -0,0 +1,905 @@
1case: Case = .lower,
2mnemonic_operands_separator: []const u8 = " ",
3operands_separator: []const u8 = ", ",
4enable_aliases: bool = true,
5
6pub const Case = enum { lower, upper };
7
8pub fn printInstruction(dis: Disassemble, inst: Instruction, writer: *std.Io.Writer) std.Io.Writer.Error!void {
9 unallocated: switch (inst.decode()) {
10 .unallocated => break :unallocated,
11 .reserved => |reserved| switch (reserved.decode()) {
12 .unallocated => break :unallocated,
13 .udf => |udf| return writer.print("{f}{s}#0x{x}", .{
14 fmtCase(.udf, dis.case),
15 dis.mnemonic_operands_separator,
16 udf.imm16,
17 }),
18 },
19 .sme => {},
20 .sve => {},
21 .data_processing_immediate => |data_processing_immediate| switch (data_processing_immediate.decode()) {
22 .unallocated => break :unallocated,
23 .pc_relative_addressing => |pc_relative_addressing| {
24 const group = pc_relative_addressing.group;
25 const imm = (@as(i33, group.immhi) << 2 | @as(i33, group.immlo) << 0) + @as(i33, switch (group.op) {
26 .adr => Instruction.size,
27 .adrp => 0,
28 });
29 return writer.print("{f}{s}{f}{s}.{c}0x{x}", .{
30 fmtCase(group.op, dis.case),
31 dis.mnemonic_operands_separator,
32 group.Rd.decodeInteger(.doubleword, .{}).fmtCase(dis.case),
33 dis.operands_separator,
34 @as(u8, if (imm < 0) '-' else '+'),
35 switch (group.op) {
36 .adr => @abs(imm),
37 .adrp => @abs(imm) << 12,
38 },
39 });
40 },
41 .add_subtract_immediate => |add_subtract_immediate| {
42 const group = add_subtract_immediate.group;
43 const op = group.op;
44 const S = group.S;
45 const sf = group.sf;
46 const sh = group.sh;
47 const imm12 = group.imm12;
48 const Rn = group.Rn.decodeInteger(sf, .{ .sp = true });
49 const Rd = group.Rd.decodeInteger(sf, .{ .sp = !S });
50 const elide_shift = sh == .@"0";
51 if (dis.enable_aliases and op == .add and S == false and elide_shift and imm12 == 0 and
52 (Rn.alias == .sp or Rd.alias == .sp)) try writer.print("{f}{s}{f}{s}{f}", .{
53 fmtCase(.mov, dis.case),
54 dis.mnemonic_operands_separator,
55 Rd.fmtCase(dis.case),
56 dis.operands_separator,
57 Rn.fmtCase(dis.case),
58 }) else try writer.print("{f}{s}{s}{f}{s}{f}{s}#0x{x}", .{
59 fmtCase(op, dis.case),
60 if (S) "s" else "",
61 dis.mnemonic_operands_separator,
62 Rd.fmtCase(dis.case),
63 dis.operands_separator,
64 Rn.fmtCase(dis.case),
65 dis.operands_separator,
66 imm12,
67 });
68 return if (!elide_shift) writer.print("{s}{f} #{s}", .{
69 dis.operands_separator,
70 fmtCase(.lsl, dis.case),
71 @tagName(sh),
72 });
73 },
74 .add_subtract_immediate_with_tags => {},
75 .logical_immediate => |logical_immediate| {
76 const decoded = logical_immediate.decode();
77 if (decoded == .unallocated) break :unallocated;
78 const group = logical_immediate.group;
79 const sf = group.sf;
80 const decoded_imm = group.imm.decodeImmediate(sf);
81 const imm = switch (sf) {
82 .word => @as(i32, @bitCast(@as(u32, @intCast(decoded_imm)))),
83 .doubleword => @as(i64, @bitCast(decoded_imm)),
84 };
85 const Rn = group.Rn.decodeInteger(sf, .{});
86 const Rd = group.Rd.decodeInteger(sf, .{ .sp = decoded != .ands });
87 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}", .{
88 fmtCase(.mov, dis.case),
89 dis.mnemonic_operands_separator,
90 Rd.fmtCase(dis.case),
91 dis.operands_separator,
92 if (imm < 0) "-" else "",
93 @abs(imm),
94 }) else if (dis.enable_aliases and decoded == .ands and Rd.alias == .zr) writer.print("{f}{s}{f}{s}#{s}0x{x}", .{
95 fmtCase(.tst, dis.case),
96 dis.mnemonic_operands_separator,
97 Rn.fmtCase(dis.case),
98 dis.operands_separator,
99 if (imm < 0) "-" else "",
100 @abs(imm),
101 }) else writer.print("{f}{s}{f}{s}{f}{s}#0x{x}", .{
102 fmtCase(decoded, dis.case),
103 dis.mnemonic_operands_separator,
104 Rd.fmtCase(dis.case),
105 dis.operands_separator,
106 Rn.fmtCase(dis.case),
107 dis.operands_separator,
108 decoded_imm,
109 });
110 },
111 .move_wide_immediate => |move_wide_immediate| {
112 const decoded = move_wide_immediate.decode();
113 if (decoded == .unallocated) break :unallocated;
114 const group = move_wide_immediate.group;
115 const sf = group.sf;
116 const hw = group.hw;
117 const imm16 = group.imm16;
118 const Rd = group.Rd.decodeInteger(sf, .{});
119 const elide_shift = hw == .@"0";
120 if (dis.enable_aliases and switch (decoded) {
121 .unallocated => unreachable,
122 .movz => elide_shift or group.imm16 != 0,
123 .movn => (elide_shift or group.imm16 != 0) and switch (sf) {
124 .word => group.imm16 != std.math.maxInt(u16),
125 .doubleword => true,
126 },
127 .movk => false,
128 }) {
129 const decoded_imm = switch (sf) {
130 .word => @as(i32, @bitCast(@as(u32, group.imm16) << @intCast(hw.int()))),
131 .doubleword => @as(i64, @bitCast(@as(u64, group.imm16) << hw.int())),
132 };
133 const imm = switch (decoded) {
134 .unallocated => unreachable,
135 .movz => decoded_imm,
136 .movn => ~decoded_imm,
137 .movk => unreachable,
138 };
139 return writer.print("{f}{s}{f}{s}#{s}0x{x}", .{
140 fmtCase(.mov, dis.case),
141 dis.mnemonic_operands_separator,
142 Rd.fmtCase(dis.case),
143 dis.operands_separator,
144 if (imm < 0) "-" else "",
145 @abs(imm),
146 });
147 }
148 try writer.print("{f}{s}{f}{s}#0x{x}", .{
149 fmtCase(decoded, dis.case),
150 dis.mnemonic_operands_separator,
151 Rd.fmtCase(dis.case),
152 dis.operands_separator,
153 imm16,
154 });
155 return if (!elide_shift) writer.print("{s}{f} #{s}", .{
156 dis.operands_separator,
157 fmtCase(.lsl, dis.case),
158 @tagName(hw),
159 });
160 },
161 .bitfield => |bitfield| {
162 const decoded = bitfield.decode();
163 if (decoded == .unallocated) break :unallocated;
164 const group = bitfield.group;
165 const sf = group.sf;
166 return writer.print("{f}{s}{f}{s}{f}{s}#{d}{s}#{d}", .{
167 fmtCase(decoded, dis.case),
168 dis.mnemonic_operands_separator,
169 group.Rd.decodeInteger(sf, .{}).fmtCase(dis.case),
170 dis.operands_separator,
171 group.Rn.decodeInteger(sf, .{}).fmtCase(dis.case),
172 dis.operands_separator,
173 group.imm.immr,
174 dis.operands_separator,
175 group.imm.imms,
176 });
177 },
178 .extract => |extract| {
179 const decoded = extract.decode();
180 if (decoded == .unallocated) break :unallocated;
181 const group = extract.group;
182 const sf = group.sf;
183 return writer.print("{f}{s}{f}{s}{f}{s}{f}{s}#{d}", .{
184 fmtCase(decoded, dis.case),
185 dis.mnemonic_operands_separator,
186 group.Rd.decodeInteger(sf, .{}).fmtCase(dis.case),
187 dis.operands_separator,
188 group.Rn.decodeInteger(sf, .{}).fmtCase(dis.case),
189 dis.operands_separator,
190 group.Rm.decodeInteger(sf, .{}).fmtCase(dis.case),
191 dis.operands_separator,
192 group.imms,
193 });
194 },
195 },
196 .branch_exception_generating_system => |branch_exception_generating_system| switch (branch_exception_generating_system.decode()) {
197 .unallocated => break :unallocated,
198 .conditional_branch_immediate => |conditional_branch_immediate| {
199 const decoded = conditional_branch_immediate.decode();
200 if (decoded == .unallocated) break :unallocated;
201 const group = conditional_branch_immediate.group;
202 const imm = @as(i21, group.imm19);
203 return writer.print("{f}.{f}{s}.{c}0x{x}", .{
204 fmtCase(decoded, dis.case),
205 fmtCase(group.cond, dis.case),
206 dis.mnemonic_operands_separator,
207 @as(u8, if (imm < 0) '-' else '+'),
208 @abs(imm) << 2,
209 });
210 },
211 .exception_generating => |exception_generating| {
212 const decoded = exception_generating.decode();
213 switch (decoded) {
214 .unallocated => break :unallocated,
215 .svc, .hvc, .smc, .brk, .hlt, .tcancel => {},
216 .dcps1, .dcps2, .dcps3 => switch (exception_generating.group.imm16) {
217 0 => return writer.print("{f}", .{fmtCase(decoded, dis.case)}),
218 else => {},
219 },
220 }
221 return switch (exception_generating.group.imm16) {
222 0 => writer.print("{f}{s}#0", .{
223 fmtCase(decoded, dis.case),
224 dis.mnemonic_operands_separator,
225 }),
226 else => writer.print("{f}{s}#0x{x}", .{
227 fmtCase(decoded, dis.case),
228 dis.mnemonic_operands_separator,
229 exception_generating.group.imm16,
230 }),
231 };
232 },
233 .system_register_argument => {},
234 .hints => |hints| switch (hints.decode()) {
235 .hint => |hint| return writer.print("{f}{s}#0x{x}", .{
236 fmtCase(.hint, dis.case),
237 dis.mnemonic_operands_separator,
238 @as(u7, hint.CRm) << 3 | @as(u7, hint.op2) << 0,
239 }),
240 else => |decoded| return writer.print("{f}", .{fmtCase(decoded, dis.case)}),
241 },
242 .barriers => {},
243 .pstate => {},
244 .system_result => {},
245 .system => {},
246 .system_register_move => {},
247 .unconditional_branch_register => |unconditional_branch_register| {
248 const decoded = unconditional_branch_register.decode();
249 if (decoded == .unallocated) break :unallocated;
250 const group = unconditional_branch_register.group;
251 const Rn = group.Rn.decodeInteger(.doubleword, .{});
252 try writer.print("{f}", .{fmtCase(decoded, dis.case)});
253 return if (decoded != .ret or Rn.alias != .r30) try writer.print("{s}{f}", .{
254 dis.mnemonic_operands_separator,
255 Rn.fmtCase(dis.case),
256 });
257 },
258 .unconditional_branch_immediate => |unconditional_branch_immediate| {
259 const group = unconditional_branch_immediate.group;
260 const imm = @as(i28, group.imm26);
261 return writer.print("{f}{s}.{c}0x{x}", .{
262 fmtCase(group.op, dis.case),
263 dis.mnemonic_operands_separator,
264 @as(u8, if (imm < 0) '-' else '+'),
265 @abs(imm) << 2,
266 });
267 },
268 .compare_branch_immediate => |compare_branch_immediate| {
269 const group = compare_branch_immediate.group;
270 const imm = @as(i21, group.imm19);
271 return writer.print("{f}{s}{f}{s}.{c}0x{x}", .{
272 fmtCase(group.op, dis.case),
273 dis.mnemonic_operands_separator,
274 group.Rt.decodeInteger(group.sf, .{}).fmtCase(dis.case),
275 dis.operands_separator,
276 @as(u8, if (imm < 0) '-' else '+'),
277 @abs(imm) << 2,
278 });
279 },
280 .test_branch_immediate => |test_branch_immediate| {
281 const group = test_branch_immediate.group;
282 const imm = @as(i16, group.imm14);
283 return writer.print("{f}{s}{f}{s}#0x{d}{s}.{c}0x{x}", .{
284 fmtCase(group.op, dis.case),
285 dis.mnemonic_operands_separator,
286 group.Rt.decodeInteger(@enumFromInt(group.b5), .{}).fmtCase(dis.case),
287 dis.operands_separator,
288 @as(u6, group.b5) << 5 |
289 @as(u6, group.b40) << 0,
290 dis.operands_separator,
291 @as(u8, if (imm < 0) '-' else '+'),
292 @abs(imm) << 2,
293 });
294 },
295 },
296 .load_store => |load_store| switch (load_store.decode()) {
297 .unallocated => break :unallocated,
298 .register_literal => {},
299 .memory => {},
300 .no_allocate_pair_offset => {},
301 .register_pair_post_indexed => |register_pair_post_indexed| switch (register_pair_post_indexed.decode()) {
302 .integer => |integer| {
303 const decoded = integer.decode();
304 if (decoded == .unallocated) break :unallocated;
305 const group = integer.group;
306 const sf: aarch64.encoding.Register.IntegerSize = @enumFromInt(group.opc >> 1);
307 return writer.print("{f}{s}{f}{s}{f}{s}[{f}]{s}#{s}0x{x}", .{
308 fmtCase(decoded, dis.case),
309 dis.mnemonic_operands_separator,
310 group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case),
311 dis.operands_separator,
312 group.Rt2.decodeInteger(sf, .{}).fmtCase(dis.case),
313 dis.operands_separator,
314 group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case),
315 dis.operands_separator,
316 if (group.imm7 < 0) "-" else "",
317 @as(u10, @abs(group.imm7)) << (@as(u2, 2) + @intFromEnum(sf)),
318 });
319 },
320 .vector => |vector| {
321 const decoded = vector.decode();
322 if (decoded == .unallocated) break :unallocated;
323 const group = vector.group;
324 const vs = group.opc.decode();
325 return writer.print("{f}{s}{f}{s}{f}{s}[{f}]{s}#{s}0x{x}", .{
326 fmtCase(decoded, dis.case),
327 dis.mnemonic_operands_separator,
328 group.Rt.decodeVector(vs).fmtCase(dis.case),
329 dis.operands_separator,
330 group.Rt2.decodeVector(vs).fmtCase(dis.case),
331 dis.operands_separator,
332 group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case),
333 dis.operands_separator,
334 if (group.imm7 < 0) "-" else "",
335 @as(u11, @abs(group.imm7)) << (@as(u3, 2) + @intFromEnum(vs)),
336 });
337 },
338 },
339 .register_pair_offset => |register_pair_offset| switch (register_pair_offset.decode()) {
340 .integer => |integer| {
341 const decoded = integer.decode();
342 if (decoded == .unallocated) break :unallocated;
343 const group = integer.group;
344 const sf: aarch64.encoding.Register.IntegerSize = @enumFromInt(group.opc >> 1);
345 try writer.print("{f}{s}{f}{s}{f}{s}[{f}", .{
346 fmtCase(decoded, dis.case),
347 dis.mnemonic_operands_separator,
348 group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case),
349 dis.operands_separator,
350 group.Rt2.decodeInteger(sf, .{}).fmtCase(dis.case),
351 dis.operands_separator,
352 group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case),
353 });
354 if (group.imm7 != 0) try writer.print("{s}#{s}0x{x}", .{
355 dis.operands_separator,
356 if (group.imm7 < 0) "-" else "",
357 @as(u10, @abs(group.imm7)) << (@as(u2, 2) + @intFromEnum(sf)),
358 });
359 return writer.writeByte(']');
360 },
361 .vector => |vector| {
362 const decoded = vector.decode();
363 if (decoded == .unallocated) break :unallocated;
364 const group = vector.group;
365 const vs = group.opc.decode();
366 try writer.print("{f}{s}{f}{s}{f}{s}[{f}", .{
367 fmtCase(decoded, dis.case),
368 dis.mnemonic_operands_separator,
369 group.Rt.decodeVector(vs).fmtCase(dis.case),
370 dis.operands_separator,
371 group.Rt2.decodeVector(vs).fmtCase(dis.case),
372 dis.operands_separator,
373 group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case),
374 });
375 if (group.imm7 != 0) try writer.print("{s}#{s}0x{x}", .{
376 dis.operands_separator,
377 if (group.imm7 < 0) "-" else "",
378 @as(u11, @abs(group.imm7)) << (@as(u3, 2) + @intFromEnum(vs)),
379 });
380 return writer.writeByte(']');
381 },
382 },
383 .register_pair_pre_indexed => |register_pair_pre_indexed| switch (register_pair_pre_indexed.decode()) {
384 .integer => |integer| {
385 const decoded = integer.decode();
386 if (decoded == .unallocated) break :unallocated;
387 const group = integer.group;
388 const sf: aarch64.encoding.Register.IntegerSize = @enumFromInt(group.opc >> 1);
389 return writer.print("{f}{s}{f}{s}{f}{s}[{f}{s}#{s}0x{x}]!", .{
390 fmtCase(decoded, dis.case),
391 dis.mnemonic_operands_separator,
392 group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case),
393 dis.operands_separator,
394 group.Rt2.decodeInteger(sf, .{}).fmtCase(dis.case),
395 dis.operands_separator,
396 group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case),
397 dis.operands_separator,
398 if (group.imm7 < 0) "-" else "",
399 @as(u10, @abs(group.imm7)) << (@as(u2, 2) + @intFromEnum(sf)),
400 });
401 },
402 .vector => |vector| {
403 const decoded = vector.decode();
404 if (decoded == .unallocated) break :unallocated;
405 const group = vector.group;
406 const vs = group.opc.decode();
407 return writer.print("{f}{s}{f}{s}{f}{s}[{f}{s}#{s}0x{x}]!", .{
408 fmtCase(decoded, dis.case),
409 dis.mnemonic_operands_separator,
410 group.Rt.decodeVector(vs).fmtCase(dis.case),
411 dis.operands_separator,
412 group.Rt2.decodeVector(vs).fmtCase(dis.case),
413 dis.operands_separator,
414 group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case),
415 dis.operands_separator,
416 if (group.imm7 < 0) "-" else "",
417 @as(u11, @abs(group.imm7)) << (@as(u3, 2) + @intFromEnum(vs)),
418 });
419 },
420 },
421 .register_unscaled_immediate => {},
422 .register_immediate_post_indexed => |register_immediate_post_indexed| switch (register_immediate_post_indexed.decode()) {
423 .integer => |integer| {
424 const decoded = integer.decode();
425 const sf: aarch64.encoding.Register.IntegerSize = switch (decoded) {
426 .unallocated => break :unallocated,
427 .strb, .ldrb, .strh, .ldrh => .word,
428 inline .ldrsb, .ldrsh => |encoded| switch (encoded.opc0) {
429 0b0 => .doubleword,
430 0b1 => .word,
431 },
432 .ldrsw => .doubleword,
433 inline .str, .ldr => |encoded| encoded.sf,
434 };
435 const group = integer.group;
436 return writer.print("{f}{s}{f}{s}[{f}]{s}#{s}0x{x}", .{
437 fmtCase(decoded, dis.case),
438 dis.mnemonic_operands_separator,
439 group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case),
440 dis.operands_separator,
441 group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case),
442 dis.operands_separator,
443 if (group.imm9 < 0) "-" else "",
444 @abs(group.imm9),
445 });
446 },
447 .vector => {},
448 },
449 .register_unprivileged => {},
450 .register_immediate_pre_indexed => |register_immediate_pre_indexed| switch (register_immediate_pre_indexed.decode()) {
451 .integer => |integer| {
452 const decoded = integer.decode();
453 const sf: aarch64.encoding.Register.IntegerSize = switch (decoded) {
454 .unallocated => break :unallocated,
455 inline .ldrsb, .ldrsh => |encoded| switch (encoded.opc0) {
456 0b0 => .doubleword,
457 0b1 => .word,
458 },
459 .strb, .ldrb, .strh, .ldrh => .word,
460 .ldrsw => .doubleword,
461 inline .str, .ldr => |encoded| encoded.sf,
462 };
463 const group = integer.group;
464 return writer.print("{f}{s}{f}{s}[{f}{s}#{s}0x{x}]!", .{
465 fmtCase(decoded, dis.case),
466 dis.mnemonic_operands_separator,
467 group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case),
468 dis.operands_separator,
469 group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case),
470 dis.operands_separator,
471 if (group.imm9 < 0) "-" else "",
472 @abs(group.imm9),
473 });
474 },
475 .vector => |vector| {
476 const decoded = vector.decode();
477 if (decoded == .unallocated) break :unallocated;
478 const group = vector.group;
479 return writer.print("{f}{s}{f}{s}[{f}{s}#{s}0x{x}]!", .{
480 fmtCase(decoded, dis.case),
481 dis.mnemonic_operands_separator,
482 group.Rt.decodeVector(group.opc1.decode(group.size)).fmtCase(dis.case),
483 dis.operands_separator,
484 group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case),
485 dis.operands_separator,
486 if (group.imm9 < 0) "-" else "",
487 @abs(group.imm9),
488 });
489 },
490 },
491 .register_register_offset => |register_register_offset| switch (register_register_offset.decode()) {
492 .integer => |integer| {
493 const decoded = integer.decode();
494 const sf: aarch64.encoding.Register.IntegerSize = switch (decoded) {
495 .unallocated, .prfm => break :unallocated,
496 .strb, .ldrb, .strh, .ldrh => .word,
497 inline .ldrsb, .ldrsh => |encoded| switch (encoded.opc0) {
498 0b0 => .doubleword,
499 0b1 => .word,
500 },
501 .ldrsw => .doubleword,
502 inline .str, .ldr => |encoded| encoded.sf,
503 };
504 const group = integer.group;
505 try writer.print("{f}{s}{f}{s}[{f}{s}{f}", .{
506 fmtCase(decoded, dis.case),
507 dis.mnemonic_operands_separator,
508 group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case),
509 dis.operands_separator,
510 group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case),
511 dis.operands_separator,
512 group.Rm.decodeInteger(group.option.sf(), .{}).fmtCase(dis.case),
513 });
514 if (group.option != .lsl or group.S) {
515 try writer.print("{s}{f}", .{
516 dis.operands_separator,
517 fmtCase(group.option, dis.case),
518 });
519 if (group.S) try writer.print(" #{d}", .{
520 @intFromEnum(group.size),
521 });
522 }
523 return writer.writeByte(']');
524 },
525 .vector => {},
526 },
527 .register_unsigned_immediate => |register_unsigned_immediate| switch (register_unsigned_immediate.decode()) {
528 .integer => |integer| {
529 const decoded = integer.decode();
530 const sf: aarch64.encoding.Register.IntegerSize = switch (decoded) {
531 .unallocated, .prfm => break :unallocated,
532 .strb, .ldrb, .strh, .ldrh => .word,
533 inline .ldrsb, .ldrsh => |encoded| switch (encoded.opc0) {
534 0b0 => .doubleword,
535 0b1 => .word,
536 },
537 .ldrsw => .doubleword,
538 inline .str, .ldr => |encoded| encoded.sf,
539 };
540 const group = integer.group;
541 try writer.print("{f}{s}{f}{s}[{f}", .{
542 fmtCase(decoded, dis.case),
543 dis.mnemonic_operands_separator,
544 group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case),
545 dis.operands_separator,
546 group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case),
547 });
548 if (group.imm12 > 0) try writer.print("{s}#0x{x}", .{
549 dis.operands_separator,
550 @as(u15, group.imm12) << @intFromEnum(group.size),
551 });
552 return writer.writeByte(']');
553 },
554 .vector => {},
555 },
556 },
557 .data_processing_register => |data_processing_register| switch (data_processing_register.decode()) {
558 .unallocated => break :unallocated,
559 .data_processing_two_source => |data_processing_two_source| {
560 const decoded = data_processing_two_source.decode();
561 if (decoded == .unallocated) break :unallocated;
562 const group = data_processing_two_source.group;
563 const sf = group.sf;
564 return writer.print("{f}{s}{f}{s}{f}{s}{f}", .{
565 fmtCase(decoded, dis.case),
566 dis.mnemonic_operands_separator,
567 group.Rd.decodeInteger(sf, .{}).fmtCase(dis.case),
568 dis.operands_separator,
569 group.Rn.decodeInteger(sf, .{}).fmtCase(dis.case),
570 dis.operands_separator,
571 group.Rm.decodeInteger(sf, .{}).fmtCase(dis.case),
572 });
573 },
574 .data_processing_one_source => |data_processing_one_source| {
575 const decoded = data_processing_one_source.decode();
576 if (decoded == .unallocated) break :unallocated;
577 const group = data_processing_one_source.group;
578 const sf = group.sf;
579 return writer.print("{f}{s}{f}{s}{f}", .{
580 fmtCase(decoded, dis.case),
581 dis.mnemonic_operands_separator,
582 group.Rd.decodeInteger(sf, .{}).fmtCase(dis.case),
583 dis.operands_separator,
584 group.Rn.decodeInteger(sf, .{}).fmtCase(dis.case),
585 });
586 },
587 .logical_shifted_register => |logical_shifted_register| {
588 const decoded = logical_shifted_register.decode();
589 if (decoded == .unallocated) break :unallocated;
590 const group = logical_shifted_register.group;
591 const sf = group.sf;
592 const shift = group.shift;
593 const Rm = group.Rm.decodeInteger(sf, .{});
594 const amount = group.imm6;
595 const Rn = group.Rn.decodeInteger(sf, .{});
596 const Rd = group.Rd.decodeInteger(sf, .{});
597 const elide_shift = shift == .lsl and amount == 0;
598 if (dis.enable_aliases and switch (decoded) {
599 else => false,
600 .orr => elide_shift,
601 .orn => true,
602 } and Rn.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{
603 fmtCase(@as(enum { mov, mvn }, switch (decoded) {
604 else => unreachable,
605 .orr => .mov,
606 .orn => .mvn,
607 }), dis.case),
608 dis.mnemonic_operands_separator,
609 Rd.fmtCase(dis.case),
610 dis.operands_separator,
611 Rm.fmtCase(dis.case),
612 }) else if (dis.enable_aliases and decoded == .ands and Rd.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{
613 fmtCase(.tst, dis.case),
614 dis.mnemonic_operands_separator,
615 Rn.fmtCase(dis.case),
616 dis.operands_separator,
617 Rm.fmtCase(dis.case),
618 }) else try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{
619 fmtCase(decoded, dis.case),
620 dis.mnemonic_operands_separator,
621 Rd.fmtCase(dis.case),
622 dis.operands_separator,
623 Rn.fmtCase(dis.case),
624 dis.operands_separator,
625 Rm.fmtCase(dis.case),
626 });
627 return if (!elide_shift) writer.print("{s}{f} #{d}", .{
628 dis.operands_separator,
629 fmtCase(shift, dis.case),
630 amount,
631 });
632 },
633 .add_subtract_shifted_register => |add_subtract_shifted_register| {
634 const decoded = add_subtract_shifted_register.decode();
635 if (decoded == .unallocated) break :unallocated;
636 const group = add_subtract_shifted_register.group;
637 const sf = group.sf;
638 const shift = group.shift;
639 const Rm = group.Rm.decodeInteger(sf, .{});
640 const imm6 = group.imm6;
641 const Rn = group.Rn.decodeInteger(sf, .{});
642 const Rd = group.Rd.decodeInteger(sf, .{});
643 if (dis.enable_aliases and group.S and Rd.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{
644 fmtCase(@as(enum { cmn, cmp }, switch (group.op) {
645 .add => .cmn,
646 .sub => .cmp,
647 }), dis.case),
648 dis.mnemonic_operands_separator,
649 Rn.fmtCase(dis.case),
650 dis.operands_separator,
651 Rm.fmtCase(dis.case),
652 }) else if (dis.enable_aliases and group.op == .sub and Rn.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{
653 fmtCase(@as(enum { neg, negs }, switch (group.S) {
654 false => .neg,
655 true => .negs,
656 }), dis.case),
657 dis.mnemonic_operands_separator,
658 Rd.fmtCase(dis.case),
659 dis.operands_separator,
660 Rm.fmtCase(dis.case),
661 }) else try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{
662 fmtCase(decoded, dis.case),
663 dis.mnemonic_operands_separator,
664 Rd.fmtCase(dis.case),
665 dis.operands_separator,
666 Rn.fmtCase(dis.case),
667 dis.operands_separator,
668 Rm.fmtCase(dis.case),
669 });
670 return if (shift != .lsl or imm6 != 0) return writer.print("{s}{f} #{d}", .{
671 dis.operands_separator,
672 fmtCase(shift, dis.case),
673 imm6,
674 });
675 },
676 .add_subtract_extended_register => |add_subtract_extended_register| {
677 const decoded = add_subtract_extended_register.decode();
678 if (decoded == .unallocated) break :unallocated;
679 const group = add_subtract_extended_register.group;
680 const sf = group.sf;
681 const Rm = group.Rm.decodeInteger(group.option.sf(), .{});
682 const Rn = group.Rn.decodeInteger(sf, .{ .sp = true });
683 const Rd = group.Rd.decodeInteger(sf, .{ .sp = true });
684 if (dis.enable_aliases and group.S and Rd.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{
685 fmtCase(@as(enum { cmn, cmp }, switch (group.op) {
686 .add => .cmn,
687 .sub => .cmp,
688 }), dis.case),
689 dis.mnemonic_operands_separator,
690 Rn.fmtCase(dis.case),
691 dis.operands_separator,
692 Rm.fmtCase(dis.case),
693 }) else try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{
694 fmtCase(decoded, dis.case),
695 dis.mnemonic_operands_separator,
696 Rd.fmtCase(dis.case),
697 dis.operands_separator,
698 Rn.fmtCase(dis.case),
699 dis.operands_separator,
700 Rm.fmtCase(dis.case),
701 });
702 return if (group.option != @as(Instruction.DataProcessingRegister.AddSubtractExtendedRegister.Option, switch (sf) {
703 .word => .uxtw,
704 .doubleword => .uxtx,
705 }) or group.imm3 != 0) writer.print("{s}{f} #{d}", .{
706 dis.operands_separator,
707 fmtCase(group.option, dis.case),
708 group.imm3,
709 });
710 },
711 .add_subtract_with_carry => |add_subtract_with_carry| {
712 const decoded = add_subtract_with_carry.decode();
713 const group = add_subtract_with_carry.group;
714 const sf = group.sf;
715 const Rm = group.Rm.decodeInteger(sf, .{});
716 const Rn = group.Rn.decodeInteger(sf, .{});
717 const Rd = group.Rd.decodeInteger(sf, .{});
718 return if (dis.enable_aliases and group.op == .sbc and Rn.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{
719 fmtCase(@as(enum { ngc, ngcs }, switch (group.S) {
720 false => .ngc,
721 true => .ngcs,
722 }), dis.case),
723 dis.mnemonic_operands_separator,
724 Rd.fmtCase(dis.case),
725 dis.operands_separator,
726 Rm.fmtCase(dis.case),
727 }) else try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{
728 fmtCase(decoded, dis.case),
729 dis.mnemonic_operands_separator,
730 Rd.fmtCase(dis.case),
731 dis.operands_separator,
732 Rn.fmtCase(dis.case),
733 dis.operands_separator,
734 Rm.fmtCase(dis.case),
735 });
736 },
737 .rotate_right_into_flags => {},
738 .evaluate_into_flags => {},
739 .conditional_compare_register => {},
740 .conditional_compare_immediate => {},
741 .conditional_select => |conditional_select| {
742 const decoded = conditional_select.decode();
743 if (decoded == .unallocated) break :unallocated;
744 const group = conditional_select.group;
745 const sf = group.sf;
746 const Rm = group.Rm.decodeInteger(sf, .{});
747 const cond = group.cond;
748 const Rn = group.Rn.decodeInteger(sf, .{});
749 const Rd = group.Rd.decodeInteger(sf, .{});
750 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}", .{
751 fmtCase(@as(enum { cset, csetm }, switch (decoded) {
752 else => unreachable,
753 .csinc => .cset,
754 .csinv => .csetm,
755 }), dis.case),
756 dis.mnemonic_operands_separator,
757 Rd.fmtCase(dis.case),
758 dis.operands_separator,
759 fmtCase(cond.invert(), dis.case),
760 }) 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}", .{
761 fmtCase(@as(enum { cinc, cinv, cneg }, switch (decoded) {
762 else => unreachable,
763 .csinc => .cinc,
764 .csinv => .cinv,
765 .csneg => .cneg,
766 }), dis.case),
767 dis.mnemonic_operands_separator,
768 Rd.fmtCase(dis.case),
769 dis.operands_separator,
770 Rn.fmtCase(dis.case),
771 dis.operands_separator,
772 fmtCase(cond.invert(), dis.case),
773 }) else writer.print("{f}{s}{f}{s}{f}{s}{f}{s}{f}", .{
774 fmtCase(decoded, dis.case),
775 dis.mnemonic_operands_separator,
776 Rd.fmtCase(dis.case),
777 dis.operands_separator,
778 Rn.fmtCase(dis.case),
779 dis.operands_separator,
780 Rm.fmtCase(dis.case),
781 dis.operands_separator,
782 fmtCase(cond, dis.case),
783 });
784 },
785 .data_processing_three_source => |data_processing_three_source| {
786 const decoded = data_processing_three_source.decode();
787 if (decoded == .unallocated) break :unallocated;
788 const group = data_processing_three_source.group;
789 const sf = group.sf;
790 try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{
791 fmtCase(decoded, dis.case),
792 dis.mnemonic_operands_separator,
793 group.Rd.decodeInteger(sf, .{}).fmtCase(dis.case),
794 dis.operands_separator,
795 group.Rn.decodeInteger(sf, .{}).fmtCase(dis.case),
796 dis.operands_separator,
797 group.Rm.decodeInteger(sf, .{}).fmtCase(dis.case),
798 });
799 return switch (decoded) {
800 .unallocated => unreachable,
801 .madd, .msub, .smaddl, .smsubl, .umaddl, .umsubl => writer.print("{s}{f}", .{
802 dis.operands_separator,
803 group.Ra.decodeInteger(sf, .{}).fmtCase(dis.case),
804 }),
805 .smulh, .umulh => {},
806 };
807 },
808 },
809 .data_processing_vector => {},
810 }
811 return writer.print(".{f}{s}0x{x:0>8}", .{
812 fmtCase(.word, dis.case),
813 dis.mnemonic_operands_separator,
814 @as(Instruction.Backing, @bitCast(inst)),
815 });
816}
817
818fn fmtCase(tag: anytype, case: Case) struct {
819 tag: []const u8,
820 case: Case,
821 pub fn format(data: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void {
822 for (data.tag) |c| try writer.writeByte(switch (data.case) {
823 .lower => std.ascii.toLower(c),
824 .upper => std.ascii.toUpper(c),
825 });
826 }
827} {
828 return .{ .tag = @tagName(tag), .case = case };
829}
830
831pub const RegisterFormatter = struct {
832 reg: aarch64.encoding.Register,
833 case: Case,
834 pub fn format(data: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void {
835 switch (data.reg.format) {
836 .alias => try writer.print("{f}", .{fmtCase(data.reg.alias, data.case)}),
837 .integer => |size| switch (data.reg.alias) {
838 .r0,
839 .r1,
840 .r2,
841 .r3,
842 .r4,
843 .r5,
844 .r6,
845 .r7,
846 .r8,
847 .r9,
848 .r10,
849 .r11,
850 .r12,
851 .r13,
852 .r14,
853 .r15,
854 .r16,
855 .r17,
856 .r18,
857 .r19,
858 .r20,
859 .r21,
860 .r22,
861 .r23,
862 .r24,
863 .r25,
864 .r26,
865 .r27,
866 .r28,
867 .r29,
868 .r30,
869 => |alias| try writer.print("{c}{d}", .{
870 size.prefix(),
871 @intFromEnum(alias.encode(.{})),
872 }),
873 .zr => try writer.print("{c}{f}", .{
874 size.prefix(),
875 fmtCase(data.reg.alias, data.case),
876 }),
877 else => try writer.print("{s}{f}", .{
878 switch (size) {
879 .word => "w",
880 .doubleword => "",
881 },
882 fmtCase(data.reg.alias, data.case),
883 }),
884 },
885 .scalar => |size| try writer.print("{c}{d}", .{
886 size.prefix(),
887 @intFromEnum(data.reg.alias.encode(.{ .V = true })),
888 }),
889 .vector => |arrangement| try writer.print("{f}.{f}", .{
890 fmtCase(data.reg.alias, data.case),
891 fmtCase(arrangement, data.case),
892 }),
893 .element => |element| try writer.print("{f}.{c}[{d}]", .{
894 fmtCase(data.reg.alias, data.case),
895 element.size.prefix(),
896 element.index,
897 }),
898 }
899 }
900};
901
902const aarch64 = @import("../aarch64.zig");
903const Disassemble = @This();
904const Instruction = aarch64.encoding.Instruction;
905const std = @import("std");
src/codegen/aarch64/Mir.zig created+275
......@@ -0,0 +1,275 @@
1prologue: []const Instruction,
2body: []const Instruction,
3epilogue: []const Instruction,
4literals: []const u32,
5nav_relocs: []const Reloc.Nav,
6uav_relocs: []const Reloc.Uav,
7global_relocs: []const Reloc.Global,
8literal_relocs: []const Reloc.Literal,
9
10pub const Reloc = struct {
11 label: u32,
12 addend: u64 align(@alignOf(u32)) = 0,
13
14 pub const Nav = struct {
15 nav: InternPool.Nav.Index,
16 reloc: Reloc,
17 };
18
19 pub const Uav = struct {
20 uav: InternPool.Key.Ptr.BaseAddr.Uav,
21 reloc: Reloc,
22 };
23
24 pub const Global = struct {
25 global: [*:0]const u8,
26 reloc: Reloc,
27 };
28
29 pub const Literal = struct {
30 label: u32,
31 };
32};
33
34pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
35 assert(mir.body.ptr + mir.body.len == mir.prologue.ptr);
36 assert(mir.prologue.ptr + mir.prologue.len == mir.epilogue.ptr);
37 gpa.free(mir.body.ptr[0 .. mir.body.len + mir.prologue.len + mir.epilogue.len]);
38 gpa.free(mir.literals);
39 gpa.free(mir.nav_relocs);
40 gpa.free(mir.uav_relocs);
41 gpa.free(mir.global_relocs);
42 gpa.free(mir.literal_relocs);
43 mir.* = undefined;
44}
45
46pub fn emit(
47 mir: Mir,
48 lf: *link.File,
49 pt: Zcu.PerThread,
50 src_loc: Zcu.LazySrcLoc,
51 func_index: InternPool.Index,
52 code: *std.ArrayListUnmanaged(u8),
53 debug_output: link.File.DebugInfoOutput,
54) !void {
55 _ = debug_output;
56 const zcu = pt.zcu;
57 const ip = &zcu.intern_pool;
58 const gpa = zcu.gpa;
59 const func = zcu.funcInfo(func_index);
60 const nav = ip.getNav(func.owner_nav);
61 const mod = zcu.navFileScope(func.owner_nav).mod.?;
62 const target = &mod.resolved_target.result;
63 mir_log.debug("{f}:", .{nav.fqn.fmt(ip)});
64
65 const func_align = switch (nav.status.fully_resolved.alignment) {
66 .none => switch (mod.optimize_mode) {
67 .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target),
68 .ReleaseSmall => target_util.minFunctionAlignment(target),
69 },
70 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
71 };
72 const code_len = mir.prologue.len + mir.body.len + mir.epilogue.len;
73 const literals_align_gap = -%code_len & (@divExact(
74 @as(u5, @intCast(func_align.minStrict(.@"16").toByteUnits().?)),
75 Instruction.size,
76 ) - 1);
77 try code.ensureUnusedCapacity(gpa, Instruction.size *
78 (code_len + literals_align_gap + mir.literals.len));
79 emitInstructionsForward(code, mir.prologue);
80 emitInstructionsBackward(code, mir.body);
81 const body_end: u32 = @intCast(code.items.len);
82 emitInstructionsBackward(code, mir.epilogue);
83 code.appendNTimesAssumeCapacity(0, Instruction.size * literals_align_gap);
84 code.appendSliceAssumeCapacity(@ptrCast(mir.literals));
85 mir_log.debug("", .{});
86
87 for (mir.nav_relocs) |nav_reloc| try emitReloc(
88 lf,
89 zcu,
90 func.owner_nav,
91 switch (try @import("../../codegen.zig").genNavRef(
92 lf,
93 pt,
94 src_loc,
95 nav_reloc.nav,
96 &mod.resolved_target.result,
97 )) {
98 .sym_index => |sym_index| sym_index,
99 .fail => |em| return zcu.codegenFailMsg(func.owner_nav, em),
100 },
101 mir.body[nav_reloc.reloc.label],
102 body_end - Instruction.size * (1 + nav_reloc.reloc.label),
103 nav_reloc.reloc.addend,
104 );
105 for (mir.uav_relocs) |uav_reloc| try emitReloc(
106 lf,
107 zcu,
108 func.owner_nav,
109 switch (try lf.lowerUav(
110 pt,
111 uav_reloc.uav.val,
112 ZigType.fromInterned(uav_reloc.uav.orig_ty).ptrAlignment(zcu),
113 src_loc,
114 )) {
115 .sym_index => |sym_index| sym_index,
116 .fail => |em| return zcu.codegenFailMsg(func.owner_nav, em),
117 },
118 mir.body[uav_reloc.reloc.label],
119 body_end - Instruction.size * (1 + uav_reloc.reloc.label),
120 uav_reloc.reloc.addend,
121 );
122 for (mir.global_relocs) |global_reloc| try emitReloc(
123 lf,
124 zcu,
125 func.owner_nav,
126 if (lf.cast(.elf)) |ef|
127 try ef.getGlobalSymbol(std.mem.span(global_reloc.global), null)
128 else if (lf.cast(.macho)) |mf|
129 try mf.getGlobalSymbol(std.mem.span(global_reloc.global), null)
130 else if (lf.cast(.coff)) |cf|
131 try cf.getGlobalSymbol(std.mem.span(global_reloc.global), "compiler_rt")
132 else
133 return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}),
134 mir.body[global_reloc.reloc.label],
135 body_end - Instruction.size * (1 + global_reloc.reloc.label),
136 global_reloc.reloc.addend,
137 );
138 const literal_reloc_offset: i19 = @intCast(mir.epilogue.len + literals_align_gap);
139 for (mir.literal_relocs) |literal_reloc| {
140 var instruction = mir.body[literal_reloc.label];
141 instruction.load_store.register_literal.group.imm19 += literal_reloc_offset;
142 instruction.write(
143 code.items[body_end - Instruction.size * (1 + literal_reloc.label) ..][0..Instruction.size],
144 );
145 }
146}
147
148fn emitInstructionsForward(code: *std.ArrayListUnmanaged(u8), instructions: []const Instruction) void {
149 for (instructions) |instruction| emitInstruction(code, instruction);
150}
151fn emitInstructionsBackward(code: *std.ArrayListUnmanaged(u8), instructions: []const Instruction) void {
152 var instruction_index = instructions.len;
153 while (instruction_index > 0) {
154 instruction_index -= 1;
155 emitInstruction(code, instructions[instruction_index]);
156 }
157}
158fn emitInstruction(code: *std.ArrayListUnmanaged(u8), instruction: Instruction) void {
159 mir_log.debug(" {f}", .{instruction});
160 instruction.write(code.addManyAsArrayAssumeCapacity(Instruction.size));
161}
162
163fn emitReloc(
164 lf: *link.File,
165 zcu: *Zcu,
166 owner_nav: InternPool.Nav.Index,
167 sym_index: u32,
168 instruction: Instruction,
169 offset: u32,
170 addend: u64,
171) !void {
172 const gpa = zcu.gpa;
173 switch (instruction.decode()) {
174 else => unreachable,
175 .branch_exception_generating_system => |decoded| if (lf.cast(.elf)) |ef| {
176 const zo = ef.zigObjectPtr().?;
177 const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?;
178 const r_type: std.elf.R_AARCH64 = switch (decoded.decode().unconditional_branch_immediate.group.op) {
179 .b => .JUMP26,
180 .bl => .CALL26,
181 };
182 try atom.addReloc(gpa, .{
183 .r_offset = offset,
184 .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type),
185 .r_addend = @bitCast(addend),
186 }, zo);
187 } else if (lf.cast(.macho)) |mf| {
188 const zo = mf.getZigObject().?;
189 const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?;
190 try atom.addReloc(mf, .{
191 .tag = .@"extern",
192 .offset = offset,
193 .target = sym_index,
194 .addend = @bitCast(addend),
195 .type = .branch,
196 .meta = .{
197 .pcrel = true,
198 .has_subtractor = false,
199 .length = 2,
200 .symbolnum = @intCast(sym_index),
201 },
202 });
203 },
204 .data_processing_immediate => |decoded| if (lf.cast(.elf)) |ef| {
205 const zo = ef.zigObjectPtr().?;
206 const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?;
207 const r_type: std.elf.R_AARCH64 = switch (decoded.decode()) {
208 else => unreachable,
209 .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) {
210 .adr => .ADR_PREL_LO21,
211 .adrp => .ADR_PREL_PG_HI21,
212 },
213 .add_subtract_immediate => |add_subtract_immediate| switch (add_subtract_immediate.group.op) {
214 .add => .ADD_ABS_LO12_NC,
215 .sub => unreachable,
216 },
217 };
218 try atom.addReloc(gpa, .{
219 .r_offset = offset,
220 .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type),
221 .r_addend = @bitCast(addend),
222 }, zo);
223 } else if (lf.cast(.macho)) |mf| {
224 const zo = mf.getZigObject().?;
225 const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?;
226 switch (decoded.decode()) {
227 else => unreachable,
228 .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) {
229 .adr => unreachable,
230 .adrp => try atom.addReloc(mf, .{
231 .tag = .@"extern",
232 .offset = offset,
233 .target = sym_index,
234 .addend = @bitCast(addend),
235 .type = .page,
236 .meta = .{
237 .pcrel = true,
238 .has_subtractor = false,
239 .length = 2,
240 .symbolnum = @intCast(sym_index),
241 },
242 }),
243 },
244 .add_subtract_immediate => |add_subtract_immediate| switch (add_subtract_immediate.group.op) {
245 .add => try atom.addReloc(mf, .{
246 .tag = .@"extern",
247 .offset = offset,
248 .target = sym_index,
249 .addend = @bitCast(addend),
250 .type = .pageoff,
251 .meta = .{
252 .pcrel = false,
253 .has_subtractor = false,
254 .length = 2,
255 .symbolnum = @intCast(sym_index),
256 },
257 }),
258 .sub => unreachable,
259 },
260 }
261 },
262 }
263}
264
265const Air = @import("../../Air.zig");
266const assert = std.debug.assert;
267const mir_log = std.log.scoped(.mir);
268const Instruction = @import("encoding.zig").Instruction;
269const InternPool = @import("../../InternPool.zig");
270const link = @import("../../link.zig");
271const Mir = @This();
272const std = @import("std");
273const target_util = @import("../../target.zig");
274const Zcu = @import("../../Zcu.zig");
275const ZigType = @import("../../Type.zig");
src/codegen/aarch64/Select.zig created+10981
......@@ -0,0 +1,10981 @@
1pt: Zcu.PerThread,
2target: *const std.Target,
3air: Air,
4nav_index: InternPool.Nav.Index,
5
6// Blocks
7def_order: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, void),
8blocks: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, Block),
9loops: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, Loop),
10active_loops: std.ArrayListUnmanaged(Loop.Index),
11loop_live: struct {
12 set: std.AutoArrayHashMapUnmanaged(struct { Loop.Index, Air.Inst.Index }, void),
13 list: std.ArrayListUnmanaged(Air.Inst.Index),
14},
15dom_start: u32,
16dom_len: u32,
17dom: std.ArrayListUnmanaged(DomInt),
18
19// Wip Mir
20saved_registers: std.enums.EnumSet(Register.Alias),
21instructions: std.ArrayListUnmanaged(codegen.aarch64.encoding.Instruction),
22literals: std.ArrayListUnmanaged(u32),
23nav_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Nav),
24uav_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Uav),
25global_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Global),
26literal_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Literal),
27
28// Stack Frame
29returns: bool,
30va_list: struct {
31 __stack: Value.Indirect,
32 __gr_top: Value.Indirect,
33 __vr_top: Value.Indirect,
34},
35stack_size: u24,
36stack_align: InternPool.Alignment,
37
38// Value Tracking
39live_registers: LiveRegisters,
40live_values: std.AutoHashMapUnmanaged(Air.Inst.Index, Value.Index),
41values: std.ArrayListUnmanaged(Value),
42
43pub const LiveRegisters = std.enums.EnumArray(Register.Alias, Value.Index);
44
45pub const Block = struct {
46 live_registers: LiveRegisters,
47 target_label: u32,
48
49 pub const main: Air.Inst.Index = @enumFromInt(
50 std.math.maxInt(@typeInfo(Air.Inst.Index).@"enum".tag_type),
51 );
52
53 fn branch(block: *const Block, isel: *Select) !void {
54 if (isel.instructions.items.len > block.target_label) {
55 try isel.emit(.b(@intCast((isel.instructions.items.len + 1 - block.target_label) << 2)));
56 }
57 try isel.merge(&block.live_registers, .{});
58 }
59};
60
61pub const Loop = struct {
62 def_order: u32,
63 dom: u32,
64 depth: u32,
65 live: u32,
66 live_registers: LiveRegisters,
67 repeat_list: u32,
68
69 pub const invalid: Air.Inst.Index = @enumFromInt(
70 std.math.maxInt(@typeInfo(Air.Inst.Index).@"enum".tag_type),
71 );
72
73 pub const Index = enum(u32) {
74 _,
75
76 fn inst(li: Loop.Index, isel: *Select) Air.Inst.Index {
77 return isel.loops.keys()[@intFromEnum(li)];
78 }
79
80 fn get(li: Loop.Index, isel: *Select) *Loop {
81 return &isel.loops.values()[@intFromEnum(li)];
82 }
83 };
84
85 pub const empty_list: u32 = std.math.maxInt(u32);
86
87 fn branch(loop: *Loop, isel: *Select) !void {
88 try isel.instructions.ensureUnusedCapacity(isel.pt.zcu.gpa, 1);
89 const repeat_list_tail = loop.repeat_list;
90 loop.repeat_list = @intCast(isel.instructions.items.len);
91 isel.instructions.appendAssumeCapacity(@bitCast(repeat_list_tail));
92 try isel.merge(&loop.live_registers, .{});
93 }
94};
95
96pub fn deinit(isel: *Select) void {
97 const gpa = isel.pt.zcu.gpa;
98
99 isel.def_order.deinit(gpa);
100 isel.blocks.deinit(gpa);
101 isel.loops.deinit(gpa);
102 isel.active_loops.deinit(gpa);
103 isel.loop_live.set.deinit(gpa);
104 isel.loop_live.list.deinit(gpa);
105 isel.dom.deinit(gpa);
106
107 isel.instructions.deinit(gpa);
108 isel.literals.deinit(gpa);
109 isel.nav_relocs.deinit(gpa);
110 isel.uav_relocs.deinit(gpa);
111 isel.global_relocs.deinit(gpa);
112 isel.literal_relocs.deinit(gpa);
113
114 isel.live_values.deinit(gpa);
115 isel.values.deinit(gpa);
116
117 isel.* = undefined;
118}
119
120pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
121 const zcu = isel.pt.zcu;
122 const ip = &zcu.intern_pool;
123 const gpa = zcu.gpa;
124 const air_tags = isel.air.instructions.items(.tag);
125 const air_data = isel.air.instructions.items(.data);
126 var air_body_index: usize = 0;
127 var air_inst_index = air_body[air_body_index];
128 const initial_def_order_len = isel.def_order.count();
129 air_tag: switch (air_tags[@intFromEnum(air_inst_index)]) {
130 .arg,
131 .ret_addr,
132 .frame_addr,
133 .err_return_trace,
134 .save_err_return_trace_index,
135 .runtime_nav_ptr,
136 .c_va_start,
137 => {
138 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
139
140 air_body_index += 1;
141 air_inst_index = air_body[air_body_index];
142 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
143 },
144 .add,
145 .add_safe,
146 .add_optimized,
147 .add_wrap,
148 .add_sat,
149 .sub,
150 .sub_safe,
151 .sub_optimized,
152 .sub_wrap,
153 .sub_sat,
154 .mul,
155 .mul_safe,
156 .mul_optimized,
157 .mul_wrap,
158 .mul_sat,
159 .div_float,
160 .div_float_optimized,
161 .div_trunc,
162 .div_trunc_optimized,
163 .div_floor,
164 .div_floor_optimized,
165 .div_exact,
166 .div_exact_optimized,
167 .rem,
168 .rem_optimized,
169 .mod,
170 .mod_optimized,
171 .max,
172 .min,
173 .bit_and,
174 .bit_or,
175 .shr,
176 .shr_exact,
177 .shl,
178 .shl_exact,
179 .shl_sat,
180 .xor,
181 .cmp_lt,
182 .cmp_lt_optimized,
183 .cmp_lte,
184 .cmp_lte_optimized,
185 .cmp_eq,
186 .cmp_eq_optimized,
187 .cmp_gte,
188 .cmp_gte_optimized,
189 .cmp_gt,
190 .cmp_gt_optimized,
191 .cmp_neq,
192 .cmp_neq_optimized,
193 .bool_and,
194 .bool_or,
195 .array_elem_val,
196 .slice_elem_val,
197 .ptr_elem_val,
198 => {
199 const bin_op = air_data[@intFromEnum(air_inst_index)].bin_op;
200
201 try isel.analyzeUse(bin_op.lhs);
202 try isel.analyzeUse(bin_op.rhs);
203 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
204
205 air_body_index += 1;
206 air_inst_index = air_body[air_body_index];
207 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
208 },
209 .ptr_add,
210 .ptr_sub,
211 .add_with_overflow,
212 .sub_with_overflow,
213 .mul_with_overflow,
214 .shl_with_overflow,
215 .slice,
216 .slice_elem_ptr,
217 .ptr_elem_ptr,
218 => {
219 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
220 const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data;
221
222 try isel.analyzeUse(bin_op.lhs);
223 try isel.analyzeUse(bin_op.rhs);
224 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
225
226 air_body_index += 1;
227 air_inst_index = air_body[air_body_index];
228 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
229 },
230 .alloc => {
231 const ty = air_data[@intFromEnum(air_inst_index)].ty;
232
233 isel.stack_align = isel.stack_align.maxStrict(ty.ptrAlignment(zcu));
234 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
235
236 air_body_index += 1;
237 air_inst_index = air_body[air_body_index];
238 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
239 },
240 .inferred_alloc,
241 .inferred_alloc_comptime,
242 .wasm_memory_size,
243 .wasm_memory_grow,
244 .work_item_id,
245 .work_group_size,
246 .work_group_id,
247 => unreachable,
248 .ret_ptr => {
249 const ty = air_data[@intFromEnum(air_inst_index)].ty;
250
251 if (isel.live_values.get(Block.main)) |ret_vi| switch (ret_vi.parent(isel)) {
252 .unallocated, .stack_slot => isel.stack_align = isel.stack_align.maxStrict(ty.ptrAlignment(zcu)),
253 .value, .constant => unreachable,
254 .address => |address_vi| try isel.live_values.putNoClobber(gpa, air_inst_index, address_vi.ref(isel)),
255 };
256 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
257
258 air_body_index += 1;
259 air_inst_index = air_body[air_body_index];
260 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
261 },
262 .assembly => {
263 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
264 const extra = isel.air.extraData(Air.Asm, ty_pl.payload);
265 const operands: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0 .. extra.data.flags.outputs_len + extra.data.inputs_len]);
266
267 for (operands) |operand| if (operand != .none) try isel.analyzeUse(operand);
268 if (ty_pl.ty != .void_type) try isel.def_order.putNoClobber(gpa, air_inst_index, {});
269
270 air_body_index += 1;
271 air_inst_index = air_body[air_body_index];
272 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
273 },
274 .not,
275 .clz,
276 .ctz,
277 .popcount,
278 .byte_swap,
279 .bit_reverse,
280 .abs,
281 .load,
282 .fptrunc,
283 .fpext,
284 .intcast,
285 .intcast_safe,
286 .trunc,
287 .optional_payload,
288 .optional_payload_ptr,
289 .optional_payload_ptr_set,
290 .wrap_optional,
291 .unwrap_errunion_payload,
292 .unwrap_errunion_err,
293 .unwrap_errunion_payload_ptr,
294 .unwrap_errunion_err_ptr,
295 .errunion_payload_ptr_set,
296 .wrap_errunion_payload,
297 .wrap_errunion_err,
298 .struct_field_ptr_index_0,
299 .struct_field_ptr_index_1,
300 .struct_field_ptr_index_2,
301 .struct_field_ptr_index_3,
302 .get_union_tag,
303 .ptr_slice_len_ptr,
304 .ptr_slice_ptr_ptr,
305 .array_to_slice,
306 .int_from_float,
307 .int_from_float_optimized,
308 .int_from_float_safe,
309 .int_from_float_optimized_safe,
310 .float_from_int,
311 .splat,
312 .error_set_has_value,
313 .addrspace_cast,
314 .c_va_arg,
315 .c_va_copy,
316 => {
317 const ty_op = air_data[@intFromEnum(air_inst_index)].ty_op;
318
319 try isel.analyzeUse(ty_op.operand);
320 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
321
322 air_body_index += 1;
323 air_inst_index = air_body[air_body_index];
324 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
325 },
326 .bitcast => {
327 const ty_op = air_data[@intFromEnum(air_inst_index)].ty_op;
328 maybe_noop: {
329 if (ty_op.ty.toInterned().? != isel.air.typeOf(ty_op.operand, ip).toIntern()) break :maybe_noop;
330 if (true) break :maybe_noop;
331 if (ty_op.operand.toIndex()) |src_air_inst_index| {
332 if (isel.hints.get(src_air_inst_index)) |hint_vpsi| {
333 try isel.hints.putNoClobber(gpa, air_inst_index, hint_vpsi);
334 }
335 }
336 }
337 try isel.analyzeUse(ty_op.operand);
338 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
339
340 air_body_index += 1;
341 air_inst_index = air_body[air_body_index];
342 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
343 },
344 inline .block, .dbg_inline_block => |air_tag| {
345 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
346 const extra = isel.air.extraData(switch (air_tag) {
347 else => comptime unreachable,
348 .block => Air.Block,
349 .dbg_inline_block => Air.DbgInlineBlock,
350 }, ty_pl.payload);
351 const result_ty = ty_pl.ty.toInterned().?;
352
353 if (result_ty == .noreturn_type) {
354 try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));
355
356 air_body_index += 1;
357 break :air_tag;
358 }
359
360 assert(!(try isel.blocks.getOrPut(gpa, air_inst_index)).found_existing);
361 try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));
362 const block_entry = isel.blocks.pop().?;
363 assert(block_entry.key == air_inst_index);
364
365 if (result_ty != .void_type) try isel.def_order.putNoClobber(gpa, air_inst_index, {});
366
367 air_body_index += 1;
368 air_inst_index = air_body[air_body_index];
369 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
370 },
371 .loop => {
372 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
373 const extra = isel.air.extraData(Air.Block, ty_pl.payload);
374
375 const initial_dom_start = isel.dom_start;
376 const initial_dom_len = isel.dom_len;
377 isel.dom_start = @intCast(isel.dom.items.len);
378 isel.dom_len = @intCast(isel.blocks.count());
379 try isel.active_loops.append(gpa, @enumFromInt(isel.loops.count()));
380 try isel.loops.putNoClobber(gpa, air_inst_index, .{
381 .def_order = @intCast(isel.def_order.count()),
382 .dom = isel.dom_start,
383 .depth = isel.dom_len,
384 .live = 0,
385 .live_registers = undefined,
386 .repeat_list = undefined,
387 });
388 try isel.dom.appendNTimes(gpa, 0, std.math.divCeil(usize, isel.dom_len, @bitSizeOf(DomInt)) catch unreachable);
389 try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));
390 for (
391 isel.dom.items[initial_dom_start..].ptr,
392 isel.dom.items[isel.dom_start..][0 .. std.math.divCeil(usize, initial_dom_len, @bitSizeOf(DomInt)) catch unreachable],
393 ) |*initial_dom, loop_dom| initial_dom.* |= loop_dom;
394 isel.dom_start = initial_dom_start;
395 isel.dom_len = initial_dom_len;
396 assert(isel.active_loops.pop().?.inst(isel) == air_inst_index);
397
398 air_body_index += 1;
399 },
400 .repeat, .trap, .unreach => air_body_index += 1,
401 .br => {
402 const br = air_data[@intFromEnum(air_inst_index)].br;
403 const block_index = isel.blocks.getIndex(br.block_inst).?;
404 if (block_index < isel.dom_len) isel.dom.items[isel.dom_start + block_index / @bitSizeOf(DomInt)] |= @as(DomInt, 1) << @truncate(block_index);
405 try isel.analyzeUse(br.operand);
406
407 air_body_index += 1;
408 },
409 .breakpoint,
410 .dbg_stmt,
411 .dbg_empty_stmt,
412 .dbg_var_ptr,
413 .dbg_var_val,
414 .dbg_arg_inline,
415 => {
416 air_body_index += 1;
417 air_inst_index = air_body[air_body_index];
418 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
419 },
420 .call,
421 .call_always_tail,
422 .call_never_tail,
423 .call_never_inline,
424 => {
425 const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op;
426 const extra = isel.air.extraData(Air.Call, pl_op.payload);
427 const args: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0..extra.data.args_len]);
428 isel.saved_registers.insert(.lr);
429
430 try isel.analyzeUse(pl_op.operand);
431 var param_it: CallAbiIterator = .init;
432 for (args) |arg| {
433 const restore_values_len = isel.values.items.len;
434 defer isel.values.shrinkRetainingCapacity(restore_values_len);
435 const param_vi = try param_it.param(isel, isel.air.typeOf(arg, ip)) orelse continue;
436 const param_parent = param_vi.parent(isel);
437 switch (switch (param_parent) {
438 .unallocated, .stack_slot => param_parent,
439 .value, .constant => unreachable,
440 .address => |address_vi| address_vi.parent(isel),
441 }) {
442 .unallocated => {},
443 .stack_slot => |stack_slot| {
444 assert(stack_slot.base == .sp);
445 isel.stack_size = @max(isel.stack_size, stack_slot.offset);
446 },
447 .value, .constant, .address => unreachable,
448 }
449
450 try isel.analyzeUse(arg);
451 }
452
453 var ret_it: CallAbiIterator = .init;
454 if (try ret_it.ret(isel, isel.air.typeOfIndex(air_inst_index, ip))) |ret_vi| {
455 tracking_log.debug("${d} <- %{d}", .{ @intFromEnum(ret_vi), @intFromEnum(air_inst_index) });
456 switch (ret_vi.parent(isel)) {
457 .unallocated, .stack_slot => {},
458 .value, .constant => unreachable,
459 .address => |address_vi| {
460 defer address_vi.deref(isel);
461 const ret_value = ret_vi.get(isel);
462 ret_value.flags.parent_tag = .unallocated;
463 ret_value.parent_payload = .{ .unallocated = {} };
464 },
465 }
466 try isel.live_values.putNoClobber(gpa, air_inst_index, ret_vi);
467
468 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
469 }
470
471 air_body_index += 1;
472 air_inst_index = air_body[air_body_index];
473 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
474 },
475 .sqrt,
476 .sin,
477 .cos,
478 .tan,
479 .exp,
480 .exp2,
481 .log,
482 .log2,
483 .log10,
484 .floor,
485 .ceil,
486 .round,
487 .trunc_float,
488 .neg,
489 .neg_optimized,
490 .is_null,
491 .is_non_null,
492 .is_null_ptr,
493 .is_non_null_ptr,
494 .is_err,
495 .is_non_err,
496 .is_err_ptr,
497 .is_non_err_ptr,
498 .is_named_enum_value,
499 .tag_name,
500 .error_name,
501 .cmp_lt_errors_len,
502 => {
503 const un_op = air_data[@intFromEnum(air_inst_index)].un_op;
504
505 try isel.analyzeUse(un_op);
506 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
507
508 air_body_index += 1;
509 air_inst_index = air_body[air_body_index];
510 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
511 },
512 .cmp_vector, .cmp_vector_optimized => {
513 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
514 const extra = isel.air.extraData(Air.VectorCmp, ty_pl.payload).data;
515
516 try isel.analyzeUse(extra.lhs);
517 try isel.analyzeUse(extra.rhs);
518 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
519
520 air_body_index += 1;
521 air_inst_index = air_body[air_body_index];
522 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
523 },
524 .cond_br => {
525 const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op;
526 const extra = isel.air.extraData(Air.CondBr, pl_op.payload);
527
528 try isel.analyzeUse(pl_op.operand);
529
530 try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.then_body_len]));
531 try isel.analyze(@ptrCast(isel.air.extra.items[extra.end + extra.data.then_body_len ..][0..extra.data.else_body_len]));
532
533 air_body_index += 1;
534 },
535 .switch_br => {
536 const switch_br = isel.air.unwrapSwitch(air_inst_index);
537
538 try isel.analyzeUse(switch_br.operand);
539
540 var cases_it = switch_br.iterateCases();
541 while (cases_it.next()) |case| try isel.analyze(case.body);
542 if (switch_br.else_body_len > 0) try isel.analyze(cases_it.elseBody());
543
544 air_body_index += 1;
545 },
546 .loop_switch_br => {
547 const switch_br = isel.air.unwrapSwitch(air_inst_index);
548
549 const initial_dom_start = isel.dom_start;
550 const initial_dom_len = isel.dom_len;
551 isel.dom_start = @intCast(isel.dom.items.len);
552 isel.dom_len = @intCast(isel.blocks.count());
553 try isel.active_loops.append(gpa, @enumFromInt(isel.loops.count()));
554 try isel.loops.putNoClobber(gpa, air_inst_index, .{
555 .def_order = @intCast(isel.def_order.count()),
556 .dom = isel.dom_start,
557 .depth = isel.dom_len,
558 .live = 0,
559 .live_registers = undefined,
560 .repeat_list = undefined,
561 });
562 try isel.dom.appendNTimes(gpa, 0, std.math.divCeil(usize, isel.dom_len, @bitSizeOf(DomInt)) catch unreachable);
563
564 var cases_it = switch_br.iterateCases();
565 while (cases_it.next()) |case| try isel.analyze(case.body);
566 if (switch_br.else_body_len > 0) try isel.analyze(cases_it.elseBody());
567
568 for (
569 isel.dom.items[initial_dom_start..].ptr,
570 isel.dom.items[isel.dom_start..][0 .. std.math.divCeil(usize, initial_dom_len, @bitSizeOf(DomInt)) catch unreachable],
571 ) |*initial_dom, loop_dom| initial_dom.* |= loop_dom;
572 isel.dom_start = initial_dom_start;
573 isel.dom_len = initial_dom_len;
574 assert(isel.active_loops.pop().?.inst(isel) == air_inst_index);
575
576 air_body_index += 1;
577 },
578 .switch_dispatch => {
579 const br = air_data[@intFromEnum(air_inst_index)].br;
580
581 try isel.analyzeUse(br.operand);
582
583 air_body_index += 1;
584 },
585 .@"try", .try_cold, .try_ptr, .try_ptr_cold => {
586 const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op;
587 const extra = isel.air.extraData(Air.Try, pl_op.payload);
588
589 try isel.analyzeUse(pl_op.operand);
590 try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));
591 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
592
593 air_body_index += 1;
594 air_inst_index = air_body[air_body_index];
595 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
596 },
597 .ret, .ret_safe, .ret_load => {
598 const un_op = air_data[@intFromEnum(air_inst_index)].un_op;
599 isel.returns = true;
600
601 const block_index = 0;
602 assert(isel.blocks.keys()[block_index] == Block.main);
603 if (isel.dom_len > 0) isel.dom.items[isel.dom_start] |= 1 << block_index;
604
605 try isel.analyzeUse(un_op);
606
607 air_body_index += 1;
608 },
609 .store,
610 .store_safe,
611 .set_union_tag,
612 .memset,
613 .memset_safe,
614 .memcpy,
615 .memmove,
616 .atomic_store_unordered,
617 .atomic_store_monotonic,
618 .atomic_store_release,
619 .atomic_store_seq_cst,
620 => {
621 const bin_op = air_data[@intFromEnum(air_inst_index)].bin_op;
622
623 try isel.analyzeUse(bin_op.lhs);
624 try isel.analyzeUse(bin_op.rhs);
625
626 air_body_index += 1;
627 air_inst_index = air_body[air_body_index];
628 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
629 },
630 .struct_field_ptr, .struct_field_val => {
631 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
632 const extra = isel.air.extraData(Air.StructField, ty_pl.payload).data;
633
634 try isel.analyzeUse(extra.struct_operand);
635 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
636
637 air_body_index += 1;
638 air_inst_index = air_body[air_body_index];
639 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
640 },
641 .slice_len => {
642 const ty_op = air_data[@intFromEnum(air_inst_index)].ty_op;
643
644 try isel.analyzeUse(ty_op.operand);
645 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
646
647 const slice_vi = try isel.use(ty_op.operand);
648 var len_part_it = slice_vi.field(isel.air.typeOf(ty_op.operand, ip), 8, 8);
649 if (try len_part_it.only(isel)) |len_part_vi|
650 try isel.live_values.putNoClobber(gpa, air_inst_index, len_part_vi.ref(isel));
651
652 air_body_index += 1;
653 air_inst_index = air_body[air_body_index];
654 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
655 },
656 .slice_ptr => {
657 const ty_op = air_data[@intFromEnum(air_inst_index)].ty_op;
658
659 try isel.analyzeUse(ty_op.operand);
660 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
661
662 const slice_vi = try isel.use(ty_op.operand);
663 var ptr_part_it = slice_vi.field(isel.air.typeOf(ty_op.operand, ip), 0, 8);
664 if (try ptr_part_it.only(isel)) |ptr_part_vi|
665 try isel.live_values.putNoClobber(gpa, air_inst_index, ptr_part_vi.ref(isel));
666
667 air_body_index += 1;
668 air_inst_index = air_body[air_body_index];
669 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
670 },
671 .reduce, .reduce_optimized => {
672 const reduce = air_data[@intFromEnum(air_inst_index)].reduce;
673
674 try isel.analyzeUse(reduce.operand);
675 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
676
677 air_body_index += 1;
678 air_inst_index = air_body[air_body_index];
679 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
680 },
681 .shuffle_one => {
682 const extra = isel.air.unwrapShuffleOne(zcu, air_inst_index);
683
684 try isel.analyzeUse(extra.operand);
685 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
686
687 air_body_index += 1;
688 air_inst_index = air_body[air_body_index];
689 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
690 },
691 .shuffle_two => {
692 const extra = isel.air.unwrapShuffleTwo(zcu, air_inst_index);
693
694 try isel.analyzeUse(extra.operand_a);
695 try isel.analyzeUse(extra.operand_b);
696 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
697
698 air_body_index += 1;
699 air_inst_index = air_body[air_body_index];
700 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
701 },
702 .select, .mul_add => {
703 const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op;
704 const bin_op = isel.air.extraData(Air.Bin, pl_op.payload).data;
705
706 try isel.analyzeUse(pl_op.operand);
707 try isel.analyzeUse(bin_op.lhs);
708 try isel.analyzeUse(bin_op.rhs);
709 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
710
711 air_body_index += 1;
712 air_inst_index = air_body[air_body_index];
713 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
714 },
715 .cmpxchg_weak, .cmpxchg_strong => {
716 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
717 const extra = isel.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
718
719 try isel.analyzeUse(extra.ptr);
720 try isel.analyzeUse(extra.expected_value);
721 try isel.analyzeUse(extra.new_value);
722 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
723
724 air_body_index += 1;
725 air_inst_index = air_body[air_body_index];
726 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
727 },
728 .atomic_load => {
729 const atomic_load = air_data[@intFromEnum(air_inst_index)].atomic_load;
730
731 try isel.analyzeUse(atomic_load.ptr);
732 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
733
734 air_body_index += 1;
735 air_inst_index = air_body[air_body_index];
736 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
737 },
738 .atomic_rmw => {
739 const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op;
740 const extra = isel.air.extraData(Air.AtomicRmw, pl_op.payload).data;
741
742 try isel.analyzeUse(extra.operand);
743 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
744
745 air_body_index += 1;
746 air_inst_index = air_body[air_body_index];
747 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
748 },
749 .aggregate_init => {
750 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
751 const elements: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[ty_pl.payload..][0..@intCast(ty_pl.ty.toType().arrayLen(zcu))]);
752
753 for (elements) |element| try isel.analyzeUse(element);
754 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
755
756 air_body_index += 1;
757 air_inst_index = air_body[air_body_index];
758 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
759 },
760 .union_init => {
761 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
762 const extra = isel.air.extraData(Air.UnionInit, ty_pl.payload).data;
763
764 try isel.analyzeUse(extra.init);
765 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
766
767 air_body_index += 1;
768 air_inst_index = air_body[air_body_index];
769 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
770 },
771 .prefetch => {
772 const prefetch = air_data[@intFromEnum(air_inst_index)].prefetch;
773
774 try isel.analyzeUse(prefetch.ptr);
775
776 air_body_index += 1;
777 air_inst_index = air_body[air_body_index];
778 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
779 },
780 .field_parent_ptr => {
781 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
782 const extra = isel.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
783
784 try isel.analyzeUse(extra.field_ptr);
785 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
786
787 air_body_index += 1;
788 air_inst_index = air_body[air_body_index];
789 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
790 },
791 .set_err_return_trace, .c_va_end => {
792 const un_op = air_data[@intFromEnum(air_inst_index)].un_op;
793
794 try isel.analyzeUse(un_op);
795
796 air_body_index += 1;
797 air_inst_index = air_body[air_body_index];
798 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
799 },
800 .vector_store_elem => {
801 const vector_store_elem = air_data[@intFromEnum(air_inst_index)].vector_store_elem;
802 const bin_op = isel.air.extraData(Air.Bin, vector_store_elem.payload).data;
803
804 try isel.analyzeUse(vector_store_elem.vector_ptr);
805 try isel.analyzeUse(bin_op.lhs);
806 try isel.analyzeUse(bin_op.rhs);
807
808 air_body_index += 1;
809 air_inst_index = air_body[air_body_index];
810 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
811 },
812 }
813 assert(air_body_index == air_body.len);
814 isel.def_order.shrinkRetainingCapacity(initial_def_order_len);
815}
816
817fn analyzeUse(isel: *Select, air_ref: Air.Inst.Ref) !void {
818 const air_inst_index = air_ref.toIndex() orelse return;
819 const def_order_index = isel.def_order.getIndex(air_inst_index).?;
820
821 // Loop liveness
822 var active_loop_index = isel.active_loops.items.len;
823 while (active_loop_index > 0) {
824 const prev_active_loop_index = active_loop_index - 1;
825 const active_loop = isel.active_loops.items[prev_active_loop_index];
826 if (def_order_index >= active_loop.get(isel).def_order) break;
827 active_loop_index = prev_active_loop_index;
828 }
829 if (active_loop_index < isel.active_loops.items.len) {
830 const active_loop = isel.active_loops.items[active_loop_index];
831 const loop_live_gop =
832 try isel.loop_live.set.getOrPut(isel.pt.zcu.gpa, .{ active_loop, air_inst_index });
833 if (!loop_live_gop.found_existing) active_loop.get(isel).live += 1;
834 }
835}
836
837pub fn finishAnalysis(isel: *Select) !void {
838 const gpa = isel.pt.zcu.gpa;
839
840 // Loop Liveness
841 if (isel.loops.count() > 0) {
842 try isel.loops.ensureUnusedCapacity(gpa, 1);
843
844 const loop_live_len: u32 = @intCast(isel.loop_live.set.count());
845 if (loop_live_len > 0) {
846 try isel.loop_live.list.resize(gpa, loop_live_len);
847
848 const loops = isel.loops.values();
849 for (loops[1..], loops[0 .. loops.len - 1]) |*loop, prev_loop| loop.live += prev_loop.live;
850 assert(loops[loops.len - 1].live == loop_live_len);
851
852 for (isel.loop_live.set.keys()) |entry| {
853 const loop, const inst = entry;
854 const loop_live = &loop.get(isel).live;
855 loop_live.* -= 1;
856 isel.loop_live.list.items[loop_live.*] = inst;
857 }
858 assert(loops[0].live == 0);
859 }
860
861 const invalid_gop = isel.loops.getOrPutAssumeCapacity(Loop.invalid);
862 assert(!invalid_gop.found_existing);
863 invalid_gop.value_ptr.live = loop_live_len;
864 }
865}
866
867pub fn body(isel: *Select, air_body: []const Air.Inst.Index) !void {
868 const zcu = isel.pt.zcu;
869 const ip = &zcu.intern_pool;
870 const gpa = zcu.gpa;
871
872 {
873 var live_reg_it = isel.live_registers.iterator();
874 while (live_reg_it.next()) |live_reg_entry| switch (live_reg_entry.value.*) {
875 _ => {
876 const ra = &live_reg_entry.value.get(isel).location_payload.small.register;
877 assert(ra.* == live_reg_entry.key);
878 ra.* = .zr;
879 live_reg_entry.value.* = .free;
880 },
881 .allocating => live_reg_entry.value.* = .free,
882 .free => {},
883 };
884 }
885
886 var air: struct {
887 isel: *Select,
888 tag_items: []const Air.Inst.Tag,
889 data_items: []const Air.Inst.Data,
890 body: []const Air.Inst.Index,
891 body_index: u32,
892 inst_index: Air.Inst.Index,
893
894 fn tag(it: *@This(), inst_index: Air.Inst.Index) Air.Inst.Tag {
895 return it.tag_items[@intFromEnum(inst_index)];
896 }
897
898 fn data(it: *@This(), inst_index: Air.Inst.Index) Air.Inst.Data {
899 return it.data_items[@intFromEnum(inst_index)];
900 }
901
902 fn next(it: *@This()) ?Air.Inst.Tag {
903 if (it.body_index == 0) {
904 @branchHint(.unlikely);
905 return null;
906 }
907 it.body_index -= 1;
908 it.inst_index = it.body[it.body_index];
909 wip_mir_log.debug("{f}", .{it.fmtAir(it.inst_index)});
910 return it.tag(it.inst_index);
911 }
912
913 fn fmtAir(it: @This(), inst: Air.Inst.Index) struct {
914 isel: *Select,
915 inst: Air.Inst.Index,
916 pub fn format(fmt_air: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void {
917 fmt_air.isel.air.writeInst(writer, fmt_air.inst, fmt_air.isel.pt, null);
918 }
919 } {
920 return .{ .isel = it.isel, .inst = inst };
921 }
922 } = .{
923 .isel = isel,
924 .tag_items = isel.air.instructions.items(.tag),
925 .data_items = isel.air.instructions.items(.data),
926 .body = air_body,
927 .body_index = @intCast(air_body.len),
928 .inst_index = undefined,
929 };
930 air_tag: switch (air.next().?) {
931 else => |air_tag| return isel.fail("unimplemented {s}", .{@tagName(air_tag)}),
932 .arg => {
933 const arg_vi = isel.live_values.fetchRemove(air.inst_index).?.value;
934 defer arg_vi.deref(isel);
935 switch (arg_vi.parent(isel)) {
936 .unallocated, .stack_slot => if (arg_vi.hint(isel)) |arg_ra| {
937 try arg_vi.defLiveIn(isel, arg_ra, comptime &.initFill(.free));
938 } else {
939 var arg_part_it = arg_vi.parts(isel);
940 while (arg_part_it.next()) |arg_part| {
941 try arg_part.defLiveIn(isel, arg_part.hint(isel).?, comptime &.initFill(.free));
942 }
943 },
944 .value, .constant => unreachable,
945 .address => |address_vi| try address_vi.defLiveIn(isel, address_vi.hint(isel).?, comptime &.initFill(.free)),
946 }
947 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
948 },
949 .add, .add_optimized, .add_wrap, .sub, .sub_optimized, .sub_wrap => |air_tag| {
950 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
951 defer res_vi.value.deref(isel);
952
953 const bin_op = air.data(air.inst_index).bin_op;
954 const ty = isel.air.typeOf(bin_op.lhs, ip);
955 if (!ty.isRuntimeFloat()) try res_vi.value.addOrSubtract(isel, ty, try isel.use(bin_op.lhs), switch (air_tag) {
956 else => unreachable,
957 .add, .add_wrap => .add,
958 .sub, .sub_wrap => .sub,
959 }, try isel.use(bin_op.rhs), .{ .wrap = switch (air_tag) {
960 else => unreachable,
961 .add, .sub => false,
962 .add_wrap, .sub_wrap => true,
963 } }) else switch (ty.floatBits(isel.target)) {
964 else => unreachable,
965 16, 32, 64 => |bits| {
966 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
967 const need_fcvt = switch (bits) {
968 else => unreachable,
969 16 => !isel.target.cpu.has(.aarch64, .fullfp16),
970 32, 64 => false,
971 };
972 if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s()));
973 const lhs_vi = try isel.use(bin_op.lhs);
974 const rhs_vi = try isel.use(bin_op.rhs);
975 const lhs_mat = try lhs_vi.matReg(isel);
976 const rhs_mat = try rhs_vi.matReg(isel);
977 const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra;
978 defer if (need_fcvt) isel.freeReg(lhs_ra);
979 const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra;
980 defer if (need_fcvt) isel.freeReg(rhs_ra);
981 try isel.emit(bits: switch (bits) {
982 else => unreachable,
983 16 => if (need_fcvt) continue :bits 32 else switch (air_tag) {
984 else => unreachable,
985 .add, .add_optimized => .fadd(res_ra.h(), lhs_ra.h(), rhs_ra.h()),
986 .sub, .sub_optimized => .fsub(res_ra.h(), lhs_ra.h(), rhs_ra.h()),
987 },
988 32 => switch (air_tag) {
989 else => unreachable,
990 .add, .add_optimized => .fadd(res_ra.s(), lhs_ra.s(), rhs_ra.s()),
991 .sub, .sub_optimized => .fsub(res_ra.s(), lhs_ra.s(), rhs_ra.s()),
992 },
993 64 => switch (air_tag) {
994 else => unreachable,
995 .add, .add_optimized => .fadd(res_ra.d(), lhs_ra.d(), rhs_ra.d()),
996 .sub, .sub_optimized => .fsub(res_ra.d(), lhs_ra.d(), rhs_ra.d()),
997 },
998 });
999 if (need_fcvt) {
1000 try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h()));
1001 try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h()));
1002 }
1003 try rhs_mat.finish(isel);
1004 try lhs_mat.finish(isel);
1005 },
1006 80, 128 => |bits| {
1007 try call.prepareReturn(isel);
1008 switch (bits) {
1009 else => unreachable,
1010 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
1011 80 => {
1012 var res_hi16_it = res_vi.value.field(ty, 8, 8);
1013 const res_hi16_vi = try res_hi16_it.only(isel);
1014 try call.returnLiveIn(isel, res_hi16_vi.?, .r1);
1015 var res_lo64_it = res_vi.value.field(ty, 0, 8);
1016 const res_lo64_vi = try res_lo64_it.only(isel);
1017 try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
1018 },
1019 }
1020 try call.finishReturn(isel);
1021
1022 try call.prepareCallee(isel);
1023 try isel.global_relocs.append(gpa, .{
1024 .global = switch (air_tag) {
1025 else => unreachable,
1026 .add, .add_optimized => switch (bits) {
1027 else => unreachable,
1028 16 => "__addhf3",
1029 32 => "__addsf3",
1030 64 => "__adddf3",
1031 80 => "__addxf3",
1032 128 => "__addtf3",
1033 },
1034 .sub, .sub_optimized => switch (bits) {
1035 else => unreachable,
1036 16 => "__subhf3",
1037 32 => "__subsf3",
1038 64 => "__subdf3",
1039 80 => "__subxf3",
1040 128 => "__subtf3",
1041 },
1042 },
1043 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
1044 });
1045 try isel.emit(.bl(0));
1046 try call.finishCallee(isel);
1047
1048 try call.prepareParams(isel);
1049 const lhs_vi = try isel.use(bin_op.lhs);
1050 const rhs_vi = try isel.use(bin_op.rhs);
1051 switch (bits) {
1052 else => unreachable,
1053 16, 32, 64, 128 => {
1054 try call.paramLiveOut(isel, rhs_vi, .v1);
1055 try call.paramLiveOut(isel, lhs_vi, .v0);
1056 },
1057 80 => {
1058 var rhs_hi16_it = rhs_vi.field(ty, 8, 8);
1059 const rhs_hi16_vi = try rhs_hi16_it.only(isel);
1060 try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3);
1061 var rhs_lo64_it = rhs_vi.field(ty, 0, 8);
1062 const rhs_lo64_vi = try rhs_lo64_it.only(isel);
1063 try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2);
1064 var lhs_hi16_it = lhs_vi.field(ty, 8, 8);
1065 const lhs_hi16_vi = try lhs_hi16_it.only(isel);
1066 try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1);
1067 var lhs_lo64_it = lhs_vi.field(ty, 0, 8);
1068 const lhs_lo64_vi = try lhs_lo64_it.only(isel);
1069 try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0);
1070 },
1071 }
1072 try call.finishParams(isel);
1073 },
1074 }
1075 }
1076 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
1077 },
1078 .add_sat, .sub_sat => |air_tag| {
1079 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
1080 defer res_vi.value.deref(isel);
1081
1082 const bin_op = air.data(air.inst_index).bin_op;
1083 const ty = isel.air.typeOf(bin_op.lhs, ip);
1084 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
1085 const int_info = ty.intInfo(zcu);
1086 switch (int_info.bits) {
1087 0 => unreachable,
1088 32, 64 => |bits| switch (int_info.signedness) {
1089 .signed => return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
1090 .unsigned => {
1091 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1092 const lhs_vi = try isel.use(bin_op.lhs);
1093 const rhs_vi = try isel.use(bin_op.rhs);
1094 const lhs_mat = try lhs_vi.matReg(isel);
1095 const rhs_mat = try rhs_vi.matReg(isel);
1096 const unsat_res_ra = try isel.allocIntReg();
1097 defer isel.freeReg(unsat_res_ra);
1098 switch (air_tag) {
1099 else => unreachable,
1100 .add_sat => switch (bits) {
1101 else => unreachable,
1102 32 => {
1103 try isel.emit(.csinv(res_ra.w(), unsat_res_ra.w(), .wzr, .invert(.cs)));
1104 try isel.emit(.adds(unsat_res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() }));
1105 },
1106 64 => {
1107 try isel.emit(.csinv(res_ra.x(), unsat_res_ra.x(), .xzr, .invert(.cs)));
1108 try isel.emit(.adds(unsat_res_ra.x(), lhs_mat.ra.x(), .{ .register = rhs_mat.ra.x() }));
1109 },
1110 },
1111 .sub_sat => switch (bits) {
1112 else => unreachable,
1113 32 => {
1114 try isel.emit(.csel(res_ra.w(), unsat_res_ra.w(), .wzr, .invert(.cc)));
1115 try isel.emit(.subs(unsat_res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() }));
1116 },
1117 64 => {
1118 try isel.emit(.csel(res_ra.x(), unsat_res_ra.x(), .xzr, .invert(.cc)));
1119 try isel.emit(.subs(unsat_res_ra.x(), lhs_mat.ra.x(), .{ .register = rhs_mat.ra.x() }));
1120 },
1121 },
1122 }
1123 try rhs_mat.finish(isel);
1124 try lhs_mat.finish(isel);
1125 },
1126 },
1127 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
1128 }
1129 }
1130 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
1131 },
1132 .mul, .mul_optimized, .mul_wrap => |air_tag| {
1133 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
1134 defer res_vi.value.deref(isel);
1135
1136 const bin_op = air.data(air.inst_index).bin_op;
1137 const ty = isel.air.typeOf(bin_op.lhs, ip);
1138 if (!ty.isRuntimeFloat()) {
1139 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
1140 const int_info = ty.intInfo(zcu);
1141 switch (int_info.bits) {
1142 0 => unreachable,
1143 1 => {
1144 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1145 switch (int_info.signedness) {
1146 .signed => switch (air_tag) {
1147 else => unreachable,
1148 .mul => break :unused try isel.emit(.orr(res_ra.w(), .wzr, .{ .register = .wzr })),
1149 .mul_wrap => {},
1150 },
1151 .unsigned => {},
1152 }
1153 const lhs_vi = try isel.use(bin_op.lhs);
1154 const rhs_vi = try isel.use(bin_op.rhs);
1155 const lhs_mat = try lhs_vi.matReg(isel);
1156 const rhs_mat = try rhs_vi.matReg(isel);
1157 try isel.emit(.@"and"(res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() }));
1158 try rhs_mat.finish(isel);
1159 try lhs_mat.finish(isel);
1160 },
1161 2...32 => |bits| {
1162 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1163 switch (air_tag) {
1164 else => unreachable,
1165 .mul => {},
1166 .mul_wrap => switch (bits) {
1167 else => unreachable,
1168 1...31 => try isel.emit(switch (int_info.signedness) {
1169 .signed => .sbfm(res_ra.w(), res_ra.w(), .{
1170 .N = .word,
1171 .immr = 0,
1172 .imms = @intCast(bits - 1),
1173 }),
1174 .unsigned => .ubfm(res_ra.w(), res_ra.w(), .{
1175 .N = .word,
1176 .immr = 0,
1177 .imms = @intCast(bits - 1),
1178 }),
1179 }),
1180 32 => {},
1181 },
1182 }
1183 const lhs_vi = try isel.use(bin_op.lhs);
1184 const rhs_vi = try isel.use(bin_op.rhs);
1185 const lhs_mat = try lhs_vi.matReg(isel);
1186 const rhs_mat = try rhs_vi.matReg(isel);
1187 try isel.emit(.madd(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w(), .wzr));
1188 try rhs_mat.finish(isel);
1189 try lhs_mat.finish(isel);
1190 },
1191 33...64 => |bits| {
1192 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1193 switch (air_tag) {
1194 else => unreachable,
1195 .mul => {},
1196 .mul_wrap => switch (bits) {
1197 else => unreachable,
1198 33...63 => try isel.emit(switch (int_info.signedness) {
1199 .signed => .sbfm(res_ra.x(), res_ra.x(), .{
1200 .N = .doubleword,
1201 .immr = 0,
1202 .imms = @intCast(bits - 1),
1203 }),
1204 .unsigned => .ubfm(res_ra.x(), res_ra.x(), .{
1205 .N = .doubleword,
1206 .immr = 0,
1207 .imms = @intCast(bits - 1),
1208 }),
1209 }),
1210 64 => {},
1211 },
1212 }
1213 const lhs_vi = try isel.use(bin_op.lhs);
1214 const rhs_vi = try isel.use(bin_op.rhs);
1215 const lhs_mat = try lhs_vi.matReg(isel);
1216 const rhs_mat = try rhs_vi.matReg(isel);
1217 try isel.emit(.madd(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), .xzr));
1218 try rhs_mat.finish(isel);
1219 try lhs_mat.finish(isel);
1220 },
1221 65...128 => |bits| {
1222 var res_hi64_it = res_vi.value.field(ty, 8, 8);
1223 const res_hi64_vi = try res_hi64_it.only(isel);
1224 const res_hi64_ra = try res_hi64_vi.?.defReg(isel);
1225 var res_lo64_it = res_vi.value.field(ty, 0, 8);
1226 const res_lo64_vi = try res_lo64_it.only(isel);
1227 const res_lo64_ra = try res_lo64_vi.?.defReg(isel);
1228 if (res_hi64_ra == null and res_lo64_ra == null) break :unused;
1229 if (res_hi64_ra) |res_ra| switch (air_tag) {
1230 else => unreachable,
1231 .mul => {},
1232 .mul_wrap => switch (bits) {
1233 else => unreachable,
1234 65...127 => try isel.emit(switch (int_info.signedness) {
1235 .signed => .sbfm(res_ra.x(), res_ra.x(), .{
1236 .N = .doubleword,
1237 .immr = 0,
1238 .imms = @intCast(bits - 1),
1239 }),
1240 .unsigned => .ubfm(res_ra.x(), res_ra.x(), .{
1241 .N = .doubleword,
1242 .immr = 0,
1243 .imms = @intCast(bits - 1),
1244 }),
1245 }),
1246 128 => {},
1247 },
1248 };
1249 const lhs_vi = try isel.use(bin_op.lhs);
1250 const rhs_vi = try isel.use(bin_op.rhs);
1251 const lhs_lo64_mat, const rhs_lo64_mat = lo64_mat: {
1252 const res_hi64_lock: RegLock = if (res_hi64_ra != null and res_lo64_ra != null)
1253 isel.lockReg(res_hi64_ra.?)
1254 else
1255 .empty;
1256 defer res_hi64_lock.unlock(isel);
1257
1258 var rhs_lo64_it = rhs_vi.field(ty, 0, 8);
1259 const rhs_lo64_vi = try rhs_lo64_it.only(isel);
1260 const rhs_lo64_mat = try rhs_lo64_vi.?.matReg(isel);
1261 var lhs_lo64_it = lhs_vi.field(ty, 0, 8);
1262 const lhs_lo64_vi = try lhs_lo64_it.only(isel);
1263 const lhs_lo64_mat = try lhs_lo64_vi.?.matReg(isel);
1264 break :lo64_mat .{ lhs_lo64_mat, rhs_lo64_mat };
1265 };
1266 if (res_lo64_ra) |res_ra| try isel.emit(.madd(res_ra.x(), lhs_lo64_mat.ra.x(), rhs_lo64_mat.ra.x(), .xzr));
1267 if (res_hi64_ra) |res_ra| {
1268 var rhs_hi64_it = rhs_vi.field(ty, 8, 8);
1269 const rhs_hi64_vi = try rhs_hi64_it.only(isel);
1270 const rhs_hi64_mat = try rhs_hi64_vi.?.matReg(isel);
1271 var lhs_hi64_it = lhs_vi.field(ty, 8, 8);
1272 const lhs_hi64_vi = try lhs_hi64_it.only(isel);
1273 const lhs_hi64_mat = try lhs_hi64_vi.?.matReg(isel);
1274 const acc_ra = try isel.allocIntReg();
1275 defer isel.freeReg(acc_ra);
1276 try isel.emit(.madd(res_ra.x(), lhs_hi64_mat.ra.x(), rhs_lo64_mat.ra.x(), acc_ra.x()));
1277 try isel.emit(.madd(acc_ra.x(), lhs_lo64_mat.ra.x(), rhs_hi64_mat.ra.x(), acc_ra.x()));
1278 try isel.emit(.umulh(acc_ra.x(), lhs_lo64_mat.ra.x(), rhs_lo64_mat.ra.x()));
1279 try rhs_hi64_mat.finish(isel);
1280 try lhs_hi64_mat.finish(isel);
1281 }
1282 try rhs_lo64_mat.finish(isel);
1283 try lhs_lo64_mat.finish(isel);
1284 },
1285 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
1286 }
1287 } else switch (ty.floatBits(isel.target)) {
1288 else => unreachable,
1289 16, 32, 64 => |bits| {
1290 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1291 const need_fcvt = switch (bits) {
1292 else => unreachable,
1293 16 => !isel.target.cpu.has(.aarch64, .fullfp16),
1294 32, 64 => false,
1295 };
1296 if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s()));
1297 const lhs_vi = try isel.use(bin_op.lhs);
1298 const rhs_vi = try isel.use(bin_op.rhs);
1299 const lhs_mat = try lhs_vi.matReg(isel);
1300 const rhs_mat = try rhs_vi.matReg(isel);
1301 const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra;
1302 defer if (need_fcvt) isel.freeReg(lhs_ra);
1303 const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra;
1304 defer if (need_fcvt) isel.freeReg(rhs_ra);
1305 try isel.emit(bits: switch (bits) {
1306 else => unreachable,
1307 16 => if (need_fcvt)
1308 continue :bits 32
1309 else
1310 .fmul(res_ra.h(), lhs_ra.h(), rhs_ra.h()),
1311 32 => .fmul(res_ra.s(), lhs_ra.s(), rhs_ra.s()),
1312 64 => .fmul(res_ra.d(), lhs_ra.d(), rhs_ra.d()),
1313 });
1314 if (need_fcvt) {
1315 try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h()));
1316 try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h()));
1317 }
1318 try rhs_mat.finish(isel);
1319 try lhs_mat.finish(isel);
1320 },
1321 80, 128 => |bits| {
1322 try call.prepareReturn(isel);
1323 switch (bits) {
1324 else => unreachable,
1325 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
1326 80 => {
1327 var res_hi16_it = res_vi.value.field(ty, 8, 8);
1328 const res_hi16_vi = try res_hi16_it.only(isel);
1329 try call.returnLiveIn(isel, res_hi16_vi.?, .r1);
1330 var res_lo64_it = res_vi.value.field(ty, 0, 8);
1331 const res_lo64_vi = try res_lo64_it.only(isel);
1332 try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
1333 },
1334 }
1335 try call.finishReturn(isel);
1336
1337 try call.prepareCallee(isel);
1338 try isel.global_relocs.append(gpa, .{
1339 .global = switch (bits) {
1340 else => unreachable,
1341 16 => "__mulhf3",
1342 32 => "__mulsf3",
1343 64 => "__muldf3",
1344 80 => "__mulxf3",
1345 128 => "__multf3",
1346 },
1347 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
1348 });
1349 try isel.emit(.bl(0));
1350 try call.finishCallee(isel);
1351
1352 try call.prepareParams(isel);
1353 const lhs_vi = try isel.use(bin_op.lhs);
1354 const rhs_vi = try isel.use(bin_op.rhs);
1355 switch (bits) {
1356 else => unreachable,
1357 16, 32, 64, 128 => {
1358 try call.paramLiveOut(isel, rhs_vi, .v1);
1359 try call.paramLiveOut(isel, lhs_vi, .v0);
1360 },
1361 80 => {
1362 var rhs_hi16_it = rhs_vi.field(ty, 8, 8);
1363 const rhs_hi16_vi = try rhs_hi16_it.only(isel);
1364 try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3);
1365 var rhs_lo64_it = rhs_vi.field(ty, 0, 8);
1366 const rhs_lo64_vi = try rhs_lo64_it.only(isel);
1367 try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2);
1368 var lhs_hi16_it = lhs_vi.field(ty, 8, 8);
1369 const lhs_hi16_vi = try lhs_hi16_it.only(isel);
1370 try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1);
1371 var lhs_lo64_it = lhs_vi.field(ty, 0, 8);
1372 const lhs_lo64_vi = try lhs_lo64_it.only(isel);
1373 try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0);
1374 },
1375 }
1376 try call.finishParams(isel);
1377 },
1378 }
1379 }
1380 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
1381 },
1382 .mul_sat => |air_tag| {
1383 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
1384 defer res_vi.value.deref(isel);
1385
1386 const bin_op = air.data(air.inst_index).bin_op;
1387 const ty = isel.air.typeOf(bin_op.lhs, ip);
1388 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
1389 const int_info = ty.intInfo(zcu);
1390 switch (int_info.bits) {
1391 0 => unreachable,
1392 1 => {
1393 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1394 switch (int_info.signedness) {
1395 .signed => try isel.emit(.orr(res_ra.w(), .wzr, .{ .register = .wzr })),
1396 .unsigned => {
1397 const lhs_vi = try isel.use(bin_op.lhs);
1398 const rhs_vi = try isel.use(bin_op.rhs);
1399 const lhs_mat = try lhs_vi.matReg(isel);
1400 const rhs_mat = try rhs_vi.matReg(isel);
1401 try isel.emit(.@"and"(res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() }));
1402 try rhs_mat.finish(isel);
1403 try lhs_mat.finish(isel);
1404 },
1405 }
1406 },
1407 2...32 => |bits| {
1408 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1409 const saturated_ra = switch (int_info.signedness) {
1410 .signed => try isel.allocIntReg(),
1411 .unsigned => switch (bits) {
1412 else => unreachable,
1413 2...31 => try isel.allocIntReg(),
1414 32 => .zr,
1415 },
1416 };
1417 defer if (saturated_ra != .zr) isel.freeReg(saturated_ra);
1418 const unwrapped_ra = try isel.allocIntReg();
1419 defer isel.freeReg(unwrapped_ra);
1420 try isel.emit(switch (saturated_ra) {
1421 else => .csel(res_ra.w(), unwrapped_ra.w(), saturated_ra.w(), .eq),
1422 .zr => .csinv(res_ra.w(), unwrapped_ra.w(), saturated_ra.w(), .eq),
1423 });
1424 switch (bits) {
1425 else => unreachable,
1426 2...7, 9...15, 17...31 => switch (int_info.signedness) {
1427 .signed => {
1428 const wrapped_ra = try isel.allocIntReg();
1429 defer isel.freeReg(wrapped_ra);
1430 switch (bits) {
1431 else => unreachable,
1432 1...7, 9...15 => {
1433 try isel.emit(.subs(.wzr, unwrapped_ra.w(), .{ .register = wrapped_ra.w() }));
1434 try isel.emit(.sbfm(wrapped_ra.w(), unwrapped_ra.w(), .{
1435 .N = .word,
1436 .immr = 0,
1437 .imms = @intCast(bits - 1),
1438 }));
1439 },
1440 17...31 => {
1441 try isel.emit(.subs(.xzr, unwrapped_ra.x(), .{ .register = wrapped_ra.x() }));
1442 try isel.emit(.sbfm(wrapped_ra.x(), unwrapped_ra.x(), .{
1443 .N = .doubleword,
1444 .immr = 0,
1445 .imms = @intCast(bits - 1),
1446 }));
1447 },
1448 }
1449 },
1450 .unsigned => switch (bits) {
1451 else => unreachable,
1452 1...7, 9...15 => try isel.emit(.ands(.wzr, unwrapped_ra.w(), .{ .immediate = .{
1453 .N = .word,
1454 .immr = @intCast(32 - bits),
1455 .imms = @intCast(32 - bits - 1),
1456 } })),
1457 17...31 => try isel.emit(.ands(.xzr, unwrapped_ra.x(), .{ .immediate = .{
1458 .N = .doubleword,
1459 .immr = @intCast(64 - bits),
1460 .imms = @intCast(64 - bits - 1),
1461 } })),
1462 },
1463 },
1464 8 => try isel.emit(.subs(.wzr, unwrapped_ra.w(), .{ .extended_register = .{
1465 .register = unwrapped_ra.w(),
1466 .extend = switch (int_info.signedness) {
1467 .signed => .{ .sxtb = 0 },
1468 .unsigned => .{ .uxtb = 0 },
1469 },
1470 } })),
1471 16 => try isel.emit(.subs(.wzr, unwrapped_ra.w(), .{ .extended_register = .{
1472 .register = unwrapped_ra.w(),
1473 .extend = switch (int_info.signedness) {
1474 .signed => .{ .sxth = 0 },
1475 .unsigned => .{ .uxth = 0 },
1476 },
1477 } })),
1478 32 => try isel.emit(.subs(.xzr, unwrapped_ra.x(), .{ .extended_register = .{
1479 .register = unwrapped_ra.w(),
1480 .extend = switch (int_info.signedness) {
1481 .signed => .{ .sxtw = 0 },
1482 .unsigned => .{ .uxtw = 0 },
1483 },
1484 } })),
1485 }
1486 const lhs_vi = try isel.use(bin_op.lhs);
1487 const rhs_vi = try isel.use(bin_op.rhs);
1488 const lhs_mat = try lhs_vi.matReg(isel);
1489 const rhs_mat = try rhs_vi.matReg(isel);
1490 switch (int_info.signedness) {
1491 .signed => {
1492 try isel.emit(.eor(saturated_ra.w(), saturated_ra.w(), .{ .immediate = .{
1493 .N = .word,
1494 .immr = 0,
1495 .imms = @intCast(bits - 1 - 1),
1496 } }));
1497 try isel.emit(.sbfm(saturated_ra.w(), saturated_ra.w(), .{
1498 .N = .word,
1499 .immr = @intCast(bits - 1),
1500 .imms = @intCast(bits - 1 + 1 - 1),
1501 }));
1502 try isel.emit(.eor(saturated_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() }));
1503 },
1504 .unsigned => switch (bits) {
1505 else => unreachable,
1506 2...31 => try isel.movImmediate(saturated_ra.w(), @as(u32, std.math.maxInt(u32)) >> @intCast(32 - bits)),
1507 32 => {},
1508 },
1509 }
1510 switch (bits) {
1511 else => unreachable,
1512 2...16 => try isel.emit(.madd(unwrapped_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w(), .wzr)),
1513 17...32 => switch (int_info.signedness) {
1514 .signed => try isel.emit(.smaddl(unwrapped_ra.x(), lhs_mat.ra.w(), rhs_mat.ra.w(), .xzr)),
1515 .unsigned => try isel.emit(.umaddl(unwrapped_ra.x(), lhs_mat.ra.w(), rhs_mat.ra.w(), .xzr)),
1516 },
1517 }
1518 try rhs_mat.finish(isel);
1519 try lhs_mat.finish(isel);
1520 },
1521 33...64 => |bits| {
1522 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1523 const saturated_ra = switch (int_info.signedness) {
1524 .signed => try isel.allocIntReg(),
1525 .unsigned => switch (bits) {
1526 else => unreachable,
1527 33...63 => try isel.allocIntReg(),
1528 64 => .zr,
1529 },
1530 };
1531 defer if (saturated_ra != .zr) isel.freeReg(saturated_ra);
1532 const unwrapped_lo64_ra = try isel.allocIntReg();
1533 defer isel.freeReg(unwrapped_lo64_ra);
1534 const unwrapped_hi64_ra = try isel.allocIntReg();
1535 defer isel.freeReg(unwrapped_hi64_ra);
1536 try isel.emit(switch (saturated_ra) {
1537 else => .csel(res_ra.x(), unwrapped_lo64_ra.x(), saturated_ra.x(), .eq),
1538 .zr => .csinv(res_ra.x(), unwrapped_lo64_ra.x(), saturated_ra.x(), .eq),
1539 });
1540 switch (int_info.signedness) {
1541 .signed => switch (bits) {
1542 else => unreachable,
1543 32...63 => {
1544 const wrapped_lo64_ra = try isel.allocIntReg();
1545 defer isel.freeReg(wrapped_lo64_ra);
1546 try isel.emit(.ccmp(
1547 unwrapped_lo64_ra.x(),
1548 .{ .register = wrapped_lo64_ra.x() },
1549 .{ .n = false, .z = false, .c = false, .v = false },
1550 .eq,
1551 ));
1552 try isel.emit(.subs(.xzr, unwrapped_hi64_ra.x(), .{ .shifted_register = .{
1553 .register = unwrapped_lo64_ra.x(),
1554 .shift = .{ .asr = 63 },
1555 } }));
1556 try isel.emit(.sbfm(wrapped_lo64_ra.x(), unwrapped_lo64_ra.x(), .{
1557 .N = .doubleword,
1558 .immr = 0,
1559 .imms = @intCast(bits - 1),
1560 }));
1561 },
1562 64 => try isel.emit(.subs(.xzr, unwrapped_hi64_ra.x(), .{ .shifted_register = .{
1563 .register = unwrapped_lo64_ra.x(),
1564 .shift = .{ .asr = @intCast(bits - 1) },
1565 } })),
1566 },
1567 .unsigned => switch (bits) {
1568 else => unreachable,
1569 32...63 => {
1570 const overflow_ra = try isel.allocIntReg();
1571 defer isel.freeReg(overflow_ra);
1572 try isel.emit(.subs(.xzr, overflow_ra.x(), .{ .immediate = 0 }));
1573 try isel.emit(.orr(overflow_ra.x(), unwrapped_hi64_ra.x(), .{ .shifted_register = .{
1574 .register = unwrapped_lo64_ra.x(),
1575 .shift = .{ .lsr = @intCast(bits) },
1576 } }));
1577 },
1578 64 => try isel.emit(.subs(.xzr, unwrapped_hi64_ra.x(), .{ .immediate = 0 })),
1579 },
1580 }
1581 const lhs_vi = try isel.use(bin_op.lhs);
1582 const rhs_vi = try isel.use(bin_op.rhs);
1583 const lhs_mat = try lhs_vi.matReg(isel);
1584 const rhs_mat = try rhs_vi.matReg(isel);
1585 switch (int_info.signedness) {
1586 .signed => {
1587 try isel.emit(.eor(saturated_ra.x(), saturated_ra.x(), .{ .immediate = .{
1588 .N = .doubleword,
1589 .immr = 0,
1590 .imms = @intCast(bits - 1 - 1),
1591 } }));
1592 try isel.emit(.sbfm(saturated_ra.x(), saturated_ra.x(), .{
1593 .N = .doubleword,
1594 .immr = @intCast(bits - 1),
1595 .imms = @intCast(bits - 1 + 1 - 1),
1596 }));
1597 try isel.emit(.eor(saturated_ra.x(), lhs_mat.ra.x(), .{ .register = rhs_mat.ra.x() }));
1598 try isel.emit(.madd(unwrapped_lo64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), .xzr));
1599 try isel.emit(.smulh(unwrapped_hi64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()));
1600 },
1601 .unsigned => {
1602 switch (bits) {
1603 else => unreachable,
1604 32...63 => try isel.movImmediate(saturated_ra.x(), @as(u64, std.math.maxInt(u64)) >> @intCast(64 - bits)),
1605 64 => {},
1606 }
1607 try isel.emit(.madd(unwrapped_lo64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), .xzr));
1608 try isel.emit(.umulh(unwrapped_hi64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()));
1609 },
1610 }
1611 try rhs_mat.finish(isel);
1612 try lhs_mat.finish(isel);
1613 },
1614 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
1615 }
1616 }
1617 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
1618 },
1619 .div_float, .div_float_optimized => {
1620 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
1621 defer res_vi.value.deref(isel);
1622
1623 const bin_op = air.data(air.inst_index).bin_op;
1624 const ty = isel.air.typeOf(bin_op.lhs, ip);
1625 switch (ty.floatBits(isel.target)) {
1626 else => unreachable,
1627 16, 32, 64 => |bits| {
1628 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1629 const need_fcvt = switch (bits) {
1630 else => unreachable,
1631 16 => !isel.target.cpu.has(.aarch64, .fullfp16),
1632 32, 64 => false,
1633 };
1634 if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s()));
1635 const lhs_vi = try isel.use(bin_op.lhs);
1636 const rhs_vi = try isel.use(bin_op.rhs);
1637 const lhs_mat = try lhs_vi.matReg(isel);
1638 const rhs_mat = try rhs_vi.matReg(isel);
1639 const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra;
1640 defer if (need_fcvt) isel.freeReg(lhs_ra);
1641 const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra;
1642 defer if (need_fcvt) isel.freeReg(rhs_ra);
1643 try isel.emit(bits: switch (bits) {
1644 else => unreachable,
1645 16 => if (need_fcvt)
1646 continue :bits 32
1647 else
1648 .fdiv(res_ra.h(), lhs_ra.h(), rhs_ra.h()),
1649 32 => .fdiv(res_ra.s(), lhs_ra.s(), rhs_ra.s()),
1650 64 => .fdiv(res_ra.d(), lhs_ra.d(), rhs_ra.d()),
1651 });
1652 if (need_fcvt) {
1653 try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h()));
1654 try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h()));
1655 }
1656 try rhs_mat.finish(isel);
1657 try lhs_mat.finish(isel);
1658 },
1659 80, 128 => |bits| {
1660 try call.prepareReturn(isel);
1661 switch (bits) {
1662 else => unreachable,
1663 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
1664 80 => {
1665 var res_hi16_it = res_vi.value.field(ty, 8, 8);
1666 const res_hi16_vi = try res_hi16_it.only(isel);
1667 try call.returnLiveIn(isel, res_hi16_vi.?, .r1);
1668 var res_lo64_it = res_vi.value.field(ty, 0, 8);
1669 const res_lo64_vi = try res_lo64_it.only(isel);
1670 try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
1671 },
1672 }
1673 try call.finishReturn(isel);
1674
1675 try call.prepareCallee(isel);
1676 try isel.global_relocs.append(gpa, .{
1677 .global = switch (bits) {
1678 else => unreachable,
1679 16 => "__divhf3",
1680 32 => "__divsf3",
1681 64 => "__divdf3",
1682 80 => "__divxf3",
1683 128 => "__divtf3",
1684 },
1685 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
1686 });
1687 try isel.emit(.bl(0));
1688 try call.finishCallee(isel);
1689
1690 try call.prepareParams(isel);
1691 const lhs_vi = try isel.use(bin_op.lhs);
1692 const rhs_vi = try isel.use(bin_op.rhs);
1693 switch (bits) {
1694 else => unreachable,
1695 16, 32, 64, 128 => {
1696 try call.paramLiveOut(isel, rhs_vi, .v1);
1697 try call.paramLiveOut(isel, lhs_vi, .v0);
1698 },
1699 80 => {
1700 var rhs_hi16_it = rhs_vi.field(ty, 8, 8);
1701 const rhs_hi16_vi = try rhs_hi16_it.only(isel);
1702 try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3);
1703 var rhs_lo64_it = rhs_vi.field(ty, 0, 8);
1704 const rhs_lo64_vi = try rhs_lo64_it.only(isel);
1705 try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2);
1706 var lhs_hi16_it = lhs_vi.field(ty, 8, 8);
1707 const lhs_hi16_vi = try lhs_hi16_it.only(isel);
1708 try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1);
1709 var lhs_lo64_it = lhs_vi.field(ty, 0, 8);
1710 const lhs_lo64_vi = try lhs_lo64_it.only(isel);
1711 try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0);
1712 },
1713 }
1714 try call.finishParams(isel);
1715 },
1716 }
1717 }
1718 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
1719 },
1720 .div_trunc, .div_trunc_optimized, .div_floor, .div_floor_optimized, .div_exact, .div_exact_optimized => |air_tag| {
1721 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
1722 defer res_vi.value.deref(isel);
1723
1724 const bin_op = air.data(air.inst_index).bin_op;
1725 const ty = isel.air.typeOf(bin_op.lhs, ip);
1726 if (!ty.isRuntimeFloat()) {
1727 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
1728 const int_info = ty.intInfo(zcu);
1729 switch (int_info.bits) {
1730 0 => unreachable,
1731 1...64 => |bits| {
1732 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1733 const lhs_vi = try isel.use(bin_op.lhs);
1734 const rhs_vi = try isel.use(bin_op.rhs);
1735 const lhs_mat = try lhs_vi.matReg(isel);
1736 const rhs_mat = try rhs_vi.matReg(isel);
1737 const div_ra = div_ra: switch (air_tag) {
1738 else => unreachable,
1739 .div_trunc, .div_exact => res_ra,
1740 .div_floor => switch (int_info.signedness) {
1741 .signed => {
1742 const div_ra = try isel.allocIntReg();
1743 errdefer isel.freeReg(div_ra);
1744 const rem_ra = try isel.allocIntReg();
1745 defer isel.freeReg(rem_ra);
1746 switch (bits) {
1747 else => unreachable,
1748 1...32 => {
1749 try isel.emit(.sub(res_ra.w(), div_ra.w(), .{ .register = rem_ra.w() }));
1750 try isel.emit(.csinc(rem_ra.w(), .wzr, .wzr, .ge));
1751 try isel.emit(.ccmp(
1752 rem_ra.w(),
1753 .{ .immediate = 0 },
1754 .{ .n = false, .z = false, .c = false, .v = false },
1755 .ne,
1756 ));
1757 try isel.emit(.eor(rem_ra.w(), rem_ra.w(), .{ .register = rhs_mat.ra.w() }));
1758 try isel.emit(.subs(.wzr, rem_ra.w(), .{ .immediate = 0 }));
1759 try isel.emit(.msub(rem_ra.w(), div_ra.w(), rhs_mat.ra.w(), lhs_mat.ra.w()));
1760 },
1761 33...64 => {
1762 try isel.emit(.sub(res_ra.x(), div_ra.x(), .{ .register = rem_ra.x() }));
1763 try isel.emit(.csinc(rem_ra.x(), .xzr, .xzr, .ge));
1764 try isel.emit(.ccmp(
1765 rem_ra.x(),
1766 .{ .immediate = 0 },
1767 .{ .n = false, .z = false, .c = false, .v = false },
1768 .ne,
1769 ));
1770 try isel.emit(.eor(rem_ra.x(), rem_ra.x(), .{ .register = rhs_mat.ra.x() }));
1771 try isel.emit(.subs(.xzr, rem_ra.x(), .{ .immediate = 0 }));
1772 try isel.emit(.msub(rem_ra.x(), div_ra.x(), rhs_mat.ra.x(), lhs_mat.ra.x()));
1773 },
1774 }
1775 break :div_ra div_ra;
1776 },
1777 .unsigned => res_ra,
1778 },
1779 };
1780 defer if (div_ra != res_ra) isel.freeReg(div_ra);
1781 try isel.emit(switch (bits) {
1782 else => unreachable,
1783 1...32 => switch (int_info.signedness) {
1784 .signed => .sdiv(div_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()),
1785 .unsigned => .udiv(div_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()),
1786 },
1787 33...64 => switch (int_info.signedness) {
1788 .signed => .sdiv(div_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()),
1789 .unsigned => .udiv(div_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()),
1790 },
1791 });
1792 try rhs_mat.finish(isel);
1793 try lhs_mat.finish(isel);
1794 },
1795 65...128 => {
1796 switch (air_tag) {
1797 else => unreachable,
1798 .div_trunc, .div_exact => {},
1799 .div_floor => switch (int_info.signedness) {
1800 .signed => return isel.fail("unimplemented {s}", .{@tagName(air_tag)}),
1801 .unsigned => {},
1802 },
1803 }
1804
1805 try call.prepareReturn(isel);
1806 var res_hi64_it = res_vi.value.field(ty, 8, 8);
1807 const res_hi64_vi = try res_hi64_it.only(isel);
1808 try call.returnLiveIn(isel, res_hi64_vi.?, .r1);
1809 var res_lo64_it = res_vi.value.field(ty, 0, 8);
1810 const res_lo64_vi = try res_lo64_it.only(isel);
1811 try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
1812 try call.finishReturn(isel);
1813
1814 try call.prepareCallee(isel);
1815 try isel.global_relocs.append(gpa, .{
1816 .global = switch (int_info.signedness) {
1817 .signed => "__divti3",
1818 .unsigned => "__udivti3",
1819 },
1820 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
1821 });
1822 try isel.emit(.bl(0));
1823 try call.finishCallee(isel);
1824
1825 try call.prepareParams(isel);
1826 const lhs_vi = try isel.use(bin_op.lhs);
1827 const rhs_vi = try isel.use(bin_op.rhs);
1828 var rhs_hi64_it = rhs_vi.field(ty, 8, 8);
1829 const rhs_hi64_vi = try rhs_hi64_it.only(isel);
1830 try call.paramLiveOut(isel, rhs_hi64_vi.?, .r3);
1831 var rhs_lo64_it = rhs_vi.field(ty, 0, 8);
1832 const rhs_lo64_vi = try rhs_lo64_it.only(isel);
1833 try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2);
1834 var lhs_hi64_it = lhs_vi.field(ty, 8, 8);
1835 const lhs_hi64_vi = try lhs_hi64_it.only(isel);
1836 try call.paramLiveOut(isel, lhs_hi64_vi.?, .r1);
1837 var lhs_lo64_it = lhs_vi.field(ty, 0, 8);
1838 const lhs_lo64_vi = try lhs_lo64_it.only(isel);
1839 try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0);
1840 try call.finishParams(isel);
1841 },
1842 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
1843 }
1844 } else switch (ty.floatBits(isel.target)) {
1845 else => unreachable,
1846 16, 32, 64 => |bits| {
1847 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1848 const need_fcvt = switch (bits) {
1849 else => unreachable,
1850 16 => !isel.target.cpu.has(.aarch64, .fullfp16),
1851 32, 64 => false,
1852 };
1853 if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s()));
1854 const lhs_vi = try isel.use(bin_op.lhs);
1855 const rhs_vi = try isel.use(bin_op.rhs);
1856 const lhs_mat = try lhs_vi.matReg(isel);
1857 const rhs_mat = try rhs_vi.matReg(isel);
1858 const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra;
1859 defer if (need_fcvt) isel.freeReg(lhs_ra);
1860 const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra;
1861 defer if (need_fcvt) isel.freeReg(rhs_ra);
1862 bits: switch (bits) {
1863 else => unreachable,
1864 16 => if (need_fcvt) continue :bits 32 else {
1865 switch (air_tag) {
1866 else => unreachable,
1867 .div_trunc, .div_trunc_optimized => try isel.emit(.frintz(res_ra.h(), res_ra.h())),
1868 .div_floor, .div_floor_optimized => try isel.emit(.frintm(res_ra.h(), res_ra.h())),
1869 .div_exact, .div_exact_optimized => {},
1870 }
1871 try isel.emit(.fdiv(res_ra.h(), lhs_ra.h(), rhs_ra.h()));
1872 },
1873 32 => {
1874 switch (air_tag) {
1875 else => unreachable,
1876 .div_trunc, .div_trunc_optimized => try isel.emit(.frintz(res_ra.s(), res_ra.s())),
1877 .div_floor, .div_floor_optimized => try isel.emit(.frintm(res_ra.s(), res_ra.s())),
1878 .div_exact, .div_exact_optimized => {},
1879 }
1880 try isel.emit(.fdiv(res_ra.s(), lhs_ra.s(), rhs_ra.s()));
1881 },
1882 64 => {
1883 switch (air_tag) {
1884 else => unreachable,
1885 .div_trunc, .div_trunc_optimized => try isel.emit(.frintz(res_ra.d(), res_ra.d())),
1886 .div_floor, .div_floor_optimized => try isel.emit(.frintm(res_ra.d(), res_ra.d())),
1887 .div_exact, .div_exact_optimized => {},
1888 }
1889 try isel.emit(.fdiv(res_ra.d(), lhs_ra.d(), rhs_ra.d()));
1890 },
1891 }
1892 if (need_fcvt) {
1893 try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h()));
1894 try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h()));
1895 }
1896 try rhs_mat.finish(isel);
1897 try lhs_mat.finish(isel);
1898 },
1899 80, 128 => |bits| {
1900 try call.prepareReturn(isel);
1901 switch (bits) {
1902 else => unreachable,
1903 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
1904 80 => {
1905 var res_hi16_it = res_vi.value.field(ty, 8, 8);
1906 const res_hi16_vi = try res_hi16_it.only(isel);
1907 try call.returnLiveIn(isel, res_hi16_vi.?, .r1);
1908 var res_lo64_it = res_vi.value.field(ty, 0, 8);
1909 const res_lo64_vi = try res_lo64_it.only(isel);
1910 try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
1911 },
1912 }
1913 try call.finishReturn(isel);
1914
1915 try call.prepareCallee(isel);
1916 switch (air_tag) {
1917 else => unreachable,
1918 .div_trunc, .div_trunc_optimized => {
1919 try isel.global_relocs.append(gpa, .{
1920 .global = switch (bits) {
1921 else => unreachable,
1922 16 => "__trunch",
1923 32 => "truncf",
1924 64 => "trunc",
1925 80 => "__truncx",
1926 128 => "truncq",
1927 },
1928 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
1929 });
1930 try isel.emit(.bl(0));
1931 },
1932 .div_floor, .div_floor_optimized => {
1933 try isel.global_relocs.append(gpa, .{
1934 .global = switch (bits) {
1935 else => unreachable,
1936 16 => "__floorh",
1937 32 => "floorf",
1938 64 => "floor",
1939 80 => "__floorx",
1940 128 => "floorq",
1941 },
1942 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
1943 });
1944 try isel.emit(.bl(0));
1945 },
1946 .div_exact, .div_exact_optimized => {},
1947 }
1948 try isel.global_relocs.append(gpa, .{
1949 .global = switch (bits) {
1950 else => unreachable,
1951 16 => "__divhf3",
1952 32 => "__divsf3",
1953 64 => "__divdf3",
1954 80 => "__divxf3",
1955 128 => "__divtf3",
1956 },
1957 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
1958 });
1959 try isel.emit(.bl(0));
1960 try call.finishCallee(isel);
1961
1962 try call.prepareParams(isel);
1963 const lhs_vi = try isel.use(bin_op.lhs);
1964 const rhs_vi = try isel.use(bin_op.rhs);
1965 switch (bits) {
1966 else => unreachable,
1967 16, 32, 64, 128 => {
1968 try call.paramLiveOut(isel, rhs_vi, .v1);
1969 try call.paramLiveOut(isel, lhs_vi, .v0);
1970 },
1971 80 => {
1972 var rhs_hi16_it = rhs_vi.field(ty, 8, 8);
1973 const rhs_hi16_vi = try rhs_hi16_it.only(isel);
1974 try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3);
1975 var rhs_lo64_it = rhs_vi.field(ty, 0, 8);
1976 const rhs_lo64_vi = try rhs_lo64_it.only(isel);
1977 try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2);
1978 var lhs_hi16_it = lhs_vi.field(ty, 8, 8);
1979 const lhs_hi16_vi = try lhs_hi16_it.only(isel);
1980 try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1);
1981 var lhs_lo64_it = lhs_vi.field(ty, 0, 8);
1982 const lhs_lo64_vi = try lhs_lo64_it.only(isel);
1983 try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0);
1984 },
1985 }
1986 try call.finishParams(isel);
1987 },
1988 }
1989 }
1990 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
1991 },
1992 .rem => |air_tag| {
1993 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
1994 defer res_vi.value.deref(isel);
1995
1996 const bin_op = air.data(air.inst_index).bin_op;
1997 const ty = isel.air.typeOf(bin_op.lhs, ip);
1998 if (!ty.isRuntimeFloat()) {
1999 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
2000 const int_info = ty.intInfo(zcu);
2001 if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
2002
2003 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
2004 const lhs_vi = try isel.use(bin_op.lhs);
2005 const rhs_vi = try isel.use(bin_op.rhs);
2006 const lhs_mat = try lhs_vi.matReg(isel);
2007 const rhs_mat = try rhs_vi.matReg(isel);
2008 const div_ra = try isel.allocIntReg();
2009 defer isel.freeReg(div_ra);
2010 switch (int_info.bits) {
2011 else => unreachable,
2012 1...32 => {
2013 try isel.emit(.msub(res_ra.w(), div_ra.w(), rhs_mat.ra.w(), lhs_mat.ra.w()));
2014 try isel.emit(switch (int_info.signedness) {
2015 .signed => .sdiv(div_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()),
2016 .unsigned => .udiv(div_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()),
2017 });
2018 },
2019 33...64 => {
2020 try isel.emit(.msub(res_ra.x(), div_ra.x(), rhs_mat.ra.x(), lhs_mat.ra.x()));
2021 try isel.emit(switch (int_info.signedness) {
2022 .signed => .sdiv(div_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()),
2023 .unsigned => .udiv(div_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()),
2024 });
2025 },
2026 }
2027 try rhs_mat.finish(isel);
2028 try lhs_mat.finish(isel);
2029 } else {
2030 const bits = ty.floatBits(isel.target);
2031
2032 try call.prepareReturn(isel);
2033 switch (bits) {
2034 else => unreachable,
2035 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
2036 80 => {
2037 var res_hi16_it = res_vi.value.field(ty, 8, 8);
2038 const res_hi16_vi = try res_hi16_it.only(isel);
2039 try call.returnLiveIn(isel, res_hi16_vi.?, .r1);
2040 var res_lo64_it = res_vi.value.field(ty, 0, 8);
2041 const res_lo64_vi = try res_lo64_it.only(isel);
2042 try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
2043 },
2044 }
2045 try call.finishReturn(isel);
2046
2047 try call.prepareCallee(isel);
2048 try isel.global_relocs.append(gpa, .{
2049 .global = switch (bits) {
2050 else => unreachable,
2051 16 => "__fmodh",
2052 32 => "fmodf",
2053 64 => "fmod",
2054 80 => "__fmodx",
2055 128 => "fmodq",
2056 },
2057 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
2058 });
2059 try isel.emit(.bl(0));
2060 try call.finishCallee(isel);
2061
2062 try call.prepareParams(isel);
2063 const lhs_vi = try isel.use(bin_op.lhs);
2064 const rhs_vi = try isel.use(bin_op.rhs);
2065 switch (bits) {
2066 else => unreachable,
2067 16, 32, 64, 128 => {
2068 try call.paramLiveOut(isel, rhs_vi, .v1);
2069 try call.paramLiveOut(isel, lhs_vi, .v0);
2070 },
2071 80 => {
2072 var rhs_hi16_it = rhs_vi.field(ty, 8, 8);
2073 const rhs_hi16_vi = try rhs_hi16_it.only(isel);
2074 try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3);
2075 var rhs_lo64_it = rhs_vi.field(ty, 0, 8);
2076 const rhs_lo64_vi = try rhs_lo64_it.only(isel);
2077 try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2);
2078 var lhs_hi16_it = lhs_vi.field(ty, 8, 8);
2079 const lhs_hi16_vi = try lhs_hi16_it.only(isel);
2080 try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1);
2081 var lhs_lo64_it = lhs_vi.field(ty, 0, 8);
2082 const lhs_lo64_vi = try lhs_lo64_it.only(isel);
2083 try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0);
2084 },
2085 }
2086 try call.finishParams(isel);
2087 }
2088 }
2089 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
2090 },
2091 .ptr_add, .ptr_sub => |air_tag| {
2092 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
2093 defer res_vi.value.deref(isel);
2094 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
2095
2096 const ty_pl = air.data(air.inst_index).ty_pl;
2097 const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data;
2098 const elem_size = ty_pl.ty.toType().elemType2(zcu).abiSize(zcu);
2099
2100 const base_vi = try isel.use(bin_op.lhs);
2101 var base_part_it = base_vi.field(ty_pl.ty.toType(), 0, 8);
2102 const base_part_vi = try base_part_it.only(isel);
2103 const base_part_mat = try base_part_vi.?.matReg(isel);
2104 const index_vi = try isel.use(bin_op.rhs);
2105 try isel.elemPtr(res_ra, base_part_mat.ra, switch (air_tag) {
2106 else => unreachable,
2107 .ptr_add => .add,
2108 .ptr_sub => .sub,
2109 }, elem_size, index_vi);
2110 try base_part_mat.finish(isel);
2111 }
2112 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
2113 },
2114 .max, .min => |air_tag| {
2115 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
2116 defer res_vi.value.deref(isel);
2117
2118 const bin_op = air.data(air.inst_index).bin_op;
2119 const ty = isel.air.typeOf(bin_op.lhs, ip);
2120 if (!ty.isRuntimeFloat()) {
2121 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
2122 const int_info = ty.intInfo(zcu);
2123 if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
2124
2125 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
2126 const lhs_vi = try isel.use(bin_op.lhs);
2127 const rhs_vi = try isel.use(bin_op.rhs);
2128 const lhs_mat = try lhs_vi.matReg(isel);
2129 const rhs_mat = try rhs_vi.matReg(isel);
2130 const cond: codegen.aarch64.encoding.ConditionCode = switch (air_tag) {
2131 else => unreachable,
2132 .max => switch (int_info.signedness) {
2133 .signed => .ge,
2134 .unsigned => .hs,
2135 },
2136 .min => switch (int_info.signedness) {
2137 .signed => .lt,
2138 .unsigned => .lo,
2139 },
2140 };
2141 switch (int_info.bits) {
2142 else => unreachable,
2143 1...32 => {
2144 try isel.emit(.csel(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w(), cond));
2145 try isel.emit(.subs(.wzr, lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() }));
2146 },
2147 33...64 => {
2148 try isel.emit(.csel(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), cond));
2149 try isel.emit(.subs(.xzr, lhs_mat.ra.x(), .{ .register = rhs_mat.ra.x() }));
2150 },
2151 }
2152 try rhs_mat.finish(isel);
2153 try lhs_mat.finish(isel);
2154 } else switch (ty.floatBits(isel.target)) {
2155 else => unreachable,
2156 16, 32, 64 => |bits| {
2157 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
2158 const need_fcvt = switch (bits) {
2159 else => unreachable,
2160 16 => !isel.target.cpu.has(.aarch64, .fullfp16),
2161 32, 64 => false,
2162 };
2163 if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s()));
2164 const lhs_vi = try isel.use(bin_op.lhs);
2165 const rhs_vi = try isel.use(bin_op.rhs);
2166 const lhs_mat = try lhs_vi.matReg(isel);
2167 const rhs_mat = try rhs_vi.matReg(isel);
2168 const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra;
2169 defer if (need_fcvt) isel.freeReg(lhs_ra);
2170 const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra;
2171 defer if (need_fcvt) isel.freeReg(rhs_ra);
2172 try isel.emit(bits: switch (bits) {
2173 else => unreachable,
2174 16 => if (need_fcvt) continue :bits 32 else switch (air_tag) {
2175 else => unreachable,
2176 .max => .fmaxnm(res_ra.h(), lhs_ra.h(), rhs_ra.h()),
2177 .min => .fminnm(res_ra.h(), lhs_ra.h(), rhs_ra.h()),
2178 },
2179 32 => switch (air_tag) {
2180 else => unreachable,
2181 .max => .fmaxnm(res_ra.s(), lhs_ra.s(), rhs_ra.s()),
2182 .min => .fminnm(res_ra.s(), lhs_ra.s(), rhs_ra.s()),
2183 },
2184 64 => switch (air_tag) {
2185 else => unreachable,
2186 .max => .fmaxnm(res_ra.d(), lhs_ra.d(), rhs_ra.d()),
2187 .min => .fminnm(res_ra.d(), lhs_ra.d(), rhs_ra.d()),
2188 },
2189 });
2190 if (need_fcvt) {
2191 try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h()));
2192 try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h()));
2193 }
2194 try rhs_mat.finish(isel);
2195 try lhs_mat.finish(isel);
2196 },
2197 80, 128 => |bits| {
2198 try call.prepareReturn(isel);
2199 switch (bits) {
2200 else => unreachable,
2201 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
2202 80 => {
2203 var res_hi16_it = res_vi.value.field(ty, 8, 8);
2204 const res_hi16_vi = try res_hi16_it.only(isel);
2205 try call.returnLiveIn(isel, res_hi16_vi.?, .r1);
2206 var res_lo64_it = res_vi.value.field(ty, 0, 8);
2207 const res_lo64_vi = try res_lo64_it.only(isel);
2208 try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
2209 },
2210 }
2211 try call.finishReturn(isel);
2212
2213 try call.prepareCallee(isel);
2214 try isel.global_relocs.append(gpa, .{
2215 .global = switch (air_tag) {
2216 else => unreachable,
2217 .max => switch (bits) {
2218 else => unreachable,
2219 16 => "__fmaxh",
2220 32 => "fmaxf",
2221 64 => "fmax",
2222 80 => "__fmaxx",
2223 128 => "fmaxq",
2224 },
2225 .min => switch (bits) {
2226 else => unreachable,
2227 16 => "__fminh",
2228 32 => "fminf",
2229 64 => "fmin",
2230 80 => "__fminx",
2231 128 => "fminq",
2232 },
2233 },
2234 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
2235 });
2236 try isel.emit(.bl(0));
2237 try call.finishCallee(isel);
2238
2239 try call.prepareParams(isel);
2240 const lhs_vi = try isel.use(bin_op.lhs);
2241 const rhs_vi = try isel.use(bin_op.rhs);
2242 switch (bits) {
2243 else => unreachable,
2244 16, 32, 64, 128 => {
2245 try call.paramLiveOut(isel, rhs_vi, .v1);
2246 try call.paramLiveOut(isel, lhs_vi, .v0);
2247 },
2248 80 => {
2249 var rhs_hi16_it = rhs_vi.field(ty, 8, 8);
2250 const rhs_hi16_vi = try rhs_hi16_it.only(isel);
2251 try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3);
2252 var rhs_lo64_it = rhs_vi.field(ty, 0, 8);
2253 const rhs_lo64_vi = try rhs_lo64_it.only(isel);
2254 try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2);
2255 var lhs_hi16_it = lhs_vi.field(ty, 8, 8);
2256 const lhs_hi16_vi = try lhs_hi16_it.only(isel);
2257 try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1);
2258 var lhs_lo64_it = lhs_vi.field(ty, 0, 8);
2259 const lhs_lo64_vi = try lhs_lo64_it.only(isel);
2260 try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0);
2261 },
2262 }
2263 try call.finishParams(isel);
2264 },
2265 }
2266 }
2267 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
2268 },
2269 .add_with_overflow, .sub_with_overflow => |air_tag| {
2270 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| {
2271 defer res_vi.value.deref(isel);
2272
2273 const ty_pl = air.data(air.inst_index).ty_pl;
2274 const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data;
2275 const ty = isel.air.typeOf(bin_op.lhs, ip);
2276 const lhs_vi = try isel.use(bin_op.lhs);
2277 const rhs_vi = try isel.use(bin_op.rhs);
2278 const ty_size = lhs_vi.size(isel);
2279 var overflow_it = res_vi.value.field(ty_pl.ty.toType(), ty_size, 1);
2280 const overflow_vi = try overflow_it.only(isel);
2281 var wrapped_it = res_vi.value.field(ty_pl.ty.toType(), 0, ty_size);
2282 const wrapped_vi = try wrapped_it.only(isel);
2283 try wrapped_vi.?.addOrSubtract(isel, ty, lhs_vi, switch (air_tag) {
2284 else => unreachable,
2285 .add_with_overflow => .add,
2286 .sub_with_overflow => .sub,
2287 }, rhs_vi, .{ .wrap = true, .overflow_ra = try overflow_vi.?.defReg(isel) orelse .zr });
2288 }
2289 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
2290 },
2291 .alloc, .ret_ptr => |air_tag| {
2292 if (isel.live_values.fetchRemove(air.inst_index)) |ptr_vi| unused: {
2293 defer ptr_vi.value.deref(isel);
2294 switch (air_tag) {
2295 else => unreachable,
2296 .alloc => {},
2297 .ret_ptr => if (isel.live_values.get(Block.main)) |ret_vi| switch (ret_vi.parent(isel)) {
2298 .unallocated, .stack_slot => {},
2299 .value, .constant => unreachable,
2300 .address => break :unused,
2301 },
2302 }
2303 const ptr_ra = try ptr_vi.value.defReg(isel) orelse break :unused;
2304
2305 const ty = air.data(air.inst_index).ty;
2306 const slot_size = ty.childType(zcu).abiSize(zcu);
2307 const slot_align = ty.ptrAlignment(zcu);
2308 const slot_offset = slot_align.forward(isel.stack_size);
2309 isel.stack_size = @intCast(slot_offset + slot_size);
2310 const lo12: u12 = @truncate(slot_offset >> 0);
2311 const hi12: u12 = @intCast(slot_offset >> 12);
2312 if (hi12 > 0) try isel.emit(.add(
2313 ptr_ra.x(),
2314 if (lo12 > 0) ptr_ra.x() else .sp,
2315 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
2316 ));
2317 if (lo12 > 0 or hi12 == 0) try isel.emit(.add(ptr_ra.x(), .sp, .{ .immediate = lo12 }));
2318 }
2319 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
2320 },
2321 .assembly => {
2322 const ty_pl = air.data(air.inst_index).ty_pl;
2323 const extra = isel.air.extraData(Air.Asm, ty_pl.payload);
2324 var extra_index = extra.end;
2325 const outputs: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra_index..][0..extra.data.flags.outputs_len]);
2326 extra_index += outputs.len;
2327 const inputs: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra_index..][0..extra.data.inputs_len]);
2328 extra_index += inputs.len;
2329
2330 var as: codegen.aarch64.Assemble = .{
2331 .source = undefined,
2332 .operands = .empty,
2333 };
2334 defer as.operands.deinit(gpa);
2335
2336 for (outputs) |output| {
2337 const extra_bytes = std.mem.sliceAsBytes(isel.air.extra.items[extra_index..]);
2338 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(isel.air.extra.items[extra_index..]), 0);
2339 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
2340 // This equation accounts for the fact that even if we have exactly 4 bytes
2341 // for the string, we still use the next u32 for the null terminator.
2342 extra_index += (constraint.len + name.len + (2 + 3)) / 4;
2343
2344 switch (output) {
2345 else => return isel.fail("invalid constraint: '{s}'", .{constraint}),
2346 .none => if (std.mem.startsWith(u8, constraint, "={") and std.mem.endsWith(u8, constraint, "}")) {
2347 const output_reg = Register.parse(constraint["={".len .. constraint.len - "}".len]) orelse
2348 return isel.fail("invalid constraint: '{s}'", .{constraint});
2349 const output_ra = output_reg.alias;
2350 if (isel.live_values.fetchRemove(air.inst_index)) |output_vi| {
2351 defer output_vi.value.deref(isel);
2352 try output_vi.value.defLiveIn(isel, output_reg.alias, comptime &.initFill(.free));
2353 isel.freeReg(output_ra);
2354 }
2355 if (!std.mem.eql(u8, name, "_")) {
2356 const operand_gop = try as.operands.getOrPut(gpa, name);
2357 if (operand_gop.found_existing) return isel.fail("duplicate output name: '{s}'", .{name});
2358 operand_gop.value_ptr.* = .{ .register = switch (ty_pl.ty.toType().abiSize(zcu)) {
2359 0 => unreachable,
2360 1...4 => output_ra.w(),
2361 5...8 => output_ra.x(),
2362 else => return isel.fail("too big output type: '{f}'", .{isel.fmtType(ty_pl.ty.toType())}),
2363 } };
2364 }
2365 } else if (std.mem.eql(u8, constraint, "=r")) {
2366 const output_ra = if (isel.live_values.fetchRemove(air.inst_index)) |output_vi| output_ra: {
2367 defer output_vi.value.deref(isel);
2368 break :output_ra try output_vi.value.defReg(isel) orelse try isel.allocIntReg();
2369 } else try isel.allocIntReg();
2370 if (!std.mem.eql(u8, name, "_")) {
2371 const operand_gop = try as.operands.getOrPut(gpa, name);
2372 if (operand_gop.found_existing) return isel.fail("duplicate output name: '{s}'", .{name});
2373 operand_gop.value_ptr.* = .{ .register = switch (ty_pl.ty.toType().abiSize(zcu)) {
2374 0 => unreachable,
2375 1...4 => output_ra.w(),
2376 5...8 => output_ra.x(),
2377 else => return isel.fail("too big output type: '{f}'", .{isel.fmtType(ty_pl.ty.toType())}),
2378 } };
2379 }
2380 } else return isel.fail("invalid constraint: '{s}'", .{constraint}),
2381 }
2382 }
2383
2384 const input_mats = try gpa.alloc(Value.Materialize, inputs.len);
2385 defer gpa.free(input_mats);
2386 const inputs_extra_index = extra_index;
2387 for (inputs, input_mats) |input, *input_mat| {
2388 const extra_bytes = std.mem.sliceAsBytes(isel.air.extra.items[extra_index..]);
2389 const constraint = std.mem.sliceTo(extra_bytes, 0);
2390 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
2391 // This equation accounts for the fact that even if we have exactly 4 bytes
2392 // for the string, we still use the next u32 for the null terminator.
2393 extra_index += (constraint.len + name.len + (2 + 3)) / 4;
2394
2395 if (std.mem.startsWith(u8, constraint, "{") and std.mem.endsWith(u8, constraint, "}")) {
2396 const input_reg = Register.parse(constraint["{".len .. constraint.len - "}".len]) orelse
2397 return isel.fail("invalid constraint: '{s}'", .{constraint});
2398 input_mat.* = .{ .vi = try isel.use(input), .ra = input_reg.alias };
2399 if (!std.mem.eql(u8, name, "_")) {
2400 const operand_gop = try as.operands.getOrPut(gpa, name);
2401 if (operand_gop.found_existing) return isel.fail("duplicate input name: '{s}'", .{name});
2402 const input_ty = isel.air.typeOf(input, ip);
2403 operand_gop.value_ptr.* = .{ .register = switch (input_ty.abiSize(zcu)) {
2404 0 => unreachable,
2405 1...4 => input_reg.alias.w(),
2406 5...8 => input_reg.alias.x(),
2407 else => return isel.fail("too big input type: '{f}'", .{
2408 isel.fmtType(isel.air.typeOf(input, ip)),
2409 }),
2410 } };
2411 }
2412 } else if (std.mem.eql(u8, constraint, "r")) {
2413 const input_vi = try isel.use(input);
2414 input_mat.* = try input_vi.matReg(isel);
2415 if (!std.mem.eql(u8, name, "_")) {
2416 const operand_gop = try as.operands.getOrPut(gpa, name);
2417 if (operand_gop.found_existing) return isel.fail("duplicate input name: '{s}'", .{name});
2418 operand_gop.value_ptr.* = .{ .register = switch (input_vi.size(isel)) {
2419 0 => unreachable,
2420 1...4 => input_mat.ra.w(),
2421 5...8 => input_mat.ra.x(),
2422 else => return isel.fail("too big input type: '{f}'", .{
2423 isel.fmtType(isel.air.typeOf(input, ip)),
2424 }),
2425 } };
2426 }
2427 } else if (std.mem.eql(u8, name, "_")) {
2428 input_mat.vi = try isel.use(input);
2429 } else return isel.fail("invalid constraint: '{s}'", .{constraint});
2430 }
2431
2432 const clobbers = ip.indexToKey(extra.data.clobbers).aggregate;
2433 const clobbers_ty: ZigType = .fromInterned(clobbers.ty);
2434 for (0..clobbers_ty.structFieldCount(zcu)) |field_index| {
2435 switch (switch (clobbers.storage) {
2436 .bytes => unreachable,
2437 .elems => |elems| elems[field_index],
2438 .repeated_elem => |repeated_elem| repeated_elem,
2439 }) {
2440 else => unreachable,
2441 .bool_false => continue,
2442 .bool_true => {},
2443 }
2444 const clobber_name = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?;
2445 if (std.mem.eql(u8, clobber_name, "memory")) continue;
2446 if (std.mem.eql(u8, clobber_name, "nzcv")) continue;
2447 const clobber_reg = Register.parse(clobber_name) orelse
2448 return isel.fail("unable to parse clobber: '{s}'", .{clobber_name});
2449 const live_vi = isel.live_registers.getPtr(clobber_reg.alias);
2450 switch (live_vi.*) {
2451 _ => {},
2452 .allocating => return isel.fail("clobbered twice: '{s}'", .{clobber_name}),
2453 .free => live_vi.* = .allocating,
2454 }
2455 }
2456 for (0..clobbers_ty.structFieldCount(zcu)) |field_index| {
2457 switch (switch (clobbers.storage) {
2458 .bytes => unreachable,
2459 .elems => |elems| elems[field_index],
2460 .repeated_elem => |repeated_elem| repeated_elem,
2461 }) {
2462 else => unreachable,
2463 .bool_false => continue,
2464 .bool_true => {},
2465 }
2466 const clobber_name = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?;
2467 if (std.mem.eql(u8, clobber_name, "memory")) continue;
2468 if (std.mem.eql(u8, clobber_name, "nzcv")) continue;
2469 const clobber_ra = Register.parse(clobber_name).?.alias;
2470 const live_vi = isel.live_registers.getPtr(clobber_ra);
2471 switch (live_vi.*) {
2472 _ => {
2473 if (!try isel.fill(clobber_ra))
2474 return isel.fail("unable to clobber: '{s}'", .{clobber_name});
2475 assert(live_vi.* == .free);
2476 live_vi.* = .allocating;
2477 },
2478 .allocating => {},
2479 .free => unreachable,
2480 }
2481 }
2482
2483 as.source = std.mem.sliceAsBytes(isel.air.extra.items[extra_index..])[0..extra.data.source_len :0];
2484 const asm_start = isel.instructions.items.len;
2485 while (as.nextInstruction() catch |err| switch (err) {
2486 error.InvalidSyntax => {
2487 const remaining_source = std.mem.span(as.source);
2488 return isel.fail("unable to assemble: '{s}'", .{std.mem.trim(
2489 u8,
2490 as.source[0 .. std.mem.indexOfScalar(u8, remaining_source, '\n') orelse remaining_source.len],
2491 &std.ascii.whitespace,
2492 )});
2493 },
2494 }) |instruction| try isel.emit(instruction);
2495 std.mem.reverse(codegen.aarch64.encoding.Instruction, isel.instructions.items[asm_start..]);
2496
2497 extra_index = inputs_extra_index;
2498 for (input_mats) |input_mat| {
2499 const extra_bytes = std.mem.sliceAsBytes(isel.air.extra.items[extra_index..]);
2500 const constraint = std.mem.sliceTo(extra_bytes, 0);
2501 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
2502 // This equation accounts for the fact that even if we have exactly 4 bytes
2503 // for the string, we still use the next u32 for the null terminator.
2504 extra_index += (constraint.len + name.len + (2 + 3)) / 4;
2505
2506 if (std.mem.startsWith(u8, constraint, "{") and std.mem.endsWith(u8, constraint, "}")) {
2507 try input_mat.vi.liveOut(isel, input_mat.ra);
2508 } else if (std.mem.eql(u8, constraint, "r")) {
2509 try input_mat.finish(isel);
2510 } else if (std.mem.eql(u8, name, "_")) {
2511 try input_mat.vi.mat(isel);
2512 } else unreachable;
2513 }
2514
2515 for (0..clobbers_ty.structFieldCount(zcu)) |field_index| {
2516 switch (switch (clobbers.storage) {
2517 .bytes => unreachable,
2518 .elems => |elems| elems[field_index],
2519 .repeated_elem => |repeated_elem| repeated_elem,
2520 }) {
2521 else => unreachable,
2522 .bool_false => continue,
2523 .bool_true => {},
2524 }
2525 const clobber_name = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?;
2526 if (std.mem.eql(u8, clobber_name, "memory")) continue;
2527 if (std.mem.eql(u8, clobber_name, "cc")) continue;
2528 isel.freeReg(Register.parse(clobber_name).?.alias);
2529 }
2530
2531 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
2532 },
2533 .bit_and, .bit_or, .xor, .bool_and, .bool_or => |air_tag| {
2534 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| {
2535 defer res_vi.value.deref(isel);
2536
2537 const bin_op = air.data(air.inst_index).bin_op;
2538 const ty = isel.air.typeOf(bin_op.lhs, ip);
2539 const int_info: std.builtin.Type.Int = if (ty.toIntern() == .bool_type)
2540 .{ .signedness = .unsigned, .bits = 1 }
2541 else if (ty.isAbiInt(zcu))
2542 ty.intInfo(zcu)
2543 else
2544 return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
2545 if (int_info.bits > 128) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
2546
2547 const lhs_vi = try isel.use(bin_op.lhs);
2548 const rhs_vi = try isel.use(bin_op.rhs);
2549 var offset = res_vi.value.size(isel);
2550 while (offset > 0) {
2551 const size = @min(offset, 8);
2552 offset -= size;
2553 var res_part_it = res_vi.value.field(ty, offset, size);
2554 const res_part_vi = try res_part_it.only(isel);
2555 const res_part_ra = try res_part_vi.?.defReg(isel) orelse continue;
2556 var lhs_part_it = lhs_vi.field(ty, offset, size);
2557 const lhs_part_vi = try lhs_part_it.only(isel);
2558 const lhs_part_mat = try lhs_part_vi.?.matReg(isel);
2559 var rhs_part_it = rhs_vi.field(ty, offset, size);
2560 const rhs_part_vi = try rhs_part_it.only(isel);
2561 const rhs_part_mat = try rhs_part_vi.?.matReg(isel);
2562 try isel.emit(switch (air_tag) {
2563 else => unreachable,
2564 .bit_and, .bool_and => switch (size) {
2565 else => unreachable,
2566 1, 2, 4 => .@"and"(res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }),
2567 8 => .@"and"(res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }),
2568 },
2569 .bit_or, .bool_or => switch (size) {
2570 else => unreachable,
2571 1, 2, 4 => .orr(res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }),
2572 8 => .orr(res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }),
2573 },
2574 .xor => switch (size) {
2575 else => unreachable,
2576 1, 2, 4 => .eor(res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }),
2577 8 => .eor(res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }),
2578 },
2579 });
2580 try rhs_part_mat.finish(isel);
2581 try lhs_part_mat.finish(isel);
2582 }
2583 }
2584 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
2585 },
2586 .shr, .shr_exact, .shl, .shl_exact => |air_tag| {
2587 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
2588 defer res_vi.value.deref(isel);
2589
2590 const bin_op = air.data(air.inst_index).bin_op;
2591 const ty = isel.air.typeOf(bin_op.lhs, ip);
2592 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
2593 const int_info = ty.intInfo(zcu);
2594 switch (int_info.bits) {
2595 0 => unreachable,
2596 1...64 => |bits| {
2597 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
2598 switch (air_tag) {
2599 else => unreachable,
2600 .shr, .shr_exact, .shl_exact => {},
2601 .shl => switch (bits) {
2602 else => unreachable,
2603 1...31 => try isel.emit(switch (int_info.signedness) {
2604 .signed => .sbfm(res_ra.w(), res_ra.w(), .{
2605 .N = .word,
2606 .immr = 0,
2607 .imms = @intCast(bits - 1),
2608 }),
2609 .unsigned => .ubfm(res_ra.w(), res_ra.w(), .{
2610 .N = .word,
2611 .immr = 0,
2612 .imms = @intCast(bits - 1),
2613 }),
2614 }),
2615 32 => {},
2616 33...63 => try isel.emit(switch (int_info.signedness) {
2617 .signed => .sbfm(res_ra.x(), res_ra.x(), .{
2618 .N = .doubleword,
2619 .immr = 0,
2620 .imms = @intCast(bits - 1),
2621 }),
2622 .unsigned => .ubfm(res_ra.x(), res_ra.x(), .{
2623 .N = .doubleword,
2624 .immr = 0,
2625 .imms = @intCast(bits - 1),
2626 }),
2627 }),
2628 64 => {},
2629 },
2630 }
2631
2632 const lhs_vi = try isel.use(bin_op.lhs);
2633 const rhs_vi = try isel.use(bin_op.rhs);
2634 const lhs_mat = try lhs_vi.matReg(isel);
2635 const rhs_mat = try rhs_vi.matReg(isel);
2636 try isel.emit(switch (air_tag) {
2637 else => unreachable,
2638 .shr, .shr_exact => switch (bits) {
2639 else => unreachable,
2640 1...32 => switch (int_info.signedness) {
2641 .signed => .asrv(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()),
2642 .unsigned => .lsrv(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()),
2643 },
2644 33...64 => switch (int_info.signedness) {
2645 .signed => .asrv(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()),
2646 .unsigned => .lsrv(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()),
2647 },
2648 },
2649 .shl, .shl_exact => switch (bits) {
2650 else => unreachable,
2651 1...32 => .lslv(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()),
2652 33...64 => .lslv(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()),
2653 },
2654 });
2655 try rhs_mat.finish(isel);
2656 try lhs_mat.finish(isel);
2657 },
2658 65...128 => |bits| {
2659 var res_hi64_it = res_vi.value.field(ty, 8, 8);
2660 const res_hi64_vi = try res_hi64_it.only(isel);
2661 const res_hi64_ra = try res_hi64_vi.?.defReg(isel);
2662 var res_lo64_it = res_vi.value.field(ty, 0, 8);
2663 const res_lo64_vi = try res_lo64_it.only(isel);
2664 const res_lo64_ra = try res_lo64_vi.?.defReg(isel);
2665 if (res_hi64_ra == null and res_lo64_ra == null) break :unused;
2666 if (res_hi64_ra) |res_ra| switch (air_tag) {
2667 else => unreachable,
2668 .shr, .shr_exact, .shl_exact => {},
2669 .shl => switch (bits) {
2670 else => unreachable,
2671 65...127 => try isel.emit(switch (int_info.signedness) {
2672 .signed => .sbfm(res_ra.x(), res_ra.x(), .{
2673 .N = .doubleword,
2674 .immr = 0,
2675 .imms = @intCast(bits - 64 - 1),
2676 }),
2677 .unsigned => .ubfm(res_ra.x(), res_ra.x(), .{
2678 .N = .doubleword,
2679 .immr = 0,
2680 .imms = @intCast(bits - 64 - 1),
2681 }),
2682 }),
2683 128 => {},
2684 },
2685 };
2686
2687 const lhs_vi = try isel.use(bin_op.lhs);
2688 const lhs_hi64_mat = lhs_hi64_mat: {
2689 const res_lock: RegLock = switch (air_tag) {
2690 else => unreachable,
2691 .shr, .shr_exact => switch (int_info.signedness) {
2692 .signed => if (res_lo64_ra) |res_ra| isel.lockReg(res_ra) else .empty,
2693 .unsigned => .empty,
2694 },
2695 .shl, .shl_exact => .empty,
2696 };
2697 defer res_lock.unlock(isel);
2698 var lhs_hi64_it = lhs_vi.field(ty, 8, 8);
2699 const lhs_hi64_vi = try lhs_hi64_it.only(isel);
2700 break :lhs_hi64_mat try lhs_hi64_vi.?.matReg(isel);
2701 };
2702 var lhs_lo64_it = lhs_vi.field(ty, 0, 8);
2703 const lhs_lo64_vi = try lhs_lo64_it.only(isel);
2704 const lhs_lo64_mat = try lhs_lo64_vi.?.matReg(isel);
2705 const rhs_vi = try isel.use(bin_op.rhs);
2706 const rhs_mat = try rhs_vi.matReg(isel);
2707 const lo64_ra = lo64_ra: {
2708 const res_lock: RegLock = switch (air_tag) {
2709 else => unreachable,
2710 .shr, .shr_exact => switch (int_info.signedness) {
2711 .signed => if (res_lo64_ra) |res_ra| isel.tryLockReg(res_ra) else .empty,
2712 .unsigned => .empty,
2713 },
2714 .shl, .shl_exact => if (res_hi64_ra) |res_ra| isel.tryLockReg(res_ra) else .empty,
2715 };
2716 defer res_lock.unlock(isel);
2717 break :lo64_ra try isel.allocIntReg();
2718 };
2719 defer isel.freeReg(lo64_ra);
2720 const hi64_ra = hi64_ra: {
2721 const res_lock: RegLock = switch (air_tag) {
2722 else => unreachable,
2723 .shr, .shr_exact => if (res_lo64_ra) |res_ra| isel.tryLockReg(res_ra) else .empty,
2724 .shl, .shl_exact => .empty,
2725 };
2726 defer res_lock.unlock(isel);
2727 break :hi64_ra try isel.allocIntReg();
2728 };
2729 defer isel.freeReg(hi64_ra);
2730 switch (air_tag) {
2731 else => unreachable,
2732 .shr, .shr_exact => {
2733 if (res_hi64_ra) |res_ra| switch (int_info.signedness) {
2734 .signed => {
2735 try isel.emit(.csel(res_ra.x(), hi64_ra.x(), lo64_ra.x(), .eq));
2736 try isel.emit(.sbfm(lo64_ra.x(), lhs_hi64_mat.ra.x(), .{
2737 .N = .doubleword,
2738 .immr = @intCast(bits - 64 - 1),
2739 .imms = @intCast(bits - 64 - 1),
2740 }));
2741 },
2742 .unsigned => try isel.emit(.csel(res_ra.x(), hi64_ra.x(), .xzr, .eq)),
2743 };
2744 if (res_lo64_ra) |res_ra| try isel.emit(.csel(res_ra.x(), lo64_ra.x(), hi64_ra.x(), .eq));
2745 switch (int_info.signedness) {
2746 .signed => try isel.emit(.asrv(hi64_ra.x(), lhs_hi64_mat.ra.x(), rhs_mat.ra.x())),
2747 .unsigned => try isel.emit(.lsrv(hi64_ra.x(), lhs_hi64_mat.ra.x(), rhs_mat.ra.x())),
2748 }
2749 },
2750 .shl, .shl_exact => {
2751 if (res_lo64_ra) |res_ra| try isel.emit(.csel(res_ra.x(), lo64_ra.x(), .xzr, .eq));
2752 if (res_hi64_ra) |res_ra| try isel.emit(.csel(res_ra.x(), hi64_ra.x(), lo64_ra.x(), .eq));
2753 try isel.emit(.lslv(lo64_ra.x(), lhs_lo64_mat.ra.x(), rhs_mat.ra.x()));
2754 },
2755 }
2756 try isel.emit(.ands(.wzr, rhs_mat.ra.w(), .{ .immediate = .{ .N = .word, .immr = 32 - 6, .imms = 0 } }));
2757 switch (air_tag) {
2758 else => unreachable,
2759 .shr, .shr_exact => if (res_lo64_ra) |_| {
2760 try isel.emit(.orr(
2761 lo64_ra.x(),
2762 lo64_ra.x(),
2763 .{ .shifted_register = .{ .register = hi64_ra.x(), .shift = .{ .lsl = 1 } } },
2764 ));
2765 try isel.emit(.lslv(hi64_ra.x(), lhs_hi64_mat.ra.x(), hi64_ra.x()));
2766 try isel.emit(.lsrv(lo64_ra.x(), lhs_lo64_mat.ra.x(), rhs_mat.ra.x()));
2767 try isel.emit(.orn(hi64_ra.w(), .wzr, .{ .register = rhs_mat.ra.w() }));
2768 },
2769 .shl, .shl_exact => if (res_hi64_ra) |_| {
2770 try isel.emit(.orr(
2771 hi64_ra.x(),
2772 hi64_ra.x(),
2773 .{ .shifted_register = .{ .register = lo64_ra.x(), .shift = .{ .lsr = 1 } } },
2774 ));
2775 try isel.emit(.lsrv(lo64_ra.x(), lhs_lo64_mat.ra.x(), lo64_ra.x()));
2776 try isel.emit(.lslv(hi64_ra.x(), lhs_hi64_mat.ra.x(), rhs_mat.ra.x()));
2777 try isel.emit(.orn(lo64_ra.w(), .wzr, .{ .register = rhs_mat.ra.w() }));
2778 },
2779 }
2780 try rhs_mat.finish(isel);
2781 try lhs_lo64_mat.finish(isel);
2782 try lhs_hi64_mat.finish(isel);
2783 break :unused;
2784 },
2785 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
2786 }
2787 }
2788 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
2789 },
2790 .not => |air_tag| {
2791 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| {
2792 defer res_vi.value.deref(isel);
2793
2794 const ty_op = air.data(air.inst_index).ty_op;
2795 const ty = ty_op.ty.toType();
2796 const int_info: std.builtin.Type.Int = int_info: {
2797 if (ty_op.ty == .bool_type) break :int_info .{ .signedness = .unsigned, .bits = 1 };
2798 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
2799 break :int_info ty.intInfo(zcu);
2800 };
2801 if (int_info.bits > 128) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
2802
2803 const src_vi = try isel.use(ty_op.operand);
2804 var offset = res_vi.value.size(isel);
2805 while (offset > 0) {
2806 const size = @min(offset, 8);
2807 offset -= size;
2808 var res_part_it = res_vi.value.field(ty, offset, size);
2809 const res_part_vi = try res_part_it.only(isel);
2810 const res_part_ra = try res_part_vi.?.defReg(isel) orelse continue;
2811 var src_part_it = src_vi.field(ty, offset, size);
2812 const src_part_vi = try src_part_it.only(isel);
2813 const src_part_mat = try src_part_vi.?.matReg(isel);
2814 try isel.emit(switch (int_info.signedness) {
2815 .signed => switch (size) {
2816 else => unreachable,
2817 1, 2, 4 => .orn(res_part_ra.w(), .wzr, .{ .register = src_part_mat.ra.w() }),
2818 8 => .orn(res_part_ra.x(), .xzr, .{ .register = src_part_mat.ra.x() }),
2819 },
2820 .unsigned => switch (@min(int_info.bits - 8 * offset, 64)) {
2821 else => unreachable,
2822 1...31 => |bits| .eor(res_part_ra.w(), src_part_mat.ra.w(), .{ .immediate = .{
2823 .N = .word,
2824 .immr = 0,
2825 .imms = @intCast(bits - 1),
2826 } }),
2827 32 => .orn(res_part_ra.w(), .wzr, .{ .register = src_part_mat.ra.w() }),
2828 33...63 => |bits| .eor(res_part_ra.x(), src_part_mat.ra.x(), .{ .immediate = .{
2829 .N = .doubleword,
2830 .immr = 0,
2831 .imms = @intCast(bits - 1),
2832 } }),
2833 64 => .orn(res_part_ra.x(), .xzr, .{ .register = src_part_mat.ra.x() }),
2834 },
2835 });
2836 try src_part_mat.finish(isel);
2837 }
2838 }
2839 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
2840 },
2841 .bitcast => |air_tag| {
2842 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
2843 defer dst_vi.value.deref(isel);
2844 const ty_op = air.data(air.inst_index).ty_op;
2845 const dst_ty = ty_op.ty.toType();
2846 const dst_tag = dst_ty.zigTypeTag(zcu);
2847 const src_ty = isel.air.typeOf(ty_op.operand, ip);
2848 const src_tag = src_ty.zigTypeTag(zcu);
2849 if (dst_ty.isAbiInt(zcu) and (src_tag == .bool or src_ty.isAbiInt(zcu))) {
2850 const dst_int_info = dst_ty.intInfo(zcu);
2851 const src_int_info: std.builtin.Type.Int = if (src_tag == .bool) .{ .signedness = undefined, .bits = 1 } else src_ty.intInfo(zcu);
2852 assert(dst_int_info.bits == src_int_info.bits);
2853 if (dst_tag != .@"struct" and src_tag != .@"struct" and src_tag != .bool and dst_int_info.signedness == src_int_info.signedness) {
2854 try dst_vi.value.move(isel, ty_op.operand);
2855 } else switch (dst_int_info.bits) {
2856 0 => unreachable,
2857 1...31 => |dst_bits| {
2858 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
2859 const src_vi = try isel.use(ty_op.operand);
2860 const src_mat = try src_vi.matReg(isel);
2861 try isel.emit(switch (dst_int_info.signedness) {
2862 .signed => .sbfm(dst_ra.w(), src_mat.ra.w(), .{
2863 .N = .word,
2864 .immr = 0,
2865 .imms = @intCast(dst_bits - 1),
2866 }),
2867 .unsigned => .ubfm(dst_ra.w(), src_mat.ra.w(), .{
2868 .N = .word,
2869 .immr = 0,
2870 .imms = @intCast(dst_bits - 1),
2871 }),
2872 });
2873 try src_mat.finish(isel);
2874 },
2875 32 => try dst_vi.value.move(isel, ty_op.operand),
2876 33...63 => |dst_bits| {
2877 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
2878 const src_vi = try isel.use(ty_op.operand);
2879 const src_mat = try src_vi.matReg(isel);
2880 try isel.emit(switch (dst_int_info.signedness) {
2881 .signed => .sbfm(dst_ra.x(), src_mat.ra.x(), .{
2882 .N = .doubleword,
2883 .immr = 0,
2884 .imms = @intCast(dst_bits - 1),
2885 }),
2886 .unsigned => .ubfm(dst_ra.x(), src_mat.ra.x(), .{
2887 .N = .doubleword,
2888 .immr = 0,
2889 .imms = @intCast(dst_bits - 1),
2890 }),
2891 });
2892 try src_mat.finish(isel);
2893 },
2894 64 => try dst_vi.value.move(isel, ty_op.operand),
2895 65...127 => |dst_bits| {
2896 const src_vi = try isel.use(ty_op.operand);
2897 var dst_hi64_it = dst_vi.value.field(dst_ty, 8, 8);
2898 const dst_hi64_vi = try dst_hi64_it.only(isel);
2899 if (try dst_hi64_vi.?.defReg(isel)) |dst_hi64_ra| {
2900 var src_hi64_it = src_vi.field(src_ty, 8, 8);
2901 const src_hi64_vi = try src_hi64_it.only(isel);
2902 const src_hi64_mat = try src_hi64_vi.?.matReg(isel);
2903 try isel.emit(switch (dst_int_info.signedness) {
2904 .signed => .sbfm(dst_hi64_ra.x(), src_hi64_mat.ra.x(), .{
2905 .N = .doubleword,
2906 .immr = 0,
2907 .imms = @intCast(dst_bits - 64 - 1),
2908 }),
2909 .unsigned => .ubfm(dst_hi64_ra.x(), src_hi64_mat.ra.x(), .{
2910 .N = .doubleword,
2911 .immr = 0,
2912 .imms = @intCast(dst_bits - 64 - 1),
2913 }),
2914 });
2915 try src_hi64_mat.finish(isel);
2916 }
2917 var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8);
2918 const dst_lo64_vi = try dst_lo64_it.only(isel);
2919 if (try dst_lo64_vi.?.defReg(isel)) |dst_lo64_ra| {
2920 var src_lo64_it = src_vi.field(src_ty, 0, 8);
2921 const src_lo64_vi = try src_lo64_it.only(isel);
2922 try src_lo64_vi.?.liveOut(isel, dst_lo64_ra);
2923 }
2924 },
2925 128 => try dst_vi.value.move(isel, ty_op.operand),
2926 else => return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }),
2927 }
2928 } else if ((dst_ty.isPtrAtRuntime(zcu) or dst_ty.isAbiInt(zcu)) and (src_ty.isPtrAtRuntime(zcu) or src_ty.isAbiInt(zcu))) {
2929 try dst_vi.value.move(isel, ty_op.operand);
2930 } else if (dst_ty.isSliceAtRuntime(zcu) and src_ty.isSliceAtRuntime(zcu)) {
2931 try dst_vi.value.move(isel, ty_op.operand);
2932 } else if (dst_tag == .error_union and src_tag == .error_union) {
2933 assert(dst_ty.errorUnionSet(zcu).hasRuntimeBitsIgnoreComptime(zcu) ==
2934 src_ty.errorUnionSet(zcu).hasRuntimeBitsIgnoreComptime(zcu));
2935 if (dst_ty.errorUnionPayload(zcu).toIntern() == src_ty.errorUnionPayload(zcu).toIntern()) {
2936 try dst_vi.value.move(isel, ty_op.operand);
2937 } else return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });
2938 } else if (dst_tag == .float and src_tag == .float) {
2939 assert(dst_ty.floatBits(isel.target) == src_ty.floatBits(isel.target));
2940 try dst_vi.value.move(isel, ty_op.operand);
2941 } else if (dst_ty.isAbiInt(zcu) and src_tag == .float) {
2942 const dst_int_info = dst_ty.intInfo(zcu);
2943 assert(dst_int_info.bits == src_ty.floatBits(isel.target));
2944 switch (dst_int_info.bits) {
2945 else => unreachable,
2946 16 => {
2947 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
2948 const src_vi = try isel.use(ty_op.operand);
2949 const src_mat = try src_vi.matReg(isel);
2950 switch (dst_int_info.signedness) {
2951 .signed => try isel.emit(.smov(dst_ra.w(), src_mat.ra.@"h[]"(0))),
2952 .unsigned => try isel.emit(if (isel.target.cpu.has(.aarch64, .fullfp16))
2953 .fmov(dst_ra.w(), .{ .register = src_mat.ra.h() })
2954 else
2955 .umov(dst_ra.w(), src_mat.ra.@"h[]"(0))),
2956 }
2957 try src_mat.finish(isel);
2958 },
2959 32 => {
2960 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
2961 const src_vi = try isel.use(ty_op.operand);
2962 const src_mat = try src_vi.matReg(isel);
2963 try isel.emit(.fmov(dst_ra.w(), .{ .register = src_mat.ra.s() }));
2964 try src_mat.finish(isel);
2965 },
2966 64 => {
2967 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
2968 const src_vi = try isel.use(ty_op.operand);
2969 const src_mat = try src_vi.matReg(isel);
2970 try isel.emit(.fmov(dst_ra.x(), .{ .register = src_mat.ra.d() }));
2971 try src_mat.finish(isel);
2972 },
2973 80 => switch (dst_int_info.signedness) {
2974 .signed => {
2975 const src_vi = try isel.use(ty_op.operand);
2976 var dst_hi16_it = dst_vi.value.field(dst_ty, 8, 8);
2977 const dst_hi16_vi = try dst_hi16_it.only(isel);
2978 if (try dst_hi16_vi.?.defReg(isel)) |dst_hi16_ra| {
2979 var src_hi16_it = src_vi.field(src_ty, 8, 8);
2980 const src_hi16_vi = try src_hi16_it.only(isel);
2981 const src_hi16_mat = try src_hi16_vi.?.matReg(isel);
2982 try isel.emit(.sbfm(dst_hi16_ra.x(), src_hi16_mat.ra.x(), .{
2983 .N = .doubleword,
2984 .immr = 0,
2985 .imms = 16 - 1,
2986 }));
2987 try src_hi16_mat.finish(isel);
2988 }
2989 var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8);
2990 const dst_lo64_vi = try dst_lo64_it.only(isel);
2991 if (try dst_lo64_vi.?.defReg(isel)) |dst_lo64_ra| {
2992 var src_lo64_it = src_vi.field(src_ty, 0, 8);
2993 const src_lo64_vi = try src_lo64_it.only(isel);
2994 try src_lo64_vi.?.liveOut(isel, dst_lo64_ra);
2995 }
2996 },
2997 else => try dst_vi.value.move(isel, ty_op.operand),
2998 },
2999 128 => {
3000 const src_vi = try isel.use(ty_op.operand);
3001 const src_mat = try src_vi.matReg(isel);
3002 var dst_hi64_it = dst_vi.value.field(dst_ty, 8, 8);
3003 const dst_hi64_vi = try dst_hi64_it.only(isel);
3004 if (try dst_hi64_vi.?.defReg(isel)) |dst_hi64_ra| try isel.emit(.fmov(dst_hi64_ra.x(), .{ .register = src_mat.ra.@"d[]"(1) }));
3005 var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8);
3006 const dst_lo64_vi = try dst_lo64_it.only(isel);
3007 if (try dst_lo64_vi.?.defReg(isel)) |dst_lo64_ra| try isel.emit(.fmov(dst_lo64_ra.x(), .{ .register = src_mat.ra.d() }));
3008 try src_mat.finish(isel);
3009 },
3010 }
3011 } else if (dst_tag == .float and src_ty.isAbiInt(zcu)) {
3012 const src_int_info = src_ty.intInfo(zcu);
3013 assert(dst_ty.floatBits(isel.target) == src_int_info.bits);
3014 switch (src_int_info.bits) {
3015 else => unreachable,
3016 16 => {
3017 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
3018 const src_vi = try isel.use(ty_op.operand);
3019 const src_mat = try src_vi.matReg(isel);
3020 try isel.emit(.fmov(
3021 if (isel.target.cpu.has(.aarch64, .fullfp16)) dst_ra.h() else dst_ra.s(),
3022 .{ .register = src_mat.ra.w() },
3023 ));
3024 try src_mat.finish(isel);
3025 },
3026 32 => {
3027 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
3028 const src_vi = try isel.use(ty_op.operand);
3029 const src_mat = try src_vi.matReg(isel);
3030 try isel.emit(.fmov(dst_ra.s(), .{ .register = src_mat.ra.w() }));
3031 try src_mat.finish(isel);
3032 },
3033 64 => {
3034 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
3035 const src_vi = try isel.use(ty_op.operand);
3036 const src_mat = try src_vi.matReg(isel);
3037 try isel.emit(.fmov(dst_ra.d(), .{ .register = src_mat.ra.x() }));
3038 try src_mat.finish(isel);
3039 },
3040 80 => switch (src_int_info.signedness) {
3041 .signed => {
3042 const src_vi = try isel.use(ty_op.operand);
3043 var dst_hi16_it = dst_vi.value.field(dst_ty, 8, 8);
3044 const dst_hi16_vi = try dst_hi16_it.only(isel);
3045 if (try dst_hi16_vi.?.defReg(isel)) |dst_hi16_ra| {
3046 var src_hi16_it = src_vi.field(src_ty, 8, 8);
3047 const src_hi16_vi = try src_hi16_it.only(isel);
3048 const src_hi16_mat = try src_hi16_vi.?.matReg(isel);
3049 try isel.emit(.ubfm(dst_hi16_ra.x(), src_hi16_mat.ra.x(), .{
3050 .N = .doubleword,
3051 .immr = 0,
3052 .imms = 16 - 1,
3053 }));
3054 try src_hi16_mat.finish(isel);
3055 }
3056 var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8);
3057 const dst_lo64_vi = try dst_lo64_it.only(isel);
3058 if (try dst_lo64_vi.?.defReg(isel)) |dst_lo64_ra| {
3059 var src_lo64_it = src_vi.field(src_ty, 0, 8);
3060 const src_lo64_vi = try src_lo64_it.only(isel);
3061 try src_lo64_vi.?.liveOut(isel, dst_lo64_ra);
3062 }
3063 },
3064 else => try dst_vi.value.move(isel, ty_op.operand),
3065 },
3066 128 => {
3067 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
3068 const src_vi = try isel.use(ty_op.operand);
3069 var src_hi64_it = src_vi.field(src_ty, 8, 8);
3070 const src_hi64_vi = try src_hi64_it.only(isel);
3071 const src_hi64_mat = try src_hi64_vi.?.matReg(isel);
3072 try isel.emit(.fmov(dst_ra.@"d[]"(1), .{ .register = src_hi64_mat.ra.x() }));
3073 try src_hi64_mat.finish(isel);
3074 var src_lo64_it = src_vi.field(src_ty, 0, 8);
3075 const src_lo64_vi = try src_lo64_it.only(isel);
3076 const src_lo64_mat = try src_lo64_vi.?.matReg(isel);
3077 try isel.emit(.fmov(dst_ra.d(), .{ .register = src_lo64_mat.ra.x() }));
3078 try src_lo64_mat.finish(isel);
3079 },
3080 }
3081 } else if (dst_ty.isAbiInt(zcu) and src_tag == .array and src_ty.childType(zcu).isAbiInt(zcu)) {
3082 const dst_int_info = dst_ty.intInfo(zcu);
3083 const src_child_int_info = src_ty.childType(zcu).intInfo(zcu);
3084 const src_len = src_ty.arrayLenIncludingSentinel(zcu);
3085 assert(dst_int_info.bits == src_child_int_info.bits * src_len);
3086 const src_child_size = src_ty.childType(zcu).abiSize(zcu);
3087 if (8 * src_child_size == src_child_int_info.bits) {
3088 try dst_vi.value.defAddr(isel, dst_ty, dst_int_info, comptime &.initFill(.free)) orelse break :unused;
3089
3090 try call.prepareReturn(isel);
3091 try call.finishReturn(isel);
3092
3093 try call.prepareCallee(isel);
3094 try isel.global_relocs.append(gpa, .{
3095 .global = "memcpy",
3096 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
3097 });
3098 try isel.emit(.bl(0));
3099 try call.finishCallee(isel);
3100
3101 try call.prepareParams(isel);
3102 const src_vi = try isel.use(ty_op.operand);
3103 try isel.movImmediate(.x2, src_child_size * src_len);
3104 try call.paramAddress(isel, src_vi, .r1);
3105 try call.paramAddress(isel, dst_vi.value, .r0);
3106 try call.finishParams(isel);
3107 } else return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });
3108 } else if (dst_tag == .array and dst_ty.childType(zcu).isAbiInt(zcu) and src_ty.isAbiInt(zcu)) {
3109 const dst_child_int_info = dst_ty.childType(zcu).intInfo(zcu);
3110 const src_int_info = src_ty.intInfo(zcu);
3111 const dst_len = dst_ty.arrayLenIncludingSentinel(zcu);
3112 assert(dst_child_int_info.bits * dst_len == src_int_info.bits);
3113 const dst_child_size = dst_ty.childType(zcu).abiSize(zcu);
3114 if (8 * dst_child_size == dst_child_int_info.bits) {
3115 try dst_vi.value.defAddr(isel, dst_ty, null, comptime &.initFill(.free)) orelse break :unused;
3116
3117 try call.prepareReturn(isel);
3118 try call.finishReturn(isel);
3119
3120 try call.prepareCallee(isel);
3121 try isel.global_relocs.append(gpa, .{
3122 .global = "memcpy",
3123 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
3124 });
3125 try isel.emit(.bl(0));
3126 try call.finishCallee(isel);
3127
3128 try call.prepareParams(isel);
3129 const src_vi = try isel.use(ty_op.operand);
3130 try isel.movImmediate(.x2, dst_child_size * dst_len);
3131 try call.paramAddress(isel, src_vi, .r1);
3132 try call.paramAddress(isel, dst_vi.value, .r0);
3133 try call.finishParams(isel);
3134 } else return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });
3135 } else return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });
3136 }
3137 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3138 },
3139 .block => {
3140 const ty_pl = air.data(air.inst_index).ty_pl;
3141 const extra = isel.air.extraData(Air.Block, ty_pl.payload);
3142
3143 if (ty_pl.ty != .noreturn_type) {
3144 isel.blocks.putAssumeCapacityNoClobber(air.inst_index, .{
3145 .live_registers = isel.live_registers,
3146 .target_label = @intCast(isel.instructions.items.len),
3147 });
3148 }
3149 try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));
3150 if (ty_pl.ty != .noreturn_type) {
3151 const block_entry = isel.blocks.pop().?;
3152 assert(block_entry.key == air.inst_index);
3153 if (isel.live_values.fetchRemove(air.inst_index)) |result_vi| result_vi.value.deref(isel);
3154 }
3155 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3156 },
3157 .loop => {
3158 const ty_pl = air.data(air.inst_index).ty_pl;
3159 const extra = isel.air.extraData(Air.Block, ty_pl.payload);
3160 const loops = isel.loops.values();
3161 const loop_index = isel.loops.getIndex(air.inst_index).?;
3162 const loop = &loops[loop_index];
3163
3164 tracking_log.debug("{f}", .{
3165 isel.fmtDom(air.inst_index, loop.dom, @intCast(isel.blocks.count())),
3166 });
3167 tracking_log.debug("{f}", .{isel.fmtLoopLive(air.inst_index)});
3168 assert(loop.depth == isel.blocks.count());
3169
3170 if (false) {
3171 // loops are dumb...
3172 for (isel.loop_live.list.items[loop.live..loops[loop_index + 1].live]) |live_inst| {
3173 const live_vi = try isel.use(live_inst.toRef());
3174 try live_vi.mat(isel);
3175 }
3176
3177 // IT'S DOM TIME!!!
3178 for (isel.blocks.values(), 0..) |*block, dom_index| {
3179 if (@as(u1, @truncate(isel.dom.items[
3180 loop.dom + dom_index / @bitSizeOf(DomInt)
3181 ] >> @truncate(dom_index))) == 0) continue;
3182 var live_reg_it = block.live_registers.iterator();
3183 while (live_reg_it.next()) |live_reg_entry| switch (live_reg_entry.value.*) {
3184 _ => |live_vi| try live_vi.mat(isel),
3185 .allocating => unreachable,
3186 .free => {},
3187 };
3188 }
3189 }
3190
3191 loop.live_registers = isel.live_registers;
3192 loop.repeat_list = Loop.empty_list;
3193 try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));
3194 try isel.merge(&loop.live_registers, .{ .fill_extra = true });
3195
3196 var repeat_label = loop.repeat_list;
3197 assert(repeat_label != Loop.empty_list);
3198 while (repeat_label != Loop.empty_list) {
3199 const instruction = &isel.instructions.items[repeat_label];
3200 const next_repeat_label = instruction.*;
3201 instruction.* = .b(-@as(i28, @intCast((isel.instructions.items.len - 1 - repeat_label) << 2)));
3202 repeat_label = @bitCast(next_repeat_label);
3203 }
3204
3205 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3206 },
3207 .repeat => {
3208 const repeat = air.data(air.inst_index).repeat;
3209 try isel.loops.getPtr(repeat.loop_inst).?.branch(isel);
3210 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3211 },
3212 .br => {
3213 const br = air.data(air.inst_index).br;
3214 const block = isel.blocks.getPtr(br.block_inst).?;
3215 try block.branch(isel);
3216 if (isel.live_values.get(br.block_inst)) |dst_vi| try dst_vi.move(isel, br.operand);
3217 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3218 },
3219 .trap => {
3220 try isel.emit(.brk(0x1));
3221 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3222 },
3223 .breakpoint => {
3224 try isel.emit(.brk(0xf000));
3225 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3226 },
3227 .call => {
3228 const pl_op = air.data(air.inst_index).pl_op;
3229 const extra = isel.air.extraData(Air.Call, pl_op.payload);
3230 const args: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0..extra.data.args_len]);
3231
3232 try call.prepareReturn(isel);
3233 const maybe_def_ret_vi = isel.live_values.fetchRemove(air.inst_index);
3234 var maybe_ret_addr_vi: ?Value.Index = null;
3235 if (maybe_def_ret_vi) |def_ret_vi| {
3236 defer def_ret_vi.value.deref(isel);
3237
3238 var ret_it: CallAbiIterator = .init;
3239 const ret_vi = try ret_it.ret(isel, isel.air.typeOfIndex(air.inst_index, ip));
3240 defer ret_vi.?.deref(isel);
3241 switch (ret_vi.?.parent(isel)) {
3242 .unallocated, .stack_slot => if (ret_vi.?.hint(isel)) |ret_ra| {
3243 try call.returnLiveIn(isel, def_ret_vi.value, ret_ra);
3244 } else {
3245 var def_ret_part_it = def_ret_vi.value.parts(isel);
3246 var ret_part_it = ret_vi.?.parts(isel);
3247 while (def_ret_part_it.next()) |ret_part_vi| {
3248 try call.returnLiveIn(isel, ret_part_vi, ret_part_it.next().?.hint(isel).?);
3249 }
3250 },
3251 .value, .constant => unreachable,
3252 .address => |address_vi| {
3253 maybe_ret_addr_vi = address_vi;
3254 _ = try def_ret_vi.value.defAddr(
3255 isel,
3256 isel.air.typeOfIndex(air.inst_index, ip),
3257 null,
3258 &call.caller_saved_regs,
3259 );
3260 },
3261 }
3262 }
3263 try call.finishReturn(isel);
3264
3265 try call.prepareCallee(isel);
3266 if (pl_op.operand.toInterned()) |ct_callee| {
3267 try isel.nav_relocs.append(gpa, switch (ip.indexToKey(ct_callee)) {
3268 else => unreachable,
3269 inline .@"extern", .func => |func| .{
3270 .nav = func.owner_nav,
3271 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
3272 },
3273 .ptr => |ptr| .{
3274 .nav = ptr.base_addr.nav,
3275 .reloc = .{
3276 .label = @intCast(isel.instructions.items.len),
3277 .addend = ptr.byte_offset,
3278 },
3279 },
3280 });
3281 try isel.emit(.bl(0));
3282 } else {
3283 const callee_vi = try isel.use(pl_op.operand);
3284 const callee_mat = try callee_vi.matReg(isel);
3285 try isel.emit(.blr(callee_mat.ra.x()));
3286 try callee_mat.finish(isel);
3287 }
3288 try call.finishCallee(isel);
3289
3290 try call.prepareParams(isel);
3291 if (maybe_ret_addr_vi) |ret_addr_vi| try call.paramAddress(
3292 isel,
3293 maybe_def_ret_vi.?.value,
3294 ret_addr_vi.hint(isel).?,
3295 );
3296 var param_it: CallAbiIterator = .init;
3297 for (args) |arg| {
3298 const param_vi = try param_it.param(isel, isel.air.typeOf(arg, ip)) orelse continue;
3299 defer param_vi.deref(isel);
3300 const arg_vi = try isel.use(arg);
3301 const passed_vi = switch (param_vi.parent(isel)) {
3302 .unallocated, .stack_slot => param_vi,
3303 .value, .constant => unreachable,
3304 .address => |address_vi| {
3305 try call.paramAddress(isel, arg_vi, address_vi.hint(isel).?);
3306 continue;
3307 },
3308 };
3309 if (passed_vi.hint(isel)) |param_ra| {
3310 try call.paramLiveOut(isel, arg_vi, param_ra);
3311 } else {
3312 var param_part_it = passed_vi.parts(isel);
3313 var arg_part_it = arg_vi.parts(isel);
3314 if (arg_part_it.only()) |_| {
3315 try isel.values.ensureUnusedCapacity(isel.pt.zcu.gpa, param_part_it.remaining);
3316 arg_vi.setParts(isel, param_part_it.remaining);
3317 while (param_part_it.next()) |param_part_vi| _ = arg_vi.addPart(
3318 isel,
3319 param_part_vi.get(isel).offset_from_parent,
3320 param_part_vi.size(isel),
3321 );
3322 param_part_it = passed_vi.parts(isel);
3323 arg_part_it = arg_vi.parts(isel);
3324 }
3325 while (param_part_it.next()) |param_part_vi| {
3326 const arg_part_vi = arg_part_it.next().?;
3327 assert(arg_part_vi.get(isel).offset_from_parent ==
3328 param_part_vi.get(isel).offset_from_parent);
3329 assert(arg_part_vi.size(isel) == param_part_vi.size(isel));
3330 try call.paramLiveOut(isel, arg_part_vi, param_part_vi.hint(isel).?);
3331 }
3332 }
3333 }
3334 try call.finishParams(isel);
3335
3336 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3337 },
3338 .clz => |air_tag| {
3339 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
3340 defer res_vi.value.deref(isel);
3341
3342 const ty_op = air.data(air.inst_index).ty_op;
3343 const ty = isel.air.typeOf(ty_op.operand, ip);
3344 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
3345 const int_info = ty.intInfo(zcu);
3346 switch (int_info.bits) {
3347 0 => unreachable,
3348 1...64 => {
3349 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3350 const src_vi = try isel.use(ty_op.operand);
3351 const src_mat = try src_vi.matReg(isel);
3352 try isel.clzLimb(res_ra, int_info, src_mat.ra);
3353 try src_mat.finish(isel);
3354 },
3355 65...128 => |bits| {
3356 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3357 const src_vi = try isel.use(ty_op.operand);
3358 var src_hi64_it = src_vi.field(ty, 8, 8);
3359 const src_hi64_vi = try src_hi64_it.only(isel);
3360 const src_hi64_mat = try src_hi64_vi.?.matReg(isel);
3361 var src_lo64_it = src_vi.field(ty, 0, 8);
3362 const src_lo64_vi = try src_lo64_it.only(isel);
3363 const src_lo64_mat = try src_lo64_vi.?.matReg(isel);
3364 const lo64_ra = try isel.allocIntReg();
3365 defer isel.freeReg(lo64_ra);
3366 const hi64_ra = try isel.allocIntReg();
3367 defer isel.freeReg(hi64_ra);
3368 try isel.emit(.csel(res_ra.w(), lo64_ra.w(), hi64_ra.w(), .eq));
3369 try isel.emit(.add(lo64_ra.w(), lo64_ra.w(), .{ .immediate = @intCast(bits - 64) }));
3370 try isel.emit(.subs(.xzr, src_hi64_mat.ra.x(), .{ .immediate = 0 }));
3371 try isel.clzLimb(hi64_ra, .{ .signedness = int_info.signedness, .bits = bits - 64 }, src_hi64_mat.ra);
3372 try isel.clzLimb(lo64_ra, .{ .signedness = .unsigned, .bits = 64 }, src_lo64_mat.ra);
3373 try src_hi64_mat.finish(isel);
3374 try src_lo64_mat.finish(isel);
3375 },
3376 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
3377 }
3378 }
3379 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3380 },
3381 .ctz => |air_tag| {
3382 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
3383 defer res_vi.value.deref(isel);
3384
3385 const ty_op = air.data(air.inst_index).ty_op;
3386 const ty = isel.air.typeOf(ty_op.operand, ip);
3387 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
3388 const int_info = ty.intInfo(zcu);
3389 switch (int_info.bits) {
3390 0 => unreachable,
3391 1...64 => {
3392 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3393 const src_vi = try isel.use(ty_op.operand);
3394 const src_mat = try src_vi.matReg(isel);
3395 try isel.ctzLimb(res_ra, int_info, src_mat.ra);
3396 try src_mat.finish(isel);
3397 },
3398 65...128 => |bits| {
3399 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3400 const src_vi = try isel.use(ty_op.operand);
3401 var src_hi64_it = src_vi.field(ty, 8, 8);
3402 const src_hi64_vi = try src_hi64_it.only(isel);
3403 const src_hi64_mat = try src_hi64_vi.?.matReg(isel);
3404 var src_lo64_it = src_vi.field(ty, 0, 8);
3405 const src_lo64_vi = try src_lo64_it.only(isel);
3406 const src_lo64_mat = try src_lo64_vi.?.matReg(isel);
3407 const lo64_ra = try isel.allocIntReg();
3408 defer isel.freeReg(lo64_ra);
3409 const hi64_ra = try isel.allocIntReg();
3410 defer isel.freeReg(hi64_ra);
3411 try isel.emit(.csel(res_ra.w(), lo64_ra.w(), hi64_ra.w(), .ne));
3412 try isel.emit(.add(hi64_ra.w(), hi64_ra.w(), .{ .immediate = 64 }));
3413 try isel.emit(.subs(.xzr, src_lo64_mat.ra.x(), .{ .immediate = 0 }));
3414 try isel.ctzLimb(hi64_ra, .{ .signedness = .unsigned, .bits = 64 }, src_hi64_mat.ra);
3415 try isel.ctzLimb(lo64_ra, .{ .signedness = int_info.signedness, .bits = bits - 64 }, src_lo64_mat.ra);
3416 try src_hi64_mat.finish(isel);
3417 try src_lo64_mat.finish(isel);
3418 },
3419 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
3420 }
3421 }
3422 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3423 },
3424 .popcount => |air_tag| {
3425 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
3426 defer res_vi.value.deref(isel);
3427
3428 const ty_op = air.data(air.inst_index).ty_op;
3429 const ty = isel.air.typeOf(ty_op.operand, ip);
3430 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
3431 const int_info = ty.intInfo(zcu);
3432 if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
3433
3434 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3435 const src_vi = try isel.use(ty_op.operand);
3436 const src_mat = try src_vi.matReg(isel);
3437 const vec_ra = try isel.allocVecReg();
3438 defer isel.freeReg(vec_ra);
3439 try isel.emit(.umov(res_ra.w(), vec_ra.@"b[]"(0)));
3440 switch (int_info.bits) {
3441 else => unreachable,
3442 1...8 => {},
3443 9...16 => try isel.emit(.addp(vec_ra.@"8b"(), vec_ra.@"8b"(), .{ .vector = vec_ra.@"8b"() })),
3444 17...64 => try isel.emit(.addv(vec_ra.b(), vec_ra.@"8b"())),
3445 }
3446 try isel.emit(.cnt(vec_ra.@"8b"(), vec_ra.@"8b"()));
3447 switch (int_info.bits) {
3448 else => unreachable,
3449 1...31 => |bits| switch (int_info.signedness) {
3450 .signed => {
3451 try isel.emit(.fmov(vec_ra.s(), .{ .register = res_ra.w() }));
3452 try isel.emit(.ubfm(res_ra.w(), src_mat.ra.w(), .{
3453 .N = .word,
3454 .immr = 0,
3455 .imms = @intCast(bits - 1),
3456 }));
3457 },
3458 .unsigned => try isel.emit(.fmov(vec_ra.s(), .{ .register = src_mat.ra.w() })),
3459 },
3460 32 => try isel.emit(.fmov(vec_ra.s(), .{ .register = src_mat.ra.w() })),
3461 33...63 => |bits| switch (int_info.signedness) {
3462 .signed => {
3463 try isel.emit(.fmov(vec_ra.d(), .{ .register = res_ra.x() }));
3464 try isel.emit(.ubfm(res_ra.x(), src_mat.ra.x(), .{
3465 .N = .doubleword,
3466 .immr = 0,
3467 .imms = @intCast(bits - 1),
3468 }));
3469 },
3470 .unsigned => try isel.emit(.fmov(vec_ra.d(), .{ .register = src_mat.ra.x() })),
3471 },
3472 64 => try isel.emit(.fmov(vec_ra.d(), .{ .register = src_mat.ra.x() })),
3473 }
3474 try src_mat.finish(isel);
3475 }
3476 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3477 },
3478 .byte_swap => |air_tag| {
3479 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
3480 defer res_vi.value.deref(isel);
3481
3482 const ty_op = air.data(air.inst_index).ty_op;
3483 const ty = ty_op.ty.toType();
3484 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
3485 const int_info = ty.intInfo(zcu);
3486 if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
3487
3488 if (int_info.bits == 8) break :unused try res_vi.value.move(isel, ty_op.operand);
3489 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3490 const src_vi = try isel.use(ty_op.operand);
3491 const src_mat = try src_vi.matReg(isel);
3492 switch (int_info.bits) {
3493 else => unreachable,
3494 16 => switch (int_info.signedness) {
3495 .signed => {
3496 try isel.emit(.sbfm(res_ra.w(), res_ra.w(), .{
3497 .N = .word,
3498 .immr = 32 - 16,
3499 .imms = 32 - 1,
3500 }));
3501 try isel.emit(.rev(res_ra.w(), src_mat.ra.w()));
3502 },
3503 .unsigned => try isel.emit(.rev16(res_ra.w(), src_mat.ra.w())),
3504 },
3505 24 => {
3506 switch (int_info.signedness) {
3507 .signed => try isel.emit(.sbfm(res_ra.w(), res_ra.w(), .{
3508 .N = .word,
3509 .immr = 32 - 24,
3510 .imms = 32 - 1,
3511 })),
3512 .unsigned => try isel.emit(.ubfm(res_ra.w(), res_ra.w(), .{
3513 .N = .word,
3514 .immr = 32 - 24,
3515 .imms = 32 - 1,
3516 })),
3517 }
3518 try isel.emit(.rev(res_ra.w(), src_mat.ra.w()));
3519 },
3520 32 => try isel.emit(.rev(res_ra.w(), src_mat.ra.w())),
3521 40, 48, 56 => |bits| {
3522 switch (int_info.signedness) {
3523 .signed => try isel.emit(.sbfm(res_ra.x(), res_ra.x(), .{
3524 .N = .doubleword,
3525 .immr = @intCast(64 - bits),
3526 .imms = 64 - 1,
3527 })),
3528 .unsigned => try isel.emit(.ubfm(res_ra.x(), res_ra.x(), .{
3529 .N = .doubleword,
3530 .immr = @intCast(64 - bits),
3531 .imms = 64 - 1,
3532 })),
3533 }
3534 try isel.emit(.rev(res_ra.x(), src_mat.ra.x()));
3535 },
3536 64 => try isel.emit(.rev(res_ra.x(), src_mat.ra.x())),
3537 }
3538 try src_mat.finish(isel);
3539 }
3540 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3541 },
3542 .bit_reverse => |air_tag| {
3543 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
3544 defer res_vi.value.deref(isel);
3545
3546 const ty_op = air.data(air.inst_index).ty_op;
3547 const ty = ty_op.ty.toType();
3548 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
3549 const int_info = ty.intInfo(zcu);
3550 if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
3551
3552 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3553 const src_vi = try isel.use(ty_op.operand);
3554 const src_mat = try src_vi.matReg(isel);
3555 switch (int_info.bits) {
3556 else => unreachable,
3557 1...31 => |bits| {
3558 switch (int_info.signedness) {
3559 .signed => try isel.emit(.sbfm(res_ra.w(), res_ra.w(), .{
3560 .N = .word,
3561 .immr = @intCast(32 - bits),
3562 .imms = 32 - 1,
3563 })),
3564 .unsigned => try isel.emit(.ubfm(res_ra.w(), res_ra.w(), .{
3565 .N = .word,
3566 .immr = @intCast(32 - bits),
3567 .imms = 32 - 1,
3568 })),
3569 }
3570 try isel.emit(.rbit(res_ra.w(), src_mat.ra.w()));
3571 },
3572 32 => try isel.emit(.rbit(res_ra.w(), src_mat.ra.w())),
3573 33...63 => |bits| {
3574 switch (int_info.signedness) {
3575 .signed => try isel.emit(.sbfm(res_ra.x(), res_ra.x(), .{
3576 .N = .doubleword,
3577 .immr = @intCast(64 - bits),
3578 .imms = 64 - 1,
3579 })),
3580 .unsigned => try isel.emit(.ubfm(res_ra.x(), res_ra.x(), .{
3581 .N = .doubleword,
3582 .immr = @intCast(64 - bits),
3583 .imms = 64 - 1,
3584 })),
3585 }
3586 try isel.emit(.rbit(res_ra.x(), src_mat.ra.x()));
3587 },
3588 64 => try isel.emit(.rbit(res_ra.x(), src_mat.ra.x())),
3589 }
3590 try src_mat.finish(isel);
3591 }
3592 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3593 },
3594 .sqrt, .floor, .ceil, .round, .trunc_float => |air_tag| {
3595 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
3596 defer res_vi.value.deref(isel);
3597
3598 const un_op = air.data(air.inst_index).un_op;
3599 const ty = isel.air.typeOf(un_op, ip);
3600 switch (ty.floatBits(isel.target)) {
3601 else => unreachable,
3602 16, 32, 64 => |bits| {
3603 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3604 const need_fcvt = switch (bits) {
3605 else => unreachable,
3606 16 => !isel.target.cpu.has(.aarch64, .fullfp16),
3607 32, 64 => false,
3608 };
3609 if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s()));
3610 const src_vi = try isel.use(un_op);
3611 const src_mat = try src_vi.matReg(isel);
3612 const src_ra = if (need_fcvt) try isel.allocVecReg() else src_mat.ra;
3613 defer if (need_fcvt) isel.freeReg(src_ra);
3614 try isel.emit(bits: switch (bits) {
3615 else => unreachable,
3616 16 => if (need_fcvt) continue :bits 32 else switch (air_tag) {
3617 else => unreachable,
3618 .sqrt => .fsqrt(res_ra.h(), src_ra.h()),
3619 .floor => .frintm(res_ra.h(), src_ra.h()),
3620 .ceil => .frintp(res_ra.h(), src_ra.h()),
3621 .round => .frinta(res_ra.h(), src_ra.h()),
3622 .trunc_float => .frintz(res_ra.h(), src_ra.h()),
3623 },
3624 32 => switch (air_tag) {
3625 else => unreachable,
3626 .sqrt => .fsqrt(res_ra.s(), src_ra.s()),
3627 .floor => .frintm(res_ra.s(), src_ra.s()),
3628 .ceil => .frintp(res_ra.s(), src_ra.s()),
3629 .round => .frinta(res_ra.s(), src_ra.s()),
3630 .trunc_float => .frintz(res_ra.s(), src_ra.s()),
3631 },
3632 64 => switch (air_tag) {
3633 else => unreachable,
3634 .sqrt => .fsqrt(res_ra.d(), src_ra.d()),
3635 .floor => .frintm(res_ra.d(), src_ra.d()),
3636 .ceil => .frintp(res_ra.d(), src_ra.d()),
3637 .round => .frinta(res_ra.d(), src_ra.d()),
3638 .trunc_float => .frintz(res_ra.d(), src_ra.d()),
3639 },
3640 });
3641 if (need_fcvt) try isel.emit(.fcvt(src_ra.s(), src_mat.ra.h()));
3642 try src_mat.finish(isel);
3643 },
3644 80, 128 => |bits| {
3645 try call.prepareReturn(isel);
3646 switch (bits) {
3647 else => unreachable,
3648 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
3649 80 => {
3650 var res_hi16_it = res_vi.value.field(ty, 8, 8);
3651 const res_hi16_vi = try res_hi16_it.only(isel);
3652 try call.returnLiveIn(isel, res_hi16_vi.?, .r1);
3653 var res_lo64_it = res_vi.value.field(ty, 0, 8);
3654 const res_lo64_vi = try res_lo64_it.only(isel);
3655 try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
3656 },
3657 }
3658 try call.finishReturn(isel);
3659
3660 try call.prepareCallee(isel);
3661 try isel.global_relocs.append(gpa, .{
3662 .global = switch (air_tag) {
3663 else => unreachable,
3664 .sqrt => switch (bits) {
3665 else => unreachable,
3666 16 => "__sqrth",
3667 32 => "sqrtf",
3668 64 => "sqrt",
3669 80 => "__sqrtx",
3670 128 => "sqrtq",
3671 },
3672 .floor => switch (bits) {
3673 else => unreachable,
3674 16 => "__floorh",
3675 32 => "floorf",
3676 64 => "floor",
3677 80 => "__floorx",
3678 128 => "floorq",
3679 },
3680 .ceil => switch (bits) {
3681 else => unreachable,
3682 16 => "__ceilh",
3683 32 => "ceilf",
3684 64 => "ceil",
3685 80 => "__ceilx",
3686 128 => "ceilq",
3687 },
3688 .round => switch (bits) {
3689 else => unreachable,
3690 16 => "__roundh",
3691 32 => "roundf",
3692 64 => "round",
3693 80 => "__roundx",
3694 128 => "roundq",
3695 },
3696 .trunc_float => switch (bits) {
3697 else => unreachable,
3698 16 => "__trunch",
3699 32 => "truncf",
3700 64 => "trunc",
3701 80 => "__truncx",
3702 128 => "truncq",
3703 },
3704 },
3705 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
3706 });
3707 try isel.emit(.bl(0));
3708 try call.finishCallee(isel);
3709
3710 try call.prepareParams(isel);
3711 const src_vi = try isel.use(un_op);
3712 switch (bits) {
3713 else => unreachable,
3714 16, 32, 64, 128 => try call.paramLiveOut(isel, src_vi, .v0),
3715 80 => {
3716 var src_hi16_it = src_vi.field(ty, 8, 8);
3717 const src_hi16_vi = try src_hi16_it.only(isel);
3718 try call.paramLiveOut(isel, src_hi16_vi.?, .r1);
3719 var src_lo64_it = src_vi.field(ty, 0, 8);
3720 const src_lo64_vi = try src_lo64_it.only(isel);
3721 try call.paramLiveOut(isel, src_lo64_vi.?, .r0);
3722 },
3723 }
3724 try call.finishParams(isel);
3725 },
3726 }
3727 }
3728 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3729 },
3730 .sin, .cos, .tan, .exp, .exp2, .log, .log2, .log10 => |air_tag| {
3731 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| {
3732 defer res_vi.value.deref(isel);
3733
3734 const un_op = air.data(air.inst_index).un_op;
3735 const ty = isel.air.typeOf(un_op, ip);
3736 const bits = ty.floatBits(isel.target);
3737 try call.prepareReturn(isel);
3738 switch (bits) {
3739 else => unreachable,
3740 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
3741 80 => {
3742 var res_hi16_it = res_vi.value.field(ty, 8, 8);
3743 const res_hi16_vi = try res_hi16_it.only(isel);
3744 try call.returnLiveIn(isel, res_hi16_vi.?, .r1);
3745 var res_lo64_it = res_vi.value.field(ty, 0, 8);
3746 const res_lo64_vi = try res_lo64_it.only(isel);
3747 try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
3748 },
3749 }
3750 try call.finishReturn(isel);
3751
3752 try call.prepareCallee(isel);
3753 try isel.global_relocs.append(gpa, .{
3754 .global = switch (air_tag) {
3755 else => unreachable,
3756 .sin => switch (bits) {
3757 else => unreachable,
3758 16 => "__sinh",
3759 32 => "sinf",
3760 64 => "sin",
3761 80 => "__sinx",
3762 128 => "sinq",
3763 },
3764 .cos => switch (bits) {
3765 else => unreachable,
3766 16 => "__cosh",
3767 32 => "cosf",
3768 64 => "cos",
3769 80 => "__cosx",
3770 128 => "cosq",
3771 },
3772 .tan => switch (bits) {
3773 else => unreachable,
3774 16 => "__tanh",
3775 32 => "tanf",
3776 64 => "tan",
3777 80 => "__tanx",
3778 128 => "tanq",
3779 },
3780 .exp => switch (bits) {
3781 else => unreachable,
3782 16 => "__exph",
3783 32 => "expf",
3784 64 => "exp",
3785 80 => "__expx",
3786 128 => "expq",
3787 },
3788 .exp2 => switch (bits) {
3789 else => unreachable,
3790 16 => "__exp2h",
3791 32 => "exp2f",
3792 64 => "exp2",
3793 80 => "__exp2x",
3794 128 => "exp2q",
3795 },
3796 .log => switch (bits) {
3797 else => unreachable,
3798 16 => "__logh",
3799 32 => "logf",
3800 64 => "log",
3801 80 => "__logx",
3802 128 => "logq",
3803 },
3804 .log2 => switch (bits) {
3805 else => unreachable,
3806 16 => "__log2h",
3807 32 => "log2f",
3808 64 => "log2",
3809 80 => "__log2x",
3810 128 => "log2q",
3811 },
3812 .log10 => switch (bits) {
3813 else => unreachable,
3814 16 => "__log10h",
3815 32 => "log10f",
3816 64 => "log10",
3817 80 => "__log10x",
3818 128 => "log10q",
3819 },
3820 },
3821 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
3822 });
3823 try isel.emit(.bl(0));
3824 try call.finishCallee(isel);
3825
3826 try call.prepareParams(isel);
3827 const src_vi = try isel.use(un_op);
3828 switch (bits) {
3829 else => unreachable,
3830 16, 32, 64, 128 => try call.paramLiveOut(isel, src_vi, .v0),
3831 80 => {
3832 var src_hi16_it = src_vi.field(ty, 8, 8);
3833 const src_hi16_vi = try src_hi16_it.only(isel);
3834 try call.paramLiveOut(isel, src_hi16_vi.?, .r1);
3835 var src_lo64_it = src_vi.field(ty, 0, 8);
3836 const src_lo64_vi = try src_lo64_it.only(isel);
3837 try call.paramLiveOut(isel, src_lo64_vi.?, .r0);
3838 },
3839 }
3840 try call.finishParams(isel);
3841 }
3842 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3843 },
3844 .abs => |air_tag| {
3845 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
3846 defer res_vi.value.deref(isel);
3847
3848 const ty_op = air.data(air.inst_index).ty_op;
3849 const ty = ty_op.ty.toType();
3850 if (!ty.isRuntimeFloat()) {
3851 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
3852 switch (ty.intInfo(zcu).bits) {
3853 0 => unreachable,
3854 1...32 => {
3855 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3856 const src_vi = try isel.use(ty_op.operand);
3857 const src_mat = try src_vi.matReg(isel);
3858 try isel.emit(.csneg(res_ra.w(), src_mat.ra.w(), src_mat.ra.w(), .pl));
3859 try isel.emit(.subs(.wzr, src_mat.ra.w(), .{ .immediate = 0 }));
3860 try src_mat.finish(isel);
3861 },
3862 33...64 => {
3863 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3864 const src_vi = try isel.use(ty_op.operand);
3865 const src_mat = try src_vi.matReg(isel);
3866 try isel.emit(.csneg(res_ra.x(), src_mat.ra.x(), src_mat.ra.x(), .pl));
3867 try isel.emit(.subs(.xzr, src_mat.ra.x(), .{ .immediate = 0 }));
3868 try src_mat.finish(isel);
3869 },
3870 65...128 => {
3871 var res_hi64_it = res_vi.value.field(ty, 8, 8);
3872 const res_hi64_vi = try res_hi64_it.only(isel);
3873 const res_hi64_ra = try res_hi64_vi.?.defReg(isel);
3874 var res_lo64_it = res_vi.value.field(ty, 0, 8);
3875 const res_lo64_vi = try res_lo64_it.only(isel);
3876 const res_lo64_ra = try res_lo64_vi.?.defReg(isel);
3877 if (res_hi64_ra == null and res_lo64_ra == null) break :unused;
3878 const src_ty = isel.air.typeOf(ty_op.operand, ip);
3879 const src_vi = try isel.use(ty_op.operand);
3880 var src_hi64_it = src_vi.field(src_ty, 8, 8);
3881 const src_hi64_vi = try src_hi64_it.only(isel);
3882 const src_hi64_mat = try src_hi64_vi.?.matReg(isel);
3883 var src_lo64_it = src_vi.field(src_ty, 0, 8);
3884 const src_lo64_vi = try src_lo64_it.only(isel);
3885 const src_lo64_mat = try src_lo64_vi.?.matReg(isel);
3886 const lo64_ra = try isel.allocIntReg();
3887 defer isel.freeReg(lo64_ra);
3888 const hi64_ra, const mask_ra = alloc_ras: {
3889 const res_lo64_lock: RegLock = if (res_lo64_ra) |res_ra| isel.tryLockReg(res_ra) else .empty;
3890 defer res_lo64_lock.unlock(isel);
3891 break :alloc_ras .{ try isel.allocIntReg(), try isel.allocIntReg() };
3892 };
3893 defer {
3894 isel.freeReg(hi64_ra);
3895 isel.freeReg(mask_ra);
3896 }
3897 if (res_hi64_ra) |res_ra| try isel.emit(.sbc(res_ra.x(), hi64_ra.x(), mask_ra.x()));
3898 try isel.emit(.subs(
3899 if (res_lo64_ra) |res_ra| res_ra.x() else .xzr,
3900 lo64_ra.x(),
3901 .{ .register = mask_ra.x() },
3902 ));
3903 if (res_hi64_ra) |_| try isel.emit(.eor(hi64_ra.x(), src_hi64_mat.ra.x(), .{ .register = mask_ra.x() }));
3904 try isel.emit(.eor(lo64_ra.x(), src_lo64_mat.ra.x(), .{ .register = mask_ra.x() }));
3905 try isel.emit(.sbfm(mask_ra.x(), src_hi64_mat.ra.x(), .{
3906 .N = .doubleword,
3907 .immr = 64 - 1,
3908 .imms = 64 - 1,
3909 }));
3910 try src_lo64_mat.finish(isel);
3911 try src_hi64_mat.finish(isel);
3912 },
3913 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
3914 }
3915 } else switch (ty.floatBits(isel.target)) {
3916 else => unreachable,
3917 16 => {
3918 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3919 const src_vi = try isel.use(ty_op.operand);
3920 const src_mat = try src_vi.matReg(isel);
3921 try isel.emit(if (isel.target.cpu.has(.aarch64, .fullfp16))
3922 .fabs(res_ra.h(), src_mat.ra.h())
3923 else
3924 .bic(res_ra.@"4h"(), res_ra.@"4h"(), .{ .shifted_immediate = .{
3925 .immediate = 0b10000000,
3926 .lsl = 8,
3927 } }));
3928 try src_mat.finish(isel);
3929 },
3930 32 => {
3931 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3932 const src_vi = try isel.use(ty_op.operand);
3933 const src_mat = try src_vi.matReg(isel);
3934 try isel.emit(.fabs(res_ra.s(), src_mat.ra.s()));
3935 try src_mat.finish(isel);
3936 },
3937 64 => {
3938 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3939 const src_vi = try isel.use(ty_op.operand);
3940 const src_mat = try src_vi.matReg(isel);
3941 try isel.emit(.fabs(res_ra.d(), src_mat.ra.d()));
3942 try src_mat.finish(isel);
3943 },
3944 80 => {
3945 const src_vi = try isel.use(ty_op.operand);
3946 var res_hi16_it = res_vi.value.field(ty, 8, 8);
3947 const res_hi16_vi = try res_hi16_it.only(isel);
3948 if (try res_hi16_vi.?.defReg(isel)) |res_hi16_ra| {
3949 var src_hi16_it = src_vi.field(ty, 8, 8);
3950 const src_hi16_vi = try src_hi16_it.only(isel);
3951 const src_hi16_mat = try src_hi16_vi.?.matReg(isel);
3952 try isel.emit(.@"and"(res_hi16_ra.w(), src_hi16_mat.ra.w(), .{ .immediate = .{
3953 .N = .word,
3954 .immr = 0,
3955 .imms = 15 - 1,
3956 } }));
3957 try src_hi16_mat.finish(isel);
3958 }
3959 var res_lo64_it = res_vi.value.field(ty, 0, 8);
3960 const res_lo64_vi = try res_lo64_it.only(isel);
3961 if (try res_lo64_vi.?.defReg(isel)) |res_lo64_ra| {
3962 var src_lo64_it = src_vi.field(ty, 0, 8);
3963 const src_lo64_vi = try src_lo64_it.only(isel);
3964 try src_lo64_vi.?.liveOut(isel, res_lo64_ra);
3965 }
3966 },
3967 128 => {
3968 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3969 const src_vi = try isel.use(ty_op.operand);
3970 const src_mat = try src_vi.matReg(isel);
3971 const neg_zero_ra = try isel.allocVecReg();
3972 defer isel.freeReg(neg_zero_ra);
3973 try isel.emit(.bic(res_ra.@"16b"(), src_mat.ra.@"16b"(), .{ .register = neg_zero_ra.@"16b"() }));
3974 try isel.literals.appendNTimes(gpa, 0, -%isel.literals.items.len % 4);
3975 try isel.literal_relocs.append(gpa, .{
3976 .label = @intCast(isel.instructions.items.len),
3977 });
3978 try isel.emit(.ldr(neg_zero_ra.q(), .{
3979 .literal = @intCast((isel.instructions.items.len + 1 + isel.literals.items.len) << 2),
3980 }));
3981 try isel.emitLiteral(&(.{0} ** 15 ++ .{0x80}));
3982 try src_mat.finish(isel);
3983 },
3984 }
3985 }
3986 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3987 },
3988 .neg, .neg_optimized => {
3989 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
3990 defer res_vi.value.deref(isel);
3991
3992 const un_op = air.data(air.inst_index).un_op;
3993 const ty = isel.air.typeOf(un_op, ip);
3994 switch (ty.floatBits(isel.target)) {
3995 else => unreachable,
3996 16 => {
3997 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3998 const src_vi = try isel.use(un_op);
3999 const src_mat = try src_vi.matReg(isel);
4000 if (isel.target.cpu.has(.aarch64, .fullfp16)) {
4001 try isel.emit(.fneg(res_ra.h(), src_mat.ra.h()));
4002 } else {
4003 const neg_zero_ra = try isel.allocVecReg();
4004 defer isel.freeReg(neg_zero_ra);
4005 try isel.emit(.eor(res_ra.@"8b"(), res_ra.@"8b"(), .{ .register = neg_zero_ra.@"8b"() }));
4006 try isel.emit(.movi(neg_zero_ra.@"4h"(), 0b10000000, .{ .lsl = 8 }));
4007 }
4008 try src_mat.finish(isel);
4009 },
4010 32 => {
4011 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
4012 const src_vi = try isel.use(un_op);
4013 const src_mat = try src_vi.matReg(isel);
4014 try isel.emit(.fneg(res_ra.s(), src_mat.ra.s()));
4015 try src_mat.finish(isel);
4016 },
4017 64 => {
4018 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
4019 const src_vi = try isel.use(un_op);
4020 const src_mat = try src_vi.matReg(isel);
4021 try isel.emit(.fneg(res_ra.d(), src_mat.ra.d()));
4022 try src_mat.finish(isel);
4023 },
4024 80 => {
4025 const src_vi = try isel.use(un_op);
4026 var res_hi16_it = res_vi.value.field(ty, 8, 8);
4027 const res_hi16_vi = try res_hi16_it.only(isel);
4028 if (try res_hi16_vi.?.defReg(isel)) |res_hi16_ra| {
4029 var src_hi16_it = src_vi.field(ty, 8, 8);
4030 const src_hi16_vi = try src_hi16_it.only(isel);
4031 const src_hi16_mat = try src_hi16_vi.?.matReg(isel);
4032 try isel.emit(.eor(res_hi16_ra.w(), src_hi16_mat.ra.w(), .{ .immediate = .{
4033 .N = .word,
4034 .immr = 32 - 15,
4035 .imms = 1 - 1,
4036 } }));
4037 try src_hi16_mat.finish(isel);
4038 }
4039 var res_lo64_it = res_vi.value.field(ty, 0, 8);
4040 const res_lo64_vi = try res_lo64_it.only(isel);
4041 if (try res_lo64_vi.?.defReg(isel)) |res_lo64_ra| {
4042 var src_lo64_it = src_vi.field(ty, 0, 8);
4043 const src_lo64_vi = try src_lo64_it.only(isel);
4044 try src_lo64_vi.?.liveOut(isel, res_lo64_ra);
4045 }
4046 },
4047 128 => {
4048 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
4049 const src_vi = try isel.use(un_op);
4050 const src_mat = try src_vi.matReg(isel);
4051 const neg_zero_ra = try isel.allocVecReg();
4052 defer isel.freeReg(neg_zero_ra);
4053 try isel.emit(.eor(res_ra.@"16b"(), src_mat.ra.@"16b"(), .{ .register = neg_zero_ra.@"16b"() }));
4054 try isel.literals.appendNTimes(gpa, 0, -%isel.literals.items.len % 4);
4055 try isel.literal_relocs.append(gpa, .{
4056 .label = @intCast(isel.instructions.items.len),
4057 });
4058 try isel.emit(.ldr(neg_zero_ra.q(), .{
4059 .literal = @intCast((isel.instructions.items.len + 1 + isel.literals.items.len) << 2),
4060 }));
4061 try isel.emitLiteral(&(.{0} ** 15 ++ .{0x80}));
4062 try src_mat.finish(isel);
4063 },
4064 }
4065 }
4066 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4067 },
4068 .cmp_lt, .cmp_lte, .cmp_eq, .cmp_gte, .cmp_gt, .cmp_neq => |air_tag| {
4069 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
4070 defer res_vi.value.deref(isel);
4071
4072 var bin_op = air.data(air.inst_index).bin_op;
4073 const ty = isel.air.typeOf(bin_op.lhs, ip);
4074 if (!ty.isRuntimeFloat()) {
4075 const int_info: std.builtin.Type.Int = if (ty.toIntern() == .bool_type)
4076 .{ .signedness = .unsigned, .bits = 1 }
4077 else if (ty.isAbiInt(zcu))
4078 ty.intInfo(zcu)
4079 else if (ty.isPtrAtRuntime(zcu))
4080 .{ .signedness = .unsigned, .bits = 64 }
4081 else
4082 return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
4083 if (int_info.bits > 256) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
4084
4085 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
4086 try isel.emit(.csinc(res_ra.w(), .wzr, .wzr, .invert(cond: switch (air_tag) {
4087 else => unreachable,
4088 .cmp_lt => switch (int_info.signedness) {
4089 .signed => .lt,
4090 .unsigned => .lo,
4091 },
4092 .cmp_lte => switch (int_info.bits) {
4093 else => unreachable,
4094 1...64 => switch (int_info.signedness) {
4095 .signed => .le,
4096 .unsigned => .ls,
4097 },
4098 65...128 => {
4099 std.mem.swap(Air.Inst.Ref, &bin_op.lhs, &bin_op.rhs);
4100 continue :cond .cmp_gte;
4101 },
4102 },
4103 .cmp_eq => .eq,
4104 .cmp_gte => switch (int_info.signedness) {
4105 .signed => .ge,
4106 .unsigned => .hs,
4107 },
4108 .cmp_gt => switch (int_info.bits) {
4109 else => unreachable,
4110 1...64 => switch (int_info.signedness) {
4111 .signed => .gt,
4112 .unsigned => .hi,
4113 },
4114 65...128 => {
4115 std.mem.swap(Air.Inst.Ref, &bin_op.lhs, &bin_op.rhs);
4116 continue :cond .cmp_lt;
4117 },
4118 },
4119 .cmp_neq => .ne,
4120 })));
4121
4122 const lhs_vi = try isel.use(bin_op.lhs);
4123 const rhs_vi = try isel.use(bin_op.rhs);
4124 var part_offset = lhs_vi.size(isel);
4125 while (part_offset > 0) {
4126 const part_size = @min(part_offset, 8);
4127 part_offset -= part_size;
4128 var lhs_part_it = lhs_vi.field(ty, part_offset, part_size);
4129 const lhs_part_vi = try lhs_part_it.only(isel);
4130 const lhs_part_mat = try lhs_part_vi.?.matReg(isel);
4131 var rhs_part_it = rhs_vi.field(ty, part_offset, part_size);
4132 const rhs_part_vi = try rhs_part_it.only(isel);
4133 const rhs_part_mat = try rhs_part_vi.?.matReg(isel);
4134 try isel.emit(switch (part_size) {
4135 else => unreachable,
4136 1...4 => switch (part_offset) {
4137 0 => .subs(.wzr, lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }),
4138 else => switch (air_tag) {
4139 else => unreachable,
4140 .cmp_lt, .cmp_lte, .cmp_gte, .cmp_gt => .sbcs(
4141 .wzr,
4142 lhs_part_mat.ra.w(),
4143 rhs_part_mat.ra.w(),
4144 ),
4145 .cmp_eq, .cmp_neq => .ccmp(
4146 lhs_part_mat.ra.w(),
4147 .{ .register = rhs_part_mat.ra.w() },
4148 .{ .n = false, .z = false, .c = false, .v = false },
4149 .eq,
4150 ),
4151 },
4152 },
4153 5...8 => switch (part_offset) {
4154 0 => .subs(.xzr, lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }),
4155 else => switch (air_tag) {
4156 else => unreachable,
4157 .cmp_lt, .cmp_lte, .cmp_gte, .cmp_gt => .sbcs(
4158 .xzr,
4159 lhs_part_mat.ra.x(),
4160 rhs_part_mat.ra.x(),
4161 ),
4162 .cmp_eq, .cmp_neq => .ccmp(
4163 lhs_part_mat.ra.x(),
4164 .{ .register = rhs_part_mat.ra.x() },
4165 .{ .n = false, .z = false, .c = false, .v = false },
4166 .eq,
4167 ),
4168 },
4169 },
4170 });
4171 try rhs_part_mat.finish(isel);
4172 try lhs_part_mat.finish(isel);
4173 }
4174 } else switch (ty.floatBits(isel.target)) {
4175 else => unreachable,
4176 16, 32, 64 => |bits| {
4177 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
4178 const need_fcvt = switch (bits) {
4179 else => unreachable,
4180 16 => !isel.target.cpu.has(.aarch64, .fullfp16),
4181 32, 64 => false,
4182 };
4183 try isel.emit(.csinc(res_ra.w(), .wzr, .wzr, .invert(switch (air_tag) {
4184 else => unreachable,
4185 .cmp_lt => .lo,
4186 .cmp_lte => .ls,
4187 .cmp_eq => .eq,
4188 .cmp_gte => .ge,
4189 .cmp_gt => .gt,
4190 .cmp_neq => .ne,
4191 })));
4192
4193 const lhs_vi = try isel.use(bin_op.lhs);
4194 const rhs_vi = try isel.use(bin_op.rhs);
4195 const lhs_mat = try lhs_vi.matReg(isel);
4196 const rhs_mat = try rhs_vi.matReg(isel);
4197 const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra;
4198 defer if (need_fcvt) isel.freeReg(lhs_ra);
4199 const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra;
4200 defer if (need_fcvt) isel.freeReg(rhs_ra);
4201 try isel.emit(bits: switch (bits) {
4202 else => unreachable,
4203 16 => if (need_fcvt)
4204 continue :bits 32
4205 else
4206 .fcmp(lhs_ra.h(), .{ .register = rhs_ra.h() }),
4207 32 => .fcmp(lhs_ra.s(), .{ .register = rhs_ra.s() }),
4208 64 => .fcmp(lhs_ra.d(), .{ .register = rhs_ra.d() }),
4209 });
4210 if (need_fcvt) {
4211 try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h()));
4212 try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h()));
4213 }
4214 try rhs_mat.finish(isel);
4215 try lhs_mat.finish(isel);
4216 },
4217 80, 128 => |bits| {
4218 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
4219
4220 try call.prepareReturn(isel);
4221 try call.returnFill(isel, .r0);
4222 try isel.emit(.csinc(res_ra.w(), .wzr, .wzr, .invert(cond: switch (air_tag) {
4223 else => unreachable,
4224 .cmp_lt => .lt,
4225 .cmp_lte => .le,
4226 .cmp_eq => .eq,
4227 .cmp_gte => {
4228 std.mem.swap(Air.Inst.Ref, &bin_op.lhs, &bin_op.rhs);
4229 continue :cond .cmp_lte;
4230 },
4231 .cmp_gt => {
4232 std.mem.swap(Air.Inst.Ref, &bin_op.lhs, &bin_op.rhs);
4233 continue :cond .cmp_lt;
4234 },
4235 .cmp_neq => .ne,
4236 })));
4237 try isel.emit(.subs(.wzr, .w0, .{ .immediate = 0 }));
4238 try call.finishReturn(isel);
4239
4240 try call.prepareCallee(isel);
4241 try isel.global_relocs.append(gpa, .{
4242 .global = switch (bits) {
4243 else => unreachable,
4244 16 => "__cmphf2",
4245 32 => "__cmpsf2",
4246 64 => "__cmpdf2",
4247 80 => "__cmpxf2",
4248 128 => "__cmptf2",
4249 },
4250 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
4251 });
4252 try isel.emit(.bl(0));
4253 try call.finishCallee(isel);
4254
4255 try call.prepareParams(isel);
4256 const lhs_vi = try isel.use(bin_op.lhs);
4257 const rhs_vi = try isel.use(bin_op.rhs);
4258 switch (bits) {
4259 else => unreachable,
4260 16, 32, 64, 128 => {
4261 try call.paramLiveOut(isel, rhs_vi, .v1);
4262 try call.paramLiveOut(isel, lhs_vi, .v0);
4263 },
4264 80 => {
4265 var rhs_hi16_it = rhs_vi.field(ty, 8, 8);
4266 const rhs_hi16_vi = try rhs_hi16_it.only(isel);
4267 try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3);
4268 var rhs_lo64_it = rhs_vi.field(ty, 0, 8);
4269 const rhs_lo64_vi = try rhs_lo64_it.only(isel);
4270 try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2);
4271 var lhs_hi16_it = lhs_vi.field(ty, 8, 8);
4272 const lhs_hi16_vi = try lhs_hi16_it.only(isel);
4273 try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1);
4274 var lhs_lo64_it = lhs_vi.field(ty, 0, 8);
4275 const lhs_lo64_vi = try lhs_lo64_it.only(isel);
4276 try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0);
4277 },
4278 }
4279 try call.finishParams(isel);
4280 },
4281 }
4282 }
4283 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4284 },
4285 .cond_br => {
4286 const pl_op = air.data(air.inst_index).pl_op;
4287 const extra = isel.air.extraData(Air.CondBr, pl_op.payload);
4288
4289 try isel.body(@ptrCast(isel.air.extra.items[extra.end + extra.data.then_body_len ..][0..extra.data.else_body_len]));
4290 const else_label = isel.instructions.items.len;
4291 const else_live_registers = isel.live_registers;
4292 try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.then_body_len]));
4293 try isel.merge(&else_live_registers, .{});
4294
4295 const cond_vi = try isel.use(pl_op.operand);
4296 const cond_mat = try cond_vi.matReg(isel);
4297 try isel.emit(.tbz(
4298 cond_mat.ra.x(),
4299 0,
4300 @intCast((isel.instructions.items.len + 1 - else_label) << 2),
4301 ));
4302 try cond_mat.finish(isel);
4303
4304 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4305 },
4306 .switch_br => {
4307 const switch_br = isel.air.unwrapSwitch(air.inst_index);
4308 const cond_ty = isel.air.typeOf(switch_br.operand, ip);
4309 const cond_int_info: std.builtin.Type.Int = if (cond_ty.toIntern() == .bool_type)
4310 .{ .signedness = .unsigned, .bits = 1 }
4311 else if (cond_ty.isAbiInt(zcu))
4312 cond_ty.intInfo(zcu)
4313 else
4314 return isel.fail("bad switch cond {f}", .{isel.fmtType(cond_ty)});
4315
4316 var final_case = true;
4317 if (switch_br.else_body_len > 0) {
4318 var cases_it = switch_br.iterateCases();
4319 while (cases_it.next()) |_| {}
4320 try isel.body(cases_it.elseBody());
4321 assert(final_case);
4322 final_case = false;
4323 }
4324 const zero_reg: Register = switch (cond_int_info.bits) {
4325 else => unreachable,
4326 1...32 => .wzr,
4327 33...64 => .xzr,
4328 };
4329 var cond_mat: ?Value.Materialize = null;
4330 var cond_reg: Register = undefined;
4331 var temp_reg: Register = undefined;
4332 var cases_it = switch_br.iterateCases();
4333 while (cases_it.next()) |case| {
4334 const next_label = isel.instructions.items.len;
4335 const next_live_registers = isel.live_registers;
4336 try isel.body(case.body);
4337 if (final_case) {
4338 final_case = false;
4339 continue;
4340 }
4341 try isel.merge(&next_live_registers, .{});
4342 if (cond_mat == null) {
4343 var cond_vi = try isel.use(switch_br.operand);
4344 cond_mat = try cond_vi.matReg(isel);
4345 const temp_ra = try isel.allocIntReg();
4346 cond_reg, temp_reg = switch (cond_int_info.bits) {
4347 else => unreachable,
4348 1...32 => .{ cond_mat.?.ra.w(), temp_ra.w() },
4349 33...64 => .{ cond_mat.?.ra.x(), temp_ra.x() },
4350 };
4351 }
4352 if (case.ranges.len == 0 and case.items.len == 1 and Constant.fromInterned(
4353 case.items[0].toInterned().?,
4354 ).orderAgainstZero(zcu).compare(.eq)) {
4355 try isel.emit(.cbnz(
4356 cond_reg,
4357 @intCast((isel.instructions.items.len + 1 - next_label) << 2),
4358 ));
4359 continue;
4360 }
4361 try isel.emit(.@"b."(
4362 .invert(switch (case.ranges.len) {
4363 0 => .eq,
4364 else => .ls,
4365 }),
4366 @intCast((isel.instructions.items.len + 1 - next_label) << 2),
4367 ));
4368 var case_range_index = case.ranges.len;
4369 while (case_range_index > 0) {
4370 case_range_index -= 1;
4371
4372 const low_val: Constant = .fromInterned(case.ranges[case_range_index][0].toInterned().?);
4373 var low_bigint_space: Constant.BigIntSpace = undefined;
4374 const low_bigint = low_val.toBigInt(&low_bigint_space, zcu);
4375 const low_int: i64 = if (low_bigint.positive) @bitCast(
4376 low_bigint.toInt(u64) catch
4377 return isel.fail("too big case range start: {f}", .{isel.fmtConstant(low_val)}),
4378 ) else low_bigint.toInt(i64) catch
4379 return isel.fail("too big case range start: {f}", .{isel.fmtConstant(low_val)});
4380
4381 const high_val: Constant = .fromInterned(case.ranges[case_range_index][1].toInterned().?);
4382 var high_bigint_space: Constant.BigIntSpace = undefined;
4383 const high_bigint = high_val.toBigInt(&high_bigint_space, zcu);
4384 const high_int: i64 = if (high_bigint.positive) @bitCast(
4385 high_bigint.toInt(u64) catch
4386 return isel.fail("too big case range end: {f}", .{isel.fmtConstant(high_val)}),
4387 ) else high_bigint.toInt(i64) catch
4388 return isel.fail("too big case range end: {f}", .{isel.fmtConstant(high_val)});
4389
4390 const delta_int = high_int -% low_int;
4391 if (case_range_index > 0) {
4392 return isel.fail("case range", .{});
4393 } else if (case.items.len > 0) {
4394 return isel.fail("case range", .{});
4395 } else {
4396 const adjusted_reg = switch (low_int) {
4397 0 => cond_reg,
4398 else => temp_reg,
4399 };
4400
4401 if (std.math.cast(u12, delta_int)) |pos_imm| try isel.emit(.subs(
4402 zero_reg,
4403 adjusted_reg,
4404 .{ .immediate = pos_imm },
4405 )) else if (std.math.cast(u12, -delta_int)) |neg_imm| try isel.emit(.adds(
4406 zero_reg,
4407 adjusted_reg,
4408 .{ .immediate = neg_imm },
4409 )) else if (if (@as(i12, @truncate(delta_int)) == 0)
4410 std.math.cast(u12, delta_int >> 12)
4411 else
4412 null) |pos_imm_lsr_12| try isel.emit(.subs(
4413 zero_reg,
4414 adjusted_reg,
4415 .{ .shifted_immediate = .{ .immediate = pos_imm_lsr_12, .lsl = .@"12" } },
4416 )) else if (if (@as(i12, @truncate(-delta_int)) == 0)
4417 std.math.cast(u12, -delta_int >> 12)
4418 else
4419 null) |neg_imm_lsr_12| try isel.emit(.adds(
4420 zero_reg,
4421 adjusted_reg,
4422 .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } },
4423 )) else {
4424 try isel.movImmediate(temp_reg, @bitCast(delta_int));
4425 try isel.emit(.subs(zero_reg, adjusted_reg, .{ .register = temp_reg }));
4426 }
4427
4428 switch (low_int) {
4429 0 => {},
4430 else => {
4431 if (std.math.cast(u12, low_int)) |pos_imm| try isel.emit(.sub(
4432 adjusted_reg,
4433 cond_reg,
4434 .{ .immediate = pos_imm },
4435 )) else if (std.math.cast(u12, -low_int)) |neg_imm| try isel.emit(.add(
4436 adjusted_reg,
4437 cond_reg,
4438 .{ .immediate = neg_imm },
4439 )) else if (if (@as(i12, @truncate(low_int)) == 0)
4440 std.math.cast(u12, low_int >> 12)
4441 else
4442 null) |pos_imm_lsr_12| try isel.emit(.sub(
4443 adjusted_reg,
4444 cond_reg,
4445 .{ .shifted_immediate = .{ .immediate = pos_imm_lsr_12, .lsl = .@"12" } },
4446 )) else if (if (@as(i12, @truncate(-low_int)) == 0)
4447 std.math.cast(u12, -low_int >> 12)
4448 else
4449 null) |neg_imm_lsr_12| try isel.emit(.add(
4450 adjusted_reg,
4451 cond_reg,
4452 .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } },
4453 )) else {
4454 try isel.movImmediate(temp_reg, @bitCast(low_int));
4455 try isel.emit(.subs(adjusted_reg, cond_reg, .{ .register = temp_reg }));
4456 }
4457 },
4458 }
4459 }
4460 }
4461 var case_item_index = case.items.len;
4462 while (case_item_index > 0) {
4463 case_item_index -= 1;
4464
4465 const item_val: Constant = .fromInterned(case.items[case_item_index].toInterned().?);
4466 var item_bigint_space: Constant.BigIntSpace = undefined;
4467 const item_bigint = item_val.toBigInt(&item_bigint_space, zcu);
4468 const item_int: i64 = if (item_bigint.positive) @bitCast(
4469 item_bigint.toInt(u64) catch
4470 return isel.fail("too big case item: {f}", .{isel.fmtConstant(item_val)}),
4471 ) else item_bigint.toInt(i64) catch
4472 return isel.fail("too big case item: {f}", .{isel.fmtConstant(item_val)});
4473
4474 if (case_item_index > 0) {
4475 if (std.math.cast(u5, item_int)) |pos_imm| try isel.emit(.ccmp(
4476 cond_reg,
4477 .{ .immediate = pos_imm },
4478 .{ .n = false, .z = true, .c = false, .v = false },
4479 .ne,
4480 )) else if (std.math.cast(u5, -item_int)) |neg_imm| try isel.emit(.ccmn(
4481 cond_reg,
4482 .{ .immediate = neg_imm },
4483 .{ .n = false, .z = true, .c = false, .v = false },
4484 .ne,
4485 )) else {
4486 try isel.movImmediate(temp_reg, @bitCast(item_int));
4487 try isel.emit(.ccmp(
4488 cond_reg,
4489 .{ .register = temp_reg },
4490 .{ .n = false, .z = true, .c = false, .v = false },
4491 .ne,
4492 ));
4493 }
4494 } else {
4495 if (std.math.cast(u12, item_int)) |pos_imm| try isel.emit(.subs(
4496 zero_reg,
4497 cond_reg,
4498 .{ .immediate = pos_imm },
4499 )) else if (std.math.cast(u12, -item_int)) |neg_imm| try isel.emit(.adds(
4500 zero_reg,
4501 cond_reg,
4502 .{ .immediate = neg_imm },
4503 )) else if (if (@as(i12, @truncate(item_int)) == 0)
4504 std.math.cast(u12, item_int >> 12)
4505 else
4506 null) |pos_imm_lsr_12| try isel.emit(.subs(
4507 zero_reg,
4508 cond_reg,
4509 .{ .shifted_immediate = .{ .immediate = pos_imm_lsr_12, .lsl = .@"12" } },
4510 )) else if (if (@as(i12, @truncate(-item_int)) == 0)
4511 std.math.cast(u12, -item_int >> 12)
4512 else
4513 null) |neg_imm_lsr_12| try isel.emit(.adds(
4514 zero_reg,
4515 cond_reg,
4516 .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } },
4517 )) else {
4518 try isel.movImmediate(temp_reg, @bitCast(item_int));
4519 try isel.emit(.subs(zero_reg, cond_reg, .{ .register = temp_reg }));
4520 }
4521 }
4522 }
4523 }
4524 if (cond_mat) |mat| {
4525 try mat.finish(isel);
4526 isel.freeReg(temp_reg.alias);
4527 }
4528 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4529 },
4530 .@"try", .try_cold => {
4531 const pl_op = air.data(air.inst_index).pl_op;
4532 const extra = isel.air.extraData(Air.Try, pl_op.payload);
4533 const error_union_ty = isel.air.typeOf(pl_op.operand, ip);
4534 const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type;
4535 const payload_ty: ZigType = .fromInterned(error_union_info.payload_type);
4536
4537 const error_union_vi = try isel.use(pl_op.operand);
4538 if (isel.live_values.fetchRemove(air.inst_index)) |payload_vi| {
4539 defer payload_vi.value.deref(isel);
4540
4541 var payload_part_it = error_union_vi.field(
4542 error_union_ty,
4543 codegen.errUnionPayloadOffset(payload_ty, zcu),
4544 payload_vi.value.size(isel),
4545 );
4546 const payload_part_vi = try payload_part_it.only(isel);
4547 try payload_vi.value.copy(isel, payload_ty, payload_part_vi.?);
4548 }
4549
4550 const cont_label = isel.instructions.items.len;
4551 const cont_live_registers = isel.live_registers;
4552 try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));
4553 try isel.merge(&cont_live_registers, .{});
4554
4555 var error_set_part_it = error_union_vi.field(
4556 error_union_ty,
4557 codegen.errUnionErrorOffset(payload_ty, zcu),
4558 ZigType.fromInterned(error_union_info.error_set_type).abiSize(zcu),
4559 );
4560 const error_set_part_vi = try error_set_part_it.only(isel);
4561 const error_set_part_mat = try error_set_part_vi.?.matReg(isel);
4562 try isel.emit(.cbz(
4563 switch (error_set_part_vi.?.size(isel)) {
4564 else => unreachable,
4565 1...4 => error_set_part_mat.ra.w(),
4566 5...8 => error_set_part_mat.ra.x(),
4567 },
4568 @intCast((isel.instructions.items.len + 1 - cont_label) << 2),
4569 ));
4570 try error_set_part_mat.finish(isel);
4571
4572 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4573 },
4574 .dbg_stmt => {
4575 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4576 },
4577 .dbg_empty_stmt => {
4578 try isel.emit(.nop());
4579 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4580 },
4581 .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => {
4582 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4583 },
4584 .is_null, .is_non_null => |air_tag| {
4585 if (isel.live_values.fetchRemove(air.inst_index)) |is_vi| unused: {
4586 defer is_vi.value.deref(isel);
4587 const is_ra = try is_vi.value.defReg(isel) orelse break :unused;
4588
4589 const un_op = air.data(air.inst_index).un_op;
4590 const opt_ty = isel.air.typeOf(un_op, ip);
4591 const payload_ty = opt_ty.optionalChild(zcu);
4592 const payload_size = payload_ty.abiSize(zcu);
4593 const has_value_offset, const has_value_size = if (!opt_ty.optionalReprIsPayload(zcu))
4594 .{ payload_size, 1 }
4595 else if (payload_ty.isSlice(zcu))
4596 .{ 0, 8 }
4597 else
4598 .{ 0, payload_size };
4599
4600 try isel.emit(.csinc(is_ra.w(), .wzr, .wzr, .invert(switch (air_tag) {
4601 else => unreachable,
4602 .is_null => .eq,
4603 .is_non_null => .ne,
4604 })));
4605 const opt_vi = try isel.use(un_op);
4606 var has_value_part_it = opt_vi.field(opt_ty, has_value_offset, has_value_size);
4607 const has_value_part_vi = try has_value_part_it.only(isel);
4608 const has_value_part_mat = try has_value_part_vi.?.matReg(isel);
4609 try isel.emit(switch (has_value_size) {
4610 else => unreachable,
4611 1...4 => .subs(.wzr, has_value_part_mat.ra.w(), .{ .immediate = 0 }),
4612 5...8 => .subs(.xzr, has_value_part_mat.ra.x(), .{ .immediate = 0 }),
4613 });
4614 try has_value_part_mat.finish(isel);
4615 }
4616 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4617 },
4618 .is_err, .is_non_err => |air_tag| {
4619 if (isel.live_values.fetchRemove(air.inst_index)) |is_vi| unused: {
4620 defer is_vi.value.deref(isel);
4621 const is_ra = try is_vi.value.defReg(isel) orelse break :unused;
4622
4623 const un_op = air.data(air.inst_index).un_op;
4624 const error_union_ty = isel.air.typeOf(un_op, ip);
4625 const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type;
4626 const error_set_ty: ZigType = .fromInterned(error_union_info.error_set_type);
4627 const payload_ty: ZigType = .fromInterned(error_union_info.payload_type);
4628 const error_set_offset = codegen.errUnionErrorOffset(payload_ty, zcu);
4629 const error_set_size = error_set_ty.abiSize(zcu);
4630
4631 try isel.emit(.csinc(is_ra.w(), .wzr, .wzr, .invert(switch (air_tag) {
4632 else => unreachable,
4633 .is_err => .ne,
4634 .is_non_err => .eq,
4635 })));
4636 const error_union_vi = try isel.use(un_op);
4637 var error_set_part_it = error_union_vi.field(error_union_ty, error_set_offset, error_set_size);
4638 const error_set_part_vi = try error_set_part_it.only(isel);
4639 const error_set_part_mat = try error_set_part_vi.?.matReg(isel);
4640 try isel.emit(.ands(.wzr, error_set_part_mat.ra.w(), .{ .immediate = .{
4641 .N = .word,
4642 .immr = 0,
4643 .imms = @intCast(8 * error_set_size - 1),
4644 } }));
4645 try error_set_part_mat.finish(isel);
4646 }
4647 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4648 },
4649 .load => {
4650 const ty_op = air.data(air.inst_index).ty_op;
4651 const ptr_ty = isel.air.typeOf(ty_op.operand, ip);
4652 const ptr_info = ptr_ty.ptrInfo(zcu);
4653 if (ptr_info.packed_offset.host_size > 0) return isel.fail("packed load", .{});
4654
4655 if (ptr_info.flags.is_volatile) _ = try isel.use(air.inst_index.toRef());
4656 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
4657 defer dst_vi.value.deref(isel);
4658 switch (dst_vi.value.size(isel)) {
4659 0 => unreachable,
4660 1...Value.max_parts => {
4661 const ptr_vi = try isel.use(ty_op.operand);
4662 const ptr_mat = try ptr_vi.matReg(isel);
4663 _ = try dst_vi.value.load(isel, ty_op.ty.toType(), ptr_mat.ra, .{
4664 .@"volatile" = ptr_info.flags.is_volatile,
4665 });
4666 try ptr_mat.finish(isel);
4667 },
4668 else => |size| {
4669 try dst_vi.value.defAddr(isel, .fromInterned(ptr_info.child), null, comptime &.initFill(.free)) orelse break :unused;
4670
4671 try call.prepareReturn(isel);
4672 try call.finishReturn(isel);
4673
4674 try call.prepareCallee(isel);
4675 try isel.global_relocs.append(gpa, .{
4676 .global = "memcpy",
4677 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
4678 });
4679 try isel.emit(.bl(0));
4680 try call.finishCallee(isel);
4681
4682 try call.prepareParams(isel);
4683 const ptr_vi = try isel.use(ty_op.operand);
4684 try isel.movImmediate(.x2, size);
4685 try call.paramLiveOut(isel, ptr_vi, .r1);
4686 try call.paramAddress(isel, dst_vi.value, .r0);
4687 try call.finishParams(isel);
4688 },
4689 }
4690 }
4691
4692 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4693 },
4694 .ret, .ret_safe => {
4695 assert(isel.blocks.keys()[0] == Block.main);
4696 try isel.blocks.values()[0].branch(isel);
4697 if (isel.live_values.get(Block.main)) |ret_vi| {
4698 const un_op = air.data(air.inst_index).un_op;
4699 const src_vi = try isel.use(un_op);
4700 switch (ret_vi.parent(isel)) {
4701 .unallocated, .stack_slot => if (ret_vi.hint(isel)) |ret_ra| {
4702 try src_vi.liveOut(isel, ret_ra);
4703 } else {
4704 var ret_part_it = ret_vi.parts(isel);
4705 var src_part_it = src_vi.parts(isel);
4706 if (src_part_it.only()) |_| {
4707 try isel.values.ensureUnusedCapacity(gpa, ret_part_it.remaining);
4708 src_vi.setParts(isel, ret_part_it.remaining);
4709 while (ret_part_it.next()) |ret_part_vi| {
4710 const src_part_vi = src_vi.addPart(
4711 isel,
4712 ret_part_vi.get(isel).offset_from_parent,
4713 ret_part_vi.size(isel),
4714 );
4715 switch (ret_part_vi.signedness(isel)) {
4716 .signed => src_part_vi.setSignedness(isel, .signed),
4717 .unsigned => {},
4718 }
4719 if (ret_part_vi.isVector(isel)) src_part_vi.setIsVector(isel);
4720 }
4721 ret_part_it = ret_vi.parts(isel);
4722 src_part_it = src_vi.parts(isel);
4723 }
4724 while (ret_part_it.next()) |ret_part_vi| {
4725 const src_part_vi = src_part_it.next().?;
4726 assert(ret_part_vi.get(isel).offset_from_parent == src_part_vi.get(isel).offset_from_parent);
4727 assert(ret_part_vi.size(isel) == src_part_vi.size(isel));
4728 try src_part_vi.liveOut(isel, ret_part_vi.hint(isel).?);
4729 }
4730 },
4731 .value, .constant => unreachable,
4732 .address => |address_vi| {
4733 const ptr_mat = try address_vi.matReg(isel);
4734 try src_vi.store(isel, isel.air.typeOf(un_op, ip), ptr_mat.ra, .{});
4735 try ptr_mat.finish(isel);
4736 },
4737 }
4738 }
4739 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4740 },
4741 .ret_load => {
4742 const un_op = air.data(air.inst_index).un_op;
4743 const ptr_ty = isel.air.typeOf(un_op, ip);
4744 const ptr_info = ptr_ty.ptrInfo(zcu);
4745 if (ptr_info.packed_offset.host_size > 0) return isel.fail("packed load", .{});
4746
4747 assert(isel.blocks.keys()[0] == Block.main);
4748 try isel.blocks.values()[0].branch(isel);
4749 if (isel.live_values.get(Block.main)) |ret_vi| switch (ret_vi.parent(isel)) {
4750 .unallocated, .stack_slot => {
4751 var ret_part_it: Value.PartIterator = if (ret_vi.hint(isel)) |_| .initOne(ret_vi) else ret_vi.parts(isel);
4752 while (ret_part_it.next()) |ret_part_vi| try ret_part_vi.liveOut(isel, ret_part_vi.hint(isel).?);
4753 const ptr_vi = try isel.use(un_op);
4754 const ptr_mat = try ptr_vi.matReg(isel);
4755 _ = try ret_vi.load(isel, .fromInterned(ptr_info.child), ptr_mat.ra, .{});
4756 try ptr_mat.finish(isel);
4757 },
4758 .value, .constant => unreachable,
4759 .address => {},
4760 };
4761 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4762 },
4763 .store, .store_safe, .atomic_store_unordered => {
4764 const bin_op = air.data(air.inst_index).bin_op;
4765 const ptr_ty = isel.air.typeOf(bin_op.lhs, ip);
4766 const ptr_info = ptr_ty.ptrInfo(zcu);
4767 if (ptr_info.packed_offset.host_size > 0) return isel.fail("packed store", .{});
4768 if (bin_op.rhs.toInterned()) |rhs_val| if (ip.isUndef(rhs_val)) {
4769 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4770 break :air_tag;
4771 };
4772
4773 const src_vi = try isel.use(bin_op.rhs);
4774 const size = src_vi.size(isel);
4775 if (ZigType.fromInterned(ptr_info.child).zigTypeTag(zcu) != .@"union") switch (size) {
4776 0 => unreachable,
4777 1...Value.max_parts => {
4778 const ptr_vi = try isel.use(bin_op.lhs);
4779 const ptr_mat = try ptr_vi.matReg(isel);
4780 try src_vi.store(isel, isel.air.typeOf(bin_op.rhs, ip), ptr_mat.ra, .{
4781 .@"volatile" = ptr_info.flags.is_volatile,
4782 });
4783 try ptr_mat.finish(isel);
4784
4785 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4786 break :air_tag;
4787 },
4788 else => {},
4789 };
4790 try call.prepareReturn(isel);
4791 try call.finishReturn(isel);
4792
4793 try call.prepareCallee(isel);
4794 try isel.global_relocs.append(gpa, .{
4795 .global = "memcpy",
4796 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
4797 });
4798 try isel.emit(.bl(0));
4799 try call.finishCallee(isel);
4800
4801 try call.prepareParams(isel);
4802 const ptr_vi = try isel.use(bin_op.lhs);
4803 try isel.movImmediate(.x2, size);
4804 try call.paramAddress(isel, src_vi, .r1);
4805 try call.paramLiveOut(isel, ptr_vi, .r0);
4806 try call.finishParams(isel);
4807
4808 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4809 },
4810 .unreach => if (air.next()) |next_air_tag| continue :air_tag next_air_tag,
4811 .fptrunc, .fpext => {
4812 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
4813 defer dst_vi.value.deref(isel);
4814
4815 const ty_op = air.data(air.inst_index).ty_op;
4816 const dst_ty = ty_op.ty.toType();
4817 const dst_bits = dst_ty.floatBits(isel.target);
4818 const src_ty = isel.air.typeOf(ty_op.operand, ip);
4819 const src_bits = src_ty.floatBits(isel.target);
4820 assert(dst_bits != src_bits);
4821 switch (@max(dst_bits, src_bits)) {
4822 else => unreachable,
4823 16, 32, 64 => {
4824 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
4825 const src_vi = try isel.use(ty_op.operand);
4826 const src_mat = try src_vi.matReg(isel);
4827 try isel.emit(.fcvt(switch (dst_bits) {
4828 else => unreachable,
4829 16 => dst_ra.h(),
4830 32 => dst_ra.s(),
4831 64 => dst_ra.d(),
4832 }, switch (src_bits) {
4833 else => unreachable,
4834 16 => src_mat.ra.h(),
4835 32 => src_mat.ra.s(),
4836 64 => src_mat.ra.d(),
4837 }));
4838 try src_mat.finish(isel);
4839 },
4840 80, 128 => {
4841 try call.prepareReturn(isel);
4842 switch (dst_bits) {
4843 else => unreachable,
4844 16, 32, 64, 128 => try call.returnLiveIn(isel, dst_vi.value, .v0),
4845 80 => {
4846 var dst_hi16_it = dst_vi.value.field(dst_ty, 8, 8);
4847 const dst_hi16_vi = try dst_hi16_it.only(isel);
4848 try call.returnLiveIn(isel, dst_hi16_vi.?, .r1);
4849 var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8);
4850 const dst_lo64_vi = try dst_lo64_it.only(isel);
4851 try call.returnLiveIn(isel, dst_lo64_vi.?, .r0);
4852 },
4853 }
4854 try call.finishReturn(isel);
4855
4856 try call.prepareCallee(isel);
4857 try isel.global_relocs.append(gpa, .{
4858 .global = switch (dst_bits) {
4859 else => unreachable,
4860 16 => switch (src_bits) {
4861 else => unreachable,
4862 32 => "__truncsfhf2",
4863 64 => "__truncdfhf2",
4864 80 => "__truncxfhf2",
4865 128 => "__trunctfhf2",
4866 },
4867 32 => switch (src_bits) {
4868 else => unreachable,
4869 16 => "__extendhfsf2",
4870 64 => "__truncdfsf2",
4871 80 => "__truncxfsf2",
4872 128 => "__trunctfsf2",
4873 },
4874 64 => switch (src_bits) {
4875 else => unreachable,
4876 16 => "__extendhfdf2",
4877 32 => "__extendsfdf2",
4878 80 => "__truncxfdf2",
4879 128 => "__trunctfdf2",
4880 },
4881 80 => switch (src_bits) {
4882 else => unreachable,
4883 16 => "__extendhfxf2",
4884 32 => "__extendsfxf2",
4885 64 => "__extenddfxf2",
4886 128 => "__trunctfxf2",
4887 },
4888 128 => switch (src_bits) {
4889 else => unreachable,
4890 16 => "__extendhftf2",
4891 32 => "__extendsftf2",
4892 64 => "__extenddftf2",
4893 80 => "__extendxftf2",
4894 },
4895 },
4896 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
4897 });
4898 try isel.emit(.bl(0));
4899 try call.finishCallee(isel);
4900
4901 try call.prepareParams(isel);
4902 const src_vi = try isel.use(ty_op.operand);
4903 switch (src_bits) {
4904 else => unreachable,
4905 16, 32, 64, 128 => try call.paramLiveOut(isel, src_vi, .v0),
4906 80 => {
4907 var src_hi16_it = src_vi.field(src_ty, 8, 8);
4908 const src_hi16_vi = try src_hi16_it.only(isel);
4909 try call.paramLiveOut(isel, src_hi16_vi.?, .r1);
4910 var src_lo64_it = src_vi.field(src_ty, 0, 8);
4911 const src_lo64_vi = try src_lo64_it.only(isel);
4912 try call.paramLiveOut(isel, src_lo64_vi.?, .r0);
4913 },
4914 }
4915 try call.finishParams(isel);
4916 },
4917 }
4918 }
4919 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4920 },
4921 .intcast => |air_tag| {
4922 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
4923 defer dst_vi.value.deref(isel);
4924
4925 const ty_op = air.data(air.inst_index).ty_op;
4926 const dst_ty = ty_op.ty.toType();
4927 const dst_int_info = dst_ty.intInfo(zcu);
4928 const src_ty = isel.air.typeOf(ty_op.operand, ip);
4929 const src_int_info = src_ty.intInfo(zcu);
4930 const can_be_negative = dst_int_info.signedness == .signed and
4931 src_int_info.signedness == .signed;
4932 if ((dst_int_info.bits <= 8 and src_int_info.bits <= 8) or
4933 (dst_int_info.bits > 8 and dst_int_info.bits <= 16 and
4934 src_int_info.bits > 8 and src_int_info.bits <= 16) or
4935 (dst_int_info.bits > 16 and dst_int_info.bits <= 32 and
4936 src_int_info.bits > 16 and src_int_info.bits <= 32) or
4937 (dst_int_info.bits > 32 and dst_int_info.bits <= 64 and
4938 src_int_info.bits > 32 and src_int_info.bits <= 64) or
4939 (dst_int_info.bits > 64 and src_int_info.bits > 64 and
4940 (dst_int_info.bits - 1) / 128 == (src_int_info.bits - 1) / 128))
4941 {
4942 try dst_vi.value.move(isel, ty_op.operand);
4943 } else if (dst_int_info.bits <= 32 and src_int_info.bits <= 64) {
4944 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
4945 const src_vi = try isel.use(ty_op.operand);
4946 const src_mat = try src_vi.matReg(isel);
4947 try isel.emit(.orr(dst_ra.w(), .wzr, .{ .register = src_mat.ra.w() }));
4948 try src_mat.finish(isel);
4949 } else if (dst_int_info.bits <= 64 and src_int_info.bits <= 32) {
4950 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
4951 const src_vi = try isel.use(ty_op.operand);
4952 const src_mat = try src_vi.matReg(isel);
4953 try isel.emit(if (can_be_negative) .sbfm(dst_ra.x(), src_mat.ra.x(), .{
4954 .N = .doubleword,
4955 .immr = 0,
4956 .imms = @intCast(src_int_info.bits - 1),
4957 }) else .orr(dst_ra.w(), .wzr, .{ .register = src_mat.ra.w() }));
4958 try src_mat.finish(isel);
4959 } else if (dst_int_info.bits <= 32 and src_int_info.bits <= 128) {
4960 assert(src_int_info.bits > 64);
4961 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
4962 const src_vi = try isel.use(ty_op.operand);
4963
4964 var src_lo64_it = src_vi.field(src_ty, 0, 8);
4965 const src_lo64_vi = try src_lo64_it.only(isel);
4966 const src_lo64_mat = try src_lo64_vi.?.matReg(isel);
4967 try isel.emit(.orr(dst_ra.w(), .wzr, .{ .register = src_lo64_mat.ra.w() }));
4968 try src_lo64_mat.finish(isel);
4969 } else if (dst_int_info.bits <= 64 and src_int_info.bits <= 128) {
4970 assert(dst_int_info.bits > 32 and src_int_info.bits > 64);
4971 const src_vi = try isel.use(ty_op.operand);
4972
4973 var src_lo64_it = src_vi.field(src_ty, 0, 8);
4974 const src_lo64_vi = try src_lo64_it.only(isel);
4975 try dst_vi.value.copy(isel, dst_ty, src_lo64_vi.?);
4976 } else if (dst_int_info.bits <= 128 and src_int_info.bits <= 64) {
4977 assert(dst_int_info.bits > 64);
4978 const src_vi = try isel.use(ty_op.operand);
4979
4980 var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8);
4981 const dst_lo64_vi = try dst_lo64_it.only(isel);
4982 if (src_int_info.bits <= 32) unused_lo64: {
4983 const dst_lo64_ra = try dst_lo64_vi.?.defReg(isel) orelse break :unused_lo64;
4984 const src_mat = try src_vi.matReg(isel);
4985 try isel.emit(if (can_be_negative) .sbfm(dst_lo64_ra.x(), src_mat.ra.x(), .{
4986 .N = .doubleword,
4987 .immr = 0,
4988 .imms = @intCast(src_int_info.bits - 1),
4989 }) else .orr(dst_lo64_ra.w(), .wzr, .{ .register = src_mat.ra.w() }));
4990 try src_mat.finish(isel);
4991 } else try dst_lo64_vi.?.copy(isel, src_ty, src_vi);
4992
4993 var dst_hi64_it = dst_vi.value.field(dst_ty, 8, 8);
4994 const dst_hi64_vi = try dst_hi64_it.only(isel);
4995 const dst_hi64_ra = try dst_hi64_vi.?.defReg(isel);
4996 if (dst_hi64_ra) |dst_ra| switch (can_be_negative) {
4997 false => try isel.emit(.orr(dst_ra.x(), .xzr, .{ .register = .xzr })),
4998 true => {
4999 const src_mat = try src_vi.matReg(isel);
5000 try isel.emit(.sbfm(dst_ra.x(), src_mat.ra.x(), .{
5001 .N = .doubleword,
5002 .immr = @intCast(src_int_info.bits - 1),
5003 .imms = @intCast(src_int_info.bits - 1),
5004 }));
5005 try src_mat.finish(isel);
5006 },
5007 };
5008 } else return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });
5009 }
5010 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5011 },
5012 .trunc => |air_tag| {
5013 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
5014 defer dst_vi.value.deref(isel);
5015
5016 const ty_op = air.data(air.inst_index).ty_op;
5017 const dst_ty = ty_op.ty.toType();
5018 const src_ty = isel.air.typeOf(ty_op.operand, ip);
5019 if (!dst_ty.isAbiInt(zcu) or !src_ty.isAbiInt(zcu)) return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });
5020 const dst_int_info = dst_ty.intInfo(zcu);
5021 switch (dst_int_info.bits) {
5022 0 => unreachable,
5023 1...64 => |dst_bits| {
5024 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
5025 const src_vi = try isel.use(ty_op.operand);
5026 var src_part_it = src_vi.field(src_ty, 0, @min(src_vi.size(isel), 8));
5027 const src_part_vi = try src_part_it.only(isel);
5028 const src_part_mat = try src_part_vi.?.matReg(isel);
5029 try isel.emit(switch (dst_bits) {
5030 else => unreachable,
5031 1...31 => |bits| switch (dst_int_info.signedness) {
5032 .signed => .sbfm(dst_ra.w(), src_part_mat.ra.w(), .{
5033 .N = .word,
5034 .immr = 0,
5035 .imms = @intCast(bits - 1),
5036 }),
5037 .unsigned => .ubfm(dst_ra.w(), src_part_mat.ra.w(), .{
5038 .N = .word,
5039 .immr = 0,
5040 .imms = @intCast(bits - 1),
5041 }),
5042 },
5043 32 => .orr(dst_ra.w(), .wzr, .{ .register = src_part_mat.ra.w() }),
5044 33...63 => |bits| switch (dst_int_info.signedness) {
5045 .signed => .sbfm(dst_ra.x(), src_part_mat.ra.x(), .{
5046 .N = .doubleword,
5047 .immr = 0,
5048 .imms = @intCast(bits - 1),
5049 }),
5050 .unsigned => .ubfm(dst_ra.x(), src_part_mat.ra.x(), .{
5051 .N = .doubleword,
5052 .immr = 0,
5053 .imms = @intCast(bits - 1),
5054 }),
5055 },
5056 64 => .orr(dst_ra.x(), .xzr, .{ .register = src_part_mat.ra.x() }),
5057 });
5058 try src_part_mat.finish(isel);
5059 },
5060 65...128 => |dst_bits| switch (src_ty.intInfo(zcu).bits) {
5061 0 => unreachable,
5062 65...128 => {
5063 const src_vi = try isel.use(ty_op.operand);
5064 var dst_hi64_it = dst_vi.value.field(dst_ty, 8, 8);
5065 const dst_hi64_vi = try dst_hi64_it.only(isel);
5066 if (try dst_hi64_vi.?.defReg(isel)) |dst_hi64_ra| {
5067 var src_hi64_it = src_vi.field(src_ty, 8, 8);
5068 const src_hi64_vi = try src_hi64_it.only(isel);
5069 const src_hi64_mat = try src_hi64_vi.?.matReg(isel);
5070 try isel.emit(switch (dst_int_info.signedness) {
5071 .signed => .sbfm(dst_hi64_ra.x(), src_hi64_mat.ra.x(), .{
5072 .N = .doubleword,
5073 .immr = 0,
5074 .imms = @intCast(dst_bits - 64 - 1),
5075 }),
5076 .unsigned => .ubfm(dst_hi64_ra.x(), src_hi64_mat.ra.x(), .{
5077 .N = .doubleword,
5078 .immr = 0,
5079 .imms = @intCast(dst_bits - 64 - 1),
5080 }),
5081 });
5082 try src_hi64_mat.finish(isel);
5083 }
5084 var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8);
5085 const dst_lo64_vi = try dst_lo64_it.only(isel);
5086 if (try dst_lo64_vi.?.defReg(isel)) |dst_lo64_ra| {
5087 var src_lo64_it = src_vi.field(src_ty, 0, 8);
5088 const src_lo64_vi = try src_lo64_it.only(isel);
5089 try src_lo64_vi.?.liveOut(isel, dst_lo64_ra);
5090 }
5091 },
5092 else => return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }),
5093 },
5094 else => return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }),
5095 }
5096 }
5097 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5098 },
5099 .optional_payload_ptr => {
5100 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| {
5101 defer dst_vi.value.deref(isel);
5102 const ty_op = air.data(air.inst_index).ty_op;
5103 try dst_vi.value.move(isel, ty_op.operand);
5104 }
5105 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5106 },
5107 .optional_payload => {
5108 if (isel.live_values.fetchRemove(air.inst_index)) |payload_vi| unused: {
5109 defer payload_vi.value.deref(isel);
5110
5111 const ty_op = air.data(air.inst_index).ty_op;
5112 const opt_ty = isel.air.typeOf(ty_op.operand, ip);
5113 if (opt_ty.optionalReprIsPayload(zcu)) {
5114 try payload_vi.value.move(isel, ty_op.operand);
5115 break :unused;
5116 }
5117
5118 const opt_vi = try isel.use(ty_op.operand);
5119 var payload_part_it = opt_vi.field(opt_ty, 0, payload_vi.value.size(isel));
5120 const payload_part_vi = try payload_part_it.only(isel);
5121 try payload_vi.value.copy(isel, ty_op.ty.toType(), payload_part_vi.?);
5122 }
5123 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5124 },
5125 .wrap_optional => {
5126 if (isel.live_values.fetchRemove(air.inst_index)) |opt_vi| unused: {
5127 defer opt_vi.value.deref(isel);
5128
5129 const ty_op = air.data(air.inst_index).ty_op;
5130 if (ty_op.ty.toType().optionalReprIsPayload(zcu)) {
5131 try opt_vi.value.move(isel, ty_op.operand);
5132 break :unused;
5133 }
5134
5135 const payload_size = isel.air.typeOf(ty_op.operand, ip).abiSize(zcu);
5136 var payload_part_it = opt_vi.value.field(ty_op.ty.toType(), 0, payload_size);
5137 const payload_part_vi = try payload_part_it.only(isel);
5138 try payload_part_vi.?.move(isel, ty_op.operand);
5139 var has_value_part_it = opt_vi.value.field(ty_op.ty.toType(), payload_size, 1);
5140 const has_value_part_vi = try has_value_part_it.only(isel);
5141 const has_value_part_ra = try has_value_part_vi.?.defReg(isel) orelse break :unused;
5142 try isel.emit(.movz(has_value_part_ra.w(), 1, .{ .lsl = .@"0" }));
5143 }
5144 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5145 },
5146 .unwrap_errunion_payload => {
5147 if (isel.live_values.fetchRemove(air.inst_index)) |payload_vi| {
5148 defer payload_vi.value.deref(isel);
5149
5150 const ty_op = air.data(air.inst_index).ty_op;
5151 const error_union_ty = isel.air.typeOf(ty_op.operand, ip);
5152
5153 const error_union_vi = try isel.use(ty_op.operand);
5154 var payload_part_it = error_union_vi.field(
5155 error_union_ty,
5156 codegen.errUnionPayloadOffset(ty_op.ty.toType(), zcu),
5157 payload_vi.value.size(isel),
5158 );
5159 const payload_part_vi = try payload_part_it.only(isel);
5160 try payload_vi.value.copy(isel, ty_op.ty.toType(), payload_part_vi.?);
5161 }
5162 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5163 },
5164 .unwrap_errunion_err => {
5165 if (isel.live_values.fetchRemove(air.inst_index)) |error_set_vi| {
5166 defer error_set_vi.value.deref(isel);
5167
5168 const ty_op = air.data(air.inst_index).ty_op;
5169 const error_union_ty = isel.air.typeOf(ty_op.operand, ip);
5170
5171 const error_union_vi = try isel.use(ty_op.operand);
5172 var error_set_part_it = error_union_vi.field(
5173 error_union_ty,
5174 codegen.errUnionErrorOffset(error_union_ty.errorUnionPayload(zcu), zcu),
5175 error_set_vi.value.size(isel),
5176 );
5177 const error_set_part_vi = try error_set_part_it.only(isel);
5178 try error_set_vi.value.copy(isel, ty_op.ty.toType(), error_set_part_vi.?);
5179 }
5180 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5181 },
5182 .wrap_errunion_payload => {
5183 if (isel.live_values.fetchRemove(air.inst_index)) |error_union_vi| {
5184 defer error_union_vi.value.deref(isel);
5185
5186 const ty_op = air.data(air.inst_index).ty_op;
5187 const error_union_ty = ty_op.ty.toType();
5188 const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type;
5189 const error_set_ty: ZigType = .fromInterned(error_union_info.error_set_type);
5190 const payload_ty: ZigType = .fromInterned(error_union_info.payload_type);
5191 const error_set_offset = codegen.errUnionErrorOffset(payload_ty, zcu);
5192 const payload_offset = codegen.errUnionPayloadOffset(payload_ty, zcu);
5193 const error_set_size = error_set_ty.abiSize(zcu);
5194 const payload_size = payload_ty.abiSize(zcu);
5195
5196 var payload_part_it = error_union_vi.value.field(error_union_ty, payload_offset, payload_size);
5197 const payload_part_vi = try payload_part_it.only(isel);
5198 try payload_part_vi.?.move(isel, ty_op.operand);
5199 var error_set_part_it = error_union_vi.value.field(error_union_ty, error_set_offset, error_set_size);
5200 const error_set_part_vi = try error_set_part_it.only(isel);
5201 if (try error_set_part_vi.?.defReg(isel)) |error_set_part_ra| try isel.emit(switch (error_set_size) {
5202 else => unreachable,
5203 1...4 => .orr(error_set_part_ra.w(), .wzr, .{ .register = .wzr }),
5204 5...8 => .orr(error_set_part_ra.x(), .xzr, .{ .register = .xzr }),
5205 });
5206 }
5207 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5208 },
5209 .wrap_errunion_err => {
5210 if (isel.live_values.fetchRemove(air.inst_index)) |error_union_vi| {
5211 defer error_union_vi.value.deref(isel);
5212
5213 const ty_op = air.data(air.inst_index).ty_op;
5214 const error_union_ty = ty_op.ty.toType();
5215 const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type;
5216 const error_set_ty: ZigType = .fromInterned(error_union_info.error_set_type);
5217 const payload_ty: ZigType = .fromInterned(error_union_info.payload_type);
5218 const error_set_offset = codegen.errUnionErrorOffset(payload_ty, zcu);
5219 const payload_offset = codegen.errUnionPayloadOffset(payload_ty, zcu);
5220 const error_set_size = error_set_ty.abiSize(zcu);
5221 const payload_size = payload_ty.abiSize(zcu);
5222
5223 if (payload_size > 0) {
5224 var payload_part_it = error_union_vi.value.field(error_union_ty, payload_offset, payload_size);
5225 const payload_part_vi = try payload_part_it.only(isel);
5226 if (try payload_part_vi.?.defReg(isel)) |payload_part_ra| try isel.emit(switch (payload_size) {
5227 else => unreachable,
5228 1...4 => .orr(payload_part_ra.w(), .wzr, .{ .immediate = .{
5229 .N = .word,
5230 .immr = 0b000001,
5231 .imms = 0b111100,
5232 } }),
5233 5...8 => .orr(payload_part_ra.x(), .xzr, .{ .immediate = .{
5234 .N = .word,
5235 .immr = 0b000001,
5236 .imms = 0b111100,
5237 } }),
5238 });
5239 }
5240 var error_set_part_it = error_union_vi.value.field(error_union_ty, error_set_offset, error_set_size);
5241 const error_set_part_vi = try error_set_part_it.only(isel);
5242 try error_set_part_vi.?.move(isel, ty_op.operand);
5243 }
5244 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5245 },
5246 .struct_field_ptr => {
5247 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
5248 defer dst_vi.value.deref(isel);
5249 const ty_pl = air.data(air.inst_index).ty_pl;
5250 const extra = isel.air.extraData(Air.StructField, ty_pl.payload).data;
5251 switch (codegen.fieldOffset(
5252 isel.air.typeOf(extra.struct_operand, ip),
5253 ty_pl.ty.toType(),
5254 extra.field_index,
5255 zcu,
5256 )) {
5257 0 => try dst_vi.value.move(isel, extra.struct_operand),
5258 else => |field_offset| {
5259 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
5260 const src_vi = try isel.use(extra.struct_operand);
5261 const src_mat = try src_vi.matReg(isel);
5262 const lo12: u12 = @truncate(field_offset >> 0);
5263 const hi12: u12 = @intCast(field_offset >> 12);
5264 if (hi12 > 0) try isel.emit(.add(
5265 dst_ra.x(),
5266 if (lo12 > 0) dst_ra.x() else src_mat.ra.x(),
5267 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
5268 ));
5269 if (lo12 > 0) try isel.emit(.add(dst_ra.x(), src_mat.ra.x(), .{ .immediate = lo12 }));
5270 try src_mat.finish(isel);
5271 },
5272 }
5273 }
5274 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5275 },
5276 .struct_field_ptr_index_0,
5277 .struct_field_ptr_index_1,
5278 .struct_field_ptr_index_2,
5279 .struct_field_ptr_index_3,
5280 => |air_tag| {
5281 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
5282 defer dst_vi.value.deref(isel);
5283 const ty_op = air.data(air.inst_index).ty_op;
5284 switch (codegen.fieldOffset(
5285 isel.air.typeOf(ty_op.operand, ip),
5286 ty_op.ty.toType(),
5287 switch (air_tag) {
5288 else => unreachable,
5289 .struct_field_ptr_index_0 => 0,
5290 .struct_field_ptr_index_1 => 1,
5291 .struct_field_ptr_index_2 => 2,
5292 .struct_field_ptr_index_3 => 3,
5293 },
5294 zcu,
5295 )) {
5296 0 => try dst_vi.value.move(isel, ty_op.operand),
5297 else => |field_offset| {
5298 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
5299 const src_vi = try isel.use(ty_op.operand);
5300 const src_mat = try src_vi.matReg(isel);
5301 const lo12: u12 = @truncate(field_offset >> 0);
5302 const hi12: u12 = @intCast(field_offset >> 12);
5303 if (hi12 > 0) try isel.emit(.add(
5304 dst_ra.x(),
5305 if (lo12 > 0) dst_ra.x() else src_mat.ra.x(),
5306 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
5307 ));
5308 if (lo12 > 0) try isel.emit(.add(dst_ra.x(), src_mat.ra.x(), .{ .immediate = lo12 }));
5309 try src_mat.finish(isel);
5310 },
5311 }
5312 }
5313 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5314 },
5315 .struct_field_val => {
5316 if (isel.live_values.fetchRemove(air.inst_index)) |field_vi| {
5317 defer field_vi.value.deref(isel);
5318
5319 const ty_pl = air.data(air.inst_index).ty_pl;
5320 const extra = isel.air.extraData(Air.StructField, ty_pl.payload).data;
5321 const agg_ty = isel.air.typeOf(extra.struct_operand, ip);
5322 const field_ty = ty_pl.ty.toType();
5323 const field_bit_offset, const field_bit_size, const is_packed = switch (agg_ty.containerLayout(zcu)) {
5324 .auto, .@"extern" => .{
5325 8 * agg_ty.structFieldOffset(extra.field_index, zcu),
5326 8 * field_ty.abiSize(zcu),
5327 false,
5328 },
5329 .@"packed" => .{
5330 if (zcu.typeToPackedStruct(agg_ty)) |loaded_struct|
5331 zcu.structPackedFieldBitOffset(loaded_struct, extra.field_index)
5332 else
5333 0,
5334 field_ty.bitSize(zcu),
5335 true,
5336 },
5337 };
5338 if (is_packed) return isel.fail("packed field of {f}", .{
5339 isel.fmtType(agg_ty),
5340 });
5341
5342 const agg_vi = try isel.use(extra.struct_operand);
5343 var agg_part_it = agg_vi.field(agg_ty, @divExact(field_bit_offset, 8), @divExact(field_bit_size, 8));
5344 while (try agg_part_it.next(isel)) |agg_part| {
5345 var field_part_it = field_vi.value.field(ty_pl.ty.toType(), agg_part.offset, agg_part.vi.size(isel));
5346 const field_part_vi = try field_part_it.only(isel);
5347 if (field_part_vi.? == agg_part.vi) continue;
5348 var field_subpart_it = field_part_vi.?.parts(isel);
5349 const field_part_offset = if (field_subpart_it.only()) |field_subpart_vi|
5350 field_subpart_vi.get(isel).offset_from_parent
5351 else
5352 0;
5353 while (field_subpart_it.next()) |field_subpart_vi| {
5354 const field_subpart_ra = try field_subpart_vi.defReg(isel) orelse continue;
5355 const field_subpart_offset, const field_subpart_size = field_subpart_vi.position(isel);
5356 var agg_subpart_it = agg_part.vi.field(
5357 field_ty,
5358 agg_part.offset + field_subpart_offset - field_part_offset,
5359 field_subpart_size,
5360 );
5361 const agg_subpart_vi = try agg_subpart_it.only(isel);
5362 try agg_subpart_vi.?.liveOut(isel, field_subpart_ra);
5363 }
5364 }
5365 }
5366 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5367 },
5368 .slice => {
5369 if (isel.live_values.fetchRemove(air.inst_index)) |slice_vi| {
5370 defer slice_vi.value.deref(isel);
5371 const ty_pl = air.data(air.inst_index).ty_pl;
5372 const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data;
5373 var ptr_part_it = slice_vi.value.field(ty_pl.ty.toType(), 0, 8);
5374 const ptr_part_vi = try ptr_part_it.only(isel);
5375 try ptr_part_vi.?.move(isel, bin_op.lhs);
5376 var len_part_it = slice_vi.value.field(ty_pl.ty.toType(), 8, 8);
5377 const len_part_vi = try len_part_it.only(isel);
5378 try len_part_vi.?.move(isel, bin_op.rhs);
5379 }
5380 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5381 },
5382 .slice_len => {
5383 if (isel.live_values.fetchRemove(air.inst_index)) |len_vi| {
5384 defer len_vi.value.deref(isel);
5385 const ty_op = air.data(air.inst_index).ty_op;
5386 const slice_vi = try isel.use(ty_op.operand);
5387 var len_part_it = slice_vi.field(isel.air.typeOf(ty_op.operand, ip), 8, 8);
5388 const len_part_vi = try len_part_it.only(isel);
5389 try len_vi.value.copy(isel, ty_op.ty.toType(), len_part_vi.?);
5390 }
5391 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5392 },
5393 .slice_ptr => {
5394 if (isel.live_values.fetchRemove(air.inst_index)) |ptr_vi| {
5395 defer ptr_vi.value.deref(isel);
5396 const ty_op = air.data(air.inst_index).ty_op;
5397 const slice_vi = try isel.use(ty_op.operand);
5398 var ptr_part_it = slice_vi.field(isel.air.typeOf(ty_op.operand, ip), 0, 8);
5399 const ptr_part_vi = try ptr_part_it.only(isel);
5400 try ptr_vi.value.copy(isel, ty_op.ty.toType(), ptr_part_vi.?);
5401 }
5402 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5403 },
5404 .array_elem_val => {
5405 if (isel.live_values.fetchRemove(air.inst_index)) |elem_vi| unused: {
5406 defer elem_vi.value.deref(isel);
5407
5408 const bin_op = air.data(air.inst_index).bin_op;
5409 const array_ty = isel.air.typeOf(bin_op.lhs, ip);
5410 const elem_ty = array_ty.childType(zcu);
5411 const elem_size = elem_ty.abiSize(zcu);
5412 if (elem_size <= 16 and array_ty.arrayLenIncludingSentinel(zcu) <= Value.max_parts) if (bin_op.rhs.toInterned()) |index_val| {
5413 const elem_offset = elem_size * Constant.fromInterned(index_val).toUnsignedInt(zcu);
5414 const array_vi = try isel.use(bin_op.lhs);
5415 var elem_part_it = array_vi.field(array_ty, elem_offset, elem_size);
5416 const elem_part_vi = try elem_part_it.only(isel);
5417 try elem_vi.value.copy(isel, elem_ty, elem_part_vi.?);
5418 break :unused;
5419 };
5420 switch (elem_size) {
5421 0 => unreachable,
5422 1, 2, 4, 8 => {
5423 const elem_ra = try elem_vi.value.defReg(isel) orelse break :unused;
5424 const array_ptr_ra = try isel.allocIntReg();
5425 defer isel.freeReg(array_ptr_ra);
5426 const index_vi = try isel.use(bin_op.rhs);
5427 const index_mat = try index_vi.matReg(isel);
5428 try isel.emit(switch (elem_size) {
5429 else => unreachable,
5430 1 => if (elem_vi.value.isVector(isel)) .ldr(elem_ra.b(), .{ .extended_register = .{
5431 .base = array_ptr_ra.x(),
5432 .index = index_mat.ra.x(),
5433 .extend = .{ .lsl = 0 },
5434 } }) else switch (elem_vi.value.signedness(isel)) {
5435 .signed => .ldrsb(elem_ra.w(), .{ .extended_register = .{
5436 .base = array_ptr_ra.x(),
5437 .index = index_mat.ra.x(),
5438 .extend = .{ .lsl = 0 },
5439 } }),
5440 .unsigned => .ldrb(elem_ra.w(), .{ .extended_register = .{
5441 .base = array_ptr_ra.x(),
5442 .index = index_mat.ra.x(),
5443 .extend = .{ .lsl = 0 },
5444 } }),
5445 },
5446 2 => if (elem_vi.value.isVector(isel)) .ldr(elem_ra.h(), .{ .extended_register = .{
5447 .base = array_ptr_ra.x(),
5448 .index = index_mat.ra.x(),
5449 .extend = .{ .lsl = 1 },
5450 } }) else switch (elem_vi.value.signedness(isel)) {
5451 .signed => .ldrsh(elem_ra.w(), .{ .extended_register = .{
5452 .base = array_ptr_ra.x(),
5453 .index = index_mat.ra.x(),
5454 .extend = .{ .lsl = 1 },
5455 } }),
5456 .unsigned => .ldrh(elem_ra.w(), .{ .extended_register = .{
5457 .base = array_ptr_ra.x(),
5458 .index = index_mat.ra.x(),
5459 .extend = .{ .lsl = 1 },
5460 } }),
5461 },
5462 4 => .ldr(if (elem_vi.value.isVector(isel)) elem_ra.s() else elem_ra.w(), .{ .extended_register = .{
5463 .base = array_ptr_ra.x(),
5464 .index = index_mat.ra.x(),
5465 .extend = .{ .lsl = 2 },
5466 } }),
5467 8 => .ldr(if (elem_vi.value.isVector(isel)) elem_ra.d() else elem_ra.x(), .{ .extended_register = .{
5468 .base = array_ptr_ra.x(),
5469 .index = index_mat.ra.x(),
5470 .extend = .{ .lsl = 3 },
5471 } }),
5472 16 => .ldr(elem_ra.q(), .{ .extended_register = .{
5473 .base = array_ptr_ra.x(),
5474 .index = index_mat.ra.x(),
5475 .extend = .{ .lsl = 4 },
5476 } }),
5477 });
5478 try index_mat.finish(isel);
5479 const array_vi = try isel.use(bin_op.lhs);
5480 try array_vi.address(isel, 0, array_ptr_ra);
5481 },
5482 else => {
5483 const ptr_ra = try isel.allocIntReg();
5484 defer isel.freeReg(ptr_ra);
5485 if (!try elem_vi.value.load(isel, elem_ty, ptr_ra, .{})) break :unused;
5486 const index_vi = try isel.use(bin_op.rhs);
5487 try isel.elemPtr(ptr_ra, ptr_ra, .add, elem_size, index_vi);
5488 const array_vi = try isel.use(bin_op.lhs);
5489 try array_vi.address(isel, 0, ptr_ra);
5490 },
5491 }
5492 }
5493 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5494 },
5495 .slice_elem_val => {
5496 if (isel.live_values.fetchRemove(air.inst_index)) |elem_vi| unused: {
5497 defer elem_vi.value.deref(isel);
5498
5499 const bin_op = air.data(air.inst_index).bin_op;
5500 const slice_ty = isel.air.typeOf(bin_op.lhs, ip);
5501 const ptr_info = slice_ty.ptrInfo(zcu);
5502 const elem_size = elem_vi.value.size(isel);
5503 const elem_is_vector = elem_vi.value.isVector(isel);
5504 if (switch (elem_size) {
5505 0 => unreachable,
5506 1, 2, 4, 8 => true,
5507 16 => elem_is_vector,
5508 else => false,
5509 }) {
5510 const elem_ra = try elem_vi.value.defReg(isel) orelse break :unused;
5511 const slice_vi = try isel.use(bin_op.lhs);
5512 const index_vi = try isel.use(bin_op.rhs);
5513 var ptr_part_it = slice_vi.field(slice_ty, 0, 8);
5514 const ptr_part_vi = try ptr_part_it.only(isel);
5515 const base_mat = try ptr_part_vi.?.matReg(isel);
5516 const index_mat = try index_vi.matReg(isel);
5517 try isel.emit(switch (elem_size) {
5518 else => unreachable,
5519 1 => if (elem_is_vector) .ldr(elem_ra.b(), .{ .extended_register = .{
5520 .base = base_mat.ra.x(),
5521 .index = index_mat.ra.x(),
5522 .extend = .{ .lsl = 0 },
5523 } }) else switch (elem_vi.value.signedness(isel)) {
5524 .signed => .ldrsb(elem_ra.w(), .{ .extended_register = .{
5525 .base = base_mat.ra.x(),
5526 .index = index_mat.ra.x(),
5527 .extend = .{ .lsl = 0 },
5528 } }),
5529 .unsigned => .ldrb(elem_ra.w(), .{ .extended_register = .{
5530 .base = base_mat.ra.x(),
5531 .index = index_mat.ra.x(),
5532 .extend = .{ .lsl = 0 },
5533 } }),
5534 },
5535 2 => if (elem_is_vector) .ldr(elem_ra.h(), .{ .extended_register = .{
5536 .base = base_mat.ra.x(),
5537 .index = index_mat.ra.x(),
5538 .extend = .{ .lsl = 0 },
5539 } }) else switch (elem_vi.value.signedness(isel)) {
5540 .signed => .ldrsh(elem_ra.w(), .{ .extended_register = .{
5541 .base = base_mat.ra.x(),
5542 .index = index_mat.ra.x(),
5543 .extend = .{ .lsl = 1 },
5544 } }),
5545 .unsigned => .ldrh(elem_ra.w(), .{ .extended_register = .{
5546 .base = base_mat.ra.x(),
5547 .index = index_mat.ra.x(),
5548 .extend = .{ .lsl = 1 },
5549 } }),
5550 },
5551 4 => .ldr(if (elem_is_vector) elem_ra.s() else elem_ra.w(), .{ .extended_register = .{
5552 .base = base_mat.ra.x(),
5553 .index = index_mat.ra.x(),
5554 .extend = .{ .lsl = 2 },
5555 } }),
5556 8 => .ldr(if (elem_is_vector) elem_ra.d() else elem_ra.x(), .{ .extended_register = .{
5557 .base = base_mat.ra.x(),
5558 .index = index_mat.ra.x(),
5559 .extend = .{ .lsl = 3 },
5560 } }),
5561 16 => .ldr(elem_ra.q(), .{ .extended_register = .{
5562 .base = base_mat.ra.x(),
5563 .index = index_mat.ra.x(),
5564 .extend = .{ .lsl = 4 },
5565 } }),
5566 });
5567 try index_mat.finish(isel);
5568 try base_mat.finish(isel);
5569 break :unused;
5570 } else {
5571 const elem_ptr_ra = try isel.allocIntReg();
5572 defer isel.freeReg(elem_ptr_ra);
5573 if (!try elem_vi.value.load(isel, slice_ty.elemType2(zcu), elem_ptr_ra, .{
5574 .@"volatile" = ptr_info.flags.is_volatile,
5575 })) break :unused;
5576 const slice_vi = try isel.use(bin_op.lhs);
5577 var ptr_part_it = slice_vi.field(slice_ty, 0, 8);
5578 const ptr_part_vi = try ptr_part_it.only(isel);
5579 const ptr_part_mat = try ptr_part_vi.?.matReg(isel);
5580 const index_vi = try isel.use(bin_op.rhs);
5581 try isel.elemPtr(elem_ptr_ra, ptr_part_mat.ra, .add, elem_size, index_vi);
5582 try ptr_part_mat.finish(isel);
5583 }
5584 }
5585 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5586 },
5587 .slice_elem_ptr => {
5588 if (isel.live_values.fetchRemove(air.inst_index)) |elem_ptr_vi| unused: {
5589 defer elem_ptr_vi.value.deref(isel);
5590 const elem_ptr_ra = try elem_ptr_vi.value.defReg(isel) orelse break :unused;
5591
5592 const ty_pl = air.data(air.inst_index).ty_pl;
5593 const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data;
5594 const elem_size = ty_pl.ty.toType().childType(zcu).abiSize(zcu);
5595
5596 const slice_vi = try isel.use(bin_op.lhs);
5597 var ptr_part_it = slice_vi.field(isel.air.typeOf(bin_op.lhs, ip), 0, 8);
5598 const ptr_part_vi = try ptr_part_it.only(isel);
5599 const ptr_part_mat = try ptr_part_vi.?.matReg(isel);
5600 const index_vi = try isel.use(bin_op.rhs);
5601 try isel.elemPtr(elem_ptr_ra, ptr_part_mat.ra, .add, elem_size, index_vi);
5602 try ptr_part_mat.finish(isel);
5603 }
5604 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5605 },
5606 .ptr_elem_val => {
5607 if (isel.live_values.fetchRemove(air.inst_index)) |elem_vi| unused: {
5608 defer elem_vi.value.deref(isel);
5609
5610 const bin_op = air.data(air.inst_index).bin_op;
5611 const ptr_ty = isel.air.typeOf(bin_op.lhs, ip);
5612 const ptr_info = ptr_ty.ptrInfo(zcu);
5613 const elem_size = elem_vi.value.size(isel);
5614 switch (elem_size) {
5615 0 => unreachable,
5616 1, 2, 4, 8 => {
5617 const elem_ra = try elem_vi.value.defReg(isel) orelse break :unused;
5618 const base_vi = try isel.use(bin_op.lhs);
5619 const index_vi = try isel.use(bin_op.rhs);
5620 const base_mat = try base_vi.matReg(isel);
5621 const index_mat = try index_vi.matReg(isel);
5622 try isel.emit(switch (elem_size) {
5623 else => unreachable,
5624 1 => switch (elem_vi.value.signedness(isel)) {
5625 .signed => .ldrsb(elem_ra.w(), .{ .extended_register = .{
5626 .base = base_mat.ra.x(),
5627 .index = index_mat.ra.x(),
5628 .extend = .{ .lsl = 0 },
5629 } }),
5630 .unsigned => .ldrb(elem_ra.w(), .{ .extended_register = .{
5631 .base = base_mat.ra.x(),
5632 .index = index_mat.ra.x(),
5633 .extend = .{ .lsl = 0 },
5634 } }),
5635 },
5636 2 => switch (elem_vi.value.signedness(isel)) {
5637 .signed => .ldrsh(elem_ra.w(), .{ .extended_register = .{
5638 .base = base_mat.ra.x(),
5639 .index = index_mat.ra.x(),
5640 .extend = .{ .lsl = 1 },
5641 } }),
5642 .unsigned => .ldrh(elem_ra.w(), .{ .extended_register = .{
5643 .base = base_mat.ra.x(),
5644 .index = index_mat.ra.x(),
5645 .extend = .{ .lsl = 1 },
5646 } }),
5647 },
5648 4 => .ldr(elem_ra.w(), .{ .extended_register = .{
5649 .base = base_mat.ra.x(),
5650 .index = index_mat.ra.x(),
5651 .extend = .{ .lsl = 2 },
5652 } }),
5653 8 => .ldr(elem_ra.x(), .{ .extended_register = .{
5654 .base = base_mat.ra.x(),
5655 .index = index_mat.ra.x(),
5656 .extend = .{ .lsl = 3 },
5657 } }),
5658 });
5659 try index_mat.finish(isel);
5660 try base_mat.finish(isel);
5661 },
5662 else => {
5663 const elem_ptr_ra = try isel.allocIntReg();
5664 defer isel.freeReg(elem_ptr_ra);
5665 if (!try elem_vi.value.load(isel, ptr_ty.elemType2(zcu), elem_ptr_ra, .{
5666 .@"volatile" = ptr_info.flags.is_volatile,
5667 })) break :unused;
5668 const base_vi = try isel.use(bin_op.lhs);
5669 const base_mat = try base_vi.matReg(isel);
5670 const index_vi = try isel.use(bin_op.rhs);
5671 try isel.elemPtr(elem_ptr_ra, base_mat.ra, .add, elem_size, index_vi);
5672 try base_mat.finish(isel);
5673 },
5674 }
5675 }
5676 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5677 },
5678 .ptr_elem_ptr => {
5679 if (isel.live_values.fetchRemove(air.inst_index)) |elem_ptr_vi| unused: {
5680 defer elem_ptr_vi.value.deref(isel);
5681 const elem_ptr_ra = try elem_ptr_vi.value.defReg(isel) orelse break :unused;
5682
5683 const ty_pl = air.data(air.inst_index).ty_pl;
5684 const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data;
5685 const elem_size = ty_pl.ty.toType().childType(zcu).abiSize(zcu);
5686
5687 const base_vi = try isel.use(bin_op.lhs);
5688 const base_mat = try base_vi.matReg(isel);
5689 const index_vi = try isel.use(bin_op.rhs);
5690 try isel.elemPtr(elem_ptr_ra, base_mat.ra, .add, elem_size, index_vi);
5691 try base_mat.finish(isel);
5692 }
5693 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5694 },
5695 .array_to_slice => {
5696 if (isel.live_values.fetchRemove(air.inst_index)) |slice_vi| {
5697 defer slice_vi.value.deref(isel);
5698 const ty_op = air.data(air.inst_index).ty_op;
5699 var ptr_part_it = slice_vi.value.field(ty_op.ty.toType(), 0, 8);
5700 const ptr_part_vi = try ptr_part_it.only(isel);
5701 try ptr_part_vi.?.move(isel, ty_op.operand);
5702 var len_part_it = slice_vi.value.field(ty_op.ty.toType(), 8, 8);
5703 const len_part_vi = try len_part_it.only(isel);
5704 if (try len_part_vi.?.defReg(isel)) |len_ra| try isel.movImmediate(
5705 len_ra.x(),
5706 isel.air.typeOf(ty_op.operand, ip).childType(zcu).arrayLen(zcu),
5707 );
5708 }
5709 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5710 },
5711 .int_from_float, .int_from_float_optimized => |air_tag| {
5712 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
5713 defer dst_vi.value.deref(isel);
5714
5715 const ty_op = air.data(air.inst_index).ty_op;
5716 const dst_ty = ty_op.ty.toType();
5717 const src_ty = isel.air.typeOf(ty_op.operand, ip);
5718 if (!dst_ty.isAbiInt(zcu)) return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });
5719 const dst_int_info = dst_ty.intInfo(zcu);
5720 const src_bits = src_ty.floatBits(isel.target);
5721 switch (@max(dst_int_info.bits, src_bits)) {
5722 0 => unreachable,
5723 1...64 => {
5724 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
5725 const need_fcvt = switch (src_bits) {
5726 else => unreachable,
5727 16 => !isel.target.cpu.has(.aarch64, .fullfp16),
5728 32, 64 => false,
5729 };
5730 const src_vi = try isel.use(ty_op.operand);
5731 const src_mat = try src_vi.matReg(isel);
5732 const src_ra = if (need_fcvt) try isel.allocVecReg() else src_mat.ra;
5733 defer if (need_fcvt) isel.freeReg(src_ra);
5734 const dst_reg = switch (dst_int_info.bits) {
5735 else => unreachable,
5736 1...32 => dst_ra.w(),
5737 33...64 => dst_ra.x(),
5738 };
5739 const src_reg = switch (src_bits) {
5740 else => unreachable,
5741 16 => if (need_fcvt) src_ra.s() else src_ra.h(),
5742 32 => src_ra.s(),
5743 64 => src_ra.d(),
5744 };
5745 try isel.emit(switch (dst_int_info.signedness) {
5746 .signed => .fcvtzs(dst_reg, src_reg),
5747 .unsigned => .fcvtzu(dst_reg, src_reg),
5748 });
5749 if (need_fcvt) try isel.emit(.fcvt(src_reg, src_mat.ra.h()));
5750 try src_mat.finish(isel);
5751 },
5752 65...128 => {
5753 try call.prepareReturn(isel);
5754 switch (dst_int_info.bits) {
5755 else => unreachable,
5756 1...64 => try call.returnLiveIn(isel, dst_vi.value, .r0),
5757 65...128 => {
5758 var dst_hi64_it = dst_vi.value.field(dst_ty, 8, 8);
5759 const dst_hi64_vi = try dst_hi64_it.only(isel);
5760 try call.returnLiveIn(isel, dst_hi64_vi.?, .r1);
5761 var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8);
5762 const dst_lo64_vi = try dst_lo64_it.only(isel);
5763 try call.returnLiveIn(isel, dst_lo64_vi.?, .r0);
5764 },
5765 }
5766 try call.finishReturn(isel);
5767
5768 try call.prepareCallee(isel);
5769 try isel.global_relocs.append(gpa, .{
5770 .global = switch (dst_int_info.bits) {
5771 else => unreachable,
5772 1...32 => switch (dst_int_info.signedness) {
5773 .signed => switch (src_bits) {
5774 else => unreachable,
5775 16 => "__fixhfsi",
5776 32 => "__fixsfsi",
5777 64 => "__fixdfsi",
5778 80 => "__fixxfsi",
5779 128 => "__fixtfsi",
5780 },
5781 .unsigned => switch (src_bits) {
5782 else => unreachable,
5783 16 => "__fixunshfsi",
5784 32 => "__fixunssfsi",
5785 64 => "__fixunsdfsi",
5786 80 => "__fixunsxfsi",
5787 128 => "__fixunstfsi",
5788 },
5789 },
5790 33...64 => switch (dst_int_info.signedness) {
5791 .signed => switch (src_bits) {
5792 else => unreachable,
5793 16 => "__fixhfdi",
5794 32 => "__fixsfdi",
5795 64 => "__fixdfdi",
5796 80 => "__fixxfdi",
5797 128 => "__fixtfdi",
5798 },
5799 .unsigned => switch (src_bits) {
5800 else => unreachable,
5801 16 => "__fixunshfdi",
5802 32 => "__fixunssfdi",
5803 64 => "__fixunsdfdi",
5804 80 => "__fixunsxfdi",
5805 128 => "__fixunstfdi",
5806 },
5807 },
5808 65...128 => switch (dst_int_info.signedness) {
5809 .signed => switch (src_bits) {
5810 else => unreachable,
5811 16 => "__fixhfti",
5812 32 => "__fixsfti",
5813 64 => "__fixdfti",
5814 80 => "__fixxfti",
5815 128 => "__fixtfti",
5816 },
5817 .unsigned => switch (src_bits) {
5818 else => unreachable,
5819 16 => "__fixunshfti",
5820 32 => "__fixunssfti",
5821 64 => "__fixunsdfti",
5822 80 => "__fixunsxfti",
5823 128 => "__fixunstfti",
5824 },
5825 },
5826 },
5827 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
5828 });
5829 try isel.emit(.bl(0));
5830 try call.finishCallee(isel);
5831
5832 try call.prepareParams(isel);
5833 const src_vi = try isel.use(ty_op.operand);
5834 switch (src_bits) {
5835 else => unreachable,
5836 16, 32, 64, 128 => try call.paramLiveOut(isel, src_vi, .v0),
5837 80 => {
5838 var src_hi16_it = src_vi.field(src_ty, 8, 8);
5839 const src_hi16_vi = try src_hi16_it.only(isel);
5840 try call.paramLiveOut(isel, src_hi16_vi.?, .r1);
5841 var src_lo64_it = src_vi.field(src_ty, 0, 8);
5842 const src_lo64_vi = try src_lo64_it.only(isel);
5843 try call.paramLiveOut(isel, src_lo64_vi.?, .r0);
5844 },
5845 }
5846 try call.finishParams(isel);
5847 },
5848 else => return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }),
5849 }
5850 }
5851 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5852 },
5853 .float_from_int => |air_tag| {
5854 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
5855 defer dst_vi.value.deref(isel);
5856
5857 const ty_op = air.data(air.inst_index).ty_op;
5858 const dst_ty = ty_op.ty.toType();
5859 const src_ty = isel.air.typeOf(ty_op.operand, ip);
5860 const dst_bits = dst_ty.floatBits(isel.target);
5861 if (!src_ty.isAbiInt(zcu)) return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });
5862 const src_int_info = src_ty.intInfo(zcu);
5863 switch (@max(dst_bits, src_int_info.bits)) {
5864 0 => unreachable,
5865 1...64 => {
5866 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
5867 const need_fcvt = switch (dst_bits) {
5868 else => unreachable,
5869 16 => !isel.target.cpu.has(.aarch64, .fullfp16),
5870 32, 64 => false,
5871 };
5872 if (need_fcvt) try isel.emit(.fcvt(dst_ra.h(), dst_ra.s()));
5873 const src_vi = try isel.use(ty_op.operand);
5874 const src_mat = try src_vi.matReg(isel);
5875 const dst_reg = switch (dst_bits) {
5876 else => unreachable,
5877 16 => if (need_fcvt) dst_ra.s() else dst_ra.h(),
5878 32 => dst_ra.s(),
5879 64 => dst_ra.d(),
5880 };
5881 const src_reg = switch (src_int_info.bits) {
5882 else => unreachable,
5883 1...32 => src_mat.ra.w(),
5884 33...64 => src_mat.ra.x(),
5885 };
5886 try isel.emit(switch (src_int_info.signedness) {
5887 .signed => .scvtf(dst_reg, src_reg),
5888 .unsigned => .ucvtf(dst_reg, src_reg),
5889 });
5890 try src_mat.finish(isel);
5891 },
5892 65...128 => {
5893 try call.prepareReturn(isel);
5894 switch (dst_bits) {
5895 else => unreachable,
5896 16, 32, 64, 128 => try call.returnLiveIn(isel, dst_vi.value, .v0),
5897 80 => {
5898 var dst_hi16_it = dst_vi.value.field(dst_ty, 8, 8);
5899 const dst_hi16_vi = try dst_hi16_it.only(isel);
5900 try call.returnLiveIn(isel, dst_hi16_vi.?, .r1);
5901 var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8);
5902 const dst_lo64_vi = try dst_lo64_it.only(isel);
5903 try call.returnLiveIn(isel, dst_lo64_vi.?, .r0);
5904 },
5905 }
5906 try call.finishReturn(isel);
5907
5908 try call.prepareCallee(isel);
5909 try isel.global_relocs.append(gpa, .{
5910 .global = switch (src_int_info.bits) {
5911 else => unreachable,
5912 1...32 => switch (src_int_info.signedness) {
5913 .signed => switch (dst_bits) {
5914 else => unreachable,
5915 16 => "__floatsihf",
5916 32 => "__floatsisf",
5917 64 => "__floatsidf",
5918 80 => "__floatsixf",
5919 128 => "__floatsitf",
5920 },
5921 .unsigned => switch (dst_bits) {
5922 else => unreachable,
5923 16 => "__floatunsihf",
5924 32 => "__floatunsisf",
5925 64 => "__floatunsidf",
5926 80 => "__floatunsixf",
5927 128 => "__floatunsitf",
5928 },
5929 },
5930 33...64 => switch (src_int_info.signedness) {
5931 .signed => switch (dst_bits) {
5932 else => unreachable,
5933 16 => "__floatdihf",
5934 32 => "__floatdisf",
5935 64 => "__floatdidf",
5936 80 => "__floatdixf",
5937 128 => "__floatditf",
5938 },
5939 .unsigned => switch (dst_bits) {
5940 else => unreachable,
5941 16 => "__floatundihf",
5942 32 => "__floatundisf",
5943 64 => "__floatundidf",
5944 80 => "__floatundixf",
5945 128 => "__floatunditf",
5946 },
5947 },
5948 65...128 => switch (src_int_info.signedness) {
5949 .signed => switch (dst_bits) {
5950 else => unreachable,
5951 16 => "__floattihf",
5952 32 => "__floattisf",
5953 64 => "__floattidf",
5954 80 => "__floattixf",
5955 128 => "__floattitf",
5956 },
5957 .unsigned => switch (dst_bits) {
5958 else => unreachable,
5959 16 => "__floatuntihf",
5960 32 => "__floatuntisf",
5961 64 => "__floatuntidf",
5962 80 => "__floatuntixf",
5963 128 => "__floatuntitf",
5964 },
5965 },
5966 },
5967 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
5968 });
5969 try isel.emit(.bl(0));
5970 try call.finishCallee(isel);
5971
5972 try call.prepareParams(isel);
5973 const src_vi = try isel.use(ty_op.operand);
5974 switch (src_int_info.bits) {
5975 else => unreachable,
5976 1...64 => try call.paramLiveOut(isel, src_vi, .r0),
5977 65...128 => {
5978 var src_hi64_it = src_vi.field(src_ty, 8, 8);
5979 const src_hi64_vi = try src_hi64_it.only(isel);
5980 try call.paramLiveOut(isel, src_hi64_vi.?, .r1);
5981 var src_lo64_it = src_vi.field(src_ty, 0, 8);
5982 const src_lo64_vi = try src_lo64_it.only(isel);
5983 try call.paramLiveOut(isel, src_lo64_vi.?, .r0);
5984 },
5985 }
5986 try call.finishParams(isel);
5987 },
5988 else => return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }),
5989 }
5990 }
5991 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5992 },
5993 .memset => |air_tag| {
5994 const bin_op = air.data(air.inst_index).bin_op;
5995 const dst_ty = isel.air.typeOf(bin_op.lhs, ip);
5996 const dst_info = dst_ty.ptrInfo(zcu);
5997 const fill_byte: union(enum) { constant: u8, value: Air.Inst.Ref } = fill_byte: {
5998 if (bin_op.rhs.toInterned()) |fill_val|
5999 if (try isel.hasRepeatedByteRepr(.fromInterned(fill_val))) |fill_byte|
6000 break :fill_byte .{ .constant = fill_byte };
6001 switch (dst_ty.elemType2(zcu).abiSize(zcu)) {
6002 0 => unreachable,
6003 1 => break :fill_byte .{ .value = bin_op.rhs },
6004 2, 4, 8 => |size| {
6005 const dst_vi = try isel.use(bin_op.lhs);
6006 const ptr_ra = try isel.allocIntReg();
6007 const fill_vi = try isel.use(bin_op.rhs);
6008 const fill_mat = try fill_vi.matReg(isel);
6009 const len_mat: Value.Materialize = len_mat: switch (dst_info.flags.size) {
6010 .one => .{ .vi = undefined, .ra = try isel.allocIntReg() },
6011 .many => unreachable,
6012 .slice => {
6013 var dst_len_it = dst_vi.field(dst_ty, 8, 8);
6014 const dst_len_vi = try dst_len_it.only(isel);
6015 break :len_mat try dst_len_vi.?.matReg(isel);
6016 },
6017 .c => unreachable,
6018 };
6019
6020 const skip_label = isel.instructions.items.len;
6021 _ = try isel.instructions.addOne(gpa);
6022 try isel.emit(.sub(len_mat.ra.x(), len_mat.ra.x(), .{ .immediate = 1 }));
6023 try isel.emit(switch (size) {
6024 else => unreachable,
6025 2 => .strh(fill_mat.ra.w(), .{ .post_index = .{ .base = ptr_ra.x(), .index = 2 } }),
6026 4 => .str(fill_mat.ra.w(), .{ .post_index = .{ .base = ptr_ra.x(), .index = 4 } }),
6027 8 => .str(fill_mat.ra.x(), .{ .post_index = .{ .base = ptr_ra.x(), .index = 8 } }),
6028 });
6029 isel.instructions.items[skip_label] = .cbnz(
6030 len_mat.ra.x(),
6031 -@as(i21, @intCast((isel.instructions.items.len - 1 - skip_label) << 2)),
6032 );
6033 switch (dst_info.flags.size) {
6034 .one => {
6035 const len_imm = ZigType.fromInterned(dst_info.child).arrayLen(zcu);
6036 assert(len_imm > 0);
6037 try isel.movImmediate(len_mat.ra.x(), len_imm);
6038 isel.freeReg(len_mat.ra);
6039 try fill_mat.finish(isel);
6040 isel.freeReg(ptr_ra);
6041 try dst_vi.liveOut(isel, ptr_ra);
6042 },
6043 .many => unreachable,
6044 .slice => {
6045 try isel.emit(.cbz(
6046 len_mat.ra.x(),
6047 @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
6048 ));
6049 try len_mat.finish(isel);
6050 try fill_mat.finish(isel);
6051 isel.freeReg(ptr_ra);
6052 var dst_ptr_it = dst_vi.field(dst_ty, 0, 8);
6053 const dst_ptr_vi = try dst_ptr_it.only(isel);
6054 try dst_ptr_vi.?.liveOut(isel, ptr_ra);
6055 },
6056 .c => unreachable,
6057 }
6058
6059 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6060 break :air_tag;
6061 },
6062 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty) }),
6063 }
6064 };
6065
6066 try call.prepareReturn(isel);
6067 try call.finishReturn(isel);
6068
6069 try call.prepareCallee(isel);
6070 try isel.global_relocs.append(gpa, .{
6071 .global = "memset",
6072 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
6073 });
6074 try isel.emit(.bl(0));
6075 try call.finishCallee(isel);
6076
6077 try call.prepareParams(isel);
6078 const dst_vi = try isel.use(bin_op.lhs);
6079 switch (dst_info.flags.size) {
6080 .one => {
6081 try isel.movImmediate(.x2, ZigType.fromInterned(dst_info.child).abiSize(zcu));
6082 switch (fill_byte) {
6083 .constant => |byte| try isel.movImmediate(.w1, byte),
6084 .value => |byte| try call.paramLiveOut(isel, try isel.use(byte), .r1),
6085 }
6086 try call.paramLiveOut(isel, dst_vi, .r0);
6087 },
6088 .many => unreachable,
6089 .slice => {
6090 var dst_ptr_it = dst_vi.field(dst_ty, 0, 8);
6091 const dst_ptr_vi = try dst_ptr_it.only(isel);
6092 var dst_len_it = dst_vi.field(dst_ty, 8, 8);
6093 const dst_len_vi = try dst_len_it.only(isel);
6094 try isel.elemPtr(.r2, .zr, .add, ZigType.fromInterned(dst_info.child).abiSize(zcu), dst_len_vi.?);
6095 switch (fill_byte) {
6096 .constant => |byte| try isel.movImmediate(.w1, byte),
6097 .value => |byte| try call.paramLiveOut(isel, try isel.use(byte), .r1),
6098 }
6099 try call.paramLiveOut(isel, dst_ptr_vi.?, .r0);
6100 },
6101 .c => unreachable,
6102 }
6103 try call.finishParams(isel);
6104
6105 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6106 },
6107 .memcpy, .memmove => |air_tag| {
6108 const bin_op = air.data(air.inst_index).bin_op;
6109 const dst_ty = isel.air.typeOf(bin_op.lhs, ip);
6110 const dst_info = dst_ty.ptrInfo(zcu);
6111
6112 try call.prepareReturn(isel);
6113 try call.finishReturn(isel);
6114
6115 try call.prepareCallee(isel);
6116 try isel.global_relocs.append(gpa, .{
6117 .global = @tagName(air_tag),
6118 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
6119 });
6120 try isel.emit(.bl(0));
6121 try call.finishCallee(isel);
6122
6123 try call.prepareParams(isel);
6124 switch (dst_info.flags.size) {
6125 .one => {
6126 const dst_vi = try isel.use(bin_op.lhs);
6127 const src_vi = try isel.use(bin_op.rhs);
6128 try isel.movImmediate(.x2, ZigType.fromInterned(dst_info.child).abiSize(zcu));
6129 try call.paramLiveOut(isel, src_vi, .r1);
6130 try call.paramLiveOut(isel, dst_vi, .r0);
6131 },
6132 .many => unreachable,
6133 .slice => {
6134 const dst_vi = try isel.use(bin_op.lhs);
6135 var dst_ptr_it = dst_vi.field(dst_ty, 0, 8);
6136 const dst_ptr_vi = try dst_ptr_it.only(isel);
6137 var dst_len_it = dst_vi.field(dst_ty, 8, 8);
6138 const dst_len_vi = try dst_len_it.only(isel);
6139 const src_vi = try isel.use(bin_op.rhs);
6140 try isel.elemPtr(.r2, .zr, .add, ZigType.fromInterned(dst_info.child).abiSize(zcu), dst_len_vi.?);
6141 try call.paramLiveOut(isel, src_vi, .r1);
6142 try call.paramLiveOut(isel, dst_ptr_vi.?, .r0);
6143 },
6144 .c => unreachable,
6145 }
6146 try call.finishParams(isel);
6147
6148 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6149 },
6150 .atomic_load => {
6151 const atomic_load = air.data(air.inst_index).atomic_load;
6152 const ptr_ty = isel.air.typeOf(atomic_load.ptr, ip);
6153 const ptr_info = ptr_ty.ptrInfo(zcu);
6154 if (atomic_load.order != .unordered) return isel.fail("ordered atomic load", .{});
6155 if (ptr_info.packed_offset.host_size > 0) return isel.fail("packed atomic load", .{});
6156
6157 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| {
6158 defer dst_vi.value.deref(isel);
6159 var ptr_mat: ?Value.Materialize = null;
6160 var dst_part_it = dst_vi.value.parts(isel);
6161 while (dst_part_it.next()) |dst_part_vi| {
6162 const dst_ra = try dst_part_vi.defReg(isel) orelse continue;
6163 if (ptr_mat == null) {
6164 const ptr_vi = try isel.use(atomic_load.ptr);
6165 ptr_mat = try ptr_vi.matReg(isel);
6166 }
6167 try isel.emit(switch (dst_part_vi.size(isel)) {
6168 else => |size| return isel.fail("bad atomic load size of {d} from {f}", .{
6169 size, isel.fmtType(ptr_ty),
6170 }),
6171 1 => switch (dst_part_vi.signedness(isel)) {
6172 .signed => .ldrsb(dst_ra.w(), .{ .unsigned_offset = .{
6173 .base = ptr_mat.?.ra.x(),
6174 .offset = @intCast(dst_part_vi.get(isel).offset_from_parent),
6175 } }),
6176 .unsigned => .ldrb(dst_ra.w(), .{ .unsigned_offset = .{
6177 .base = ptr_mat.?.ra.x(),
6178 .offset = @intCast(dst_part_vi.get(isel).offset_from_parent),
6179 } }),
6180 },
6181 2 => switch (dst_part_vi.signedness(isel)) {
6182 .signed => .ldrsh(dst_ra.w(), .{ .unsigned_offset = .{
6183 .base = ptr_mat.?.ra.x(),
6184 .offset = @intCast(dst_part_vi.get(isel).offset_from_parent),
6185 } }),
6186 .unsigned => .ldrh(dst_ra.w(), .{ .unsigned_offset = .{
6187 .base = ptr_mat.?.ra.x(),
6188 .offset = @intCast(dst_part_vi.get(isel).offset_from_parent),
6189 } }),
6190 },
6191 4 => .ldr(dst_ra.w(), .{ .unsigned_offset = .{
6192 .base = ptr_mat.?.ra.x(),
6193 .offset = @intCast(dst_part_vi.get(isel).offset_from_parent),
6194 } }),
6195 8 => .ldr(dst_ra.x(), .{ .unsigned_offset = .{
6196 .base = ptr_mat.?.ra.x(),
6197 .offset = @intCast(dst_part_vi.get(isel).offset_from_parent),
6198 } }),
6199 });
6200 }
6201 if (ptr_mat) |mat| try mat.finish(isel);
6202 } else if (ptr_info.flags.is_volatile) return isel.fail("volatile atomic load", .{});
6203
6204 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6205 },
6206 .aggregate_init => {
6207 if (isel.live_values.fetchRemove(air.inst_index)) |agg_vi| {
6208 defer agg_vi.value.deref(isel);
6209
6210 const ty_pl = air.data(air.inst_index).ty_pl;
6211 const agg_ty = ty_pl.ty.toType();
6212 switch (ip.indexToKey(agg_ty.toIntern())) {
6213 .array_type => |array_type| {
6214 const elems: []const Air.Inst.Ref =
6215 @ptrCast(isel.air.extra.items[ty_pl.payload..][0..@intCast(array_type.len)]);
6216 var elem_offset: u64 = 0;
6217 const elem_size = ZigType.fromInterned(array_type.child).abiSize(zcu);
6218 for (elems) |elem| {
6219 var agg_part_it = agg_vi.value.field(agg_ty, elem_offset, elem_size);
6220 const agg_part_vi = try agg_part_it.only(isel);
6221 try agg_part_vi.?.move(isel, elem);
6222 elem_offset += elem_size;
6223 }
6224 switch (array_type.sentinel) {
6225 .none => {},
6226 else => |sentinel| {
6227 var agg_part_it = agg_vi.value.field(agg_ty, elem_offset, elem_size);
6228 const agg_part_vi = try agg_part_it.only(isel);
6229 try agg_part_vi.?.move(isel, .fromIntern(sentinel));
6230 },
6231 }
6232 },
6233 .struct_type => {
6234 const loaded_struct = ip.loadStructType(agg_ty.toIntern());
6235 const elems: []const Air.Inst.Ref =
6236 @ptrCast(isel.air.extra.items[ty_pl.payload..][0..loaded_struct.field_types.len]);
6237 var field_offset: u64 = 0;
6238 var field_it = loaded_struct.iterateRuntimeOrder(ip);
6239 while (field_it.next()) |field_index| {
6240 const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
6241 field_offset = field_ty.structFieldAlignment(
6242 loaded_struct.fieldAlign(ip, field_index),
6243 loaded_struct.layout,
6244 zcu,
6245 ).forward(field_offset);
6246 const field_size = field_ty.abiSize(zcu);
6247 if (field_size == 0) continue;
6248 var agg_part_it = agg_vi.value.field(agg_ty, field_offset, field_size);
6249 const agg_part_vi = try agg_part_it.only(isel);
6250 try agg_part_vi.?.move(isel, elems[field_index]);
6251 field_offset += field_size;
6252 }
6253 assert(field_offset == agg_vi.value.size(isel));
6254 },
6255 .tuple_type => |tuple_type| {
6256 const elems: []const Air.Inst.Ref =
6257 @ptrCast(isel.air.extra.items[ty_pl.payload..][0..tuple_type.types.len]);
6258 var field_offset: u64 = 0;
6259 for (
6260 tuple_type.types.get(ip),
6261 tuple_type.values.get(ip),
6262 elems,
6263 ) |field_ty_index, field_val, elem| {
6264 if (field_val != .none) continue;
6265 const field_ty: ZigType = .fromInterned(field_ty_index);
6266 field_offset = field_ty.abiAlignment(zcu).forward(field_offset);
6267 const field_size = field_ty.abiSize(zcu);
6268 if (field_size == 0) continue;
6269 var agg_part_it = agg_vi.value.field(agg_ty, field_offset, field_size);
6270 const agg_part_vi = try agg_part_it.only(isel);
6271 try agg_part_vi.?.move(isel, elem);
6272 field_offset += field_size;
6273 }
6274 assert(field_offset == agg_vi.value.size(isel));
6275 },
6276 else => return isel.fail("aggregate init {f}", .{isel.fmtType(agg_ty)}),
6277 }
6278 }
6279 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6280 },
6281 .union_init => {
6282 if (isel.live_values.fetchRemove(air.inst_index)) |un_vi| unused: {
6283 defer un_vi.value.deref(isel);
6284
6285 const ty_pl = air.data(air.inst_index).ty_pl;
6286 const extra = isel.air.extraData(Air.UnionInit, ty_pl.payload).data;
6287 const un_ty = ty_pl.ty.toType();
6288 if (un_ty.containerLayout(zcu) != .@"extern") return isel.fail("bad union init {f}", .{isel.fmtType(un_ty)});
6289
6290 try un_vi.value.defAddr(isel, un_ty, null, comptime &.initFill(.free)) orelse break :unused;
6291
6292 try call.prepareReturn(isel);
6293 try call.finishReturn(isel);
6294
6295 try call.prepareCallee(isel);
6296 try isel.global_relocs.append(gpa, .{
6297 .global = "memcpy",
6298 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
6299 });
6300 try isel.emit(.bl(0));
6301 try call.finishCallee(isel);
6302
6303 try call.prepareParams(isel);
6304 const init_vi = try isel.use(extra.init);
6305 try isel.movImmediate(.x2, init_vi.size(isel));
6306 try call.paramAddress(isel, init_vi, .r1);
6307 try call.paramAddress(isel, un_vi.value, .r0);
6308 try call.finishParams(isel);
6309 }
6310 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6311 },
6312 .prefetch => {
6313 const prefetch = air.data(air.inst_index).prefetch;
6314 if (!(prefetch.rw == .write and prefetch.cache == .instruction)) {
6315 const maybe_slice_ty = isel.air.typeOf(prefetch.ptr, ip);
6316 const maybe_slice_vi = try isel.use(prefetch.ptr);
6317 const ptr_vi = if (maybe_slice_ty.isSlice(zcu)) ptr_vi: {
6318 var ptr_part_it = maybe_slice_vi.field(maybe_slice_ty, 0, 8);
6319 const ptr_part_vi = try ptr_part_it.only(isel);
6320 break :ptr_vi ptr_part_vi.?;
6321 } else maybe_slice_vi;
6322 const ptr_mat = try ptr_vi.matReg(isel);
6323 try isel.emit(.prfm(.{
6324 .policy = switch (prefetch.locality) {
6325 1, 2, 3 => .keep,
6326 0 => .strm,
6327 },
6328 .target = switch (prefetch.locality) {
6329 0, 3 => .l1,
6330 2 => .l2,
6331 1 => .l3,
6332 },
6333 .type = switch (prefetch.rw) {
6334 .read => switch (prefetch.cache) {
6335 .data => .pld,
6336 .instruction => .pli,
6337 },
6338 .write => switch (prefetch.cache) {
6339 .data => .pst,
6340 .instruction => unreachable,
6341 },
6342 },
6343 }, .{ .base = ptr_mat.ra.x() }));
6344 try ptr_mat.finish(isel);
6345 }
6346 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6347 },
6348 .mul_add => {
6349 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
6350 defer res_vi.value.deref(isel);
6351
6352 const pl_op = air.data(air.inst_index).pl_op;
6353 const bin_op = isel.air.extraData(Air.Bin, pl_op.payload).data;
6354 const ty = isel.air.typeOf(pl_op.operand, ip);
6355 switch (ty.floatBits(isel.target)) {
6356 else => unreachable,
6357 16, 32, 64 => |bits| {
6358 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
6359 const need_fcvt = switch (bits) {
6360 else => unreachable,
6361 16 => !isel.target.cpu.has(.aarch64, .fullfp16),
6362 32, 64 => false,
6363 };
6364 if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s()));
6365 const lhs_vi = try isel.use(bin_op.lhs);
6366 const rhs_vi = try isel.use(bin_op.rhs);
6367 const addend_vi = try isel.use(pl_op.operand);
6368 const lhs_mat = try lhs_vi.matReg(isel);
6369 const rhs_mat = try rhs_vi.matReg(isel);
6370 const addend_mat = try addend_vi.matReg(isel);
6371 const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra;
6372 defer if (need_fcvt) isel.freeReg(lhs_ra);
6373 const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra;
6374 defer if (need_fcvt) isel.freeReg(rhs_ra);
6375 const addend_ra = if (need_fcvt) try isel.allocVecReg() else addend_mat.ra;
6376 defer if (need_fcvt) isel.freeReg(addend_ra);
6377 try isel.emit(bits: switch (bits) {
6378 else => unreachable,
6379 16 => if (need_fcvt)
6380 continue :bits 32
6381 else
6382 .fmadd(res_ra.h(), lhs_ra.h(), rhs_ra.h(), addend_ra.h()),
6383 32 => .fmadd(res_ra.s(), lhs_ra.s(), rhs_ra.s(), addend_ra.s()),
6384 64 => .fmadd(res_ra.d(), lhs_ra.d(), rhs_ra.d(), addend_ra.d()),
6385 });
6386 if (need_fcvt) {
6387 try isel.emit(.fcvt(addend_ra.s(), addend_mat.ra.h()));
6388 try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h()));
6389 try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h()));
6390 }
6391 try addend_mat.finish(isel);
6392 try rhs_mat.finish(isel);
6393 try lhs_mat.finish(isel);
6394 },
6395 80, 128 => |bits| {
6396 try call.prepareReturn(isel);
6397 switch (bits) {
6398 else => unreachable,
6399 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
6400 80 => {
6401 var res_hi16_it = res_vi.value.field(ty, 8, 8);
6402 const res_hi16_vi = try res_hi16_it.only(isel);
6403 try call.returnLiveIn(isel, res_hi16_vi.?, .r1);
6404 var res_lo64_it = res_vi.value.field(ty, 0, 8);
6405 const res_lo64_vi = try res_lo64_it.only(isel);
6406 try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
6407 },
6408 }
6409 try call.finishReturn(isel);
6410
6411 try call.prepareCallee(isel);
6412 try isel.global_relocs.append(gpa, .{
6413 .global = switch (bits) {
6414 else => unreachable,
6415 16 => "__fmah",
6416 32 => "fmaf",
6417 64 => "fma",
6418 80 => "__fmax",
6419 128 => "fmaq",
6420 },
6421 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
6422 });
6423 try isel.emit(.bl(0));
6424 try call.finishCallee(isel);
6425
6426 try call.prepareParams(isel);
6427 const lhs_vi = try isel.use(bin_op.lhs);
6428 const rhs_vi = try isel.use(bin_op.rhs);
6429 const addend_vi = try isel.use(pl_op.operand);
6430 switch (bits) {
6431 else => unreachable,
6432 16, 32, 64, 128 => {
6433 try call.paramLiveOut(isel, addend_vi, .v2);
6434 try call.paramLiveOut(isel, rhs_vi, .v1);
6435 try call.paramLiveOut(isel, lhs_vi, .v0);
6436 },
6437 80 => {
6438 var addend_hi16_it = addend_vi.field(ty, 8, 8);
6439 const addend_hi16_vi = try addend_hi16_it.only(isel);
6440 try call.paramLiveOut(isel, addend_hi16_vi.?, .r5);
6441 var addend_lo64_it = addend_vi.field(ty, 0, 8);
6442 const addend_lo64_vi = try addend_lo64_it.only(isel);
6443 try call.paramLiveOut(isel, addend_lo64_vi.?, .r4);
6444 var rhs_hi16_it = rhs_vi.field(ty, 8, 8);
6445 const rhs_hi16_vi = try rhs_hi16_it.only(isel);
6446 try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3);
6447 var rhs_lo64_it = rhs_vi.field(ty, 0, 8);
6448 const rhs_lo64_vi = try rhs_lo64_it.only(isel);
6449 try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2);
6450 var lhs_hi16_it = lhs_vi.field(ty, 8, 8);
6451 const lhs_hi16_vi = try lhs_hi16_it.only(isel);
6452 try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1);
6453 var lhs_lo64_it = lhs_vi.field(ty, 0, 8);
6454 const lhs_lo64_vi = try lhs_lo64_it.only(isel);
6455 try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0);
6456 },
6457 }
6458 try call.finishParams(isel);
6459 },
6460 }
6461 }
6462 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6463 },
6464 .field_parent_ptr => {
6465 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
6466 defer dst_vi.value.deref(isel);
6467 const ty_pl = air.data(air.inst_index).ty_pl;
6468 const extra = isel.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
6469 switch (codegen.fieldOffset(
6470 ty_pl.ty.toType(),
6471 isel.air.typeOf(extra.field_ptr, ip),
6472 extra.field_index,
6473 zcu,
6474 )) {
6475 0 => try dst_vi.value.move(isel, extra.field_ptr),
6476 else => |field_offset| {
6477 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
6478 const src_vi = try isel.use(extra.field_ptr);
6479 const src_mat = try src_vi.matReg(isel);
6480 const lo12: u12 = @truncate(field_offset >> 0);
6481 const hi12: u12 = @intCast(field_offset >> 12);
6482 if (hi12 > 0) try isel.emit(.sub(
6483 dst_ra.x(),
6484 if (lo12 > 0) dst_ra.x() else src_mat.ra.x(),
6485 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
6486 ));
6487 if (lo12 > 0) try isel.emit(.sub(dst_ra.x(), src_mat.ra.x(), .{ .immediate = lo12 }));
6488 try src_mat.finish(isel);
6489 },
6490 }
6491 }
6492 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6493 },
6494 .runtime_nav_ptr => {
6495 if (isel.live_values.fetchRemove(air.inst_index)) |ptr_vi| unused: {
6496 defer ptr_vi.value.deref(isel);
6497 const ptr_ra = try ptr_vi.value.defReg(isel) orelse break :unused;
6498
6499 const ty_nav = air.data(air.inst_index).ty_nav;
6500 if (ZigType.fromInterned(ip.getNav(ty_nav.nav).typeOf(ip)).isFnOrHasRuntimeBits(zcu)) switch (true) {
6501 false => {
6502 try isel.nav_relocs.append(zcu.gpa, .{
6503 .nav = ty_nav.nav,
6504 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
6505 });
6506 try isel.emit(.adr(ptr_ra.x(), 0));
6507 },
6508 true => {
6509 try isel.nav_relocs.append(zcu.gpa, .{
6510 .nav = ty_nav.nav,
6511 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
6512 });
6513 try isel.emit(.add(ptr_ra.x(), ptr_ra.x(), .{ .immediate = 0 }));
6514 try isel.nav_relocs.append(zcu.gpa, .{
6515 .nav = ty_nav.nav,
6516 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
6517 });
6518 try isel.emit(.adrp(ptr_ra.x(), 0));
6519 },
6520 } else try isel.movImmediate(ptr_ra.x(), isel.pt.navAlignment(ty_nav.nav).forward(0xaaaaaaaaaaaaaaaa));
6521 }
6522 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6523 },
6524 .add_safe,
6525 .sub_safe,
6526 .mul_safe,
6527 .inferred_alloc,
6528 .inferred_alloc_comptime,
6529 .int_from_float_safe,
6530 .int_from_float_optimized_safe,
6531 .wasm_memory_size,
6532 .wasm_memory_grow,
6533 .work_item_id,
6534 .work_group_size,
6535 .work_group_id,
6536 => unreachable,
6537 }
6538 assert(air.body_index == 0);
6539}
6540
6541pub fn verify(isel: *Select, check_values: bool) void {
6542 if (!std.debug.runtime_safety) return;
6543 assert(isel.blocks.count() == 1 and isel.blocks.keys()[0] == Select.Block.main);
6544 assert(isel.active_loops.items.len == 0);
6545 assert(isel.dom_start == 0 and isel.dom_len == 0);
6546 var live_reg_it = isel.live_registers.iterator();
6547 while (live_reg_it.next()) |live_reg_entry| switch (live_reg_entry.value.*) {
6548 _ => {
6549 isel.dumpValues(.all);
6550 unreachable;
6551 },
6552 .allocating, .free => {},
6553 };
6554 if (check_values) for (isel.values.items) |value| if (value.refs != 0) {
6555 isel.dumpValues(.only_referenced);
6556 unreachable;
6557 };
6558}
6559
6560/// Stack Frame Layout
6561/// +-+-----------------------------------+
6562/// |R| allocated stack |
6563/// +-+-----------------------------------+
6564/// |S| caller frame record | +---------------+
6565/// +-+-----------------------------------+ <-| entry/exit FP |
6566/// |R| caller frame | +---------------+
6567/// +-+-----------------------------------+
6568/// |R| variable incoming stack arguments | +---------------+
6569/// +-+-----------------------------------+ <-| __stack |
6570/// |S| named incoming stack arguments | +---------------+
6571/// +-+-----------------------------------+ <-| entry/exit SP |
6572/// |S| incoming gr arguments | | __gr_top |
6573/// +-+-----------------------------------+ +---------------+
6574/// |S| alignment gap |
6575/// +-+-----------------------------------+
6576/// |S| frame record | +----------+
6577/// +-+-----------------------------------+ <-| FP |
6578/// |S| incoming vr arguments | | __vr_top |
6579/// +-+-----------------------------------+ +----------+
6580/// |L| alignment gap |
6581/// +-+-----------------------------------+
6582/// |L| callee saved vr area |
6583/// +-+-----------------------------------+
6584/// |L| callee saved gr area | +----------------------+
6585/// +-+-----------------------------------+ <-| prologue/epilogue SP |
6586/// |R| realignment gap | +----------------------+
6587/// +-+-----------------------------------+
6588/// |L| locals |
6589/// +-+-----------------------------------+
6590/// |S| outgoing stack arguments | +----+
6591/// +-+-----------------------------------+ <-| SP |
6592/// |R| unallocated stack | +----+
6593/// +-+-----------------------------------+
6594/// [S] Size computed by `analyze`, can be used by the body.
6595/// [L] Size computed by `layout`, can be used by the prologue/epilogue.
6596/// [R] Size unknown until runtime, can vary from one call to the next.
6597///
6598/// Constraints that led to this layout:
6599/// * FP to __stack/__gr_top/__vr_top must only pass through [S]
6600/// * SP to outgoing stack arguments/locals must only pass through [S]
6601/// * entry/exit SP to prologue/epilogue SP must only pass through [S/L]
6602/// * all save areas must be at a positive offset from prologue/epilogue SP
6603/// * the entry/exit SP to prologue/epilogue SP distance must
6604/// - be a multiple of 16 due to hardware restrictions on the value of SP
6605/// - conform to the limit from the first matching condition in the
6606/// following list due to instruction encoding limitations
6607/// 1. callee saved gr count >= 2: multiple of 8 of at most 504 bytes
6608/// 2. callee saved vr count >= 2: multiple of 8 of at most 504 bytes
6609/// 3. callee saved gr count >= 1: at most 255 bytes
6610/// 4. callee saved vr count >= 1: at most 255 bytes
6611/// 5. variable incoming vr argument count >= 2: multiple of 16 of at most 1008 bytes
6612/// 6. variable incoming vr argument count >= 1: at most 255 bytes
6613/// 7. have frame record: multiple of 8 of at most 504 bytes
6614pub fn layout(
6615 isel: *Select,
6616 incoming: CallAbiIterator,
6617 have_va: bool,
6618 saved_gra_len: u7,
6619 saved_vra_len: u7,
6620 mod: *const Package.Module,
6621) !usize {
6622 const zcu = isel.pt.zcu;
6623 const ip = &zcu.intern_pool;
6624 const nav = ip.getNav(isel.nav_index);
6625 wip_mir_log.debug("{f}<body>:\n", .{nav.fqn.fmt(ip)});
6626
6627 const stack_size: u24 = @intCast(InternPool.Alignment.@"16".forward(isel.stack_size));
6628 const stack_size_low: u12 = @truncate(stack_size >> 0);
6629 const stack_size_high: u12 = @truncate(stack_size >> 12);
6630
6631 var saves_buf: [10 + 8 + 8 + 2 + 8]struct {
6632 class: enum { integer, vector },
6633 needs_restore: bool,
6634 register: Register,
6635 offset: u10,
6636 size: u5,
6637 } = undefined;
6638 const saves, const saves_size, const frame_record_offset = saves: {
6639 var saves_len: usize = 0;
6640 var saves_size: u10 = 0;
6641 var save_ra: Register.Alias = undefined;
6642
6643 // callee saved gr area
6644 save_ra = .r19;
6645 while (save_ra != .r29) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) {
6646 if (!isel.saved_registers.contains(save_ra)) continue;
6647 saves_size = std.mem.alignForward(u10, saves_size, 8);
6648 saves_buf[saves_len] = .{
6649 .class = .integer,
6650 .needs_restore = true,
6651 .register = save_ra.x(),
6652 .offset = saves_size,
6653 .size = 8,
6654 };
6655 saves_len += 1;
6656 saves_size += 8;
6657 }
6658 var deferred_gr = if (saves_size == 8 or (saves_size % 16 != 0 and saved_gra_len % 2 != 0)) gr: {
6659 saves_len -= 1;
6660 saves_size -= 8;
6661 break :gr saves_buf[saves_len].register;
6662 } else null;
6663 defer assert(deferred_gr == null);
6664
6665 // callee saved vr area
6666 save_ra = .v8;
6667 while (save_ra != .v16) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) {
6668 if (!isel.saved_registers.contains(save_ra)) continue;
6669 saves_size = std.mem.alignForward(u10, saves_size, 8);
6670 saves_buf[saves_len] = .{
6671 .class = .vector,
6672 .needs_restore = true,
6673 .register = save_ra.d(),
6674 .offset = saves_size,
6675 .size = 8,
6676 };
6677 saves_len += 1;
6678 saves_size += 8;
6679 }
6680 if (deferred_gr != null and saved_gra_len % 2 == 0) {
6681 saves_size = std.mem.alignForward(u10, saves_size, 8);
6682 saves_buf[saves_len] = .{
6683 .class = .integer,
6684 .needs_restore = true,
6685 .register = deferred_gr.?,
6686 .offset = saves_size,
6687 .size = 8,
6688 };
6689 saves_len += 1;
6690 saves_size += 8;
6691 deferred_gr = null;
6692 }
6693 if (saves_size % 16 != 0 and saved_vra_len % 2 != 0) {
6694 const prev_save = &saves_buf[saves_len - 1];
6695 switch (prev_save.class) {
6696 .integer => {},
6697 .vector => {
6698 prev_save.register = prev_save.register.alias.q();
6699 prev_save.size = 16;
6700 saves_size += 8;
6701 },
6702 }
6703 }
6704
6705 // incoming vr arguments
6706 save_ra = if (mod.strip) incoming.nsrn else CallAbiIterator.nsrn_start;
6707 while (save_ra != if (have_va) CallAbiIterator.nsrn_end else incoming.nsrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) {
6708 saves_size = std.mem.alignForward(u10, saves_size, 16);
6709 saves_buf[saves_len] = .{
6710 .class = .vector,
6711 .needs_restore = false,
6712 .register = save_ra.q(),
6713 .offset = saves_size,
6714 .size = 16,
6715 };
6716 saves_len += 1;
6717 saves_size += 16;
6718 }
6719
6720 // frame record
6721 saves_size = std.mem.alignForward(u10, saves_size, 16);
6722 const frame_record_offset = saves_size;
6723 saves_buf[saves_len] = .{
6724 .class = .integer,
6725 .needs_restore = true,
6726 .register = .fp,
6727 .offset = saves_size,
6728 .size = 8,
6729 };
6730 saves_len += 1;
6731 saves_size += 8;
6732
6733 saves_size = std.mem.alignForward(u10, saves_size, 8);
6734 saves_buf[saves_len] = .{
6735 .class = .integer,
6736 .needs_restore = true,
6737 .register = .lr,
6738 .offset = saves_size,
6739 .size = 8,
6740 };
6741 saves_len += 1;
6742 saves_size += 8;
6743
6744 // incoming gr arguments
6745 if (deferred_gr) |gr| {
6746 saves_size = std.mem.alignForward(u10, saves_size, 8);
6747 saves_buf[saves_len] = .{
6748 .class = .integer,
6749 .needs_restore = true,
6750 .register = gr,
6751 .offset = saves_size,
6752 .size = 8,
6753 };
6754 saves_len += 1;
6755 saves_size += 8;
6756 deferred_gr = null;
6757 }
6758 save_ra = if (mod.strip) incoming.ngrn else CallAbiIterator.ngrn_start;
6759 while (save_ra != if (have_va) CallAbiIterator.ngrn_end else incoming.ngrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) {
6760 saves_size = std.mem.alignForward(u10, saves_size, 8);
6761 saves_buf[saves_len] = .{
6762 .class = .integer,
6763 .needs_restore = false,
6764 .register = save_ra.x(),
6765 .offset = saves_size,
6766 .size = 8,
6767 };
6768 saves_len += 1;
6769 saves_size += 8;
6770 }
6771
6772 assert(InternPool.Alignment.@"16".check(saves_size));
6773 break :saves .{ saves_buf[0..saves_len], saves_size, frame_record_offset };
6774 };
6775
6776 {
6777 wip_mir_log.debug("{f}<prologue>:", .{nav.fqn.fmt(ip)});
6778 var save_index: usize = 0;
6779 while (save_index < saves.len) {
6780 if (save_index + 2 <= saves.len and saves[save_index + 0].class == saves[save_index + 1].class and
6781 saves[save_index + 0].offset + saves[save_index + 0].size == saves[save_index + 1].offset)
6782 {
6783 try isel.emit(.stp(
6784 saves[save_index + 0].register,
6785 saves[save_index + 1].register,
6786 switch (saves[save_index + 0].offset) {
6787 0 => .{ .pre_index = .{
6788 .base = .sp,
6789 .index = @intCast(-@as(i11, saves_size)),
6790 } },
6791 else => |offset| .{ .signed_offset = .{
6792 .base = .sp,
6793 .offset = @intCast(offset),
6794 } },
6795 },
6796 ));
6797 save_index += 2;
6798 } else {
6799 try isel.emit(.str(
6800 saves[save_index].register,
6801 switch (saves[save_index].offset) {
6802 0 => .{ .pre_index = .{
6803 .base = .sp,
6804 .index = @intCast(-@as(i11, saves_size)),
6805 } },
6806 else => |offset| .{ .unsigned_offset = .{
6807 .base = .sp,
6808 .offset = @intCast(offset),
6809 } },
6810 },
6811 ));
6812 save_index += 1;
6813 }
6814 }
6815
6816 const scratch_reg: Register = if (isel.stack_align == .@"16")
6817 .sp
6818 else if (stack_size == 0)
6819 .fp
6820 else
6821 .x9;
6822 try isel.emit(.add(.fp, .sp, .{ .immediate = frame_record_offset }));
6823 if (stack_size_high > 0) try isel.emit(.sub(scratch_reg, .sp, .{
6824 .shifted_immediate = .{ .immediate = stack_size_high, .lsl = .@"12" },
6825 }));
6826 if (stack_size_low > 0) try isel.emit(.sub(
6827 scratch_reg,
6828 if (stack_size_high > 0) scratch_reg else .sp,
6829 .{ .immediate = stack_size_low },
6830 ));
6831 if (isel.stack_align != .@"16") {
6832 try isel.emit(.@"and"(.sp, scratch_reg, .{ .immediate = .{
6833 .N = .doubleword,
6834 .immr = -%isel.stack_align.toLog2Units(),
6835 .imms = ~isel.stack_align.toLog2Units(),
6836 } }));
6837 }
6838 wip_mir_log.debug("", .{});
6839 }
6840
6841 const epilogue = isel.instructions.items.len;
6842 if (isel.returns) {
6843 try isel.emit(.ret(.lr));
6844 var save_index: usize = 0;
6845 while (save_index < saves.len) {
6846 if (save_index + 2 <= saves.len and saves[save_index + 1].needs_restore and
6847 saves[save_index + 0].class == saves[save_index + 1].class and
6848 saves[save_index + 0].offset + saves[save_index + 0].size == saves[save_index + 1].offset)
6849 {
6850 try isel.emit(.ldp(
6851 saves[save_index + 0].register,
6852 saves[save_index + 1].register,
6853 switch (saves[save_index + 0].offset) {
6854 0 => .{ .post_index = .{
6855 .base = .sp,
6856 .index = @intCast(saves_size),
6857 } },
6858 else => |offset| .{ .signed_offset = .{
6859 .base = .sp,
6860 .offset = @intCast(offset),
6861 } },
6862 },
6863 ));
6864 save_index += 2;
6865 } else if (saves[save_index].needs_restore) {
6866 try isel.emit(.ldr(
6867 saves[save_index].register,
6868 switch (saves[save_index].offset) {
6869 0 => .{ .post_index = .{
6870 .base = .sp,
6871 .index = @intCast(saves_size),
6872 } },
6873 else => |offset| .{ .unsigned_offset = .{
6874 .base = .sp,
6875 .offset = @intCast(offset),
6876 } },
6877 },
6878 ));
6879 save_index += 1;
6880 } else save_index += 1;
6881 }
6882 if (isel.stack_align != .@"16" or (stack_size_low > 0 and stack_size_high > 0)) {
6883 try isel.emit(switch (frame_record_offset) {
6884 0 => .add(.sp, .fp, .{ .immediate = 0 }),
6885 else => |offset| .sub(.sp, .fp, .{ .immediate = offset }),
6886 });
6887 } else {
6888 if (stack_size_high > 0) try isel.emit(.add(.sp, .sp, .{
6889 .shifted_immediate = .{ .immediate = stack_size_high, .lsl = .@"12" },
6890 }));
6891 if (stack_size_low > 0) try isel.emit(.add(.sp, .sp, .{
6892 .immediate = stack_size_low,
6893 }));
6894 }
6895 wip_mir_log.debug("{f}<epilogue>:\n", .{nav.fqn.fmt(ip)});
6896 }
6897 return epilogue;
6898}
6899
6900fn fmtDom(isel: *Select, inst: Air.Inst.Index, start: u32, len: u32) struct {
6901 isel: *Select,
6902 inst: Air.Inst.Index,
6903 start: u32,
6904 len: u32,
6905 pub fn format(data: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void {
6906 try writer.print("%{d} -> {{", .{@intFromEnum(data.inst)});
6907 var first = true;
6908 for (data.isel.blocks.keys()[0..data.len], 0..) |block_inst_index, dom_index| {
6909 if (@as(u1, @truncate(data.isel.dom.items[
6910 data.start + dom_index / @bitSizeOf(DomInt)
6911 ] >> @truncate(dom_index))) == 0) continue;
6912 if (first) {
6913 first = false;
6914 } else {
6915 try writer.writeByte(',');
6916 }
6917 switch (block_inst_index) {
6918 Block.main => try writer.writeAll(" %main"),
6919 else => try writer.print(" %{d}", .{@intFromEnum(block_inst_index)}),
6920 }
6921 }
6922 if (!first) try writer.writeByte(' ');
6923 try writer.writeByte('}');
6924 }
6925} {
6926 return .{ .isel = isel, .inst = inst, .start = start, .len = len };
6927}
6928
6929fn fmtLoopLive(isel: *Select, loop_inst: Air.Inst.Index) struct {
6930 isel: *Select,
6931 inst: Air.Inst.Index,
6932 pub fn format(data: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void {
6933 const loops = data.isel.loops.values();
6934 const loop_index = data.isel.loops.getIndex(data.inst).?;
6935 const live_insts =
6936 data.isel.loop_live.list.items[loops[loop_index].live..loops[loop_index + 1].live];
6937
6938 try writer.print("%{d} <- {{", .{@intFromEnum(data.inst)});
6939 var first = true;
6940 for (live_insts) |live_inst| {
6941 if (first) {
6942 first = false;
6943 } else {
6944 try writer.writeByte(',');
6945 }
6946 try writer.print(" %{d}", .{@intFromEnum(live_inst)});
6947 }
6948 if (!first) try writer.writeByte(' ');
6949 try writer.writeByte('}');
6950 }
6951} {
6952 return .{ .isel = isel, .inst = loop_inst };
6953}
6954
6955fn fmtType(isel: *Select, ty: ZigType) ZigType.Formatter {
6956 return ty.fmt(isel.pt);
6957}
6958
6959fn fmtConstant(isel: *Select, constant: Constant) @typeInfo(@TypeOf(Constant.fmtValue)).@"fn".return_type.? {
6960 return constant.fmtValue(isel.pt);
6961}
6962
6963fn emit(isel: *Select, instruction: codegen.aarch64.encoding.Instruction) !void {
6964 wip_mir_log.debug(" | {f}", .{instruction});
6965 try isel.instructions.append(isel.pt.zcu.gpa, instruction);
6966}
6967
6968fn emitLiteral(isel: *Select, bytes: []const u8) !void {
6969 const words: []align(1) const u32 = @ptrCast(bytes);
6970 const literals = try isel.literals.addManyAsSlice(isel.pt.zcu.gpa, words.len);
6971 switch (isel.target.cpu.arch.endian()) {
6972 .little => @memcpy(literals, words),
6973 .big => for (words, 0..) |word, word_index| {
6974 literals[literals.len - 1 - word_index] = @byteSwap(word);
6975 },
6976 }
6977}
6978
6979fn fail(isel: *Select, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {
6980 @branchHint(.cold);
6981 return isel.pt.zcu.codegenFail(isel.nav_index, format, args);
6982}
6983
6984/// dst = src
6985fn movImmediate(isel: *Select, dst_reg: Register, src_imm: u64) !void {
6986 const sf = dst_reg.format.integer;
6987 if (src_imm == 0) {
6988 const zr: Register = switch (sf) {
6989 .word => .wzr,
6990 .doubleword => .xzr,
6991 };
6992 return isel.emit(.orr(dst_reg, zr, .{ .register = zr }));
6993 }
6994
6995 const Part = u16;
6996 const min_part: Part = std.math.minInt(Part);
6997 const max_part: Part = std.math.maxInt(Part);
6998
6999 const parts: [4]Part = @bitCast(switch (sf) {
7000 .word => @as(u32, @intCast(src_imm)),
7001 .doubleword => @as(u64, @intCast(src_imm)),
7002 });
7003 const width: u7 = switch (sf) {
7004 .word => 32,
7005 .doubleword => 64,
7006 };
7007 const parts_len: u3 = @intCast(@divExact(width, @bitSizeOf(Part)));
7008 var equal_min_count: u3 = 0;
7009 var equal_max_count: u3 = 0;
7010 for (parts[0..parts_len]) |part| {
7011 equal_min_count += @intFromBool(part == min_part);
7012 equal_max_count += @intFromBool(part == max_part);
7013 }
7014
7015 const equal_fill_count, const fill_part: Part = if (equal_min_count >= equal_max_count)
7016 .{ equal_min_count, min_part }
7017 else
7018 .{ equal_max_count, max_part };
7019 var remaining_parts = @max(parts_len - equal_fill_count, 1);
7020
7021 if (remaining_parts > 1) {
7022 var elem_width: u8 = 2;
7023 while (elem_width <= width) : (elem_width <<= 1) {
7024 const emask = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - elem_width);
7025 const rmask = @divExact(@as(u64, switch (sf) {
7026 .word => std.math.maxInt(u32),
7027 .doubleword => std.math.maxInt(u64),
7028 }), emask);
7029 const elem = src_imm & emask;
7030 if (src_imm != elem * rmask) continue;
7031 const imask: u64 = @bitCast(@as(i64, @bitCast(elem << 63)) >> 63);
7032 const lsb0 = elem ^ (imask & emask);
7033 const lsb1 = (lsb0 - 1) | lsb0;
7034 if ((lsb1 +% 1) & lsb1 == 0) {
7035 const lo: u6 = @intCast(@ctz(lsb0));
7036 const hi: u6 = @intCast(@clz(lsb0) - (64 - elem_width));
7037 const mid: u6 = @intCast(elem_width - lo - hi);
7038 const smask: u6 = @truncate(imask);
7039 const mid_masked = mid & ~smask;
7040 return isel.emit(.orr(
7041 dst_reg,
7042 switch (sf) {
7043 .word => .wzr,
7044 .doubleword => .xzr,
7045 },
7046 .{ .immediate = .{
7047 .N = @enumFromInt(elem_width >> 6),
7048 .immr = hi + mid_masked,
7049 .imms = ((((lo + hi) & smask) | mid_masked) - 1) | -%@as(u6, @truncate(elem_width)) << 1,
7050 } },
7051 ));
7052 }
7053 }
7054 }
7055
7056 var part_index = parts_len;
7057 while (part_index > 0) {
7058 part_index -= 1;
7059 if (part_index >= remaining_parts and parts[part_index] == fill_part) continue;
7060 remaining_parts -= 1;
7061 try isel.emit(if (remaining_parts > 0) .movk(
7062 dst_reg,
7063 parts[part_index],
7064 .{ .lsl = @enumFromInt(part_index) },
7065 ) else switch (fill_part) {
7066 else => unreachable,
7067 min_part => .movz(
7068 dst_reg,
7069 parts[part_index],
7070 .{ .lsl = @enumFromInt(part_index) },
7071 ),
7072 max_part => .movn(
7073 dst_reg,
7074 ~parts[part_index],
7075 .{ .lsl = @enumFromInt(part_index) },
7076 ),
7077 });
7078 }
7079 assert(remaining_parts == 0);
7080}
7081
7082/// elem_ptr = base +- elem_size * index
7083/// elem_ptr, base, and index may alias
7084fn elemPtr(
7085 isel: *Select,
7086 elem_ptr_ra: Register.Alias,
7087 base_ra: Register.Alias,
7088 op: codegen.aarch64.encoding.Instruction.AddSubtractOp,
7089 elem_size: u64,
7090 index_vi: Value.Index,
7091) !void {
7092 const index_mat = try index_vi.matReg(isel);
7093 switch (@popCount(elem_size)) {
7094 0 => unreachable,
7095 1 => try isel.emit(switch (op) {
7096 .add => switch (base_ra) {
7097 else => .add(elem_ptr_ra.x(), base_ra.x(), .{ .shifted_register = .{
7098 .register = index_mat.ra.x(),
7099 .shift = .{ .lsl = @intCast(@ctz(elem_size)) },
7100 } }),
7101 .zr => switch (@ctz(elem_size)) {
7102 0 => .orr(elem_ptr_ra.x(), .xzr, .{ .register = index_mat.ra.x() }),
7103 else => |shift| .ubfm(elem_ptr_ra.x(), index_mat.ra.x(), .{
7104 .N = .doubleword,
7105 .immr = @intCast(64 - shift),
7106 .imms = @intCast(63 - shift),
7107 }),
7108 },
7109 },
7110 .sub => .sub(elem_ptr_ra.x(), base_ra.x(), .{ .shifted_register = .{
7111 .register = index_mat.ra.x(),
7112 .shift = .{ .lsl = @intCast(@ctz(elem_size)) },
7113 } }),
7114 }),
7115 2 => {
7116 const shift: u6 = @intCast(@ctz(elem_size));
7117 const temp_ra = temp_ra: switch (op) {
7118 .add => switch (base_ra) {
7119 else => {
7120 const temp_ra = try isel.allocIntReg();
7121 errdefer isel.freeReg(temp_ra);
7122 try isel.emit(.add(elem_ptr_ra.x(), base_ra.x(), .{ .shifted_register = .{
7123 .register = temp_ra.x(),
7124 .shift = .{ .lsl = shift },
7125 } }));
7126 break :temp_ra temp_ra;
7127 },
7128 .zr => {
7129 if (shift > 0) try isel.emit(.ubfm(elem_ptr_ra.x(), elem_ptr_ra.x(), .{
7130 .N = .doubleword,
7131 .immr = -%shift,
7132 .imms = ~shift,
7133 }));
7134 break :temp_ra elem_ptr_ra;
7135 },
7136 },
7137 .sub => {
7138 const temp_ra = try isel.allocIntReg();
7139 errdefer isel.freeReg(temp_ra);
7140 try isel.emit(.sub(elem_ptr_ra.x(), base_ra.x(), .{ .shifted_register = .{
7141 .register = temp_ra.x(),
7142 .shift = .{ .lsl = shift },
7143 } }));
7144 break :temp_ra temp_ra;
7145 },
7146 };
7147 defer if (temp_ra != elem_ptr_ra) isel.freeReg(temp_ra);
7148 try isel.emit(.add(temp_ra.x(), index_mat.ra.x(), .{ .shifted_register = .{
7149 .register = index_mat.ra.x(),
7150 .shift = .{ .lsl = @intCast(63 - @clz(elem_size) - shift) },
7151 } }));
7152 },
7153 else => {
7154 const elem_size_lsb1 = (elem_size - 1) | elem_size;
7155 if ((elem_size_lsb1 +% 1) & elem_size_lsb1 == 0) {
7156 const shift: u6 = @intCast(@ctz(elem_size));
7157 const temp_ra = temp_ra: switch (op) {
7158 .add => {
7159 const temp_ra = try isel.allocIntReg();
7160 errdefer isel.freeReg(temp_ra);
7161 try isel.emit(.sub(elem_ptr_ra.x(), base_ra.x(), .{ .shifted_register = .{
7162 .register = temp_ra.x(),
7163 .shift = .{ .lsl = shift },
7164 } }));
7165 break :temp_ra temp_ra;
7166 },
7167 .sub => switch (base_ra) {
7168 else => {
7169 const temp_ra = try isel.allocIntReg();
7170 errdefer isel.freeReg(temp_ra);
7171 try isel.emit(.add(elem_ptr_ra.x(), base_ra.x(), .{ .shifted_register = .{
7172 .register = temp_ra.x(),
7173 .shift = .{ .lsl = shift },
7174 } }));
7175 break :temp_ra temp_ra;
7176 },
7177 .zr => {
7178 if (shift > 0) try isel.emit(.ubfm(elem_ptr_ra.x(), elem_ptr_ra.x(), .{
7179 .N = .doubleword,
7180 .immr = -%shift,
7181 .imms = ~shift,
7182 }));
7183 break :temp_ra elem_ptr_ra;
7184 },
7185 },
7186 };
7187 defer if (temp_ra != elem_ptr_ra) isel.freeReg(temp_ra);
7188 try isel.emit(.sub(temp_ra.x(), index_mat.ra.x(), .{ .shifted_register = .{
7189 .register = index_mat.ra.x(),
7190 .shift = .{ .lsl = @intCast(64 - @clz(elem_size) - shift) },
7191 } }));
7192 } else {
7193 try isel.emit(switch (op) {
7194 .add => .madd(elem_ptr_ra.x(), index_mat.ra.x(), elem_ptr_ra.x(), base_ra.x()),
7195 .sub => .msub(elem_ptr_ra.x(), index_mat.ra.x(), elem_ptr_ra.x(), base_ra.x()),
7196 });
7197 try isel.movImmediate(elem_ptr_ra.x(), elem_size);
7198 }
7199 },
7200 }
7201 try index_mat.finish(isel);
7202}
7203
7204fn clzLimb(
7205 isel: *Select,
7206 res_ra: Register.Alias,
7207 src_int_info: std.builtin.Type.Int,
7208 src_ra: Register.Alias,
7209) !void {
7210 switch (src_int_info.bits) {
7211 else => unreachable,
7212 1...31 => |bits| {
7213 try isel.emit(.sub(res_ra.w(), res_ra.w(), .{
7214 .immediate = @intCast(32 - bits),
7215 }));
7216 switch (src_int_info.signedness) {
7217 .signed => {
7218 try isel.emit(.clz(res_ra.w(), res_ra.w()));
7219 try isel.emit(.ubfm(res_ra.w(), src_ra.w(), .{
7220 .N = .word,
7221 .immr = 0,
7222 .imms = @intCast(bits - 1),
7223 }));
7224 },
7225 .unsigned => try isel.emit(.clz(res_ra.w(), src_ra.w())),
7226 }
7227 },
7228 32 => try isel.emit(.clz(res_ra.w(), src_ra.w())),
7229 33...63 => |bits| {
7230 try isel.emit(.sub(res_ra.w(), res_ra.w(), .{
7231 .immediate = @intCast(64 - bits),
7232 }));
7233 switch (src_int_info.signedness) {
7234 .signed => {
7235 try isel.emit(.clz(res_ra.x(), res_ra.x()));
7236 try isel.emit(.ubfm(res_ra.x(), src_ra.x(), .{
7237 .N = .doubleword,
7238 .immr = 0,
7239 .imms = @intCast(bits - 1),
7240 }));
7241 },
7242 .unsigned => try isel.emit(.clz(res_ra.x(), src_ra.x())),
7243 }
7244 },
7245 64 => try isel.emit(.clz(res_ra.x(), src_ra.x())),
7246 }
7247}
7248
7249fn ctzLimb(
7250 isel: *Select,
7251 res_ra: Register.Alias,
7252 src_int_info: std.builtin.Type.Int,
7253 src_ra: Register.Alias,
7254) !void {
7255 switch (src_int_info.bits) {
7256 else => unreachable,
7257 1...31 => |bits| {
7258 try isel.emit(.clz(res_ra.w(), res_ra.w()));
7259 try isel.emit(.rbit(res_ra.w(), res_ra.w()));
7260 try isel.emit(.orr(res_ra.w(), src_ra.w(), .{ .immediate = .{
7261 .N = .word,
7262 .immr = @intCast(32 - bits),
7263 .imms = @intCast(32 - bits - 1),
7264 } }));
7265 },
7266 32 => {
7267 try isel.emit(.clz(res_ra.w(), res_ra.w()));
7268 try isel.emit(.rbit(res_ra.w(), src_ra.w()));
7269 },
7270 33...63 => |bits| {
7271 try isel.emit(.clz(res_ra.x(), res_ra.x()));
7272 try isel.emit(.rbit(res_ra.x(), res_ra.x()));
7273 try isel.emit(.orr(res_ra.x(), src_ra.x(), .{ .immediate = .{
7274 .N = .doubleword,
7275 .immr = @intCast(64 - bits),
7276 .imms = @intCast(64 - bits - 1),
7277 } }));
7278 },
7279 64 => {
7280 try isel.emit(.clz(res_ra.x(), res_ra.x()));
7281 try isel.emit(.rbit(res_ra.x(), src_ra.x()));
7282 },
7283 }
7284}
7285
7286fn storeReg(
7287 isel: *Select,
7288 ra: Register.Alias,
7289 size: u64,
7290 base_ra: Register.Alias,
7291 offset: i65,
7292) !void {
7293 switch (size) {
7294 0 => unreachable,
7295 1 => {
7296 if (std.math.cast(u12, offset)) |unsigned_offset| return isel.emit(if (ra.isVector()) .str(
7297 ra.b(),
7298 .{ .unsigned_offset = .{
7299 .base = base_ra.x(),
7300 .offset = unsigned_offset,
7301 } },
7302 ) else .strb(
7303 ra.w(),
7304 .{ .unsigned_offset = .{
7305 .base = base_ra.x(),
7306 .offset = unsigned_offset,
7307 } },
7308 ));
7309 if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(if (ra.isVector())
7310 .stur(ra.b(), base_ra.x(), signed_offset)
7311 else
7312 .sturb(ra.w(), base_ra.x(), signed_offset));
7313 },
7314 2 => {
7315 if (std.math.cast(u13, offset)) |unsigned_offset| if (unsigned_offset % 2 == 0)
7316 return isel.emit(if (ra.isVector()) .str(
7317 ra.h(),
7318 .{ .unsigned_offset = .{
7319 .base = base_ra.x(),
7320 .offset = unsigned_offset,
7321 } },
7322 ) else .strh(
7323 ra.w(),
7324 .{ .unsigned_offset = .{
7325 .base = base_ra.x(),
7326 .offset = unsigned_offset,
7327 } },
7328 ));
7329 if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(if (ra.isVector())
7330 .stur(ra.h(), base_ra.x(), signed_offset)
7331 else
7332 .sturh(ra.w(), base_ra.x(), signed_offset));
7333 },
7334 3 => {
7335 const hi8_ra = try isel.allocIntReg();
7336 defer isel.freeReg(hi8_ra);
7337 try isel.storeReg(hi8_ra, 1, base_ra, offset + 2);
7338 try isel.storeReg(ra, 2, base_ra, offset);
7339 return isel.emit(.ubfm(hi8_ra.w(), ra.w(), .{
7340 .N = .word,
7341 .immr = 16,
7342 .imms = 16 + 8 - 1,
7343 }));
7344 },
7345 4 => {
7346 if (std.math.cast(u14, offset)) |unsigned_offset| if (unsigned_offset % 4 == 0) return isel.emit(.str(
7347 if (ra.isVector()) ra.s() else ra.w(),
7348 .{ .unsigned_offset = .{
7349 .base = base_ra.x(),
7350 .offset = unsigned_offset,
7351 } },
7352 ));
7353 if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(.stur(
7354 if (ra.isVector()) ra.s() else ra.w(),
7355 base_ra.x(),
7356 signed_offset,
7357 ));
7358 },
7359 5 => {
7360 const hi8_ra = try isel.allocIntReg();
7361 defer isel.freeReg(hi8_ra);
7362 try isel.storeReg(hi8_ra, 1, base_ra, offset + 4);
7363 try isel.storeReg(ra, 4, base_ra, offset);
7364 return isel.emit(.ubfm(hi8_ra.x(), ra.x(), .{
7365 .N = .doubleword,
7366 .immr = 32,
7367 .imms = 32 + 8 - 1,
7368 }));
7369 },
7370 6 => {
7371 const hi16_ra = try isel.allocIntReg();
7372 defer isel.freeReg(hi16_ra);
7373 try isel.storeReg(hi16_ra, 2, base_ra, offset + 4);
7374 try isel.storeReg(ra, 4, base_ra, offset);
7375 return isel.emit(.ubfm(hi16_ra.x(), ra.x(), .{
7376 .N = .doubleword,
7377 .immr = 32,
7378 .imms = 32 + 16 - 1,
7379 }));
7380 },
7381 7 => {
7382 const hi16_ra = try isel.allocIntReg();
7383 defer isel.freeReg(hi16_ra);
7384 const hi8_ra = try isel.allocIntReg();
7385 defer isel.freeReg(hi8_ra);
7386 try isel.storeReg(hi8_ra, 1, base_ra, offset + 6);
7387 try isel.storeReg(hi16_ra, 2, base_ra, offset + 4);
7388 try isel.storeReg(ra, 4, base_ra, offset);
7389 try isel.emit(.ubfm(hi8_ra.x(), ra.x(), .{
7390 .N = .doubleword,
7391 .immr = 32 + 16,
7392 .imms = 32 + 16 + 8 - 1,
7393 }));
7394 return isel.emit(.ubfm(hi16_ra.x(), ra.x(), .{
7395 .N = .doubleword,
7396 .immr = 32,
7397 .imms = 32 + 16 - 1,
7398 }));
7399 },
7400 8 => {
7401 if (std.math.cast(u15, offset)) |unsigned_offset| if (unsigned_offset % 8 == 0) return isel.emit(.str(
7402 if (ra.isVector()) ra.d() else ra.x(),
7403 .{ .unsigned_offset = .{
7404 .base = base_ra.x(),
7405 .offset = unsigned_offset,
7406 } },
7407 ));
7408 if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(.stur(
7409 if (ra.isVector()) ra.d() else ra.x(),
7410 base_ra.x(),
7411 signed_offset,
7412 ));
7413 },
7414 16 => {
7415 if (std.math.cast(u16, offset)) |unsigned_offset| if (unsigned_offset % 16 == 0) return isel.emit(.str(
7416 ra.q(),
7417 .{ .unsigned_offset = .{
7418 .base = base_ra.x(),
7419 .offset = unsigned_offset,
7420 } },
7421 ));
7422 if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(.stur(ra.q(), base_ra.x(), signed_offset));
7423 },
7424 else => return isel.fail("bad store size: {d}", .{size}),
7425 }
7426 const ptr_ra = try isel.allocIntReg();
7427 defer isel.freeReg(ptr_ra);
7428 try isel.storeReg(ra, size, ptr_ra, 0);
7429 if (std.math.cast(u24, offset)) |pos_offset| {
7430 const lo12: u12 = @truncate(pos_offset >> 0);
7431 const hi12: u12 = @intCast(pos_offset >> 12);
7432 if (hi12 > 0) try isel.emit(.add(
7433 ptr_ra.x(),
7434 if (lo12 > 0) ptr_ra.x() else base_ra.x(),
7435 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
7436 ));
7437 if (lo12 > 0 or hi12 == 0) try isel.emit(.add(ptr_ra.x(), base_ra.x(), .{ .immediate = lo12 }));
7438 } else if (std.math.cast(u24, -offset)) |neg_offset| {
7439 const lo12: u12 = @truncate(neg_offset >> 0);
7440 const hi12: u12 = @intCast(neg_offset >> 12);
7441 if (hi12 > 0) try isel.emit(.sub(
7442 ptr_ra.x(),
7443 if (lo12 > 0) ptr_ra.x() else base_ra.x(),
7444 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
7445 ));
7446 if (lo12 > 0 or hi12 == 0) try isel.emit(.sub(ptr_ra.x(), base_ra.x(), .{ .immediate = lo12 }));
7447 } else {
7448 try isel.emit(.add(ptr_ra.x(), base_ra.x(), .{ .register = ptr_ra.x() }));
7449 try isel.movImmediate(ptr_ra.x(), @truncate(@as(u65, @bitCast(offset))));
7450 }
7451}
7452
7453const DomInt = u8;
7454
7455pub const Value = struct {
7456 refs: u32,
7457 flags: Flags,
7458 offset_from_parent: u64,
7459 parent_payload: Parent.Payload,
7460 location_payload: Location.Payload,
7461 parts: Value.Index,
7462
7463 /// Must be at least 16 to compute call abi.
7464 /// Must be at least 16, the largest hardware alignment.
7465 pub const max_parts = 16;
7466 pub const PartsLen = std.math.IntFittingRange(0, Value.max_parts);
7467
7468 comptime {
7469 if (!std.debug.runtime_safety) assert(@sizeOf(Value) == 32);
7470 }
7471
7472 pub const Flags = packed struct(u32) {
7473 alignment: InternPool.Alignment,
7474 parent_tag: Parent.Tag,
7475 location_tag: Location.Tag,
7476 parts_len_minus_one: std.math.IntFittingRange(0, Value.max_parts - 1),
7477 unused: u18 = 0,
7478 };
7479
7480 pub const Parent = union(enum(u3)) {
7481 unallocated: void,
7482 stack_slot: Indirect,
7483 address: Value.Index,
7484 value: Value.Index,
7485 constant: Constant,
7486
7487 pub const Tag = @typeInfo(Parent).@"union".tag_type.?;
7488 pub const Payload = @Type(.{ .@"union" = .{
7489 .layout = .auto,
7490 .tag_type = null,
7491 .fields = @typeInfo(Parent).@"union".fields,
7492 .decls = &.{},
7493 } });
7494 };
7495
7496 pub const Location = union(enum(u1)) {
7497 large: struct {
7498 size: u64,
7499 },
7500 small: struct {
7501 size: u5,
7502 signedness: std.builtin.Signedness,
7503 is_vector: bool,
7504 hint: Register.Alias,
7505 register: Register.Alias,
7506 },
7507
7508 pub const Tag = @typeInfo(Location).@"union".tag_type.?;
7509 pub const Payload = @Type(.{ .@"union" = .{
7510 .layout = .auto,
7511 .tag_type = null,
7512 .fields = @typeInfo(Location).@"union".fields,
7513 .decls = &.{},
7514 } });
7515 };
7516
7517 pub const Indirect = packed struct(u32) {
7518 base: Register.Alias,
7519 offset: i25,
7520
7521 pub fn withOffset(ind: Indirect, offset: i25) Indirect {
7522 return .{
7523 .base = ind.base,
7524 .offset = ind.offset + offset,
7525 };
7526 }
7527 };
7528
7529 pub const Index = enum(u32) {
7530 allocating = std.math.maxInt(u32) - 1,
7531 free = std.math.maxInt(u32) - 0,
7532 _,
7533
7534 fn get(vi: Value.Index, isel: *Select) *Value {
7535 return &isel.values.items[@intFromEnum(vi)];
7536 }
7537
7538 fn setAlignment(vi: Value.Index, isel: *Select, new_alignment: InternPool.Alignment) void {
7539 vi.get(isel).flags.alignment = new_alignment;
7540 }
7541
7542 pub fn alignment(vi: Value.Index, isel: *Select) InternPool.Alignment {
7543 return vi.get(isel).flags.alignment;
7544 }
7545
7546 pub fn setParent(vi: Value.Index, isel: *Select, new_parent: Parent) void {
7547 const value = vi.get(isel);
7548 assert(value.flags.parent_tag == .unallocated);
7549 value.flags.parent_tag = new_parent;
7550 value.parent_payload = switch (new_parent) {
7551 .unallocated => unreachable,
7552 inline else => |payload, tag| @unionInit(Parent.Payload, @tagName(tag), payload),
7553 };
7554 if (value.refs > 0) switch (new_parent) {
7555 .unallocated => unreachable,
7556 .stack_slot, .constant => {},
7557 .address, .value => |parent_vi| _ = parent_vi.ref(isel),
7558 };
7559 }
7560
7561 pub fn parent(vi: Value.Index, isel: *Select) Parent {
7562 const value = vi.get(isel);
7563 return switch (value.flags.parent_tag) {
7564 inline else => |tag| @unionInit(
7565 Parent,
7566 @tagName(tag),
7567 @field(value.parent_payload, @tagName(tag)),
7568 ),
7569 };
7570 }
7571
7572 pub fn valueParent(initial_vi: Value.Index, isel: *Select) struct { u64, Value.Index } {
7573 var offset: u64 = 0;
7574 var vi = initial_vi;
7575 parent: switch (vi.parent(isel)) {
7576 else => return .{ offset, vi },
7577 .value => |parent_vi| {
7578 offset += vi.position(isel)[0];
7579 vi = parent_vi;
7580 continue :parent parent_vi.parent(isel);
7581 },
7582 }
7583 }
7584
7585 pub fn location(vi: Value.Index, isel: *Select) Location {
7586 const value = vi.get(isel);
7587 return switch (value.flags.location_tag) {
7588 inline else => |tag| @unionInit(
7589 Location,
7590 @tagName(tag),
7591 @field(value.location_payload, @tagName(tag)),
7592 ),
7593 };
7594 }
7595
7596 pub fn position(vi: Value.Index, isel: *Select) struct { u64, u64 } {
7597 return .{ vi.get(isel).offset_from_parent, vi.size(isel) };
7598 }
7599
7600 pub fn size(vi: Value.Index, isel: *Select) u64 {
7601 return switch (vi.location(isel)) {
7602 inline else => |loc| loc.size,
7603 };
7604 }
7605
7606 fn setHint(vi: Value.Index, isel: *Select, new_hint: Register.Alias) void {
7607 vi.get(isel).location_payload.small.hint = new_hint;
7608 }
7609
7610 pub fn hint(vi: Value.Index, isel: *Select) ?Register.Alias {
7611 return switch (vi.location(isel)) {
7612 .large => null,
7613 .small => |loc| switch (loc.hint) {
7614 .zr => null,
7615 else => |hint_reg| hint_reg,
7616 },
7617 };
7618 }
7619
7620 fn setSignedness(vi: Value.Index, isel: *Select, new_signedness: std.builtin.Signedness) void {
7621 const value = vi.get(isel);
7622 assert(value.location_payload.small.size <= 2);
7623 value.location_payload.small.signedness = new_signedness;
7624 }
7625
7626 pub fn signedness(vi: Value.Index, isel: *Select) std.builtin.Signedness {
7627 const value = vi.get(isel);
7628 return switch (value.flags.location_tag) {
7629 .large => .unsigned,
7630 .small => value.location_payload.small.signedness,
7631 };
7632 }
7633
7634 fn setIsVector(vi: Value.Index, isel: *Select) void {
7635 const is_vector = &vi.get(isel).location_payload.small.is_vector;
7636 assert(!is_vector.*);
7637 is_vector.* = true;
7638 }
7639
7640 pub fn isVector(vi: Value.Index, isel: *Select) bool {
7641 const value = vi.get(isel);
7642 return switch (value.flags.location_tag) {
7643 .large => false,
7644 .small => value.location_payload.small.is_vector,
7645 };
7646 }
7647
7648 pub fn register(vi: Value.Index, isel: *Select) ?Register.Alias {
7649 return switch (vi.location(isel)) {
7650 .large => null,
7651 .small => |loc| switch (loc.register) {
7652 .zr => null,
7653 else => |reg| reg,
7654 },
7655 };
7656 }
7657
7658 pub fn isUsed(vi: Value.Index, isel: *Select) bool {
7659 return vi.valueParent(isel)[1].parent(isel) != .unallocated or vi.hasRegisterRecursive(isel);
7660 }
7661
7662 fn hasRegisterRecursive(vi: Value.Index, isel: *Select) bool {
7663 if (vi.register(isel)) |_| return true;
7664 var part_it = vi.parts(isel);
7665 if (part_it.only() == null) while (part_it.next()) |part_vi| if (part_vi.hasRegisterRecursive(isel)) return true;
7666 return false;
7667 }
7668
7669 fn setParts(vi: Value.Index, isel: *Select, parts_len: Value.PartsLen) void {
7670 assert(parts_len > 1);
7671 const value = vi.get(isel);
7672 assert(value.flags.parts_len_minus_one == 0);
7673 value.parts = @enumFromInt(isel.values.items.len);
7674 value.flags.parts_len_minus_one = @intCast(parts_len - 1);
7675 }
7676
7677 fn addPart(vi: Value.Index, isel: *Select, part_offset: u64, part_size: u64) Value.Index {
7678 const part_vi = isel.initValueAdvanced(vi.alignment(isel), part_offset, part_size);
7679 tracking_log.debug("${d} <- ${d}[{d}]", .{
7680 @intFromEnum(part_vi),
7681 @intFromEnum(vi),
7682 part_offset,
7683 });
7684 part_vi.setParent(isel, .{ .value = vi });
7685 return part_vi;
7686 }
7687
7688 pub fn parts(vi: Value.Index, isel: *Select) Value.PartIterator {
7689 const value = vi.get(isel);
7690 return switch (value.flags.parts_len_minus_one) {
7691 0 => .initOne(vi),
7692 else => |parts_len_minus_one| .{
7693 .vi = value.parts,
7694 .remaining = @as(Value.PartsLen, parts_len_minus_one) + 1,
7695 },
7696 };
7697 }
7698
7699 fn containingParts(vi: Value.Index, isel: *Select, part_offset: u64, part_size: u64) Value.PartIterator {
7700 const start_vi = vi.partAtOffset(isel, part_offset);
7701 const start_offset, const start_size = start_vi.position(isel);
7702 if (part_offset >= start_offset and part_size <= start_size) return .initOne(start_vi);
7703 const end_vi = vi.partAtOffset(isel, part_size - 1 + part_offset);
7704 return .{
7705 .vi = start_vi,
7706 .remaining = @intCast(@intFromEnum(end_vi) - @intFromEnum(start_vi) + 1),
7707 };
7708 }
7709 comptime {
7710 _ = containingParts;
7711 }
7712
7713 fn partAtOffset(vi: Value.Index, isel: *Select, offset: u64) Value.Index {
7714 const SearchPartIndex = std.math.IntFittingRange(0, Value.max_parts * 2 - 1);
7715 const value = vi.get(isel);
7716 var last: SearchPartIndex = value.flags.parts_len_minus_one;
7717 if (last == 0) return vi;
7718 var first: SearchPartIndex = 0;
7719 last += 1;
7720 while (true) {
7721 const mid = (first + last) / 2;
7722 const mid_vi: Value.Index = @enumFromInt(@intFromEnum(value.parts) + mid);
7723 if (mid == first) return mid_vi;
7724 if (offset < mid_vi.get(isel).offset_from_parent) last = mid else first = mid;
7725 }
7726 }
7727
7728 fn field(
7729 vi: Value.Index,
7730 ty: ZigType,
7731 field_offset: u64,
7732 field_size: u64,
7733 ) Value.FieldPartIterator {
7734 assert(field_size > 0);
7735 return .{
7736 .vi = vi,
7737 .ty = ty,
7738 .field_offset = field_offset,
7739 .field_size = field_size,
7740 .next_offset = 0,
7741 };
7742 }
7743
7744 fn ref(initial_vi: Value.Index, isel: *Select) Value.Index {
7745 var vi = initial_vi;
7746 while (true) {
7747 const refs = &vi.get(isel).refs;
7748 refs.* += 1;
7749 if (refs.* > 1) return initial_vi;
7750 switch (vi.parent(isel)) {
7751 .unallocated, .stack_slot, .constant => {},
7752 .address, .value => |parent_vi| {
7753 vi = parent_vi;
7754 continue;
7755 },
7756 }
7757 return initial_vi;
7758 }
7759 }
7760
7761 pub fn deref(initial_vi: Value.Index, isel: *Select) void {
7762 var vi = initial_vi;
7763 while (true) {
7764 const refs = &vi.get(isel).refs;
7765 refs.* -= 1;
7766 if (refs.* > 0) return;
7767 switch (vi.parent(isel)) {
7768 .unallocated, .constant => {},
7769 .stack_slot => {
7770 // reuse stack slot
7771 },
7772 .address, .value => |parent_vi| {
7773 vi = parent_vi;
7774 continue;
7775 },
7776 }
7777 return;
7778 }
7779 }
7780
7781 fn move(dst_vi: Value.Index, isel: *Select, src_ref: Air.Inst.Ref) !void {
7782 try dst_vi.copy(
7783 isel,
7784 isel.air.typeOf(src_ref, &isel.pt.zcu.intern_pool),
7785 try isel.use(src_ref),
7786 );
7787 }
7788
7789 fn copy(dst_vi: Value.Index, isel: *Select, ty: ZigType, src_vi: Value.Index) !void {
7790 try dst_vi.copyAdvanced(isel, src_vi, .{
7791 .ty = ty,
7792 .dst_vi = dst_vi,
7793 .dst_offset = 0,
7794 .src_vi = src_vi,
7795 .src_offset = 0,
7796 });
7797 }
7798
7799 fn copyAdvanced(dst_vi: Value.Index, isel: *Select, src_vi: Value.Index, root: struct {
7800 ty: ZigType,
7801 dst_vi: Value.Index,
7802 dst_offset: u64,
7803 src_vi: Value.Index,
7804 src_offset: u64,
7805 }) !void {
7806 if (dst_vi == src_vi) return;
7807 var dst_part_it = dst_vi.parts(isel);
7808 if (dst_part_it.only()) |dst_part_vi| {
7809 var src_part_it = src_vi.parts(isel);
7810 if (src_part_it.only()) |src_part_vi| {
7811 try src_part_vi.liveOut(isel, try dst_part_vi.defReg(isel) orelse return);
7812 } else while (src_part_it.next()) |src_part_vi| {
7813 const src_part_offset, const src_part_size = src_part_vi.position(isel);
7814 var dst_field_it = root.dst_vi.field(root.ty, root.dst_offset + src_part_offset, src_part_size);
7815 const dst_field_vi = try dst_field_it.only(isel);
7816 try dst_field_vi.?.copyAdvanced(isel, src_part_vi, .{
7817 .ty = root.ty,
7818 .dst_vi = root.dst_vi,
7819 .dst_offset = root.dst_offset + src_part_offset,
7820 .src_vi = root.src_vi,
7821 .src_offset = root.src_offset + src_part_offset,
7822 });
7823 }
7824 } else while (dst_part_it.next()) |dst_part_vi| {
7825 const dst_part_offset, const dst_part_size = dst_part_vi.position(isel);
7826 var src_field_it = root.src_vi.field(root.ty, root.src_offset + dst_part_offset, dst_part_size);
7827 const src_part_vi = try src_field_it.only(isel);
7828 try dst_part_vi.copyAdvanced(isel, src_part_vi.?, .{
7829 .ty = root.ty,
7830 .dst_vi = root.dst_vi,
7831 .dst_offset = root.dst_offset + dst_part_offset,
7832 .src_vi = root.src_vi,
7833 .src_offset = root.src_offset + dst_part_offset,
7834 });
7835 }
7836 }
7837
7838 fn addOrSubtract(
7839 res_vi: Value.Index,
7840 isel: *Select,
7841 ty: ZigType,
7842 lhs_vi: Value.Index,
7843 op: codegen.aarch64.encoding.Instruction.AddSubtractOp,
7844 rhs_vi: Value.Index,
7845 opts: struct {
7846 wrap: bool,
7847 overflow_ra: Register.Alias = .zr,
7848 },
7849 ) !void {
7850 assert(opts.wrap or opts.overflow_ra == .zr);
7851 const zcu = isel.pt.zcu;
7852 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(op), isel.fmtType(ty) });
7853 const int_info = ty.intInfo(zcu);
7854 if (int_info.bits > 128) return isel.fail("too big {s} {f}", .{ @tagName(op), isel.fmtType(ty) });
7855 var part_offset = res_vi.size(isel);
7856 var need_wrap = opts.wrap;
7857 var need_carry = opts.overflow_ra != .zr;
7858 while (part_offset > 0) : (need_wrap = false) {
7859 const part_size = @min(part_offset, 8);
7860 part_offset -= part_size;
7861 var wrapped_res_part_it = res_vi.field(ty, part_offset, part_size);
7862 const wrapped_res_part_vi = try wrapped_res_part_it.only(isel);
7863 const wrapped_res_part_ra = try wrapped_res_part_vi.?.defReg(isel) orelse if (need_carry) .zr else continue;
7864 const unwrapped_res_part_ra = unwrapped_res_part_ra: {
7865 if (!need_wrap) break :unwrapped_res_part_ra wrapped_res_part_ra;
7866 if (int_info.bits % 32 == 0) {
7867 if (opts.overflow_ra != .zr) try isel.emit(.csinc(opts.overflow_ra.w(), .wzr, .wzr, .invert(switch (int_info.signedness) {
7868 .signed => .vs,
7869 .unsigned => switch (op) {
7870 .add => .cs,
7871 .sub => .cc,
7872 },
7873 })));
7874 break :unwrapped_res_part_ra wrapped_res_part_ra;
7875 }
7876 const wrapped_part_ra, const unwrapped_part_ra = if (opts.overflow_ra != .zr) part_ra: {
7877 switch (op) {
7878 .add => {},
7879 .sub => switch (int_info.signedness) {
7880 .signed => {},
7881 .unsigned => {
7882 try isel.emit(.csinc(opts.overflow_ra.w(), .wzr, .wzr, .invert(.cc)));
7883 break :part_ra .{ wrapped_res_part_ra, wrapped_res_part_ra };
7884 },
7885 },
7886 }
7887 try isel.emit(.csinc(opts.overflow_ra.w(), .wzr, .wzr, .invert(.ne)));
7888 const wrapped_part_ra = switch (wrapped_res_part_ra) {
7889 else => |res_part_ra| res_part_ra,
7890 .zr => try isel.allocIntReg(),
7891 };
7892 errdefer if (wrapped_part_ra != wrapped_res_part_ra) isel.freeReg(wrapped_part_ra);
7893 const unwrapped_part_ra = unwrapped_part_ra: {
7894 const wrapped_res_part_lock: RegLock = switch (wrapped_res_part_ra) {
7895 else => |res_part_ra| isel.lockReg(res_part_ra),
7896 .zr => .empty,
7897 };
7898 defer wrapped_res_part_lock.unlock(isel);
7899 break :unwrapped_part_ra try isel.allocIntReg();
7900 };
7901 errdefer isel.freeReg(unwrapped_part_ra);
7902 switch (part_size) {
7903 else => unreachable,
7904 1...4 => try isel.emit(.subs(.wzr, wrapped_part_ra.w(), .{ .register = unwrapped_part_ra.w() })),
7905 5...8 => try isel.emit(.subs(.xzr, wrapped_part_ra.x(), .{ .register = unwrapped_part_ra.x() })),
7906 }
7907 break :part_ra .{ wrapped_part_ra, unwrapped_part_ra };
7908 } else .{ wrapped_res_part_ra, wrapped_res_part_ra };
7909 defer if (wrapped_part_ra != wrapped_res_part_ra) isel.freeReg(wrapped_part_ra);
7910 errdefer if (unwrapped_part_ra != wrapped_res_part_ra) isel.freeReg(unwrapped_part_ra);
7911 if (wrapped_part_ra != .zr) try isel.emit(switch (part_size) {
7912 else => unreachable,
7913 1...4 => switch (int_info.signedness) {
7914 .signed => .sbfm(wrapped_part_ra.w(), unwrapped_part_ra.w(), .{
7915 .N = .word,
7916 .immr = 0,
7917 .imms = @truncate(int_info.bits - 1),
7918 }),
7919 .unsigned => .ubfm(wrapped_part_ra.w(), unwrapped_part_ra.w(), .{
7920 .N = .word,
7921 .immr = 0,
7922 .imms = @truncate(int_info.bits - 1),
7923 }),
7924 },
7925 5...8 => switch (int_info.signedness) {
7926 .signed => .sbfm(wrapped_part_ra.x(), unwrapped_part_ra.x(), .{
7927 .N = .doubleword,
7928 .immr = 0,
7929 .imms = @truncate(int_info.bits - 1),
7930 }),
7931 .unsigned => .ubfm(wrapped_part_ra.x(), unwrapped_part_ra.x(), .{
7932 .N = .doubleword,
7933 .immr = 0,
7934 .imms = @truncate(int_info.bits - 1),
7935 }),
7936 },
7937 });
7938 break :unwrapped_res_part_ra unwrapped_part_ra;
7939 };
7940 defer if (unwrapped_res_part_ra != wrapped_res_part_ra) isel.freeReg(unwrapped_res_part_ra);
7941 var lhs_part_it = lhs_vi.field(ty, part_offset, part_size);
7942 const lhs_part_vi = try lhs_part_it.only(isel);
7943 const lhs_part_mat = try lhs_part_vi.?.matReg(isel);
7944 var rhs_part_it = rhs_vi.field(ty, part_offset, part_size);
7945 const rhs_part_vi = try rhs_part_it.only(isel);
7946 const rhs_part_mat = try rhs_part_vi.?.matReg(isel);
7947 try isel.emit(switch (part_size) {
7948 else => unreachable,
7949 1...4 => switch (op) {
7950 .add => switch (part_offset) {
7951 0 => switch (need_carry) {
7952 false => .add(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }),
7953 true => .adds(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }),
7954 },
7955 else => switch (need_carry) {
7956 false => .adc(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), rhs_part_mat.ra.w()),
7957 true => .adcs(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), rhs_part_mat.ra.w()),
7958 },
7959 },
7960 .sub => switch (part_offset) {
7961 0 => switch (need_carry) {
7962 false => .sub(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }),
7963 true => .subs(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }),
7964 },
7965 else => switch (need_carry) {
7966 false => .sbc(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), rhs_part_mat.ra.w()),
7967 true => .sbcs(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), rhs_part_mat.ra.w()),
7968 },
7969 },
7970 },
7971 5...8 => switch (op) {
7972 .add => switch (part_offset) {
7973 0 => switch (need_carry) {
7974 false => .add(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }),
7975 true => .adds(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }),
7976 },
7977 else => switch (need_carry) {
7978 false => .adc(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), rhs_part_mat.ra.x()),
7979 true => .adcs(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), rhs_part_mat.ra.x()),
7980 },
7981 },
7982 .sub => switch (part_offset) {
7983 0 => switch (need_carry) {
7984 false => .sub(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }),
7985 true => .subs(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }),
7986 },
7987 else => switch (need_carry) {
7988 false => .sbc(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), rhs_part_mat.ra.x()),
7989 true => .sbcs(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), rhs_part_mat.ra.x()),
7990 },
7991 },
7992 },
7993 });
7994 try rhs_part_mat.finish(isel);
7995 try lhs_part_mat.finish(isel);
7996 need_carry = true;
7997 }
7998 }
7999
8000 const MemoryAccessOptions = struct {
8001 root_vi: Value.Index = .free,
8002 offset: u64 = 0,
8003 @"volatile": bool = false,
8004 split: bool = true,
8005 wrap: ?std.builtin.Type.Int = null,
8006 expected_live_registers: *const LiveRegisters = &.initFill(.free),
8007 };
8008
8009 fn load(
8010 vi: Value.Index,
8011 isel: *Select,
8012 root_ty: ZigType,
8013 base_ra: Register.Alias,
8014 opts: MemoryAccessOptions,
8015 ) !bool {
8016 const root_vi = switch (opts.root_vi) {
8017 _ => |root_vi| root_vi,
8018 .allocating => unreachable,
8019 .free => vi,
8020 };
8021 var part_it = vi.parts(isel);
8022 if (part_it.only()) |part_vi| only: {
8023 const part_size = part_vi.size(isel);
8024 const part_is_vector = part_vi.isVector(isel);
8025 if (part_size > @as(@TypeOf(part_size), if (part_is_vector) 16 else 8)) {
8026 if (!opts.split) return false;
8027 var subpart_it = root_vi.field(root_ty, opts.offset, part_size - 1);
8028 _ = try subpart_it.next(isel);
8029 part_it = vi.parts(isel);
8030 assert(part_it.only() == null);
8031 break :only;
8032 }
8033 const part_ra = if (try part_vi.defReg(isel)) |part_ra|
8034 part_ra
8035 else if (opts.@"volatile")
8036 .zr
8037 else
8038 return false;
8039 if (part_ra != .zr) {
8040 const live_vi = isel.live_registers.getPtr(part_ra);
8041 assert(live_vi.* == .free);
8042 live_vi.* = .allocating;
8043 }
8044 if (opts.wrap) |int_info| switch (int_info.bits) {
8045 else => unreachable,
8046 1...7, 9...15, 17...31 => |bits| try isel.emit(switch (int_info.signedness) {
8047 .signed => .sbfm(part_ra.w(), part_ra.w(), .{
8048 .N = .word,
8049 .immr = 0,
8050 .imms = @intCast(bits - 1),
8051 }),
8052 .unsigned => .ubfm(part_ra.w(), part_ra.w(), .{
8053 .N = .word,
8054 .immr = 0,
8055 .imms = @intCast(bits - 1),
8056 }),
8057 }),
8058 8, 16, 32 => {},
8059 33...63 => |bits| try isel.emit(switch (int_info.signedness) {
8060 .signed => .sbfm(part_ra.x(), part_ra.x(), .{
8061 .N = .doubleword,
8062 .immr = 0,
8063 .imms = @intCast(bits - 1),
8064 }),
8065 .unsigned => .ubfm(part_ra.x(), part_ra.x(), .{
8066 .N = .doubleword,
8067 .immr = 0,
8068 .imms = @intCast(bits - 1),
8069 }),
8070 }),
8071 64 => {},
8072 };
8073 try isel.emit(emit: switch (part_size) {
8074 else => return isel.fail("bad load size of {d}", .{part_size}),
8075 1 => if (part_is_vector) .ldr(part_ra.b(), .{ .unsigned_offset = .{
8076 .base = base_ra.x(),
8077 .offset = @intCast(opts.offset),
8078 } }) else switch (part_vi.signedness(isel)) {
8079 .signed => .ldrsb(part_ra.w(), .{ .unsigned_offset = .{
8080 .base = base_ra.x(),
8081 .offset = @intCast(opts.offset),
8082 } }),
8083 .unsigned => .ldrb(part_ra.w(), .{ .unsigned_offset = .{
8084 .base = base_ra.x(),
8085 .offset = @intCast(opts.offset),
8086 } }),
8087 },
8088 2 => if (part_is_vector) .ldr(part_ra.h(), .{ .unsigned_offset = .{
8089 .base = base_ra.x(),
8090 .offset = @intCast(opts.offset),
8091 } }) else switch (part_vi.signedness(isel)) {
8092 .signed => .ldrsh(part_ra.w(), .{ .unsigned_offset = .{
8093 .base = base_ra.x(),
8094 .offset = @intCast(opts.offset),
8095 } }),
8096 .unsigned => .ldrh(part_ra.w(), .{ .unsigned_offset = .{
8097 .base = base_ra.x(),
8098 .offset = @intCast(opts.offset),
8099 } }),
8100 },
8101 3 => {
8102 const lo16_ra = try isel.allocIntReg();
8103 defer isel.freeReg(lo16_ra);
8104 try isel.emit(.orr(part_ra.w(), lo16_ra.w(), .{ .shifted_register = .{
8105 .register = part_ra.w(),
8106 .shift = .{ .lsl = 16 },
8107 } }));
8108 try isel.emit(switch (part_vi.signedness(isel)) {
8109 .signed => .ldrsb(part_ra.w(), .{ .unsigned_offset = .{
8110 .base = base_ra.x(),
8111 .offset = @intCast(opts.offset + 2),
8112 } }),
8113 .unsigned => .ldrb(part_ra.w(), .{ .unsigned_offset = .{
8114 .base = base_ra.x(),
8115 .offset = @intCast(opts.offset + 2),
8116 } }),
8117 });
8118 break :emit .ldrh(lo16_ra.w(), .{ .unsigned_offset = .{
8119 .base = base_ra.x(),
8120 .offset = @intCast(opts.offset),
8121 } });
8122 },
8123 4 => .ldr(if (part_is_vector) part_ra.s() else part_ra.w(), .{ .unsigned_offset = .{
8124 .base = base_ra.x(),
8125 .offset = @intCast(opts.offset),
8126 } }),
8127 5 => {
8128 const lo32_ra = try isel.allocIntReg();
8129 defer isel.freeReg(lo32_ra);
8130 try isel.emit(.orr(part_ra.x(), lo32_ra.x(), .{ .shifted_register = .{
8131 .register = part_ra.x(),
8132 .shift = .{ .lsl = 32 },
8133 } }));
8134 try isel.emit(switch (part_vi.signedness(isel)) {
8135 .signed => .ldrsb(part_ra.w(), .{ .unsigned_offset = .{
8136 .base = base_ra.x(),
8137 .offset = @intCast(opts.offset + 4),
8138 } }),
8139 .unsigned => .ldrb(part_ra.w(), .{ .unsigned_offset = .{
8140 .base = base_ra.x(),
8141 .offset = @intCast(opts.offset + 4),
8142 } }),
8143 });
8144 break :emit .ldr(lo32_ra.w(), .{ .unsigned_offset = .{
8145 .base = base_ra.x(),
8146 .offset = @intCast(opts.offset),
8147 } });
8148 },
8149 7 => {
8150 const lo32_ra = try isel.allocIntReg();
8151 defer isel.freeReg(lo32_ra);
8152 const lo48_ra = try isel.allocIntReg();
8153 defer isel.freeReg(lo48_ra);
8154 try isel.emit(.orr(part_ra.x(), lo48_ra.x(), .{ .shifted_register = .{
8155 .register = part_ra.x(),
8156 .shift = .{ .lsl = 32 + 16 },
8157 } }));
8158 try isel.emit(switch (part_vi.signedness(isel)) {
8159 .signed => .ldrsb(part_ra.w(), .{ .unsigned_offset = .{
8160 .base = base_ra.x(),
8161 .offset = @intCast(opts.offset + 4 + 2),
8162 } }),
8163 .unsigned => .ldrb(part_ra.w(), .{ .unsigned_offset = .{
8164 .base = base_ra.x(),
8165 .offset = @intCast(opts.offset + 4 + 2),
8166 } }),
8167 });
8168 try isel.emit(.orr(lo48_ra.x(), lo32_ra.x(), .{ .shifted_register = .{
8169 .register = lo48_ra.x(),
8170 .shift = .{ .lsl = 32 },
8171 } }));
8172 try isel.emit(.ldrh(lo48_ra.w(), .{ .unsigned_offset = .{
8173 .base = base_ra.x(),
8174 .offset = @intCast(opts.offset + 4),
8175 } }));
8176 break :emit .ldr(lo32_ra.w(), .{ .unsigned_offset = .{
8177 .base = base_ra.x(),
8178 .offset = @intCast(opts.offset),
8179 } });
8180 },
8181 8 => .ldr(if (part_is_vector) part_ra.d() else part_ra.x(), .{ .unsigned_offset = .{
8182 .base = base_ra.x(),
8183 .offset = @intCast(opts.offset),
8184 } }),
8185 16 => .ldr(part_ra.q(), .{ .unsigned_offset = .{
8186 .base = base_ra.x(),
8187 .offset = @intCast(opts.offset),
8188 } }),
8189 });
8190 if (part_ra != .zr) {
8191 const live_vi = isel.live_registers.getPtr(part_ra);
8192 assert(live_vi.* == .allocating);
8193 switch (opts.expected_live_registers.get(part_ra)) {
8194 _ => {},
8195 .allocating => unreachable,
8196 .free => live_vi.* = .free,
8197 }
8198 }
8199 return true;
8200 }
8201 var used = false;
8202 while (part_it.next()) |part_vi| used |= try part_vi.load(isel, root_ty, base_ra, .{
8203 .root_vi = root_vi,
8204 .offset = opts.offset + part_vi.get(isel).offset_from_parent,
8205 .@"volatile" = opts.@"volatile",
8206 .split = opts.split,
8207 .wrap = switch (part_it.remaining) {
8208 else => null,
8209 0 => if (opts.wrap) |wrap| .{
8210 .signedness = wrap.signedness,
8211 .bits = @intCast(wrap.bits - 8 * part_vi.position(isel)[0]),
8212 } else null,
8213 },
8214 .expected_live_registers = opts.expected_live_registers,
8215 });
8216 return used;
8217 }
8218
8219 fn store(
8220 vi: Value.Index,
8221 isel: *Select,
8222 root_ty: ZigType,
8223 base_ra: Register.Alias,
8224 opts: MemoryAccessOptions,
8225 ) !void {
8226 const root_vi = switch (opts.root_vi) {
8227 _ => |root_vi| root_vi,
8228 .allocating => unreachable,
8229 .free => vi,
8230 };
8231 var part_it = vi.parts(isel);
8232 if (part_it.only()) |part_vi| only: {
8233 const part_size = part_vi.size(isel);
8234 const part_is_vector = part_vi.isVector(isel);
8235 if (part_size > @as(@TypeOf(part_size), if (part_is_vector) 16 else 8)) {
8236 if (!opts.split) return;
8237 var subpart_it = root_vi.field(root_ty, opts.offset, part_size - 1);
8238 _ = try subpart_it.next(isel);
8239 part_it = vi.parts(isel);
8240 assert(part_it.only() == null);
8241 break :only;
8242 }
8243 const part_mat = try part_vi.matReg(isel);
8244 try isel.storeReg(part_mat.ra, part_size, base_ra, opts.offset);
8245 return part_mat.finish(isel);
8246 }
8247 while (part_it.next()) |part_vi| try part_vi.store(isel, root_ty, base_ra, .{
8248 .root_vi = root_vi,
8249 .offset = opts.offset + part_vi.get(isel).offset_from_parent,
8250 .@"volatile" = opts.@"volatile",
8251 .split = opts.split,
8252 .wrap = switch (part_it.remaining) {
8253 else => null,
8254 0 => if (opts.wrap) |wrap| .{
8255 .signedness = wrap.signedness,
8256 .bits = @intCast(wrap.bits - 8 * part_vi.position(isel)[0]),
8257 } else null,
8258 },
8259 .expected_live_registers = opts.expected_live_registers,
8260 });
8261 }
8262
8263 fn mat(vi: Value.Index, isel: *Select) !void {
8264 if (false) {
8265 var part_it: Value.PartIterator = if (vi.size(isel) > 8) vi.parts(isel) else .initOne(vi);
8266 if (part_it.only()) |part_vi| only: {
8267 const mat_ra = mat_ra: {
8268 if (part_vi.register(isel)) |mat_ra| {
8269 part_vi.get(isel).location_payload.small.register = .zr;
8270 const live_vi = isel.live_registers.getPtr(mat_ra);
8271 assert(live_vi.* == part_vi);
8272 live_vi.* = .allocating;
8273 break :mat_ra mat_ra;
8274 }
8275 if (part_vi.hint(isel)) |hint_ra| {
8276 const live_vi = isel.live_registers.getPtr(hint_ra);
8277 if (live_vi.* == .free) {
8278 live_vi.* = .allocating;
8279 isel.saved_registers.insert(hint_ra);
8280 break :mat_ra hint_ra;
8281 }
8282 }
8283 const part_size = part_vi.size(isel);
8284 const part_is_vector = part_vi.isVector(isel);
8285 if (part_size <= @as(@TypeOf(part_size), if (part_is_vector) 16 else 8))
8286 switch (if (part_is_vector) isel.tryAllocVecReg() else isel.tryAllocIntReg()) {
8287 .allocated => |ra| break :mat_ra ra,
8288 .fill_candidate, .out_of_registers => {},
8289 };
8290 _, const parent_vi = vi.valueParent(isel);
8291 switch (parent_vi.parent(isel)) {
8292 .unallocated => parent_vi.setParent(isel, .{ .stack_slot = parent_vi.allocStackSlot(isel) }),
8293 else => {},
8294 }
8295 break :only;
8296 };
8297 assert(isel.live_registers.get(mat_ra) == .allocating);
8298 try Value.Materialize.finish(.{ .vi = part_vi, .ra = mat_ra }, isel);
8299 } else while (part_it.next()) |part_vi| try part_vi.mat(isel);
8300 } else {
8301 _, const parent_vi = vi.valueParent(isel);
8302 switch (parent_vi.parent(isel)) {
8303 .unallocated => parent_vi.setParent(isel, .{ .stack_slot = parent_vi.allocStackSlot(isel) }),
8304 else => {},
8305 }
8306 }
8307 }
8308
8309 fn matReg(vi: Value.Index, isel: *Select) !Value.Materialize {
8310 const mat_ra = mat_ra: {
8311 if (vi.register(isel)) |mat_ra| {
8312 vi.get(isel).location_payload.small.register = .zr;
8313 const live_vi = isel.live_registers.getPtr(mat_ra);
8314 assert(live_vi.* == vi);
8315 live_vi.* = .allocating;
8316 break :mat_ra mat_ra;
8317 }
8318 if (vi.hint(isel)) |hint_ra| {
8319 const live_vi = isel.live_registers.getPtr(hint_ra);
8320 if (live_vi.* == .free) {
8321 live_vi.* = .allocating;
8322 isel.saved_registers.insert(hint_ra);
8323 break :mat_ra hint_ra;
8324 }
8325 }
8326 break :mat_ra if (vi.isVector(isel)) try isel.allocVecReg() else try isel.allocIntReg();
8327 };
8328 assert(isel.live_registers.get(mat_ra) == .allocating);
8329 return .{ .vi = vi, .ra = mat_ra };
8330 }
8331
8332 fn defAddr(
8333 def_vi: Value.Index,
8334 isel: *Select,
8335 def_ty: ZigType,
8336 wrap: ?std.builtin.Type.Int,
8337 expected_live_registers: *const LiveRegisters,
8338 ) !?void {
8339 if (!def_vi.isUsed(isel)) return null;
8340 const offset_from_parent: i65, const parent_vi = def_vi.valueParent(isel);
8341 const stack_slot, const allocated = switch (parent_vi.parent(isel)) {
8342 .unallocated => .{ parent_vi.allocStackSlot(isel), true },
8343 .stack_slot => |stack_slot| .{ stack_slot, false },
8344 else => unreachable,
8345 };
8346 _ = try def_vi.load(isel, def_ty, stack_slot.base, .{
8347 .offset = @intCast(stack_slot.offset + offset_from_parent),
8348 .split = false,
8349 .wrap = wrap,
8350 .expected_live_registers = expected_live_registers,
8351 });
8352 if (allocated) parent_vi.setParent(isel, .{ .stack_slot = stack_slot });
8353 }
8354
8355 fn defReg(def_vi: Value.Index, isel: *Select) !?Register.Alias {
8356 var vi = def_vi;
8357 var offset: i65 = 0;
8358 var def_ra: ?Register.Alias = null;
8359 while (true) {
8360 if (vi.register(isel)) |ra| {
8361 vi.get(isel).location_payload.small.register = .zr;
8362 const live_vi = isel.live_registers.getPtr(ra);
8363 assert(live_vi.* == vi);
8364 if (def_ra == null and vi != def_vi) {
8365 var part_it = vi.parts(isel);
8366 assert(part_it.only() == null);
8367
8368 const first_part_vi = part_it.next().?;
8369 const first_part_value = first_part_vi.get(isel);
8370 assert(first_part_value.offset_from_parent == 0);
8371 first_part_value.location_payload.small.register = ra;
8372 live_vi.* = first_part_vi;
8373
8374 const vi_size = vi.size(isel);
8375 while (part_it.next()) |part_vi| {
8376 const part_offset, const part_size = part_vi.position(isel);
8377 const part_mat = try part_vi.matReg(isel);
8378 try isel.emit(if (part_vi.isVector(isel)) emit: {
8379 assert(part_offset == 0 and part_size == vi_size);
8380 break :emit size: switch (vi_size) {
8381 else => unreachable,
8382 2 => if (isel.target.cpu.has(.aarch64, .fullfp16))
8383 .fmov(ra.h(), .{ .register = part_mat.ra.h() })
8384 else
8385 continue :size 4,
8386 4 => .fmov(ra.s(), .{ .register = part_mat.ra.s() }),
8387 8 => .fmov(ra.d(), .{ .register = part_mat.ra.d() }),
8388 16 => .orr(ra.@"16b"(), part_mat.ra.@"16b"(), .{ .register = part_mat.ra.@"16b"() }),
8389 };
8390 } else switch (vi_size) {
8391 else => unreachable,
8392 1...4 => .bfm(ra.w(), part_mat.ra.w(), .{
8393 .N = .word,
8394 .immr = @as(u5, @truncate(32 - 8 * part_offset)),
8395 .imms = @intCast(8 * part_size - 1),
8396 }),
8397 5...8 => .bfm(ra.x(), part_mat.ra.x(), .{
8398 .N = .doubleword,
8399 .immr = @as(u6, @truncate(64 - 8 * part_offset)),
8400 .imms = @intCast(8 * part_size - 1),
8401 }),
8402 });
8403 try part_mat.finish(isel);
8404 }
8405 vi = def_vi;
8406 offset = 0;
8407 continue;
8408 }
8409 live_vi.* = .free;
8410 def_ra = ra;
8411 }
8412 offset += vi.get(isel).offset_from_parent;
8413 switch (vi.parent(isel)) {
8414 else => unreachable,
8415 .unallocated => return def_ra,
8416 .stack_slot => |stack_slot| {
8417 offset += stack_slot.offset;
8418 const def_is_vector = def_vi.isVector(isel);
8419 const ra = def_ra orelse if (def_is_vector) try isel.allocVecReg() else try isel.allocIntReg();
8420 defer if (def_ra == null) isel.freeReg(ra);
8421 try isel.storeReg(ra, def_vi.size(isel), stack_slot.base, offset);
8422 return ra;
8423 },
8424 .value => |parent_vi| vi = parent_vi,
8425 }
8426 }
8427 }
8428
8429 pub fn liveIn(
8430 vi: Value.Index,
8431 isel: *Select,
8432 src_ra: Register.Alias,
8433 expected_live_registers: *const LiveRegisters,
8434 ) !void {
8435 const src_live_vi = isel.live_registers.getPtr(src_ra);
8436 if (vi.register(isel)) |dst_ra| {
8437 const dst_live_vi = isel.live_registers.getPtr(dst_ra);
8438 assert(dst_live_vi.* == vi);
8439 if (dst_ra == src_ra) {
8440 src_live_vi.* = .allocating;
8441 return;
8442 }
8443 dst_live_vi.* = .allocating;
8444 if (try isel.fill(src_ra)) {
8445 assert(src_live_vi.* == .free);
8446 src_live_vi.* = .allocating;
8447 }
8448 assert(src_live_vi.* == .allocating);
8449 try isel.emit(switch (dst_ra.isVector()) {
8450 false => switch (src_ra.isVector()) {
8451 false => switch (vi.size(isel)) {
8452 else => unreachable,
8453 1...4 => .orr(dst_ra.w(), .wzr, .{ .register = src_ra.w() }),
8454 5...8 => .orr(dst_ra.x(), .xzr, .{ .register = src_ra.x() }),
8455 },
8456 true => switch (vi.size(isel)) {
8457 else => unreachable,
8458 2 => .fmov(dst_ra.w(), .{ .register = src_ra.h() }),
8459 4 => .fmov(dst_ra.w(), .{ .register = src_ra.s() }),
8460 8 => .fmov(dst_ra.x(), .{ .register = src_ra.d() }),
8461 },
8462 },
8463 true => switch (src_ra.isVector()) {
8464 false => switch (vi.size(isel)) {
8465 else => unreachable,
8466 2 => .fmov(dst_ra.h(), .{ .register = src_ra.w() }),
8467 4 => .fmov(dst_ra.s(), .{ .register = src_ra.w() }),
8468 8 => .fmov(dst_ra.d(), .{ .register = src_ra.x() }),
8469 },
8470 true => switch (vi.size(isel)) {
8471 else => unreachable,
8472 2 => .fmov(dst_ra.h(), .{ .register = src_ra.h() }),
8473 4 => .fmov(dst_ra.s(), .{ .register = src_ra.s() }),
8474 8 => .fmov(dst_ra.d(), .{ .register = src_ra.d() }),
8475 16 => .orr(dst_ra.@"16b"(), src_ra.@"16b"(), .{ .register = src_ra.@"16b"() }),
8476 },
8477 },
8478 });
8479 assert(dst_live_vi.* == .allocating);
8480 dst_live_vi.* = switch (expected_live_registers.get(dst_ra)) {
8481 _ => .allocating,
8482 .allocating => .allocating,
8483 .free => .free,
8484 };
8485 } else if (try isel.fill(src_ra)) {
8486 assert(src_live_vi.* == .free);
8487 src_live_vi.* = .allocating;
8488 }
8489 assert(src_live_vi.* == .allocating);
8490 vi.get(isel).location_payload.small.register = src_ra;
8491 }
8492
8493 pub fn defLiveIn(
8494 vi: Value.Index,
8495 isel: *Select,
8496 src_ra: Register.Alias,
8497 expected_live_registers: *const LiveRegisters,
8498 ) !void {
8499 try vi.liveIn(isel, src_ra, expected_live_registers);
8500 const offset_from_parent: i65, const parent_vi = vi.valueParent(isel);
8501 switch (parent_vi.parent(isel)) {
8502 .unallocated => {},
8503 .stack_slot => |stack_slot| {
8504 const offset = stack_slot.offset + offset_from_parent;
8505 try isel.emit(switch (vi.size(isel)) {
8506 else => unreachable,
8507 1 => if (src_ra.isVector()) .str(src_ra.b(), .{ .unsigned_offset = .{
8508 .base = stack_slot.base.x(),
8509 .offset = @intCast(offset),
8510 } }) else .strb(src_ra.w(), .{ .unsigned_offset = .{
8511 .base = stack_slot.base.x(),
8512 .offset = @intCast(offset),
8513 } }),
8514 2 => if (src_ra.isVector()) .str(src_ra.h(), .{ .unsigned_offset = .{
8515 .base = stack_slot.base.x(),
8516 .offset = @intCast(offset),
8517 } }) else .strh(src_ra.w(), .{ .unsigned_offset = .{
8518 .base = stack_slot.base.x(),
8519 .offset = @intCast(offset),
8520 } }),
8521 4 => .str(if (src_ra.isVector()) src_ra.s() else src_ra.w(), .{ .unsigned_offset = .{
8522 .base = stack_slot.base.x(),
8523 .offset = @intCast(offset),
8524 } }),
8525 8 => .str(if (src_ra.isVector()) src_ra.d() else src_ra.x(), .{ .unsigned_offset = .{
8526 .base = stack_slot.base.x(),
8527 .offset = @intCast(offset),
8528 } }),
8529 16 => .str(src_ra.q(), .{ .unsigned_offset = .{
8530 .base = stack_slot.base.x(),
8531 .offset = @intCast(offset),
8532 } }),
8533 });
8534 },
8535 else => unreachable,
8536 }
8537 try vi.spillReg(isel, src_ra, 0, expected_live_registers);
8538 }
8539
8540 fn spillReg(
8541 vi: Value.Index,
8542 isel: *Select,
8543 src_ra: Register.Alias,
8544 start_offset: u64,
8545 expected_live_registers: *const LiveRegisters,
8546 ) !void {
8547 assert(isel.live_registers.get(src_ra) == .allocating);
8548 var part_it = vi.parts(isel);
8549 if (part_it.only()) |part_vi| {
8550 const dst_ra = part_vi.register(isel) orelse return;
8551 if (dst_ra == src_ra) return;
8552 const part_size = part_vi.size(isel);
8553 const part_ra = if (part_vi.isVector(isel)) try isel.allocIntReg() else dst_ra;
8554 defer if (part_ra != dst_ra) isel.freeReg(part_ra);
8555 if (part_ra != dst_ra) try isel.emit(switch (part_size) {
8556 else => unreachable,
8557 2 => .fmov(dst_ra.h(), .{ .register = part_ra.w() }),
8558 4 => .fmov(dst_ra.s(), .{ .register = part_ra.w() }),
8559 8 => .fmov(dst_ra.d(), .{ .register = part_ra.x() }),
8560 });
8561 try isel.emit(switch (start_offset + part_size) {
8562 else => unreachable,
8563 1...4 => |end_offset| switch (part_vi.signedness(isel)) {
8564 .signed => .sbfm(part_ra.w(), src_ra.w(), .{
8565 .N = .word,
8566 .immr = @intCast(8 * start_offset),
8567 .imms = @intCast(8 * end_offset - 1),
8568 }),
8569 .unsigned => .ubfm(part_ra.w(), src_ra.w(), .{
8570 .N = .word,
8571 .immr = @intCast(8 * start_offset),
8572 .imms = @intCast(8 * end_offset - 1),
8573 }),
8574 },
8575 5...8 => |end_offset| switch (part_vi.signedness(isel)) {
8576 .signed => .sbfm(part_ra.x(), src_ra.x(), .{
8577 .N = .doubleword,
8578 .immr = @intCast(8 * start_offset),
8579 .imms = @intCast(8 * end_offset - 1),
8580 }),
8581 .unsigned => .ubfm(part_ra.x(), src_ra.x(), .{
8582 .N = .doubleword,
8583 .immr = @intCast(8 * start_offset),
8584 .imms = @intCast(8 * end_offset - 1),
8585 }),
8586 },
8587 });
8588 const value_ra = &part_vi.get(isel).location_payload.small.register;
8589 assert(value_ra.* == dst_ra);
8590 value_ra.* = .zr;
8591 const dst_live_vi = isel.live_registers.getPtr(dst_ra);
8592 assert(dst_live_vi.* == part_vi);
8593 dst_live_vi.* = switch (expected_live_registers.get(dst_ra)) {
8594 _ => .allocating,
8595 .allocating => unreachable,
8596 .free => .free,
8597 };
8598 } else while (part_it.next()) |part_vi| try part_vi.spillReg(
8599 isel,
8600 src_ra,
8601 start_offset + part_vi.get(isel).offset_from_parent,
8602 expected_live_registers,
8603 );
8604 }
8605
8606 fn liveOut(vi: Value.Index, isel: *Select, ra: Register.Alias) !void {
8607 assert(try isel.fill(ra));
8608 const live_vi = isel.live_registers.getPtr(ra);
8609 assert(live_vi.* == .free);
8610 live_vi.* = .allocating;
8611 try Value.Materialize.finish(.{ .vi = vi, .ra = ra }, isel);
8612 }
8613
8614 fn allocStackSlot(vi: Value.Index, isel: *Select) Value.Indirect {
8615 const offset = vi.alignment(isel).forward(isel.stack_size);
8616 isel.stack_size = @intCast(offset + vi.size(isel));
8617 tracking_log.debug("${d} -> [sp, #0x{x}]", .{ @intFromEnum(vi), @abs(offset) });
8618 return .{
8619 .base = .sp,
8620 .offset = @intCast(offset),
8621 };
8622 }
8623
8624 fn address(initial_vi: Value.Index, isel: *Select, initial_offset: u64, ptr_ra: Register.Alias) !void {
8625 var vi = initial_vi;
8626 var offset: i65 = vi.get(isel).offset_from_parent + initial_offset;
8627 parent: switch (vi.parent(isel)) {
8628 .unallocated => {
8629 const stack_slot = vi.allocStackSlot(isel);
8630 vi.setParent(isel, .{ .stack_slot = stack_slot });
8631 continue :parent .{ .stack_slot = stack_slot };
8632 },
8633 .stack_slot => |stack_slot| {
8634 offset += stack_slot.offset;
8635 const lo12: u12 = @truncate(@abs(offset) >> 0);
8636 const hi12: u12 = @intCast(@abs(offset) >> 12);
8637 if (hi12 > 0) try isel.emit(if (offset >= 0) .add(
8638 ptr_ra.x(),
8639 if (lo12 > 0) ptr_ra.x() else stack_slot.base.x(),
8640 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
8641 ) else .sub(
8642 ptr_ra.x(),
8643 if (lo12 > 0) ptr_ra.x() else stack_slot.base.x(),
8644 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
8645 ));
8646 if (lo12 > 0 or hi12 == 0) try isel.emit(if (offset >= 0) .add(
8647 ptr_ra.x(),
8648 stack_slot.base.x(),
8649 .{ .immediate = lo12 },
8650 ) else .sub(
8651 ptr_ra.x(),
8652 stack_slot.base.x(),
8653 .{ .immediate = lo12 },
8654 ));
8655 },
8656 .address => |address_vi| try address_vi.liveOut(isel, ptr_ra),
8657 .value => |parent_vi| {
8658 vi = parent_vi;
8659 offset += vi.get(isel).offset_from_parent;
8660 continue :parent vi.parent(isel);
8661 },
8662 .constant => |constant| {
8663 const pt = isel.pt;
8664 const zcu = pt.zcu;
8665 switch (true) {
8666 false => {
8667 try isel.uav_relocs.append(zcu.gpa, .{
8668 .uav = .{
8669 .val = constant.toIntern(),
8670 .orig_ty = (try pt.singleConstPtrType(constant.typeOf(zcu))).toIntern(),
8671 },
8672 .reloc = .{
8673 .label = @intCast(isel.instructions.items.len),
8674 .addend = @intCast(offset),
8675 },
8676 });
8677 try isel.emit(.adr(ptr_ra.x(), 0));
8678 },
8679 true => {
8680 try isel.uav_relocs.append(zcu.gpa, .{
8681 .uav = .{
8682 .val = constant.toIntern(),
8683 .orig_ty = (try pt.singleConstPtrType(constant.typeOf(zcu))).toIntern(),
8684 },
8685 .reloc = .{
8686 .label = @intCast(isel.instructions.items.len),
8687 .addend = @intCast(offset),
8688 },
8689 });
8690 try isel.emit(.add(ptr_ra.x(), ptr_ra.x(), .{ .immediate = 0 }));
8691 try isel.uav_relocs.append(zcu.gpa, .{
8692 .uav = .{
8693 .val = constant.toIntern(),
8694 .orig_ty = (try pt.singleConstPtrType(constant.typeOf(zcu))).toIntern(),
8695 },
8696 .reloc = .{
8697 .label = @intCast(isel.instructions.items.len),
8698 .addend = @intCast(offset),
8699 },
8700 });
8701 try isel.emit(.adrp(ptr_ra.x(), 0));
8702 },
8703 }
8704 },
8705 }
8706 }
8707 };
8708
8709 pub const PartIterator = struct {
8710 vi: Value.Index,
8711 remaining: Value.PartsLen,
8712
8713 fn initOne(vi: Value.Index) PartIterator {
8714 return .{ .vi = vi, .remaining = 1 };
8715 }
8716
8717 pub fn next(it: *PartIterator) ?Value.Index {
8718 if (it.remaining == 0) return null;
8719 it.remaining -= 1;
8720 defer it.vi = @enumFromInt(@intFromEnum(it.vi) + 1);
8721 return it.vi;
8722 }
8723
8724 pub fn only(it: PartIterator) ?Value.Index {
8725 return if (it.remaining == 1) it.vi else null;
8726 }
8727 };
8728
8729 const FieldPartIterator = struct {
8730 vi: Value.Index,
8731 ty: ZigType,
8732 field_offset: u64,
8733 field_size: u64,
8734 next_offset: u64,
8735
8736 fn next(it: *FieldPartIterator, isel: *Select) !?struct { offset: u64, vi: Value.Index } {
8737 const next_offset = it.next_offset;
8738 const next_part_size = it.field_size - next_offset;
8739 if (next_part_size == 0) return null;
8740 var next_part_offset = it.field_offset + next_offset;
8741
8742 const zcu = isel.pt.zcu;
8743 const ip = &zcu.intern_pool;
8744 var vi = it.vi;
8745 var ty = it.ty;
8746 var ty_size = vi.size(isel);
8747 assert(ty_size == ty.abiSize(zcu));
8748 var offset: u64 = 0;
8749 var size = ty_size;
8750 assert(next_part_offset + next_part_size <= size);
8751 while (next_part_offset > 0 or next_part_size < size) {
8752 const part_vi = vi.partAtOffset(isel, next_part_offset);
8753 if (part_vi != vi) {
8754 vi = part_vi;
8755 const part_offset, size = part_vi.position(isel);
8756 assert(part_offset <= next_part_offset and part_offset + size > next_part_offset);
8757 offset += part_offset;
8758 next_part_offset -= part_offset;
8759 continue;
8760 }
8761 try isel.values.ensureUnusedCapacity(zcu.gpa, Value.max_parts);
8762 type_key: switch (ip.indexToKey(ty.toIntern())) {
8763 else => return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}),
8764 .int_type => |int_type| switch (int_type.bits) {
8765 0 => unreachable,
8766 1...64 => unreachable,
8767 65...256 => |bits| if (offset == 0 and size == ty_size) {
8768 const parts_len = std.math.divCeil(u16, bits, 64) catch unreachable;
8769 vi.setParts(isel, @intCast(parts_len));
8770 for (0..parts_len) |part_index| _ = vi.addPart(isel, 8 * part_index, 8);
8771 },
8772 else => return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}),
8773 },
8774 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
8775 .one, .many, .c => unreachable,
8776 .slice => if (offset == 0 and size == ty_size) {
8777 vi.setParts(isel, 2);
8778 _ = vi.addPart(isel, 0, 8);
8779 _ = vi.addPart(isel, 8, 8);
8780 } else unreachable,
8781 },
8782 .opt_type => |child_type| if (ty.optionalReprIsPayload(zcu))
8783 continue :type_key ip.indexToKey(child_type)
8784 else switch (ZigType.fromInterned(child_type).abiSize(zcu)) {
8785 0...8, 16 => |child_size| if (offset == 0 and size == ty_size) {
8786 vi.setParts(isel, 2);
8787 _ = vi.addPart(isel, 0, child_size);
8788 _ = vi.addPart(isel, child_size, 1);
8789 } else unreachable,
8790 9...15 => |child_size| if (offset == 0 and size == ty_size) {
8791 vi.setParts(isel, 2);
8792 _ = vi.addPart(isel, 0, 8);
8793 _ = vi.addPart(isel, 8, ty_size - 8);
8794 } else if (offset == 8 and size == ty_size - 8) {
8795 vi.setParts(isel, 2);
8796 _ = vi.addPart(isel, 0, child_size - 8);
8797 _ = vi.addPart(isel, child_size - 8, 1);
8798 } else unreachable,
8799 else => return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}),
8800 },
8801 .array_type => |array_type| {
8802 const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0;
8803 const array_len = array_type.lenIncludingSentinel();
8804 if (array_len > Value.max_parts and
8805 (std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts)
8806 return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)});
8807 const alignment = vi.alignment(isel);
8808 const Part = struct { offset: u64, size: u64 };
8809 var parts: [Value.max_parts]Part = undefined;
8810 var parts_len: Value.PartsLen = 0;
8811 const elem_ty: ZigType = .fromInterned(array_type.child);
8812 const elem_size = elem_ty.abiSize(zcu);
8813 const elem_signedness = if (ty.isAbiInt(zcu)) elem_signedness: {
8814 const elem_int_info = elem_ty.intInfo(zcu);
8815 break :elem_signedness if (elem_int_info.bits <= 16) elem_int_info.signedness else null;
8816 } else null;
8817 const elem_is_vector = elem_size <= 16 and
8818 CallAbiIterator.homogeneousAggregateBaseType(zcu, elem_ty.toIntern()) != null;
8819 var elem_end: u64 = 0;
8820 for (0..@intCast(array_len)) |_| {
8821 const elem_begin = elem_end;
8822 if (elem_begin >= offset + size) break;
8823 elem_end = elem_begin + elem_size;
8824 if (elem_end <= offset) continue;
8825 if (offset >= elem_begin and offset + size <= elem_begin + elem_size) {
8826 ty = elem_ty;
8827 ty_size = elem_size;
8828 offset -= elem_begin;
8829 continue :type_key ip.indexToKey(elem_ty.toIntern());
8830 }
8831 if (parts_len > 0) combine: {
8832 const prev_part = &parts[parts_len - 1];
8833 const combined_size = elem_end - prev_part.offset;
8834 if (combined_size > @as(u64, 1) << @min(
8835 min_part_log2_stride,
8836 alignment.toLog2Units(),
8837 @ctz(prev_part.offset),
8838 )) break :combine;
8839 prev_part.size = combined_size;
8840 continue;
8841 }
8842 parts[parts_len] = .{ .offset = elem_begin, .size = elem_size };
8843 parts_len += 1;
8844 }
8845 vi.setParts(isel, parts_len);
8846 for (parts[0..parts_len]) |part| {
8847 const subpart_vi = vi.addPart(isel, part.offset - offset, part.size);
8848 if (elem_signedness) |signedness| subpart_vi.setSignedness(isel, signedness);
8849 if (elem_is_vector) subpart_vi.setIsVector(isel);
8850 }
8851 },
8852 .anyframe_type => unreachable,
8853 .error_union_type => |error_union_type| {
8854 const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0;
8855 if ((std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts)
8856 return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)});
8857 const alignment = vi.alignment(isel);
8858 const payload_ty: ZigType = .fromInterned(error_union_type.payload_type);
8859 const error_set_offset = codegen.errUnionErrorOffset(payload_ty, zcu);
8860 const payload_offset = codegen.errUnionPayloadOffset(payload_ty, zcu);
8861 const Part = struct { offset: u64, size: u64, signedness: ?std.builtin.Signedness, is_vector: bool };
8862 var parts: [2]Part = undefined;
8863 var parts_len: Value.PartsLen = 0;
8864 var field_end: u64 = 0;
8865 for (0..2) |field_index| {
8866 const field_ty: ZigType, const field_begin = switch (@as(enum { error_set, payload }, switch (field_index) {
8867 0 => if (error_set_offset < payload_offset) .error_set else .payload,
8868 1 => if (error_set_offset < payload_offset) .payload else .error_set,
8869 else => unreachable,
8870 })) {
8871 .error_set => .{ .fromInterned(error_union_type.error_set_type), error_set_offset },
8872 .payload => .{ payload_ty, payload_offset },
8873 };
8874 if (field_begin >= offset + size) break;
8875 const field_size = field_ty.abiSize(zcu);
8876 if (field_size == 0) continue;
8877 field_end = field_begin + field_size;
8878 if (field_end <= offset) continue;
8879 if (offset >= field_begin and offset + size <= field_begin + field_size) {
8880 ty = field_ty;
8881 ty_size = field_size;
8882 offset -= field_begin;
8883 continue :type_key ip.indexToKey(field_ty.toIntern());
8884 }
8885 const field_signedness = if (field_ty.isAbiInt(zcu)) field_signedness: {
8886 const field_int_info = field_ty.intInfo(zcu);
8887 break :field_signedness if (field_int_info.bits <= 16) field_int_info.signedness else null;
8888 } else null;
8889 const field_is_vector = field_size <= 16 and
8890 CallAbiIterator.homogeneousAggregateBaseType(zcu, field_ty.toIntern()) != null;
8891 if (parts_len > 0) combine: {
8892 const prev_part = &parts[parts_len - 1];
8893 const combined_size = field_end - prev_part.offset;
8894 if (combined_size > @as(u64, 1) << @min(
8895 min_part_log2_stride,
8896 alignment.toLog2Units(),
8897 @ctz(prev_part.offset),
8898 )) break :combine;
8899 prev_part.size = combined_size;
8900 prev_part.signedness = null;
8901 prev_part.is_vector &= field_is_vector;
8902 continue;
8903 }
8904 parts[parts_len] = .{
8905 .offset = field_begin,
8906 .size = field_size,
8907 .signedness = field_signedness,
8908 .is_vector = field_is_vector,
8909 };
8910 parts_len += 1;
8911 }
8912 vi.setParts(isel, parts_len);
8913 for (parts[0..parts_len]) |part| {
8914 const subpart_vi = vi.addPart(isel, part.offset - offset, part.size);
8915 if (part.signedness) |signedness| subpart_vi.setSignedness(isel, signedness);
8916 if (part.is_vector) subpart_vi.setIsVector(isel);
8917 }
8918 },
8919 .simple_type => |simple_type| switch (simple_type) {
8920 .f16, .f32, .f64, .f128, .c_longdouble => return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}),
8921 .f80 => continue :type_key .{ .int_type = .{ .signedness = .unsigned, .bits = 80 } },
8922 .usize,
8923 .isize,
8924 .c_char,
8925 .c_short,
8926 .c_ushort,
8927 .c_int,
8928 .c_uint,
8929 .c_long,
8930 .c_ulong,
8931 .c_longlong,
8932 .c_ulonglong,
8933 => continue :type_key .{ .int_type = ty.intInfo(zcu) },
8934 .anyopaque,
8935 .void,
8936 .type,
8937 .comptime_int,
8938 .comptime_float,
8939 .noreturn,
8940 .null,
8941 .undefined,
8942 .enum_literal,
8943 .adhoc_inferred_error_set,
8944 .generic_poison,
8945 => unreachable,
8946 .bool => continue :type_key .{ .int_type = .{ .signedness = .unsigned, .bits = 1 } },
8947 .anyerror => continue :type_key .{ .int_type = .{
8948 .signedness = .unsigned,
8949 .bits = zcu.errorSetBits(),
8950 } },
8951 },
8952 .struct_type => {
8953 const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0;
8954 const loaded_struct = ip.loadStructType(ty.toIntern());
8955 if (loaded_struct.field_types.len > Value.max_parts and
8956 (std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts)
8957 return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)});
8958 const alignment = vi.alignment(isel);
8959 const Part = struct { offset: u64, size: u64, signedness: ?std.builtin.Signedness, is_vector: bool };
8960 var parts: [Value.max_parts]Part = undefined;
8961 var parts_len: Value.PartsLen = 0;
8962 var field_end: u64 = 0;
8963 var field_it = loaded_struct.iterateRuntimeOrder(ip);
8964 while (field_it.next()) |field_index| {
8965 const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
8966 const field_begin = switch (loaded_struct.fieldAlign(ip, field_index)) {
8967 .none => field_ty.abiAlignment(zcu),
8968 else => |field_align| field_align,
8969 }.forward(field_end);
8970 if (field_begin >= offset + size) break;
8971 const field_size = field_ty.abiSize(zcu);
8972 field_end = field_begin + field_size;
8973 if (field_end <= offset) continue;
8974 if (offset >= field_begin and offset + size <= field_begin + field_size) {
8975 ty = field_ty;
8976 ty_size = field_size;
8977 offset -= field_begin;
8978 continue :type_key ip.indexToKey(field_ty.toIntern());
8979 }
8980 const field_signedness = if (field_ty.isAbiInt(zcu)) field_signedness: {
8981 const field_int_info = field_ty.intInfo(zcu);
8982 break :field_signedness if (field_int_info.bits <= 16) field_int_info.signedness else null;
8983 } else null;
8984 const field_is_vector = field_size <= 16 and
8985 CallAbiIterator.homogeneousAggregateBaseType(zcu, field_ty.toIntern()) != null;
8986 if (parts_len > 0) combine: {
8987 const prev_part = &parts[parts_len - 1];
8988 const combined_size = field_end - prev_part.offset;
8989 if (combined_size > @as(u64, 1) << @min(
8990 min_part_log2_stride,
8991 alignment.toLog2Units(),
8992 @ctz(prev_part.offset),
8993 )) break :combine;
8994 prev_part.size = combined_size;
8995 prev_part.signedness = null;
8996 prev_part.is_vector &= field_is_vector;
8997 continue;
8998 }
8999 parts[parts_len] = .{
9000 .offset = field_begin,
9001 .size = field_size,
9002 .signedness = field_signedness,
9003 .is_vector = field_is_vector,
9004 };
9005 parts_len += 1;
9006 }
9007 vi.setParts(isel, parts_len);
9008 for (parts[0..parts_len]) |part| {
9009 const subpart_vi = vi.addPart(isel, part.offset - offset, part.size);
9010 if (part.signedness) |signedness| subpart_vi.setSignedness(isel, signedness);
9011 if (part.is_vector) subpart_vi.setIsVector(isel);
9012 }
9013 },
9014 .tuple_type => |tuple_type| {
9015 const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0;
9016 if (tuple_type.types.len > Value.max_parts and
9017 (std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts)
9018 return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)});
9019 const alignment = vi.alignment(isel);
9020 const Part = struct { offset: u64, size: u64, is_vector: bool };
9021 var parts: [Value.max_parts]Part = undefined;
9022 var parts_len: Value.PartsLen = 0;
9023 var field_end: u64 = 0;
9024 for (tuple_type.types.get(ip), tuple_type.values.get(ip)) |field_type, field_value| {
9025 if (field_value != .none) continue;
9026 const field_ty: ZigType = .fromInterned(field_type);
9027 const field_begin = field_ty.abiAlignment(zcu).forward(field_end);
9028 if (field_begin >= offset + size) break;
9029 const field_size = field_ty.abiSize(zcu);
9030 if (field_size == 0) continue;
9031 field_end = field_begin + field_size;
9032 if (field_end <= offset) continue;
9033 if (offset >= field_begin and offset + size <= field_begin + field_size) {
9034 ty = field_ty;
9035 ty_size = field_size;
9036 offset -= field_begin;
9037 continue :type_key ip.indexToKey(field_ty.toIntern());
9038 }
9039 const field_is_vector = field_size <= 16 and
9040 CallAbiIterator.homogeneousAggregateBaseType(zcu, field_ty.toIntern()) != null;
9041 if (parts_len > 0) combine: {
9042 const prev_part = &parts[parts_len - 1];
9043 const combined_size = field_end - prev_part.offset;
9044 if (combined_size > @as(u64, 1) << @min(
9045 min_part_log2_stride,
9046 alignment.toLog2Units(),
9047 @ctz(prev_part.offset),
9048 )) break :combine;
9049 prev_part.size = combined_size;
9050 prev_part.is_vector &= field_is_vector;
9051 continue;
9052 }
9053 parts[parts_len] = .{ .offset = field_begin, .size = field_size, .is_vector = field_is_vector };
9054 parts_len += 1;
9055 }
9056 vi.setParts(isel, parts_len);
9057 for (parts[0..parts_len]) |part| {
9058 const subpart_vi = vi.addPart(isel, part.offset - offset, part.size);
9059 if (part.is_vector) subpart_vi.setIsVector(isel);
9060 }
9061 },
9062 .opaque_type, .func_type => continue :type_key .{ .simple_type = .anyopaque },
9063 .enum_type => continue :type_key ip.indexToKey(ip.loadEnumType(ty.toIntern()).tag_ty),
9064 .error_set_type,
9065 .inferred_error_set_type,
9066 => continue :type_key .{ .simple_type = .anyerror },
9067 .undef,
9068 .simple_value,
9069 .variable,
9070 .@"extern",
9071 .func,
9072 .int,
9073 .err,
9074 .error_union,
9075 .enum_literal,
9076 .enum_tag,
9077 .empty_enum_value,
9078 .float,
9079 .ptr,
9080 .slice,
9081 .opt,
9082 .aggregate,
9083 .un,
9084 .memoized_call,
9085 => unreachable, // values, not types
9086 }
9087 }
9088 it.next_offset = next_offset + size;
9089 return .{ .offset = next_part_offset - next_offset, .vi = vi };
9090 }
9091
9092 fn only(it: *FieldPartIterator, isel: *Select) !?Value.Index {
9093 const part = try it.next(isel);
9094 assert(part.?.offset == 0);
9095 return if (try it.next(isel)) |_| null else part.?.vi;
9096 }
9097 };
9098
9099 const Materialize = struct {
9100 vi: Value.Index,
9101 ra: Register.Alias,
9102
9103 fn finish(mat: Value.Materialize, isel: *Select) error{ OutOfMemory, CodegenFail }!void {
9104 const live_vi = isel.live_registers.getPtr(mat.ra);
9105 assert(live_vi.* == .allocating);
9106 var vi = mat.vi;
9107 var offset: i65 = 0;
9108 const size = mat.vi.size(isel);
9109 free: while (true) {
9110 if (vi.register(isel)) |ra| {
9111 if (ra != mat.ra) break :free try isel.emit(if (vi == mat.vi) if (mat.ra.isVector()) switch (size) {
9112 else => unreachable,
9113 2 => .fmov(mat.ra.h(), .{ .register = ra.h() }),
9114 4 => .fmov(mat.ra.s(), .{ .register = ra.s() }),
9115 8 => .fmov(mat.ra.d(), .{ .register = ra.d() }),
9116 16 => .orr(mat.ra.@"16b"(), ra.@"16b"(), .{ .register = ra.@"16b"() }),
9117 } else switch (size) {
9118 else => unreachable,
9119 1...4 => .orr(mat.ra.w(), .wzr, .{ .register = ra.w() }),
9120 5...8 => .orr(mat.ra.x(), .xzr, .{ .register = ra.x() }),
9121 } else switch (offset + size) {
9122 else => unreachable,
9123 1...4 => |end_offset| switch (mat.vi.signedness(isel)) {
9124 .signed => .sbfm(mat.ra.w(), ra.w(), .{
9125 .N = .word,
9126 .immr = @intCast(8 * offset),
9127 .imms = @intCast(8 * end_offset - 1),
9128 }),
9129 .unsigned => .ubfm(mat.ra.w(), ra.w(), .{
9130 .N = .word,
9131 .immr = @intCast(8 * offset),
9132 .imms = @intCast(8 * end_offset - 1),
9133 }),
9134 },
9135 5...8 => |end_offset| switch (mat.vi.signedness(isel)) {
9136 .signed => .sbfm(mat.ra.x(), ra.x(), .{
9137 .N = .doubleword,
9138 .immr = @intCast(8 * offset),
9139 .imms = @intCast(8 * end_offset - 1),
9140 }),
9141 .unsigned => .ubfm(mat.ra.x(), ra.x(), .{
9142 .N = .doubleword,
9143 .immr = @intCast(8 * offset),
9144 .imms = @intCast(8 * end_offset - 1),
9145 }),
9146 },
9147 });
9148 mat.vi.get(isel).location_payload.small.register = mat.ra;
9149 live_vi.* = mat.vi;
9150 return;
9151 }
9152 offset += vi.get(isel).offset_from_parent;
9153 switch (vi.parent(isel)) {
9154 .unallocated => {
9155 mat.vi.get(isel).location_payload.small.register = mat.ra;
9156 live_vi.* = mat.vi;
9157 return;
9158 },
9159 .stack_slot => |stack_slot| {
9160 offset += stack_slot.offset;
9161 break :free try isel.emit(switch (size) {
9162 else => unreachable,
9163 1 => if (mat.ra.isVector()) .ldr(mat.ra.b(), .{ .unsigned_offset = .{
9164 .base = stack_slot.base.x(),
9165 .offset = @intCast(offset),
9166 } }) else switch (mat.vi.signedness(isel)) {
9167 .signed => .ldrsb(mat.ra.w(), .{ .unsigned_offset = .{
9168 .base = stack_slot.base.x(),
9169 .offset = @intCast(offset),
9170 } }),
9171 .unsigned => .ldrb(mat.ra.w(), .{ .unsigned_offset = .{
9172 .base = stack_slot.base.x(),
9173 .offset = @intCast(offset),
9174 } }),
9175 },
9176 2 => if (mat.ra.isVector()) .ldr(mat.ra.h(), .{ .unsigned_offset = .{
9177 .base = stack_slot.base.x(),
9178 .offset = @intCast(offset),
9179 } }) else switch (mat.vi.signedness(isel)) {
9180 .signed => .ldrsh(mat.ra.w(), .{ .unsigned_offset = .{
9181 .base = stack_slot.base.x(),
9182 .offset = @intCast(offset),
9183 } }),
9184 .unsigned => .ldrh(mat.ra.w(), .{ .unsigned_offset = .{
9185 .base = stack_slot.base.x(),
9186 .offset = @intCast(offset),
9187 } }),
9188 },
9189 4 => .ldr(if (mat.ra.isVector()) mat.ra.s() else mat.ra.w(), .{ .unsigned_offset = .{
9190 .base = stack_slot.base.x(),
9191 .offset = @intCast(offset),
9192 } }),
9193 8 => .ldr(if (mat.ra.isVector()) mat.ra.d() else mat.ra.x(), .{ .unsigned_offset = .{
9194 .base = stack_slot.base.x(),
9195 .offset = @intCast(offset),
9196 } }),
9197 16 => .ldr(mat.ra.q(), .{ .unsigned_offset = .{
9198 .base = stack_slot.base.x(),
9199 .offset = @intCast(offset),
9200 } }),
9201 });
9202 },
9203 .address => |base_vi| {
9204 const base_mat = try base_vi.matReg(isel);
9205 try isel.emit(switch (size) {
9206 else => unreachable,
9207 1 => if (mat.ra.isVector()) .ldr(mat.ra.b(), .{ .unsigned_offset = .{
9208 .base = base_mat.ra.x(),
9209 .offset = @intCast(offset),
9210 } }) else switch (mat.vi.signedness(isel)) {
9211 .signed => .ldrsb(mat.ra.w(), .{ .unsigned_offset = .{
9212 .base = base_mat.ra.x(),
9213 .offset = @intCast(offset),
9214 } }),
9215 .unsigned => .ldrb(mat.ra.w(), .{ .unsigned_offset = .{
9216 .base = base_mat.ra.x(),
9217 .offset = @intCast(offset),
9218 } }),
9219 },
9220 2 => if (mat.ra.isVector()) .ldr(mat.ra.h(), .{ .unsigned_offset = .{
9221 .base = base_mat.ra.x(),
9222 .offset = @intCast(offset),
9223 } }) else switch (mat.vi.signedness(isel)) {
9224 .signed => .ldrsh(mat.ra.w(), .{ .unsigned_offset = .{
9225 .base = base_mat.ra.x(),
9226 .offset = @intCast(offset),
9227 } }),
9228 .unsigned => .ldrh(mat.ra.w(), .{ .unsigned_offset = .{
9229 .base = base_mat.ra.x(),
9230 .offset = @intCast(offset),
9231 } }),
9232 },
9233 4 => .ldr(if (mat.ra.isVector()) mat.ra.s() else mat.ra.w(), .{ .unsigned_offset = .{
9234 .base = base_mat.ra.x(),
9235 .offset = @intCast(offset),
9236 } }),
9237 8 => .ldr(if (mat.ra.isVector()) mat.ra.d() else mat.ra.x(), .{ .unsigned_offset = .{
9238 .base = base_mat.ra.x(),
9239 .offset = @intCast(offset),
9240 } }),
9241 16 => .ldr(mat.ra.q(), .{ .unsigned_offset = .{
9242 .base = base_mat.ra.x(),
9243 .offset = @intCast(offset),
9244 } }),
9245 });
9246 break :free try base_mat.finish(isel);
9247 },
9248 .value => |parent_vi| vi = parent_vi,
9249 .constant => |initial_constant| {
9250 const zcu = isel.pt.zcu;
9251 const ip = &zcu.intern_pool;
9252 var constant = initial_constant.toIntern();
9253 var constant_key = ip.indexToKey(constant);
9254 while (true) {
9255 constant_key: switch (constant_key) {
9256 .int_type,
9257 .ptr_type,
9258 .array_type,
9259 .vector_type,
9260 .opt_type,
9261 .anyframe_type,
9262 .error_union_type,
9263 .simple_type,
9264 .struct_type,
9265 .tuple_type,
9266 .union_type,
9267 .opaque_type,
9268 .enum_type,
9269 .func_type,
9270 .error_set_type,
9271 .inferred_error_set_type,
9272
9273 .enum_literal,
9274 .empty_enum_value,
9275 .memoized_call,
9276 => unreachable, // not a runtime value
9277 .undef => break :free try isel.emit(if (mat.ra.isVector()) .movi(switch (size) {
9278 else => unreachable,
9279 1...8 => mat.ra.@"8b"(),
9280 9...16 => mat.ra.@"16b"(),
9281 }, 0xaa, .{ .lsl = 0 }) else switch (size) {
9282 else => unreachable,
9283 1...4 => .orr(mat.ra.w(), .wzr, .{ .immediate = .{
9284 .N = .word,
9285 .immr = 0b000001,
9286 .imms = 0b111100,
9287 } }),
9288 5...8 => .orr(mat.ra.x(), .xzr, .{ .immediate = .{
9289 .N = .word,
9290 .immr = 0b000001,
9291 .imms = 0b111100,
9292 } }),
9293 }),
9294 .simple_value => |simple_value| switch (simple_value) {
9295 .undefined, .void, .null, .empty_tuple, .@"unreachable" => unreachable,
9296 .true => continue :constant_key .{ .int = .{
9297 .ty = .bool_type,
9298 .storage = .{ .u64 = 1 },
9299 } },
9300 .false => continue :constant_key .{ .int = .{
9301 .ty = .bool_type,
9302 .storage = .{ .u64 = 0 },
9303 } },
9304 },
9305 .int => |int| break :free storage: switch (int.storage) {
9306 .u64 => |imm| try isel.movImmediate(switch (size) {
9307 else => unreachable,
9308 1...4 => mat.ra.w(),
9309 5...8 => mat.ra.x(),
9310 }, @bitCast(std.math.shr(u64, imm, 8 * offset))),
9311 .i64 => |imm| switch (size) {
9312 else => unreachable,
9313 1...4 => try isel.movImmediate(mat.ra.w(), @as(u32, @bitCast(@as(i32, @truncate(std.math.shr(i64, imm, 8 * offset)))))),
9314 5...8 => try isel.movImmediate(mat.ra.x(), @bitCast(std.math.shr(i64, imm, 8 * offset))),
9315 },
9316 .big_int => |big_int| {
9317 assert(size == 8);
9318 var imm: u64 = 0;
9319 const limb_bits = @bitSizeOf(std.math.big.Limb);
9320 const limbs = @divExact(64, limb_bits);
9321 var limb_index: usize = @intCast(@divExact(offset, @divExact(limb_bits, 8)) + limbs);
9322 for (0..limbs) |_| {
9323 limb_index -= 1;
9324 if (limb_index >= big_int.limbs.len) continue;
9325 if (limb_bits < 64) imm <<= limb_bits;
9326 imm |= big_int.limbs[limb_index];
9327 }
9328 if (!big_int.positive) {
9329 limb_index = @min(limb_index, big_int.limbs.len);
9330 imm = while (limb_index > 0) {
9331 limb_index -= 1;
9332 if (big_int.limbs[limb_index] != 0) break ~imm;
9333 } else -%imm;
9334 }
9335 try isel.movImmediate(mat.ra.x(), imm);
9336 },
9337 .lazy_align => |ty| continue :storage .{
9338 .u64 = ZigType.fromInterned(ty).abiAlignment(zcu).toByteUnits().?,
9339 },
9340 .lazy_size => |ty| continue :storage .{
9341 .u64 = ZigType.fromInterned(ty).abiSize(zcu),
9342 },
9343 },
9344 .err => |err| continue :constant_key .{ .int = .{
9345 .ty = err.ty,
9346 .storage = .{ .u64 = ip.getErrorValueIfExists(err.name).? },
9347 } },
9348 .error_union => |error_union| {
9349 const error_union_type = ip.indexToKey(error_union.ty).error_union_type;
9350 const payload_ty: ZigType = .fromInterned(error_union_type.payload_type);
9351 if (!ip.isNoReturn(error_union_type.error_set_type) and
9352 offset == codegen.errUnionErrorOffset(payload_ty, zcu))
9353 {
9354 offset = 0;
9355 continue :constant_key switch (error_union.val) {
9356 .err_name => |err_name| .{ .err = .{
9357 .ty = error_union_type.error_set_type,
9358 .name = err_name,
9359 } },
9360 .payload => .{ .int = .{
9361 .ty = error_union_type.error_set_type,
9362 .storage = .{ .u64 = 0 },
9363 } },
9364 };
9365 }
9366 assert(payload_ty.hasRuntimeBitsIgnoreComptime(zcu));
9367 offset -= @intCast(codegen.errUnionPayloadOffset(payload_ty, zcu));
9368 switch (error_union.val) {
9369 .err_name => continue :constant_key .{ .undef = error_union_type.payload_type },
9370 .payload => |payload| {
9371 constant = payload;
9372 constant_key = ip.indexToKey(payload);
9373 continue :constant_key constant_key;
9374 },
9375 }
9376 },
9377 .enum_tag => |enum_tag| continue :constant_key .{ .int = ip.indexToKey(enum_tag.int).int },
9378 .float => |float| storage: switch (float.storage) {
9379 .f16 => |imm| {
9380 if (!mat.ra.isVector()) continue :constant_key .{ .int = .{
9381 .ty = .u16_type,
9382 .storage = .{ .u64 = @as(u16, @bitCast(imm)) },
9383 } };
9384 const feat_fp16 = isel.target.cpu.has(.aarch64, .fullfp16);
9385 if (feat_fp16) {
9386 const Repr = std.math.FloatRepr(f16);
9387 const repr: Repr = @bitCast(imm);
9388 if (repr.mantissa & std.math.maxInt(Repr.Mantissa) >> 5 == 0 and switch (repr.exponent) {
9389 .denormal, .infinite => false,
9390 else => std.math.cast(i3, repr.exponent.unbias() - 1) != null,
9391 }) break :free try isel.emit(.fmov(mat.ra.h(), .{ .immediate = imm }));
9392 }
9393 const bits: u16 = @bitCast(imm);
9394 if (bits == 0) break :free try isel.emit(.movi(mat.ra.d(), 0b00000000, .replicate));
9395 if (bits & std.math.maxInt(u8) == 0) break :free try isel.emit(.movi(
9396 mat.ra.@"4h"(),
9397 @intCast(@shrExact(bits, 8)),
9398 .{ .lsl = 8 },
9399 ));
9400 const temp_ra = try isel.allocIntReg();
9401 defer isel.freeReg(temp_ra);
9402 try isel.emit(.fmov(if (feat_fp16) mat.ra.h() else mat.ra.s(), .{ .register = temp_ra.w() }));
9403 break :free try isel.movImmediate(temp_ra.w(), bits);
9404 },
9405 .f32 => |imm| {
9406 if (!mat.ra.isVector()) continue :constant_key .{ .int = .{
9407 .ty = .u32_type,
9408 .storage = .{ .u64 = @as(u32, @bitCast(imm)) },
9409 } };
9410 const Repr = std.math.FloatRepr(f32);
9411 const repr: Repr = @bitCast(imm);
9412 if (repr.mantissa & std.math.maxInt(Repr.Mantissa) >> 5 == 0 and switch (repr.exponent) {
9413 .denormal, .infinite => false,
9414 else => std.math.cast(i3, repr.exponent.unbias() - 1) != null,
9415 }) break :free try isel.emit(.fmov(mat.ra.s(), .{ .immediate = @floatCast(imm) }));
9416 const bits: u32 = @bitCast(imm);
9417 if (bits == 0) break :free try isel.emit(.movi(mat.ra.d(), 0b00000000, .replicate));
9418 if (bits & std.math.maxInt(u24) == 0) break :free try isel.emit(.movi(
9419 mat.ra.@"2s"(),
9420 @intCast(@shrExact(bits, 24)),
9421 .{ .lsl = 24 },
9422 ));
9423 const temp_ra = try isel.allocIntReg();
9424 defer isel.freeReg(temp_ra);
9425 try isel.emit(.fmov(mat.ra.s(), .{ .register = temp_ra.w() }));
9426 break :free try isel.movImmediate(temp_ra.w(), bits);
9427 },
9428 .f64 => |imm| {
9429 if (!mat.ra.isVector()) continue :constant_key .{ .int = .{
9430 .ty = .u64_type,
9431 .storage = .{ .u64 = @as(u64, @bitCast(imm)) },
9432 } };
9433 const Repr = std.math.FloatRepr(f64);
9434 const repr: Repr = @bitCast(imm);
9435 if (repr.mantissa & std.math.maxInt(Repr.Mantissa) >> 5 == 0 and switch (repr.exponent) {
9436 .denormal, .infinite => false,
9437 else => std.math.cast(i3, repr.exponent.unbias() - 1) != null,
9438 }) break :free try isel.emit(.fmov(mat.ra.d(), .{ .immediate = @floatCast(imm) }));
9439 const bits: u64 = @bitCast(imm);
9440 if (bits == 0) break :free try isel.emit(.movi(mat.ra.d(), 0b00000000, .replicate));
9441 const temp_ra = try isel.allocIntReg();
9442 defer isel.freeReg(temp_ra);
9443 try isel.emit(.fmov(mat.ra.d(), .{ .register = temp_ra.x() }));
9444 break :free try isel.movImmediate(temp_ra.x(), bits);
9445 },
9446 .f80 => |imm| break :free try isel.movImmediate(
9447 mat.ra.x(),
9448 @truncate(std.math.shr(u80, @bitCast(imm), 8 * offset)),
9449 ),
9450 .f128 => |imm| switch (ZigType.fromInterned(float.ty).floatBits(isel.target)) {
9451 else => unreachable,
9452 16 => continue :storage .{ .f16 = @floatCast(imm) },
9453 32 => continue :storage .{ .f32 = @floatCast(imm) },
9454 64 => continue :storage .{ .f64 = @floatCast(imm) },
9455 128 => {
9456 const bits: u128 = @bitCast(imm);
9457 const hi64: u64 = @intCast(bits >> 64);
9458 const lo64: u64 = @truncate(bits >> 0);
9459 const temp_ra = try isel.allocIntReg();
9460 defer isel.freeReg(temp_ra);
9461 switch (hi64) {
9462 0 => {},
9463 else => {
9464 try isel.emit(.fmov(mat.ra.@"d[]"(1), .{ .register = temp_ra.x() }));
9465 try isel.movImmediate(temp_ra.x(), hi64);
9466 },
9467 }
9468 break :free switch (lo64) {
9469 0 => try isel.emit(.movi(switch (hi64) {
9470 else => mat.ra.d(),
9471 0 => mat.ra.@"2d"(),
9472 }, 0b00000000, .replicate)),
9473 else => {
9474 try isel.emit(.fmov(mat.ra.d(), .{ .register = temp_ra.x() }));
9475 try isel.movImmediate(temp_ra.x(), lo64);
9476 },
9477 };
9478 },
9479 },
9480 },
9481 .ptr => |ptr| {
9482 assert(offset == 0 and size == 8);
9483 break :free switch (ptr.base_addr) {
9484 .nav => |nav| if (ZigType.fromInterned(ip.getNav(nav).typeOf(ip)).isFnOrHasRuntimeBits(zcu)) switch (true) {
9485 false => {
9486 try isel.nav_relocs.append(zcu.gpa, .{
9487 .nav = nav,
9488 .reloc = .{
9489 .label = @intCast(isel.instructions.items.len),
9490 .addend = ptr.byte_offset,
9491 },
9492 });
9493 try isel.emit(.adr(mat.ra.x(), 0));
9494 },
9495 true => {
9496 try isel.nav_relocs.append(zcu.gpa, .{
9497 .nav = nav,
9498 .reloc = .{
9499 .label = @intCast(isel.instructions.items.len),
9500 .addend = ptr.byte_offset,
9501 },
9502 });
9503 try isel.emit(.add(mat.ra.x(), mat.ra.x(), .{ .immediate = 0 }));
9504 try isel.nav_relocs.append(zcu.gpa, .{
9505 .nav = nav,
9506 .reloc = .{
9507 .label = @intCast(isel.instructions.items.len),
9508 .addend = ptr.byte_offset,
9509 },
9510 });
9511 try isel.emit(.adrp(mat.ra.x(), 0));
9512 },
9513 } else continue :constant_key .{ .int = .{
9514 .ty = .usize_type,
9515 .storage = .{ .u64 = isel.pt.navAlignment(nav).forward(0xaaaaaaaaaaaaaaaa) },
9516 } },
9517 .uav => |uav| if (ZigType.fromInterned(ip.typeOf(uav.val)).isFnOrHasRuntimeBits(zcu)) switch (true) {
9518 false => {
9519 try isel.uav_relocs.append(zcu.gpa, .{
9520 .uav = uav,
9521 .reloc = .{
9522 .label = @intCast(isel.instructions.items.len),
9523 .addend = ptr.byte_offset,
9524 },
9525 });
9526 try isel.emit(.adr(mat.ra.x(), 0));
9527 },
9528 true => {
9529 try isel.uav_relocs.append(zcu.gpa, .{
9530 .uav = uav,
9531 .reloc = .{
9532 .label = @intCast(isel.instructions.items.len),
9533 .addend = ptr.byte_offset,
9534 },
9535 });
9536 try isel.emit(.add(mat.ra.x(), mat.ra.x(), .{ .immediate = 0 }));
9537 try isel.uav_relocs.append(zcu.gpa, .{
9538 .uav = uav,
9539 .reloc = .{
9540 .label = @intCast(isel.instructions.items.len),
9541 .addend = ptr.byte_offset,
9542 },
9543 });
9544 try isel.emit(.adrp(mat.ra.x(), 0));
9545 },
9546 } else continue :constant_key .{ .int = .{
9547 .ty = .usize_type,
9548 .storage = .{ .u64 = ZigType.fromInterned(uav.orig_ty).ptrAlignment(zcu).forward(0xaaaaaaaaaaaaaaaa) },
9549 } },
9550 .int => continue :constant_key .{ .int = .{
9551 .ty = .usize_type,
9552 .storage = .{ .u64 = ptr.byte_offset },
9553 } },
9554 .eu_payload => |base| {
9555 var base_ptr = ip.indexToKey(base).ptr;
9556 const eu_ty = ip.indexToKey(base_ptr.ty).ptr_type.child;
9557 const payload_ty = ip.indexToKey(eu_ty).error_union_type.payload_type;
9558 base_ptr.byte_offset += codegen.errUnionPayloadOffset(.fromInterned(payload_ty), zcu);
9559 continue :constant_key .{ .ptr = base_ptr };
9560 },
9561 .opt_payload => |base| continue :constant_key .{ .ptr = ip.indexToKey(base).ptr },
9562 .field => |field| {
9563 var base_ptr = ip.indexToKey(field.base).ptr;
9564 const agg_ty: ZigType = .fromInterned(ip.indexToKey(base_ptr.ty).ptr_type.child);
9565 base_ptr.byte_offset += agg_ty.structFieldOffset(@intCast(field.index), zcu);
9566 continue :constant_key .{ .ptr = base_ptr };
9567 },
9568 .comptime_alloc, .comptime_field, .arr_elem => unreachable,
9569 };
9570 },
9571 .slice => |slice| switch (offset) {
9572 0 => continue :constant_key .{ .ptr = ip.indexToKey(slice.ptr).ptr },
9573 else => {
9574 assert(offset == @divExact(isel.target.ptrBitWidth(), 8));
9575 offset = 0;
9576 continue :constant_key .{ .int = ip.indexToKey(slice.len).int };
9577 },
9578 },
9579 .opt => |opt| {
9580 const child_ty = ip.indexToKey(opt.ty).opt_type;
9581 const child_size = ZigType.fromInterned(child_ty).abiSize(zcu);
9582 if (offset == child_size and size == 1) {
9583 offset = 0;
9584 continue :constant_key .{ .simple_value = switch (opt.val) {
9585 .none => .false,
9586 else => .true,
9587 } };
9588 }
9589 const opt_ty: ZigType = .fromInterned(opt.ty);
9590 if (offset + size <= child_size) continue :constant_key switch (opt.val) {
9591 .none => if (opt_ty.optionalReprIsPayload(zcu)) .{ .int = .{
9592 .ty = opt.ty,
9593 .storage = .{ .u64 = 0 },
9594 } } else .{ .undef = child_ty },
9595 else => |child| {
9596 constant = child;
9597 constant_key = ip.indexToKey(child);
9598 continue :constant_key constant_key;
9599 },
9600 };
9601 },
9602 .aggregate => |aggregate| switch (ip.indexToKey(aggregate.ty)) {
9603 else => unreachable,
9604 .array_type => |array_type| {
9605 const elem_size = ZigType.fromInterned(array_type.child).abiSize(zcu);
9606 const elem_offset = @mod(offset, elem_size);
9607 if (size <= elem_size - elem_offset) {
9608 defer offset = elem_offset;
9609 continue :constant_key switch (aggregate.storage) {
9610 .bytes => |bytes| .{ .int = .{ .ty = .u8_type, .storage = .{
9611 .u64 = bytes.toSlice(array_type.lenIncludingSentinel(), ip)[@intCast(@divFloor(offset, elem_size))],
9612 } } },
9613 .elems => |elems| {
9614 constant = elems[@intCast(@divFloor(offset, elem_size))];
9615 constant_key = ip.indexToKey(constant);
9616 continue :constant_key constant_key;
9617 },
9618 .repeated_elem => |repeated_elem| {
9619 constant = repeated_elem;
9620 constant_key = ip.indexToKey(repeated_elem);
9621 continue :constant_key constant_key;
9622 },
9623 };
9624 }
9625 },
9626 .vector_type => {},
9627 .struct_type => {
9628 const loaded_struct = ip.loadStructType(aggregate.ty);
9629 switch (loaded_struct.layout) {
9630 .auto => {
9631 var field_offset: u64 = 0;
9632 var field_it = loaded_struct.iterateRuntimeOrder(ip);
9633 while (field_it.next()) |field_index| {
9634 if (loaded_struct.fieldIsComptime(ip, field_index)) continue;
9635 const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
9636 field_offset = field_ty.structFieldAlignment(
9637 loaded_struct.fieldAlign(ip, field_index),
9638 loaded_struct.layout,
9639 zcu,
9640 ).forward(field_offset);
9641 const field_size = field_ty.abiSize(zcu);
9642 if (offset >= field_offset and offset + size <= field_offset + field_size) {
9643 offset -= field_offset;
9644 constant = switch (aggregate.storage) {
9645 .bytes => unreachable,
9646 .elems => |elems| elems[field_index],
9647 .repeated_elem => |repeated_elem| repeated_elem,
9648 };
9649 constant_key = ip.indexToKey(constant);
9650 continue :constant_key constant_key;
9651 }
9652 field_offset += field_size;
9653 }
9654 },
9655 .@"extern", .@"packed" => {},
9656 }
9657 },
9658 .tuple_type => |tuple_type| {
9659 var field_offset: u64 = 0;
9660 for (tuple_type.types.get(ip), tuple_type.values.get(ip), 0..) |field_type, field_value, field_index| {
9661 if (field_value != .none) continue;
9662 const field_ty: ZigType = .fromInterned(field_type);
9663 field_offset = field_ty.abiAlignment(zcu).forward(field_offset);
9664 const field_size = field_ty.abiSize(zcu);
9665 if (offset >= field_offset and offset + size <= field_offset + field_size) {
9666 offset -= field_offset;
9667 constant = switch (aggregate.storage) {
9668 .bytes => unreachable,
9669 .elems => |elems| elems[field_index],
9670 .repeated_elem => |repeated_elem| repeated_elem,
9671 };
9672 constant_key = ip.indexToKey(constant);
9673 continue :constant_key constant_key;
9674 }
9675 field_offset += field_size;
9676 }
9677 },
9678 },
9679 else => {},
9680 }
9681 var buffer: [16]u8 = @splat(0);
9682 if (ZigType.fromInterned(constant_key.typeOf()).abiSize(zcu) <= buffer.len and
9683 try isel.writeToMemory(.fromInterned(constant), &buffer))
9684 {
9685 constant_key = if (mat.ra.isVector()) .{ .float = switch (size) {
9686 else => unreachable,
9687 2 => .{ .ty = .f16_type, .storage = .{ .f16 = @bitCast(std.mem.readInt(
9688 u16,
9689 buffer[@intCast(offset)..][0..2],
9690 isel.target.cpu.arch.endian(),
9691 )) } },
9692 4 => .{ .ty = .f32_type, .storage = .{ .f32 = @bitCast(std.mem.readInt(
9693 u32,
9694 buffer[@intCast(offset)..][0..4],
9695 isel.target.cpu.arch.endian(),
9696 )) } },
9697 8 => .{ .ty = .f64_type, .storage = .{ .f64 = @bitCast(std.mem.readInt(
9698 u64,
9699 buffer[@intCast(offset)..][0..8],
9700 isel.target.cpu.arch.endian(),
9701 )) } },
9702 16 => .{ .ty = .f128_type, .storage = .{ .f128 = @bitCast(std.mem.readInt(
9703 u128,
9704 buffer[@intCast(offset)..][0..16],
9705 isel.target.cpu.arch.endian(),
9706 )) } },
9707 } } else .{ .int = .{
9708 .ty = .u64_type,
9709 .storage = .{ .u64 = switch (size) {
9710 else => unreachable,
9711 inline 1...8 => |ct_size| std.mem.readInt(
9712 @Type(.{ .int = .{ .signedness = .unsigned, .bits = 8 * ct_size } }),
9713 buffer[@intCast(offset)..][0..ct_size],
9714 isel.target.cpu.arch.endian(),
9715 ),
9716 } },
9717 } };
9718 offset = 0;
9719 continue;
9720 }
9721 return isel.fail("unsupported value <{f}, {f}>", .{
9722 isel.fmtType(.fromInterned(constant_key.typeOf())),
9723 isel.fmtConstant(.fromInterned(constant)),
9724 });
9725 }
9726 },
9727 }
9728 }
9729 live_vi.* = .free;
9730 }
9731 };
9732};
9733fn initValue(isel: *Select, ty: ZigType) Value.Index {
9734 const zcu = isel.pt.zcu;
9735 return isel.initValueAdvanced(ty.abiAlignment(zcu), 0, ty.abiSize(zcu));
9736}
9737fn initValueAdvanced(
9738 isel: *Select,
9739 parent_alignment: InternPool.Alignment,
9740 offset_from_parent: u64,
9741 size: u64,
9742) Value.Index {
9743 defer isel.values.addOneAssumeCapacity().* = .{
9744 .refs = 0,
9745 .flags = .{
9746 .alignment = .fromLog2Units(@min(parent_alignment.toLog2Units(), @ctz(offset_from_parent))),
9747 .parent_tag = .unallocated,
9748 .location_tag = if (size > 16) .large else .small,
9749 .parts_len_minus_one = 0,
9750 },
9751 .offset_from_parent = offset_from_parent,
9752 .parent_payload = .{ .unallocated = {} },
9753 .location_payload = if (size > 16) .{ .large = .{
9754 .size = size,
9755 } } else .{ .small = .{
9756 .size = @intCast(size),
9757 .signedness = .unsigned,
9758 .is_vector = false,
9759 .hint = .zr,
9760 .register = .zr,
9761 } },
9762 .parts = undefined,
9763 };
9764 return @enumFromInt(isel.values.items.len);
9765}
9766pub fn dumpValues(isel: *Select, which: enum { only_referenced, all }) void {
9767 errdefer |err| @panic(@errorName(err));
9768 const stderr = std.debug.lockStderrWriter(&.{});
9769 defer std.debug.unlockStderrWriter();
9770
9771 const zcu = isel.pt.zcu;
9772 const gpa = zcu.gpa;
9773 const ip = &zcu.intern_pool;
9774 const nav = ip.getNav(isel.nav_index);
9775
9776 var reverse_live_values: std.AutoArrayHashMapUnmanaged(Value.Index, std.ArrayListUnmanaged(Air.Inst.Index)) = .empty;
9777 defer {
9778 for (reverse_live_values.values()) |*list| list.deinit(gpa);
9779 reverse_live_values.deinit(gpa);
9780 }
9781 {
9782 try reverse_live_values.ensureTotalCapacity(gpa, isel.live_values.count());
9783 var live_val_it = isel.live_values.iterator();
9784 while (live_val_it.next()) |live_val_entry| switch (live_val_entry.value_ptr.*) {
9785 _ => {
9786 const gop = reverse_live_values.getOrPutAssumeCapacity(live_val_entry.value_ptr.*);
9787 if (!gop.found_existing) gop.value_ptr.* = .empty;
9788 try gop.value_ptr.append(gpa, live_val_entry.key_ptr.*);
9789 },
9790 .allocating, .free => unreachable,
9791 };
9792 }
9793
9794 var reverse_live_registers: std.AutoHashMapUnmanaged(Value.Index, Register.Alias) = .empty;
9795 defer reverse_live_registers.deinit(gpa);
9796 {
9797 try reverse_live_registers.ensureTotalCapacity(gpa, @typeInfo(Register.Alias).@"enum".fields.len);
9798 var live_reg_it = isel.live_registers.iterator();
9799 while (live_reg_it.next()) |live_reg_entry| switch (live_reg_entry.value.*) {
9800 _ => reverse_live_registers.putAssumeCapacityNoClobber(live_reg_entry.value.*, live_reg_entry.key),
9801 .allocating, .free => {},
9802 };
9803 }
9804
9805 var roots: std.AutoArrayHashMapUnmanaged(Value.Index, u32) = .empty;
9806 defer roots.deinit(gpa);
9807 {
9808 try roots.ensureTotalCapacity(gpa, isel.values.items.len);
9809 var vi: Value.Index = @enumFromInt(isel.values.items.len);
9810 while (@intFromEnum(vi) > 0) {
9811 vi = @enumFromInt(@intFromEnum(vi) - 1);
9812 if (which == .only_referenced and vi.get(isel).refs == 0) continue;
9813 while (true) switch (vi.parent(isel)) {
9814 .unallocated, .stack_slot, .constant => break,
9815 .value => |parent_vi| vi = parent_vi,
9816 .address => |address_vi| break roots.putAssumeCapacity(address_vi, 0),
9817 };
9818 roots.putAssumeCapacity(vi, 0);
9819 }
9820 }
9821
9822 try stderr.print("# Begin {s} Value Dump: {f}:\n", .{ @typeName(Select), nav.fqn.fmt(ip) });
9823 while (roots.pop()) |root_entry| {
9824 const vi = root_entry.key;
9825 const value = vi.get(isel);
9826 try stderr.splatByteAll(' ', 2 * (@as(usize, 1) + root_entry.value));
9827 try stderr.print("${d}", .{@intFromEnum(vi)});
9828 {
9829 var first = true;
9830 if (reverse_live_values.get(vi)) |aiis| for (aiis.items) |aii| {
9831 if (aii == Block.main) {
9832 try stderr.print("{s}%main", .{if (first) " <- " else ", "});
9833 } else {
9834 try stderr.print("{s}%{d}", .{ if (first) " <- " else ", ", @intFromEnum(aii) });
9835 }
9836 first = false;
9837 };
9838 if (reverse_live_registers.get(vi)) |ra| {
9839 try stderr.print("{s}{s}", .{ if (first) " <- " else ", ", @tagName(ra) });
9840 first = false;
9841 }
9842 }
9843 try stderr.writeByte(':');
9844 switch (value.flags.parent_tag) {
9845 .unallocated => if (value.offset_from_parent != 0) try stderr.print(" +0x{x}", .{value.offset_from_parent}),
9846 .stack_slot => {
9847 try stderr.print(" [{s}, #{s}0x{x}", .{
9848 @tagName(value.parent_payload.stack_slot.base),
9849 if (value.parent_payload.stack_slot.offset < 0) "-" else "",
9850 @abs(value.parent_payload.stack_slot.offset),
9851 });
9852 if (value.offset_from_parent != 0) try stderr.print("+0x{x}", .{value.offset_from_parent});
9853 try stderr.writeByte(']');
9854 },
9855 .value => try stderr.print(" ${d}+0x{x}", .{ @intFromEnum(value.parent_payload.value), value.offset_from_parent }),
9856 .address => try stderr.print(" ${d}[0x{x}]", .{ @intFromEnum(value.parent_payload.address), value.offset_from_parent }),
9857 .constant => try stderr.print(" <{f}, {f}>", .{
9858 isel.fmtType(value.parent_payload.constant.typeOf(zcu)),
9859 isel.fmtConstant(value.parent_payload.constant),
9860 }),
9861 }
9862 try stderr.print(" align({s})", .{@tagName(value.flags.alignment)});
9863 switch (value.flags.location_tag) {
9864 .large => try stderr.print(" size=0x{x} large", .{value.location_payload.large.size}),
9865 .small => {
9866 const loc = value.location_payload.small;
9867 try stderr.print(" size=0x{x}", .{loc.size});
9868 switch (loc.signedness) {
9869 .unsigned => {},
9870 .signed => try stderr.writeAll(" signed"),
9871 }
9872 if (loc.hint != .zr) try stderr.print(" hint={s}", .{@tagName(loc.hint)});
9873 if (loc.register != .zr) try stderr.print(" loc={s}", .{@tagName(loc.register)});
9874 },
9875 }
9876 try stderr.print(" refs={d}\n", .{value.refs});
9877
9878 var part_index = value.flags.parts_len_minus_one;
9879 if (part_index > 0) while (true) : (part_index -= 1) {
9880 roots.putAssumeCapacityNoClobber(
9881 @enumFromInt(@intFromEnum(value.parts) + part_index),
9882 root_entry.value + 1,
9883 );
9884 if (part_index == 0) break;
9885 };
9886 }
9887 try stderr.print("# End {s} Value Dump: {f}\n\n", .{ @typeName(Select), nav.fqn.fmt(ip) });
9888}
9889
9890fn hasRepeatedByteRepr(isel: *Select, constant: Constant) error{OutOfMemory}!?u8 {
9891 const zcu = isel.pt.zcu;
9892 const ty = constant.typeOf(zcu);
9893 const abi_size = std.math.cast(usize, ty.abiSize(zcu)) orelse return null;
9894 const byte_buffer = try zcu.gpa.alloc(u8, abi_size);
9895 defer zcu.gpa.free(byte_buffer);
9896 return if (try isel.writeToMemory(constant, byte_buffer) and
9897 std.mem.allEqual(u8, byte_buffer[1..], byte_buffer[0])) byte_buffer[0] else null;
9898}
9899
9900fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMemory}!bool {
9901 const zcu = isel.pt.zcu;
9902 const ip = &zcu.intern_pool;
9903 switch (ip.indexToKey(constant.toIntern())) {
9904 .int_type,
9905 .ptr_type,
9906 .array_type,
9907 .vector_type,
9908 .opt_type,
9909 .anyframe_type,
9910 .error_union_type,
9911 .simple_type,
9912 .struct_type,
9913 .tuple_type,
9914 .union_type,
9915 .opaque_type,
9916 .enum_type,
9917 .func_type,
9918 .error_set_type,
9919 .inferred_error_set_type,
9920
9921 .enum_literal,
9922 .empty_enum_value,
9923 .memoized_call,
9924 => unreachable, // not a runtime value
9925 .opt => |opt| {
9926 const child_size: usize = @intCast(ZigType.fromInterned(ip.indexToKey(opt.ty).opt_type).abiSize(zcu));
9927 switch (opt.val) {
9928 .none => if (!ZigType.fromInterned(opt.ty).optionalReprIsPayload(zcu)) {
9929 buffer[child_size] = @intFromBool(false);
9930 } else @memset(buffer[0..child_size], 0x00),
9931 else => |child_constant| {
9932 if (!try isel.writeToMemory(.fromInterned(child_constant), buffer[0..child_size])) return false;
9933 if (!ZigType.fromInterned(opt.ty).optionalReprIsPayload(zcu)) buffer[child_size] = @intFromBool(true);
9934 },
9935 }
9936 return true;
9937 },
9938 .aggregate => |aggregate| switch (ip.indexToKey(aggregate.ty)) {
9939 else => unreachable,
9940 .array_type => |array_type| {
9941 var elem_offset: usize = 0;
9942 const elem_size: usize = @intCast(ZigType.fromInterned(array_type.child).abiSize(zcu));
9943 const len_including_sentinel: usize = @intCast(array_type.lenIncludingSentinel());
9944 switch (aggregate.storage) {
9945 .bytes => |bytes| @memcpy(buffer[0..len_including_sentinel], bytes.toSlice(len_including_sentinel, ip)),
9946 .elems => |elems| for (elems) |elem| {
9947 if (!try isel.writeToMemory(.fromInterned(elem), buffer[elem_offset..][0..elem_size])) return false;
9948 elem_offset += elem_size;
9949 },
9950 .repeated_elem => |repeated_elem| for (0..len_including_sentinel) |_| {
9951 if (!try isel.writeToMemory(.fromInterned(repeated_elem), buffer[elem_offset..][0..elem_size])) return false;
9952 elem_offset += elem_size;
9953 },
9954 }
9955 return true;
9956 },
9957 .vector_type => {},
9958 .struct_type => {
9959 const loaded_struct = ip.loadStructType(aggregate.ty);
9960 switch (loaded_struct.layout) {
9961 .auto => {
9962 var field_offset: u64 = 0;
9963 var field_it = loaded_struct.iterateRuntimeOrder(ip);
9964 while (field_it.next()) |field_index| {
9965 if (loaded_struct.fieldIsComptime(ip, field_index)) continue;
9966 const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
9967 field_offset = field_ty.structFieldAlignment(
9968 loaded_struct.fieldAlign(ip, field_index),
9969 loaded_struct.layout,
9970 zcu,
9971 ).forward(field_offset);
9972 const field_size = field_ty.abiSize(zcu);
9973 if (!try isel.writeToMemory(.fromInterned(switch (aggregate.storage) {
9974 .bytes => unreachable,
9975 .elems => |elems| elems[field_index],
9976 .repeated_elem => |repeated_elem| repeated_elem,
9977 }), buffer[@intCast(field_offset)..][0..@intCast(field_size)])) return false;
9978 field_offset += field_size;
9979 }
9980 return true;
9981 },
9982 .@"extern", .@"packed" => {},
9983 }
9984 },
9985 .tuple_type => |tuple_type| {
9986 var field_offset: u64 = 0;
9987 for (tuple_type.types.get(ip), tuple_type.values.get(ip), 0..) |field_type, field_value, field_index| {
9988 if (field_value != .none) continue;
9989 const field_ty: ZigType = .fromInterned(field_type);
9990 field_offset = field_ty.abiAlignment(zcu).forward(field_offset);
9991 const field_size = field_ty.abiSize(zcu);
9992 if (!try isel.writeToMemory(.fromInterned(switch (aggregate.storage) {
9993 .bytes => unreachable,
9994 .elems => |elems| elems[field_index],
9995 .repeated_elem => |repeated_elem| repeated_elem,
9996 }), buffer[@intCast(field_offset)..][0..@intCast(field_size)])) return false;
9997 field_offset += field_size;
9998 }
9999 return true;
10000 },
10001 },
10002 else => {},
10003 }
10004 constant.writeToMemory(isel.pt, buffer) catch |err| switch (err) {
10005 error.OutOfMemory => return error.OutOfMemory,
10006 error.ReinterpretDeclRef, error.Unimplemented, error.IllDefinedMemoryLayout => return false,
10007 };
10008 return true;
10009}
10010
10011const TryAllocRegResult = union(enum) {
10012 allocated: Register.Alias,
10013 fill_candidate: Register.Alias,
10014 out_of_registers,
10015};
10016
10017fn tryAllocIntReg(isel: *Select) TryAllocRegResult {
10018 var failed_result: TryAllocRegResult = .out_of_registers;
10019 var ra: Register.Alias = .r0;
10020 while (true) : (ra = @enumFromInt(@intFromEnum(ra) + 1)) {
10021 if (ra == .r18) continue; // The Platform Register
10022 if (ra == Register.Alias.fp) continue;
10023 const live_vi = isel.live_registers.getPtr(ra);
10024 switch (live_vi.*) {
10025 _ => switch (failed_result) {
10026 .allocated => unreachable,
10027 .fill_candidate => {},
10028 .out_of_registers => failed_result = .{ .fill_candidate = ra },
10029 },
10030 .allocating => {},
10031 .free => {
10032 live_vi.* = .allocating;
10033 isel.saved_registers.insert(ra);
10034 return .{ .allocated = ra };
10035 },
10036 }
10037 if (ra == Register.Alias.lr) return failed_result;
10038 }
10039}
10040
10041fn allocIntReg(isel: *Select) !Register.Alias {
10042 switch (isel.tryAllocIntReg()) {
10043 .allocated => |ra| return ra,
10044 .fill_candidate => |ra| {
10045 assert(try isel.fillMemory(ra));
10046 const live_vi = isel.live_registers.getPtr(ra);
10047 assert(live_vi.* == .free);
10048 live_vi.* = .allocating;
10049 return ra;
10050 },
10051 .out_of_registers => return isel.fail("ran out of registers", .{}),
10052 }
10053}
10054
10055fn tryAllocVecReg(isel: *Select) TryAllocRegResult {
10056 var failed_result: TryAllocRegResult = .out_of_registers;
10057 var ra: Register.Alias = .v0;
10058 while (true) : (ra = @enumFromInt(@intFromEnum(ra) + 1)) {
10059 const live_vi = isel.live_registers.getPtr(ra);
10060 switch (live_vi.*) {
10061 _ => switch (failed_result) {
10062 .allocated => unreachable,
10063 .fill_candidate => {},
10064 .out_of_registers => failed_result = .{ .fill_candidate = ra },
10065 },
10066 .allocating => {},
10067 .free => {
10068 live_vi.* = .allocating;
10069 isel.saved_registers.insert(ra);
10070 return .{ .allocated = ra };
10071 },
10072 }
10073 if (ra == Register.Alias.v31) return failed_result;
10074 }
10075}
10076
10077fn allocVecReg(isel: *Select) !Register.Alias {
10078 switch (isel.tryAllocVecReg()) {
10079 .allocated => |ra| return ra,
10080 .fill_candidate => |ra| {
10081 assert(try isel.fillMemory(ra));
10082 return ra;
10083 },
10084 .out_of_registers => return isel.fail("ran out of registers", .{}),
10085 }
10086}
10087
10088const RegLock = struct {
10089 ra: Register.Alias,
10090 const empty: RegLock = .{ .ra = .zr };
10091 fn unlock(lock: RegLock, isel: *Select) void {
10092 switch (lock.ra) {
10093 else => |ra| isel.freeReg(ra),
10094 .zr => {},
10095 }
10096 }
10097};
10098fn lockReg(isel: *Select, ra: Register.Alias) RegLock {
10099 assert(ra != .zr);
10100 const live_vi = isel.live_registers.getPtr(ra);
10101 assert(live_vi.* == .free);
10102 live_vi.* = .allocating;
10103 return .{ .ra = ra };
10104}
10105fn tryLockReg(isel: *Select, ra: Register.Alias) RegLock {
10106 assert(ra != .zr);
10107 const live_vi = isel.live_registers.getPtr(ra);
10108 switch (live_vi.*) {
10109 _ => unreachable,
10110 .allocating => return .{ .ra = .zr },
10111 .free => {
10112 live_vi.* = .allocating;
10113 return .{ .ra = ra };
10114 },
10115 }
10116}
10117
10118fn freeReg(isel: *Select, ra: Register.Alias) void {
10119 assert(ra != .zr);
10120 const live_vi = isel.live_registers.getPtr(ra);
10121 assert(live_vi.* == .allocating);
10122 live_vi.* = .free;
10123}
10124
10125fn use(isel: *Select, air_ref: Air.Inst.Ref) !Value.Index {
10126 const zcu = isel.pt.zcu;
10127 const ip = &zcu.intern_pool;
10128 try isel.values.ensureUnusedCapacity(zcu.gpa, 1);
10129 const vi, const ty = if (air_ref.toIndex()) |air_inst_index| vi_ty: {
10130 const live_gop = try isel.live_values.getOrPut(zcu.gpa, air_inst_index);
10131 if (live_gop.found_existing) return live_gop.value_ptr.*;
10132 const ty = isel.air.typeOf(air_ref, ip);
10133 const vi = isel.initValue(ty);
10134 tracking_log.debug("${d} <- %{d}", .{
10135 @intFromEnum(vi),
10136 @intFromEnum(air_inst_index),
10137 });
10138 live_gop.value_ptr.* = vi.ref(isel);
10139 break :vi_ty .{ vi, ty };
10140 } else vi_ty: {
10141 const constant: Constant = .fromInterned(air_ref.toInterned().?);
10142 const ty = constant.typeOf(zcu);
10143 const vi = isel.initValue(ty);
10144 tracking_log.debug("${d} <- <{f}, {f}>", .{
10145 @intFromEnum(vi),
10146 isel.fmtType(ty),
10147 isel.fmtConstant(constant),
10148 });
10149 vi.setParent(isel, .{ .constant = constant });
10150 break :vi_ty .{ vi, ty };
10151 };
10152 if (ty.isAbiInt(zcu)) {
10153 const int_info = ty.intInfo(zcu);
10154 if (int_info.bits <= 16) vi.setSignedness(isel, int_info.signedness);
10155 } else if (vi.size(isel) <= 16 and
10156 CallAbiIterator.homogeneousAggregateBaseType(zcu, ty.toIntern()) != null) vi.setIsVector(isel);
10157 return vi;
10158}
10159
10160fn fill(isel: *Select, dst_ra: Register.Alias) error{ OutOfMemory, CodegenFail }!bool {
10161 switch (dst_ra) {
10162 else => {},
10163 Register.Alias.fp, .zr, .sp, .pc, .fpcr, .fpsr, .ffr => return false,
10164 }
10165 const dst_live_vi = isel.live_registers.getPtr(dst_ra);
10166 const dst_vi = switch (dst_live_vi.*) {
10167 _ => |dst_vi| dst_vi,
10168 .allocating => return false,
10169 .free => return true,
10170 };
10171 const src_ra = src_ra: {
10172 if (dst_vi.hint(isel)) |hint_ra| {
10173 assert(dst_live_vi.* == dst_vi);
10174 dst_live_vi.* = .allocating;
10175 defer dst_live_vi.* = dst_vi;
10176 if (try isel.fill(hint_ra)) {
10177 isel.saved_registers.insert(hint_ra);
10178 break :src_ra hint_ra;
10179 }
10180 }
10181 switch (if (dst_vi.isVector(isel)) isel.tryAllocVecReg() else isel.tryAllocIntReg()) {
10182 .allocated => |ra| break :src_ra ra,
10183 .fill_candidate, .out_of_registers => return isel.fillMemory(dst_ra),
10184 }
10185 };
10186 try dst_vi.liveIn(isel, src_ra, comptime &.initFill(.free));
10187 const src_live_vi = isel.live_registers.getPtr(src_ra);
10188 assert(src_live_vi.* == .allocating);
10189 src_live_vi.* = dst_vi;
10190 return true;
10191}
10192
10193fn fillMemory(isel: *Select, dst_ra: Register.Alias) error{ OutOfMemory, CodegenFail }!bool {
10194 const dst_live_vi = isel.live_registers.getPtr(dst_ra);
10195 const dst_vi = switch (dst_live_vi.*) {
10196 _ => |dst_vi| dst_vi,
10197 .allocating => return false,
10198 .free => return true,
10199 };
10200 const dst_vi_ra = &dst_vi.get(isel).location_payload.small.register;
10201 assert(dst_vi_ra.* == dst_ra);
10202 const base_ra = if (dst_ra.isVector()) try isel.allocIntReg() else dst_ra;
10203 defer if (base_ra != dst_ra) isel.freeReg(base_ra);
10204 try isel.emit(switch (dst_vi.size(isel)) {
10205 else => unreachable,
10206 1 => if (dst_ra.isVector())
10207 .ldr(dst_ra.b(), .{ .base = base_ra.x() })
10208 else switch (dst_vi.signedness(isel)) {
10209 .signed => .ldrsb(dst_ra.w(), .{ .base = base_ra.x() }),
10210 .unsigned => .ldrb(dst_ra.w(), .{ .base = base_ra.x() }),
10211 },
10212 2 => if (dst_ra.isVector())
10213 .ldr(dst_ra.h(), .{ .base = base_ra.x() })
10214 else switch (dst_vi.signedness(isel)) {
10215 .signed => .ldrsh(dst_ra.w(), .{ .base = base_ra.x() }),
10216 .unsigned => .ldrh(dst_ra.w(), .{ .base = base_ra.x() }),
10217 },
10218 4 => .ldr(if (dst_ra.isVector()) dst_ra.s() else dst_ra.w(), .{ .base = base_ra.x() }),
10219 8 => .ldr(if (dst_ra.isVector()) dst_ra.d() else dst_ra.x(), .{ .base = base_ra.x() }),
10220 16 => .ldr(dst_ra.q(), .{ .base = base_ra.x() }),
10221 });
10222 dst_vi_ra.* = .zr;
10223 try dst_vi.address(isel, 0, base_ra);
10224 dst_live_vi.* = .free;
10225 return true;
10226}
10227
10228/// Merges possibly differing value tracking into a consistent state.
10229///
10230/// At a conditional branch, if a value is expected in the same register on both
10231/// paths, or only expected in a register on only one path, tracking is updated:
10232///
10233/// $0 -> r0 // final state is now consistent with both paths
10234/// b.cond else
10235/// then:
10236/// $0 -> r0 // updated if not already consistent with else
10237/// ...
10238/// b end
10239/// else:
10240/// $0 -> r0
10241/// ...
10242/// end:
10243///
10244/// At a conditional branch, if a value is expected in different registers on
10245/// each path, mov instructions are emitted:
10246///
10247/// $0 -> r0 // final state is now consistent with both paths
10248/// b.cond else
10249/// then:
10250/// $0 -> r0 // updated to be consistent with else
10251/// mov x1, x0 // emitted to merge the inconsistent states
10252/// $0 -> r1
10253/// ...
10254/// b end
10255/// else:
10256/// $0 -> r0
10257/// ...
10258/// end:
10259///
10260/// At a loop, a value that is expected in a register at the repeats is updated:
10261///
10262/// $0 -> r0 // final state is now consistent with all paths
10263/// loop:
10264/// $0 -> r0 // updated to be consistent with the repeats
10265/// ...
10266/// $0 -> r0
10267/// b.cond loop
10268/// ...
10269/// $0 -> r0
10270/// b loop
10271///
10272/// At a loop, a value that is expected in a register at the top is filled:
10273///
10274/// $0 -> [sp, #A] // final state is now consistent with all paths
10275/// loop:
10276/// $0 -> [sp, #A] // updated to be consistent with the repeats
10277/// ldr x0, [sp, #A] // emitted to merge the inconsistent states
10278/// $0 -> r0
10279/// ...
10280/// $0 -> [sp, #A]
10281/// b.cond loop
10282/// ...
10283/// $0 -> [sp, #A]
10284/// b loop
10285///
10286/// At a loop, if a value that is expected in different registers on each path,
10287/// mov instructions are emitted:
10288///
10289/// $0 -> r0 // final state is now consistent with all paths
10290/// loop:
10291/// $0 -> r0 // updated to be consistent with the repeats
10292/// mov x1, x0 // emitted to merge the inconsistent states
10293/// $0 -> r1
10294/// ...
10295/// $0 -> r0
10296/// b.cond loop
10297/// ...
10298/// $0 -> r0
10299/// b loop
10300fn merge(
10301 isel: *Select,
10302 expected_live_registers: *const LiveRegisters,
10303 comptime opts: struct { fill_extra: bool = false },
10304) !void {
10305 var live_reg_it = isel.live_registers.iterator();
10306 while (live_reg_it.next()) |live_reg_entry| {
10307 const ra = live_reg_entry.key;
10308 const actual_vi = live_reg_entry.value;
10309 const expected_vi = expected_live_registers.get(ra);
10310 switch (expected_vi) {
10311 else => switch (actual_vi.*) {
10312 _ => {},
10313 .allocating => unreachable,
10314 .free => actual_vi.* = .allocating,
10315 },
10316 .free => {},
10317 }
10318 }
10319 live_reg_it = isel.live_registers.iterator();
10320 while (live_reg_it.next()) |live_reg_entry| {
10321 const ra = live_reg_entry.key;
10322 const actual_vi = live_reg_entry.value;
10323 const expected_vi = expected_live_registers.get(ra);
10324 switch (expected_vi) {
10325 _ => {
10326 switch (actual_vi.*) {
10327 _ => _ = if (opts.fill_extra) {
10328 assert(try isel.fillMemory(ra));
10329 assert(actual_vi.* == .free);
10330 },
10331 .allocating => actual_vi.* = .free,
10332 .free => unreachable,
10333 }
10334 try expected_vi.liveIn(isel, ra, expected_live_registers);
10335 },
10336 .allocating => if (if (opts.fill_extra) try isel.fillMemory(ra) else try isel.fill(ra)) {
10337 assert(actual_vi.* == .free);
10338 actual_vi.* = .allocating;
10339 },
10340 .free => if (opts.fill_extra) assert(try isel.fillMemory(ra) and actual_vi.* == .free),
10341 }
10342 }
10343 live_reg_it = isel.live_registers.iterator();
10344 while (live_reg_it.next()) |live_reg_entry| {
10345 const ra = live_reg_entry.key;
10346 const actual_vi = live_reg_entry.value;
10347 const expected_vi = expected_live_registers.get(ra);
10348 switch (expected_vi) {
10349 _ => {
10350 assert(actual_vi.* == .allocating and expected_vi.register(isel) == ra);
10351 actual_vi.* = expected_vi;
10352 },
10353 .allocating => assert(actual_vi.* == .allocating),
10354 .free => if (opts.fill_extra) assert(actual_vi.* == .free),
10355 }
10356 }
10357}
10358
10359const call = struct {
10360 const param_reg: Value.Index = @enumFromInt(@intFromEnum(Value.Index.allocating) - 2);
10361 const callee_clobbered_reg: Value.Index = @enumFromInt(@intFromEnum(Value.Index.allocating) - 1);
10362 const caller_saved_regs: LiveRegisters = .init(.{
10363 .r0 = param_reg,
10364 .r1 = param_reg,
10365 .r2 = param_reg,
10366 .r3 = param_reg,
10367 .r4 = param_reg,
10368 .r5 = param_reg,
10369 .r6 = param_reg,
10370 .r7 = param_reg,
10371 .r8 = param_reg,
10372 .r9 = callee_clobbered_reg,
10373 .r10 = callee_clobbered_reg,
10374 .r11 = callee_clobbered_reg,
10375 .r12 = callee_clobbered_reg,
10376 .r13 = callee_clobbered_reg,
10377 .r14 = callee_clobbered_reg,
10378 .r15 = callee_clobbered_reg,
10379 .r16 = callee_clobbered_reg,
10380 .r17 = callee_clobbered_reg,
10381 .r18 = callee_clobbered_reg,
10382 .r19 = .free,
10383 .r20 = .free,
10384 .r21 = .free,
10385 .r22 = .free,
10386 .r23 = .free,
10387 .r24 = .free,
10388 .r25 = .free,
10389 .r26 = .free,
10390 .r27 = .free,
10391 .r28 = .free,
10392 .r29 = .free,
10393 .r30 = callee_clobbered_reg,
10394 .zr = .free,
10395 .sp = .free,
10396
10397 .pc = .free,
10398
10399 .v0 = param_reg,
10400 .v1 = param_reg,
10401 .v2 = param_reg,
10402 .v3 = param_reg,
10403 .v4 = param_reg,
10404 .v5 = param_reg,
10405 .v6 = param_reg,
10406 .v7 = param_reg,
10407 .v8 = .free,
10408 .v9 = .free,
10409 .v10 = .free,
10410 .v11 = .free,
10411 .v12 = .free,
10412 .v13 = .free,
10413 .v14 = .free,
10414 .v15 = .free,
10415 .v16 = callee_clobbered_reg,
10416 .v17 = callee_clobbered_reg,
10417 .v18 = callee_clobbered_reg,
10418 .v19 = callee_clobbered_reg,
10419 .v20 = callee_clobbered_reg,
10420 .v21 = callee_clobbered_reg,
10421 .v22 = callee_clobbered_reg,
10422 .v23 = callee_clobbered_reg,
10423 .v24 = callee_clobbered_reg,
10424 .v25 = callee_clobbered_reg,
10425 .v26 = callee_clobbered_reg,
10426 .v27 = callee_clobbered_reg,
10427 .v28 = callee_clobbered_reg,
10428 .v29 = callee_clobbered_reg,
10429 .v30 = callee_clobbered_reg,
10430 .v31 = callee_clobbered_reg,
10431
10432 .fpcr = .free,
10433 .fpsr = .free,
10434
10435 .p0 = callee_clobbered_reg,
10436 .p1 = callee_clobbered_reg,
10437 .p2 = callee_clobbered_reg,
10438 .p3 = callee_clobbered_reg,
10439 .p4 = callee_clobbered_reg,
10440 .p5 = callee_clobbered_reg,
10441 .p6 = callee_clobbered_reg,
10442 .p7 = callee_clobbered_reg,
10443 .p8 = callee_clobbered_reg,
10444 .p9 = callee_clobbered_reg,
10445 .p10 = callee_clobbered_reg,
10446 .p11 = callee_clobbered_reg,
10447 .p12 = callee_clobbered_reg,
10448 .p13 = callee_clobbered_reg,
10449 .p14 = callee_clobbered_reg,
10450 .p15 = callee_clobbered_reg,
10451
10452 .ffr = .free,
10453 });
10454 fn prepareReturn(isel: *Select) !void {
10455 var live_reg_it = isel.live_registers.iterator();
10456 while (live_reg_it.next()) |live_reg_entry| switch (caller_saved_regs.get(live_reg_entry.key)) {
10457 else => unreachable,
10458 param_reg, callee_clobbered_reg => switch (live_reg_entry.value.*) {
10459 _ => {},
10460 .allocating => unreachable,
10461 .free => live_reg_entry.value.* = .allocating,
10462 },
10463 .free => {},
10464 };
10465 }
10466 fn returnFill(isel: *Select, ra: Register.Alias) !void {
10467 const live_vi = isel.live_registers.getPtr(ra);
10468 if (try isel.fill(ra)) {
10469 assert(live_vi.* == .free);
10470 live_vi.* = .allocating;
10471 }
10472 assert(live_vi.* == .allocating);
10473 }
10474 fn returnLiveIn(isel: *Select, vi: Value.Index, ra: Register.Alias) !void {
10475 try vi.defLiveIn(isel, ra, &caller_saved_regs);
10476 }
10477 fn finishReturn(isel: *Select) !void {
10478 var live_reg_it = isel.live_registers.iterator();
10479 while (live_reg_it.next()) |live_reg_entry| {
10480 switch (live_reg_entry.value.*) {
10481 _ => |live_vi| switch (live_vi.size(isel)) {
10482 else => unreachable,
10483 1, 2, 4, 8 => {},
10484 16 => {
10485 assert(try isel.fillMemory(live_reg_entry.key));
10486 assert(live_reg_entry.value.* == .free);
10487 switch (caller_saved_regs.get(live_reg_entry.key)) {
10488 else => unreachable,
10489 param_reg, callee_clobbered_reg => live_reg_entry.value.* = .allocating,
10490 .free => {},
10491 }
10492 continue;
10493 },
10494 },
10495 .allocating, .free => {},
10496 }
10497 switch (caller_saved_regs.get(live_reg_entry.key)) {
10498 else => unreachable,
10499 param_reg, callee_clobbered_reg => switch (live_reg_entry.value.*) {
10500 _ => {
10501 assert(try isel.fill(live_reg_entry.key));
10502 assert(live_reg_entry.value.* == .free);
10503 live_reg_entry.value.* = .allocating;
10504 },
10505 .allocating => {},
10506 .free => unreachable,
10507 },
10508 .free => {},
10509 }
10510 }
10511 }
10512 fn prepareCallee(isel: *Select) !void {
10513 var live_reg_it = isel.live_registers.iterator();
10514 while (live_reg_it.next()) |live_reg_entry| switch (caller_saved_regs.get(live_reg_entry.key)) {
10515 else => unreachable,
10516 param_reg => assert(live_reg_entry.value.* == .allocating),
10517 callee_clobbered_reg => isel.freeReg(live_reg_entry.key),
10518 .free => {},
10519 };
10520 }
10521 fn finishCallee(_: *Select) !void {}
10522 fn prepareParams(_: *Select) !void {}
10523 fn paramLiveOut(isel: *Select, vi: Value.Index, ra: Register.Alias) !void {
10524 isel.freeReg(ra);
10525 try vi.liveOut(isel, ra);
10526 const live_vi = isel.live_registers.getPtr(ra);
10527 if (live_vi.* == .free) live_vi.* = .allocating;
10528 }
10529 fn paramAddress(isel: *Select, vi: Value.Index, ra: Register.Alias) !void {
10530 isel.freeReg(ra);
10531 try vi.address(isel, 0, ra);
10532 const live_vi = isel.live_registers.getPtr(ra);
10533 if (live_vi.* == .free) live_vi.* = .allocating;
10534 }
10535 fn finishParams(isel: *Select) !void {
10536 var live_reg_it = isel.live_registers.iterator();
10537 while (live_reg_it.next()) |live_reg_entry| switch (caller_saved_regs.get(live_reg_entry.key)) {
10538 else => unreachable,
10539 param_reg => switch (live_reg_entry.value.*) {
10540 _ => {},
10541 .allocating => live_reg_entry.value.* = .free,
10542 .free => unreachable,
10543 },
10544 callee_clobbered_reg, .free => {},
10545 };
10546 }
10547};
10548
10549pub const CallAbiIterator = struct {
10550 /// Next General-purpose Register Number
10551 ngrn: Register.Alias,
10552 /// Next SIMD and Floating-point Register Number
10553 nsrn: Register.Alias,
10554 /// next stacked argument address
10555 nsaa: u24,
10556
10557 pub const ngrn_start: Register.Alias = .r0;
10558 pub const ngrn_end: Register.Alias = .r8;
10559 pub const nsrn_start: Register.Alias = .v0;
10560 pub const nsrn_end: Register.Alias = .v8;
10561 pub const nsaa_start: u42 = 0;
10562
10563 pub const init: CallAbiIterator = .{
10564 // A.1
10565 .ngrn = ngrn_start,
10566 // A.2
10567 .nsrn = nsrn_start,
10568 // A.3
10569 .nsaa = nsaa_start,
10570 };
10571
10572 pub fn param(it: *CallAbiIterator, isel: *Select, ty: ZigType) !?Value.Index {
10573 const zcu = isel.pt.zcu;
10574 const ip = &zcu.intern_pool;
10575
10576 if (ty.isNoReturn(zcu) or !ty.hasRuntimeBitsIgnoreComptime(zcu)) return null;
10577 try isel.values.ensureUnusedCapacity(zcu.gpa, Value.max_parts);
10578 const wip_vi = isel.initValue(ty);
10579 type_key: switch (ip.indexToKey(ty.toIntern())) {
10580 else => return isel.fail("CallAbiIterator.param({f})", .{isel.fmtType(ty)}),
10581 .int_type => |int_type| switch (int_type.bits) {
10582 0 => unreachable,
10583 1...16 => {
10584 wip_vi.setSignedness(isel, int_type.signedness);
10585 // C.7
10586 it.integer(isel, wip_vi);
10587 },
10588 // C.7
10589 17...64 => it.integer(isel, wip_vi),
10590 // C.9
10591 65...128 => it.integers(isel, wip_vi, @splat(@divExact(wip_vi.size(isel), 2))),
10592 else => it.indirect(isel, wip_vi),
10593 },
10594 .array_type => switch (wip_vi.size(isel)) {
10595 0 => unreachable,
10596 1...8 => it.integer(isel, wip_vi),
10597 9...16 => |size| it.integers(isel, wip_vi, .{ 8, size - 8 }),
10598 else => it.indirect(isel, wip_vi),
10599 },
10600 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
10601 .one, .many, .c => continue :type_key .{ .int_type = .{
10602 .signedness = .unsigned,
10603 .bits = 64,
10604 } },
10605 .slice => it.integers(isel, wip_vi, @splat(8)),
10606 },
10607 .opt_type => |child_type| if (ty.optionalReprIsPayload(zcu))
10608 continue :type_key ip.indexToKey(child_type)
10609 else switch (ZigType.fromInterned(child_type).abiSize(zcu)) {
10610 0 => continue :type_key .{ .simple_type = .bool },
10611 1...7 => it.integer(isel, wip_vi),
10612 8...15 => |child_size| it.integers(isel, wip_vi, .{ 8, child_size - 7 }),
10613 else => return isel.fail("CallAbiIterator.param({f})", .{isel.fmtType(ty)}),
10614 },
10615 .anyframe_type => unreachable,
10616 .error_union_type => |error_union_type| switch (wip_vi.size(isel)) {
10617 0 => unreachable,
10618 1...8 => it.integer(isel, wip_vi),
10619 9...16 => {
10620 var sizes: [2]u64 = @splat(0);
10621 const payload_ty: ZigType = .fromInterned(error_union_type.payload_type);
10622 {
10623 const error_set_ty: ZigType = .fromInterned(error_union_type.error_set_type);
10624 const offset = codegen.errUnionErrorOffset(payload_ty, zcu);
10625 const size = error_set_ty.abiSize(zcu);
10626 const end = offset % 8 + size;
10627 const part_index: usize = @intCast(offset / 8);
10628 sizes[part_index] = @max(sizes[part_index], @min(end, 8));
10629 if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8);
10630 }
10631 {
10632 const offset = codegen.errUnionPayloadOffset(payload_ty, zcu);
10633 const size = payload_ty.abiSize(zcu);
10634 const end = offset % 8 + size;
10635 const part_index: usize = @intCast(offset / 8);
10636 sizes[part_index] = @max(sizes[part_index], @min(end, 8));
10637 if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8);
10638 }
10639 it.integers(isel, wip_vi, sizes);
10640 },
10641 else => it.indirect(isel, wip_vi),
10642 },
10643 .simple_type => |simple_type| switch (simple_type) {
10644 .f16, .f32, .f64, .f128, .c_longdouble => it.vector(isel, wip_vi),
10645 .f80 => continue :type_key .{ .int_type = .{ .signedness = .unsigned, .bits = 80 } },
10646 .usize,
10647 .isize,
10648 .c_char,
10649 .c_short,
10650 .c_ushort,
10651 .c_int,
10652 .c_uint,
10653 .c_long,
10654 .c_ulong,
10655 .c_longlong,
10656 .c_ulonglong,
10657 => continue :type_key .{ .int_type = ty.intInfo(zcu) },
10658 // B.1
10659 .anyopaque => it.indirect(isel, wip_vi),
10660 .bool => continue :type_key .{ .int_type = .{ .signedness = .unsigned, .bits = 1 } },
10661 .anyerror => continue :type_key .{ .int_type = .{
10662 .signedness = .unsigned,
10663 .bits = zcu.errorSetBits(),
10664 } },
10665 .void,
10666 .type,
10667 .comptime_int,
10668 .comptime_float,
10669 .noreturn,
10670 .null,
10671 .undefined,
10672 .enum_literal,
10673 .adhoc_inferred_error_set,
10674 .generic_poison,
10675 => unreachable,
10676 },
10677 .struct_type => {
10678 const size = wip_vi.size(isel);
10679 const loaded_struct = ip.loadStructType(ty.toIntern());
10680 if (size <= 16 * 4) homogeneous_aggregate: {
10681 const fdt = homogeneousStructBaseType(zcu, &loaded_struct) orelse break :homogeneous_aggregate;
10682 const parts_len = @shrExact(size, fdt.log2Size());
10683 if (parts_len > 4) break :homogeneous_aggregate;
10684 it.vectors(isel, wip_vi, fdt, @intCast(parts_len));
10685 break :type_key;
10686 }
10687 switch (size) {
10688 0 => unreachable,
10689 1...8 => it.integer(isel, wip_vi),
10690 9...16 => {
10691 var part_offset: u64 = 0;
10692 var part_sizes: [2]u64 = undefined;
10693 var parts_len: Value.PartsLen = 0;
10694 var next_field_end: u64 = 0;
10695 var field_it = loaded_struct.iterateRuntimeOrder(ip);
10696 while (part_offset < size) {
10697 const field_end = next_field_end;
10698 const next_field_begin = if (field_it.next()) |field_index| next_field_begin: {
10699 const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
10700 const next_field_begin = switch (loaded_struct.fieldAlign(ip, field_index)) {
10701 .none => field_ty.abiAlignment(zcu),
10702 else => |field_align| field_align,
10703 }.forward(field_end);
10704 next_field_end = next_field_begin + field_ty.abiSize(zcu);
10705 break :next_field_begin next_field_begin;
10706 } else std.mem.alignForward(u64, size, 8);
10707 while (next_field_begin - part_offset >= 8) {
10708 const part_size = field_end - part_offset;
10709 part_sizes[parts_len] = part_size;
10710 assert(part_offset + part_size <= size);
10711 parts_len += 1;
10712 part_offset = next_field_begin;
10713 }
10714 }
10715 assert(parts_len == part_sizes.len);
10716 it.integers(isel, wip_vi, part_sizes);
10717 },
10718 else => it.indirect(isel, wip_vi),
10719 }
10720 },
10721 .tuple_type => |tuple_type| {
10722 const size = wip_vi.size(isel);
10723 if (size <= 16 * 4) homogeneous_aggregate: {
10724 const fdt = homogeneousTupleBaseType(zcu, tuple_type) orelse break :homogeneous_aggregate;
10725 const parts_len = @shrExact(size, fdt.log2Size());
10726 if (parts_len > 4) break :homogeneous_aggregate;
10727 it.vectors(isel, wip_vi, fdt, @intCast(parts_len));
10728 break :type_key;
10729 }
10730 switch (size) {
10731 0 => unreachable,
10732 1...8 => it.integer(isel, wip_vi),
10733 9...16 => {
10734 var part_offset: u64 = 0;
10735 var part_sizes: [2]u64 = undefined;
10736 var parts_len: Value.PartsLen = 0;
10737 var next_field_end: u64 = 0;
10738 var field_index: usize = 0;
10739 while (part_offset < size) {
10740 const field_end = next_field_end;
10741 const next_field_begin = while (field_index < tuple_type.types.len) {
10742 defer field_index += 1;
10743 if (tuple_type.values.get(ip)[field_index] != .none) continue;
10744 const field_ty: ZigType = .fromInterned(tuple_type.types.get(ip)[field_index]);
10745 const next_field_begin = field_ty.abiAlignment(zcu).forward(field_end);
10746 next_field_end = next_field_begin + field_ty.abiSize(zcu);
10747 break next_field_begin;
10748 } else std.mem.alignForward(u64, size, 8);
10749 while (next_field_begin - part_offset >= 8) {
10750 const part_size = @min(field_end - part_offset, 8);
10751 part_sizes[parts_len] = part_size;
10752 assert(part_offset + part_size <= size);
10753 parts_len += 1;
10754 part_offset += part_size;
10755 if (part_offset >= field_end) part_offset = next_field_begin;
10756 }
10757 }
10758 assert(parts_len == part_sizes.len);
10759 it.integers(isel, wip_vi, part_sizes);
10760 },
10761 else => it.indirect(isel, wip_vi),
10762 }
10763 },
10764 .opaque_type, .func_type => continue :type_key .{ .simple_type = .anyopaque },
10765 .enum_type => continue :type_key ip.indexToKey(ip.loadEnumType(ty.toIntern()).tag_ty),
10766 .error_set_type,
10767 .inferred_error_set_type,
10768 => continue :type_key .{ .simple_type = .anyerror },
10769 .undef,
10770 .simple_value,
10771 .variable,
10772 .@"extern",
10773 .func,
10774 .int,
10775 .err,
10776 .error_union,
10777 .enum_literal,
10778 .enum_tag,
10779 .empty_enum_value,
10780 .float,
10781 .ptr,
10782 .slice,
10783 .opt,
10784 .aggregate,
10785 .un,
10786 .memoized_call,
10787 => unreachable, // values, not types
10788 }
10789 return wip_vi.ref(isel);
10790 }
10791
10792 pub fn ret(it: *CallAbiIterator, isel: *Select, ty: ZigType) !?Value.Index {
10793 const wip_vi = try it.param(isel, ty) orelse return null;
10794 switch (wip_vi.parent(isel)) {
10795 .unallocated, .stack_slot => {},
10796 .value, .constant => unreachable,
10797 .address => |address_vi| {
10798 assert(address_vi.hint(isel) == ngrn_start);
10799 address_vi.setHint(isel, ngrn_end);
10800 },
10801 }
10802 return wip_vi;
10803 }
10804
10805 pub const FundamentalDataType = enum {
10806 half,
10807 single,
10808 double,
10809 quad,
10810 vector64,
10811 vector128,
10812 fn log2Size(fdt: FundamentalDataType) u3 {
10813 return switch (fdt) {
10814 .half => 1,
10815 .single => 2,
10816 .double, .vector64 => 3,
10817 .quad, .vector128 => 4,
10818 };
10819 }
10820 fn size(fdt: FundamentalDataType) u64 {
10821 return @as(u64, 1) << fdt.log2Size();
10822 }
10823 };
10824 fn homogeneousAggregateBaseType(zcu: *Zcu, initial_ty: InternPool.Index) ?FundamentalDataType {
10825 const ip = &zcu.intern_pool;
10826 var ty = initial_ty;
10827 return type_key: switch (ip.indexToKey(ty)) {
10828 else => null,
10829 .array_type => |array_type| {
10830 ty = array_type.child;
10831 continue :type_key ip.indexToKey(ty);
10832 },
10833 .vector_type => switch (ZigType.fromInterned(ty).abiSize(zcu)) {
10834 else => null,
10835 8 => .vector64,
10836 16 => .vector128,
10837 },
10838 .simple_type => |simple_type| switch (simple_type) {
10839 .f16 => .half,
10840 .f32 => .single,
10841 .f64 => .double,
10842 .f128 => .quad,
10843 .c_longdouble => switch (zcu.getTarget().cTypeBitSize(.longdouble)) {
10844 else => unreachable,
10845 16 => .half,
10846 32 => .single,
10847 64 => .double,
10848 80 => null,
10849 128 => .quad,
10850 },
10851 else => null,
10852 },
10853 .struct_type => homogeneousStructBaseType(zcu, &ip.loadStructType(ty)),
10854 .tuple_type => |tuple_type| homogeneousTupleBaseType(zcu, tuple_type),
10855 };
10856 }
10857 fn homogeneousStructBaseType(zcu: *Zcu, loaded_struct: *const InternPool.LoadedStructType) ?FundamentalDataType {
10858 const ip = &zcu.intern_pool;
10859 var common_fdt: ?FundamentalDataType = null;
10860 for (0.., loaded_struct.field_types.get(ip)) |field_index, field_ty| {
10861 if (loaded_struct.fieldIsComptime(ip, field_index)) continue;
10862 if (loaded_struct.fieldAlign(ip, field_index) != .none) return null;
10863 if (!ZigType.fromInterned(field_ty).hasRuntimeBits(zcu)) continue;
10864 const fdt = homogeneousAggregateBaseType(zcu, field_ty);
10865 if (common_fdt == null) common_fdt = fdt else if (fdt != common_fdt) return null;
10866 }
10867 return common_fdt;
10868 }
10869 fn homogeneousTupleBaseType(zcu: *Zcu, tuple_type: InternPool.Key.TupleType) ?FundamentalDataType {
10870 const ip = &zcu.intern_pool;
10871 var common_fdt: ?FundamentalDataType = null;
10872 for (tuple_type.values.get(ip), tuple_type.types.get(ip)) |field_val, field_ty| {
10873 if (field_val != .none) continue;
10874 const fdt = homogeneousAggregateBaseType(zcu, field_ty);
10875 if (common_fdt == null) common_fdt = fdt else if (fdt != common_fdt) return null;
10876 }
10877 return common_fdt;
10878 }
10879
10880 const Spec = struct {
10881 offset: u64,
10882 size: u64,
10883 };
10884
10885 fn stack(it: *CallAbiIterator, isel: *Select, wip_vi: Value.Index) void {
10886 // C.12
10887 it.nsaa = @intCast(wip_vi.alignment(isel).forward(it.nsaa));
10888 const parent_vi = switch (wip_vi.parent(isel)) {
10889 .unallocated, .stack_slot => wip_vi,
10890 .address, .constant => unreachable,
10891 .value => |parent_vi| parent_vi,
10892 };
10893 switch (parent_vi.parent(isel)) {
10894 .unallocated => parent_vi.setParent(isel, .{ .stack_slot = .{
10895 .base = .sp,
10896 .offset = it.nsaa,
10897 } }),
10898 .stack_slot => {},
10899 .address, .value, .constant => unreachable,
10900 }
10901 it.nsaa += @intCast(wip_vi.size(isel));
10902 }
10903
10904 fn integer(it: *CallAbiIterator, isel: *Select, wip_vi: Value.Index) void {
10905 assert(wip_vi.size(isel) <= 8);
10906 const natural_alignment = wip_vi.alignment(isel);
10907 assert(natural_alignment.order(.@"16").compare(.lte));
10908 wip_vi.setAlignment(isel, natural_alignment.maxStrict(.@"8"));
10909 if (it.ngrn == ngrn_end) return it.stack(isel, wip_vi);
10910 wip_vi.setHint(isel, it.ngrn);
10911 it.ngrn = @enumFromInt(@intFromEnum(it.ngrn) + 1);
10912 }
10913
10914 fn integers(it: *CallAbiIterator, isel: *Select, wip_vi: Value.Index, part_sizes: [2]u64) void {
10915 assert(wip_vi.size(isel) <= 16);
10916 const natural_alignment = wip_vi.alignment(isel);
10917 assert(natural_alignment.order(.@"16").compare(.lte));
10918 wip_vi.setAlignment(isel, natural_alignment.maxStrict(.@"8"));
10919 // C.8
10920 if (natural_alignment == .@"16") it.ngrn = @enumFromInt(std.mem.alignForward(
10921 @typeInfo(Register.Alias).@"enum".tag_type,
10922 @intFromEnum(it.ngrn),
10923 2,
10924 ));
10925 if (it.ngrn == ngrn_end) return it.stack(isel, wip_vi);
10926 wip_vi.setParts(isel, part_sizes.len);
10927 for (0.., part_sizes) |part_index, part_size|
10928 it.integer(isel, wip_vi.addPart(isel, 8 * part_index, part_size));
10929 }
10930
10931 fn vector(it: *CallAbiIterator, isel: *Select, wip_vi: Value.Index) void {
10932 assert(wip_vi.size(isel) <= 16);
10933 const natural_alignment = wip_vi.alignment(isel);
10934 assert(natural_alignment.order(.@"16").compare(.lte));
10935 wip_vi.setAlignment(isel, natural_alignment.maxStrict(.@"8"));
10936 wip_vi.setIsVector(isel);
10937 if (it.nsrn == nsrn_end) return it.stack(isel, wip_vi);
10938 wip_vi.setHint(isel, it.nsrn);
10939 it.nsrn = @enumFromInt(@intFromEnum(it.nsrn) + 1);
10940 }
10941
10942 fn vectors(
10943 it: *CallAbiIterator,
10944 isel: *Select,
10945 wip_vi: Value.Index,
10946 fdt: FundamentalDataType,
10947 parts_len: Value.PartsLen,
10948 ) void {
10949 const fdt_log2_size = fdt.log2Size();
10950 assert(wip_vi.size(isel) == @shlExact(@as(u9, parts_len), fdt_log2_size));
10951 const natural_alignment = wip_vi.alignment(isel);
10952 assert(natural_alignment.order(.@"16").compare(.lte));
10953 wip_vi.setAlignment(isel, natural_alignment.maxStrict(.@"8"));
10954 if (@intFromEnum(it.nsrn) > @intFromEnum(nsrn_end) - parts_len) return it.stack(isel, wip_vi);
10955 if (parts_len == 1) return it.vector(isel, wip_vi);
10956 wip_vi.setParts(isel, parts_len);
10957 const fdt_size = @as(u64, 1) << fdt_log2_size;
10958 for (0..parts_len) |part_index|
10959 it.vector(isel, wip_vi.addPart(isel, part_index << fdt_log2_size, fdt_size));
10960 }
10961
10962 fn indirect(it: *CallAbiIterator, isel: *Select, wip_vi: Value.Index) void {
10963 const wip_address_vi = isel.initValue(.usize);
10964 wip_vi.setParent(isel, .{ .address = wip_address_vi });
10965 it.integer(isel, wip_address_vi);
10966 }
10967};
10968
10969const Air = @import("../../Air.zig");
10970const assert = std.debug.assert;
10971const codegen = @import("../../codegen.zig");
10972const Constant = @import("../../Value.zig");
10973const InternPool = @import("../../InternPool.zig");
10974const Package = @import("../../Package.zig");
10975const Register = codegen.aarch64.encoding.Register;
10976const Select = @This();
10977const std = @import("std");
10978const tracking_log = std.log.scoped(.tracking);
10979const wip_mir_log = std.log.scoped(.@"wip-mir");
10980const Zcu = @import("../../Zcu.zig");
10981const ZigType = @import("../../Type.zig");
src/codegen/aarch64/abi.zig+4-16
......@@ -1,7 +1,5 @@
1const assert = @import("std").debug.assert;
12const std = @import("std");
2const builtin = @import("builtin");
3const bits = @import("../../arch/aarch64/bits.zig");
4const Register = bits.Register;
53const Type = @import("../../Type.zig");
64const Zcu = @import("../../Zcu.zig");
75
......@@ -15,7 +13,7 @@ pub const Class = union(enum) {
1513
1614/// For `float_array` the second element will be the amount of floats.
1715pub fn classifyType(ty: Type, zcu: *Zcu) Class {
18 std.debug.assert(ty.hasRuntimeBitsIgnoreComptime(zcu));
16 assert(ty.hasRuntimeBitsIgnoreComptime(zcu));
1917
2018 var maybe_float_bits: ?u16 = null;
2119 switch (ty.zigTypeTag(zcu)) {
......@@ -47,11 +45,11 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class {
4745 return .byval;
4846 },
4947 .optional => {
50 std.debug.assert(ty.isPtrLikeOptional(zcu));
48 assert(ty.isPtrLikeOptional(zcu));
5149 return .byval;
5250 },
5351 .pointer => {
54 std.debug.assert(!ty.isSlice(zcu));
52 assert(!ty.isSlice(zcu));
5553 return .byval;
5654 },
5755 .error_union,
......@@ -138,13 +136,3 @@ pub fn getFloatArrayType(ty: Type, zcu: *Zcu) ?Type {
138136 else => return null,
139137 }
140138}
141
142pub const callee_preserved_regs = [_]Register{
143 .x19, .x20, .x21, .x22, .x23,
144 .x24, .x25, .x26, .x27, .x28,
145};
146
147pub const c_abi_int_param_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 };
148pub const c_abi_int_return_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 };
149
150const allocatable_registers = callee_preserved_regs;
src/codegen/aarch64/encoding.zig created+11799
......@@ -0,0 +1,11799 @@
1/// B1.2 Registers in AArch64 Execution state
2pub const Register = struct {
3 alias: Alias,
4 format: Format,
5
6 pub const Format = union(enum) {
7 alias,
8 integer: IntegerSize,
9 scalar: VectorSize,
10 vector: Arrangement,
11 element: struct { size: VectorSize, index: u4 },
12 };
13
14 pub const IntegerSize = enum(u1) {
15 word = 0b0,
16 doubleword = 0b1,
17
18 pub fn prefix(is: IntegerSize) u8 {
19 return (comptime std.enums.EnumArray(IntegerSize, u8).init(.{
20 .word = 'w',
21 .doubleword = 'x',
22 })).get(is);
23 }
24 };
25
26 pub const VectorSize = enum(u3) {
27 byte = 0,
28 half = 1,
29 single = 2,
30 double = 3,
31 quad = 4,
32 scalable,
33 predicate,
34
35 pub fn prefix(vs: VectorSize) u8 {
36 return (comptime std.enums.EnumArray(VectorSize, u8).init(.{
37 .byte = 'b',
38 .half = 'h',
39 .single = 's',
40 .double = 'd',
41 .quad = 'q',
42 .scalable = 'z',
43 .predicate = 'p',
44 })).get(vs);
45 }
46 };
47
48 pub const Arrangement = enum {
49 @"2d",
50 @"4s",
51 @"8h",
52 @"16b",
53
54 @"1d",
55 @"2s",
56 @"4h",
57 @"8b",
58
59 pub fn len(arrangement: Arrangement) u5 {
60 return switch (arrangement) {
61 .@"1d" => 1,
62 .@"2d", .@"2s" => 2,
63 .@"4s", .@"4h" => 4,
64 .@"8h", .@"8b" => 8,
65 .@"16b" => 16,
66 };
67 }
68
69 pub fn size(arrangement: Arrangement) Instruction.DataProcessingVector.Q {
70 return switch (arrangement) {
71 .@"2d", .@"4s", .@"8h", .@"16b" => .quad,
72 .@"1d", .@"2s", .@"4h", .@"8b" => .double,
73 };
74 }
75
76 pub fn elemSize(arrangement: Arrangement) Instruction.DataProcessingVector.Size {
77 return switch (arrangement) {
78 .@"2d", .@"1d" => .double,
79 .@"4s", .@"2s" => .single,
80 .@"8h", .@"4h" => .half,
81 .@"16b", .@"8b" => .byte,
82 };
83 }
84 };
85
86 pub const x0: Register = .{ .alias = .r0, .format = .{ .integer = .doubleword } };
87 pub const x1: Register = .{ .alias = .r1, .format = .{ .integer = .doubleword } };
88 pub const x2: Register = .{ .alias = .r2, .format = .{ .integer = .doubleword } };
89 pub const x3: Register = .{ .alias = .r3, .format = .{ .integer = .doubleword } };
90 pub const x4: Register = .{ .alias = .r4, .format = .{ .integer = .doubleword } };
91 pub const x5: Register = .{ .alias = .r5, .format = .{ .integer = .doubleword } };
92 pub const x6: Register = .{ .alias = .r6, .format = .{ .integer = .doubleword } };
93 pub const x7: Register = .{ .alias = .r7, .format = .{ .integer = .doubleword } };
94 pub const x8: Register = .{ .alias = .r8, .format = .{ .integer = .doubleword } };
95 pub const x9: Register = .{ .alias = .r9, .format = .{ .integer = .doubleword } };
96 pub const x10: Register = .{ .alias = .r10, .format = .{ .integer = .doubleword } };
97 pub const x11: Register = .{ .alias = .r11, .format = .{ .integer = .doubleword } };
98 pub const x12: Register = .{ .alias = .r12, .format = .{ .integer = .doubleword } };
99 pub const x13: Register = .{ .alias = .r13, .format = .{ .integer = .doubleword } };
100 pub const x14: Register = .{ .alias = .r14, .format = .{ .integer = .doubleword } };
101 pub const x15: Register = .{ .alias = .r15, .format = .{ .integer = .doubleword } };
102 pub const x16: Register = .{ .alias = .r16, .format = .{ .integer = .doubleword } };
103 pub const x17: Register = .{ .alias = .r17, .format = .{ .integer = .doubleword } };
104 pub const x18: Register = .{ .alias = .r18, .format = .{ .integer = .doubleword } };
105 pub const x19: Register = .{ .alias = .r19, .format = .{ .integer = .doubleword } };
106 pub const x20: Register = .{ .alias = .r20, .format = .{ .integer = .doubleword } };
107 pub const x21: Register = .{ .alias = .r21, .format = .{ .integer = .doubleword } };
108 pub const x22: Register = .{ .alias = .r22, .format = .{ .integer = .doubleword } };
109 pub const x23: Register = .{ .alias = .r23, .format = .{ .integer = .doubleword } };
110 pub const x24: Register = .{ .alias = .r24, .format = .{ .integer = .doubleword } };
111 pub const x25: Register = .{ .alias = .r25, .format = .{ .integer = .doubleword } };
112 pub const x26: Register = .{ .alias = .r26, .format = .{ .integer = .doubleword } };
113 pub const x27: Register = .{ .alias = .r27, .format = .{ .integer = .doubleword } };
114 pub const x28: Register = .{ .alias = .r28, .format = .{ .integer = .doubleword } };
115 pub const x29: Register = .{ .alias = .r29, .format = .{ .integer = .doubleword } };
116 pub const x30: Register = .{ .alias = .r30, .format = .{ .integer = .doubleword } };
117 pub const xzr: Register = .{ .alias = .zr, .format = .{ .integer = .doubleword } };
118 pub const sp: Register = .{ .alias = .sp, .format = .{ .integer = .doubleword } };
119
120 pub const w0: Register = .{ .alias = .r0, .format = .{ .integer = .word } };
121 pub const w1: Register = .{ .alias = .r1, .format = .{ .integer = .word } };
122 pub const w2: Register = .{ .alias = .r2, .format = .{ .integer = .word } };
123 pub const w3: Register = .{ .alias = .r3, .format = .{ .integer = .word } };
124 pub const w4: Register = .{ .alias = .r4, .format = .{ .integer = .word } };
125 pub const w5: Register = .{ .alias = .r5, .format = .{ .integer = .word } };
126 pub const w6: Register = .{ .alias = .r6, .format = .{ .integer = .word } };
127 pub const w7: Register = .{ .alias = .r7, .format = .{ .integer = .word } };
128 pub const w8: Register = .{ .alias = .r8, .format = .{ .integer = .word } };
129 pub const w9: Register = .{ .alias = .r9, .format = .{ .integer = .word } };
130 pub const w10: Register = .{ .alias = .r10, .format = .{ .integer = .word } };
131 pub const w11: Register = .{ .alias = .r11, .format = .{ .integer = .word } };
132 pub const w12: Register = .{ .alias = .r12, .format = .{ .integer = .word } };
133 pub const w13: Register = .{ .alias = .r13, .format = .{ .integer = .word } };
134 pub const w14: Register = .{ .alias = .r14, .format = .{ .integer = .word } };
135 pub const w15: Register = .{ .alias = .r15, .format = .{ .integer = .word } };
136 pub const w16: Register = .{ .alias = .r16, .format = .{ .integer = .word } };
137 pub const w17: Register = .{ .alias = .r17, .format = .{ .integer = .word } };
138 pub const w18: Register = .{ .alias = .r18, .format = .{ .integer = .word } };
139 pub const w19: Register = .{ .alias = .r19, .format = .{ .integer = .word } };
140 pub const w20: Register = .{ .alias = .r20, .format = .{ .integer = .word } };
141 pub const w21: Register = .{ .alias = .r21, .format = .{ .integer = .word } };
142 pub const w22: Register = .{ .alias = .r22, .format = .{ .integer = .word } };
143 pub const w23: Register = .{ .alias = .r23, .format = .{ .integer = .word } };
144 pub const w24: Register = .{ .alias = .r24, .format = .{ .integer = .word } };
145 pub const w25: Register = .{ .alias = .r25, .format = .{ .integer = .word } };
146 pub const w26: Register = .{ .alias = .r26, .format = .{ .integer = .word } };
147 pub const w27: Register = .{ .alias = .r27, .format = .{ .integer = .word } };
148 pub const w28: Register = .{ .alias = .r28, .format = .{ .integer = .word } };
149 pub const w29: Register = .{ .alias = .r29, .format = .{ .integer = .word } };
150 pub const w30: Register = .{ .alias = .r30, .format = .{ .integer = .word } };
151 pub const wzr: Register = .{ .alias = .zr, .format = .{ .integer = .word } };
152 pub const wsp: Register = .{ .alias = .sp, .format = .{ .integer = .word } };
153
154 pub const ip0 = x16;
155 pub const ip1 = x17;
156 pub const fp = x29;
157 pub const lr = x30;
158 pub const pc: Register = .{ .alias = .pc, .format = .{ .integer = .doubleword } };
159
160 pub const q0: Register = .{ .alias = .v0, .format = .{ .scalar = .quad } };
161 pub const q1: Register = .{ .alias = .v1, .format = .{ .scalar = .quad } };
162 pub const q2: Register = .{ .alias = .v2, .format = .{ .scalar = .quad } };
163 pub const q3: Register = .{ .alias = .v3, .format = .{ .scalar = .quad } };
164 pub const q4: Register = .{ .alias = .v4, .format = .{ .scalar = .quad } };
165 pub const q5: Register = .{ .alias = .v5, .format = .{ .scalar = .quad } };
166 pub const q6: Register = .{ .alias = .v6, .format = .{ .scalar = .quad } };
167 pub const q7: Register = .{ .alias = .v7, .format = .{ .scalar = .quad } };
168 pub const q8: Register = .{ .alias = .v8, .format = .{ .scalar = .quad } };
169 pub const q9: Register = .{ .alias = .v9, .format = .{ .scalar = .quad } };
170 pub const q10: Register = .{ .alias = .v10, .format = .{ .scalar = .quad } };
171 pub const q11: Register = .{ .alias = .v11, .format = .{ .scalar = .quad } };
172 pub const q12: Register = .{ .alias = .v12, .format = .{ .scalar = .quad } };
173 pub const q13: Register = .{ .alias = .v13, .format = .{ .scalar = .quad } };
174 pub const q14: Register = .{ .alias = .v14, .format = .{ .scalar = .quad } };
175 pub const q15: Register = .{ .alias = .v15, .format = .{ .scalar = .quad } };
176 pub const q16: Register = .{ .alias = .v16, .format = .{ .scalar = .quad } };
177 pub const q17: Register = .{ .alias = .v17, .format = .{ .scalar = .quad } };
178 pub const q18: Register = .{ .alias = .v18, .format = .{ .scalar = .quad } };
179 pub const q19: Register = .{ .alias = .v19, .format = .{ .scalar = .quad } };
180 pub const q20: Register = .{ .alias = .v20, .format = .{ .scalar = .quad } };
181 pub const q21: Register = .{ .alias = .v21, .format = .{ .scalar = .quad } };
182 pub const q22: Register = .{ .alias = .v22, .format = .{ .scalar = .quad } };
183 pub const q23: Register = .{ .alias = .v23, .format = .{ .scalar = .quad } };
184 pub const q24: Register = .{ .alias = .v24, .format = .{ .scalar = .quad } };
185 pub const q25: Register = .{ .alias = .v25, .format = .{ .scalar = .quad } };
186 pub const q26: Register = .{ .alias = .v26, .format = .{ .scalar = .quad } };
187 pub const q27: Register = .{ .alias = .v27, .format = .{ .scalar = .quad } };
188 pub const q28: Register = .{ .alias = .v28, .format = .{ .scalar = .quad } };
189 pub const q29: Register = .{ .alias = .v29, .format = .{ .scalar = .quad } };
190 pub const q30: Register = .{ .alias = .v30, .format = .{ .scalar = .quad } };
191 pub const q31: Register = .{ .alias = .v31, .format = .{ .scalar = .quad } };
192
193 pub const d0: Register = .{ .alias = .v0, .format = .{ .scalar = .double } };
194 pub const d1: Register = .{ .alias = .v1, .format = .{ .scalar = .double } };
195 pub const d2: Register = .{ .alias = .v2, .format = .{ .scalar = .double } };
196 pub const d3: Register = .{ .alias = .v3, .format = .{ .scalar = .double } };
197 pub const d4: Register = .{ .alias = .v4, .format = .{ .scalar = .double } };
198 pub const d5: Register = .{ .alias = .v5, .format = .{ .scalar = .double } };
199 pub const d6: Register = .{ .alias = .v6, .format = .{ .scalar = .double } };
200 pub const d7: Register = .{ .alias = .v7, .format = .{ .scalar = .double } };
201 pub const d8: Register = .{ .alias = .v8, .format = .{ .scalar = .double } };
202 pub const d9: Register = .{ .alias = .v9, .format = .{ .scalar = .double } };
203 pub const d10: Register = .{ .alias = .v10, .format = .{ .scalar = .double } };
204 pub const d11: Register = .{ .alias = .v11, .format = .{ .scalar = .double } };
205 pub const d12: Register = .{ .alias = .v12, .format = .{ .scalar = .double } };
206 pub const d13: Register = .{ .alias = .v13, .format = .{ .scalar = .double } };
207 pub const d14: Register = .{ .alias = .v14, .format = .{ .scalar = .double } };
208 pub const d15: Register = .{ .alias = .v15, .format = .{ .scalar = .double } };
209 pub const d16: Register = .{ .alias = .v16, .format = .{ .scalar = .double } };
210 pub const d17: Register = .{ .alias = .v17, .format = .{ .scalar = .double } };
211 pub const d18: Register = .{ .alias = .v18, .format = .{ .scalar = .double } };
212 pub const d19: Register = .{ .alias = .v19, .format = .{ .scalar = .double } };
213 pub const d20: Register = .{ .alias = .v20, .format = .{ .scalar = .double } };
214 pub const d21: Register = .{ .alias = .v21, .format = .{ .scalar = .double } };
215 pub const d22: Register = .{ .alias = .v22, .format = .{ .scalar = .double } };
216 pub const d23: Register = .{ .alias = .v23, .format = .{ .scalar = .double } };
217 pub const d24: Register = .{ .alias = .v24, .format = .{ .scalar = .double } };
218 pub const d25: Register = .{ .alias = .v25, .format = .{ .scalar = .double } };
219 pub const d26: Register = .{ .alias = .v26, .format = .{ .scalar = .double } };
220 pub const d27: Register = .{ .alias = .v27, .format = .{ .scalar = .double } };
221 pub const d28: Register = .{ .alias = .v28, .format = .{ .scalar = .double } };
222 pub const d29: Register = .{ .alias = .v29, .format = .{ .scalar = .double } };
223 pub const d30: Register = .{ .alias = .v30, .format = .{ .scalar = .double } };
224 pub const d31: Register = .{ .alias = .v31, .format = .{ .scalar = .double } };
225
226 pub const s0: Register = .{ .alias = .v0, .format = .{ .scalar = .single } };
227 pub const s1: Register = .{ .alias = .v1, .format = .{ .scalar = .single } };
228 pub const s2: Register = .{ .alias = .v2, .format = .{ .scalar = .single } };
229 pub const s3: Register = .{ .alias = .v3, .format = .{ .scalar = .single } };
230 pub const s4: Register = .{ .alias = .v4, .format = .{ .scalar = .single } };
231 pub const s5: Register = .{ .alias = .v5, .format = .{ .scalar = .single } };
232 pub const s6: Register = .{ .alias = .v6, .format = .{ .scalar = .single } };
233 pub const s7: Register = .{ .alias = .v7, .format = .{ .scalar = .single } };
234 pub const s8: Register = .{ .alias = .v8, .format = .{ .scalar = .single } };
235 pub const s9: Register = .{ .alias = .v9, .format = .{ .scalar = .single } };
236 pub const s10: Register = .{ .alias = .v10, .format = .{ .scalar = .single } };
237 pub const s11: Register = .{ .alias = .v11, .format = .{ .scalar = .single } };
238 pub const s12: Register = .{ .alias = .v12, .format = .{ .scalar = .single } };
239 pub const s13: Register = .{ .alias = .v13, .format = .{ .scalar = .single } };
240 pub const s14: Register = .{ .alias = .v14, .format = .{ .scalar = .single } };
241 pub const s15: Register = .{ .alias = .v15, .format = .{ .scalar = .single } };
242 pub const s16: Register = .{ .alias = .v16, .format = .{ .scalar = .single } };
243 pub const s17: Register = .{ .alias = .v17, .format = .{ .scalar = .single } };
244 pub const s18: Register = .{ .alias = .v18, .format = .{ .scalar = .single } };
245 pub const s19: Register = .{ .alias = .v19, .format = .{ .scalar = .single } };
246 pub const s20: Register = .{ .alias = .v20, .format = .{ .scalar = .single } };
247 pub const s21: Register = .{ .alias = .v21, .format = .{ .scalar = .single } };
248 pub const s22: Register = .{ .alias = .v22, .format = .{ .scalar = .single } };
249 pub const s23: Register = .{ .alias = .v23, .format = .{ .scalar = .single } };
250 pub const s24: Register = .{ .alias = .v24, .format = .{ .scalar = .single } };
251 pub const s25: Register = .{ .alias = .v25, .format = .{ .scalar = .single } };
252 pub const s26: Register = .{ .alias = .v26, .format = .{ .scalar = .single } };
253 pub const s27: Register = .{ .alias = .v27, .format = .{ .scalar = .single } };
254 pub const s28: Register = .{ .alias = .v28, .format = .{ .scalar = .single } };
255 pub const s29: Register = .{ .alias = .v29, .format = .{ .scalar = .single } };
256 pub const s30: Register = .{ .alias = .v30, .format = .{ .scalar = .single } };
257 pub const s31: Register = .{ .alias = .v31, .format = .{ .scalar = .single } };
258
259 pub const h0: Register = .{ .alias = .v0, .format = .{ .scalar = .half } };
260 pub const h1: Register = .{ .alias = .v1, .format = .{ .scalar = .half } };
261 pub const h2: Register = .{ .alias = .v2, .format = .{ .scalar = .half } };
262 pub const h3: Register = .{ .alias = .v3, .format = .{ .scalar = .half } };
263 pub const h4: Register = .{ .alias = .v4, .format = .{ .scalar = .half } };
264 pub const h5: Register = .{ .alias = .v5, .format = .{ .scalar = .half } };
265 pub const h6: Register = .{ .alias = .v6, .format = .{ .scalar = .half } };
266 pub const h7: Register = .{ .alias = .v7, .format = .{ .scalar = .half } };
267 pub const h8: Register = .{ .alias = .v8, .format = .{ .scalar = .half } };
268 pub const h9: Register = .{ .alias = .v9, .format = .{ .scalar = .half } };
269 pub const h10: Register = .{ .alias = .v10, .format = .{ .scalar = .half } };
270 pub const h11: Register = .{ .alias = .v11, .format = .{ .scalar = .half } };
271 pub const h12: Register = .{ .alias = .v12, .format = .{ .scalar = .half } };
272 pub const h13: Register = .{ .alias = .v13, .format = .{ .scalar = .half } };
273 pub const h14: Register = .{ .alias = .v14, .format = .{ .scalar = .half } };
274 pub const h15: Register = .{ .alias = .v15, .format = .{ .scalar = .half } };
275 pub const h16: Register = .{ .alias = .v16, .format = .{ .scalar = .half } };
276 pub const h17: Register = .{ .alias = .v17, .format = .{ .scalar = .half } };
277 pub const h18: Register = .{ .alias = .v18, .format = .{ .scalar = .half } };
278 pub const h19: Register = .{ .alias = .v19, .format = .{ .scalar = .half } };
279 pub const h20: Register = .{ .alias = .v20, .format = .{ .scalar = .half } };
280 pub const h21: Register = .{ .alias = .v21, .format = .{ .scalar = .half } };
281 pub const h22: Register = .{ .alias = .v22, .format = .{ .scalar = .half } };
282 pub const h23: Register = .{ .alias = .v23, .format = .{ .scalar = .half } };
283 pub const h24: Register = .{ .alias = .v24, .format = .{ .scalar = .half } };
284 pub const h25: Register = .{ .alias = .v25, .format = .{ .scalar = .half } };
285 pub const h26: Register = .{ .alias = .v26, .format = .{ .scalar = .half } };
286 pub const h27: Register = .{ .alias = .v27, .format = .{ .scalar = .half } };
287 pub const h28: Register = .{ .alias = .v28, .format = .{ .scalar = .half } };
288 pub const h29: Register = .{ .alias = .v29, .format = .{ .scalar = .half } };
289 pub const h30: Register = .{ .alias = .v30, .format = .{ .scalar = .half } };
290 pub const h31: Register = .{ .alias = .v31, .format = .{ .scalar = .half } };
291
292 pub const b0: Register = .{ .alias = .v0, .format = .{ .scalar = .byte } };
293 pub const b1: Register = .{ .alias = .v1, .format = .{ .scalar = .byte } };
294 pub const b2: Register = .{ .alias = .v2, .format = .{ .scalar = .byte } };
295 pub const b3: Register = .{ .alias = .v3, .format = .{ .scalar = .byte } };
296 pub const b4: Register = .{ .alias = .v4, .format = .{ .scalar = .byte } };
297 pub const b5: Register = .{ .alias = .v5, .format = .{ .scalar = .byte } };
298 pub const b6: Register = .{ .alias = .v6, .format = .{ .scalar = .byte } };
299 pub const b7: Register = .{ .alias = .v7, .format = .{ .scalar = .byte } };
300 pub const b8: Register = .{ .alias = .v8, .format = .{ .scalar = .byte } };
301 pub const b9: Register = .{ .alias = .v9, .format = .{ .scalar = .byte } };
302 pub const b10: Register = .{ .alias = .v10, .format = .{ .scalar = .byte } };
303 pub const b11: Register = .{ .alias = .v11, .format = .{ .scalar = .byte } };
304 pub const b12: Register = .{ .alias = .v12, .format = .{ .scalar = .byte } };
305 pub const b13: Register = .{ .alias = .v13, .format = .{ .scalar = .byte } };
306 pub const b14: Register = .{ .alias = .v14, .format = .{ .scalar = .byte } };
307 pub const b15: Register = .{ .alias = .v15, .format = .{ .scalar = .byte } };
308 pub const b16: Register = .{ .alias = .v16, .format = .{ .scalar = .byte } };
309 pub const b17: Register = .{ .alias = .v17, .format = .{ .scalar = .byte } };
310 pub const b18: Register = .{ .alias = .v18, .format = .{ .scalar = .byte } };
311 pub const b19: Register = .{ .alias = .v19, .format = .{ .scalar = .byte } };
312 pub const b20: Register = .{ .alias = .v20, .format = .{ .scalar = .byte } };
313 pub const b21: Register = .{ .alias = .v21, .format = .{ .scalar = .byte } };
314 pub const b22: Register = .{ .alias = .v22, .format = .{ .scalar = .byte } };
315 pub const b23: Register = .{ .alias = .v23, .format = .{ .scalar = .byte } };
316 pub const b24: Register = .{ .alias = .v24, .format = .{ .scalar = .byte } };
317 pub const b25: Register = .{ .alias = .v25, .format = .{ .scalar = .byte } };
318 pub const b26: Register = .{ .alias = .v26, .format = .{ .scalar = .byte } };
319 pub const b27: Register = .{ .alias = .v27, .format = .{ .scalar = .byte } };
320 pub const b28: Register = .{ .alias = .v28, .format = .{ .scalar = .byte } };
321 pub const b29: Register = .{ .alias = .v29, .format = .{ .scalar = .byte } };
322 pub const b30: Register = .{ .alias = .v30, .format = .{ .scalar = .byte } };
323 pub const b31: Register = .{ .alias = .v31, .format = .{ .scalar = .byte } };
324
325 pub const fpcr: Register = .{ .alias = .fpcr, .format = .{ .integer = .doubleword } };
326 pub const fpsr: Register = .{ .alias = .fpsr, .format = .{ .integer = .doubleword } };
327
328 pub const z0: Register = .{ .alias = .v0, .format = .{ .scalar = .scalable } };
329 pub const z1: Register = .{ .alias = .v1, .format = .{ .scalar = .scalable } };
330 pub const z2: Register = .{ .alias = .v2, .format = .{ .scalar = .scalable } };
331 pub const z3: Register = .{ .alias = .v3, .format = .{ .scalar = .scalable } };
332 pub const z4: Register = .{ .alias = .v4, .format = .{ .scalar = .scalable } };
333 pub const z5: Register = .{ .alias = .v5, .format = .{ .scalar = .scalable } };
334 pub const z6: Register = .{ .alias = .v6, .format = .{ .scalar = .scalable } };
335 pub const z7: Register = .{ .alias = .v7, .format = .{ .scalar = .scalable } };
336 pub const z8: Register = .{ .alias = .v8, .format = .{ .scalar = .scalable } };
337 pub const z9: Register = .{ .alias = .v9, .format = .{ .scalar = .scalable } };
338 pub const z10: Register = .{ .alias = .v10, .format = .{ .scalar = .scalable } };
339 pub const z11: Register = .{ .alias = .v11, .format = .{ .scalar = .scalable } };
340 pub const z12: Register = .{ .alias = .v12, .format = .{ .scalar = .scalable } };
341 pub const z13: Register = .{ .alias = .v13, .format = .{ .scalar = .scalable } };
342 pub const z14: Register = .{ .alias = .v14, .format = .{ .scalar = .scalable } };
343 pub const z15: Register = .{ .alias = .v15, .format = .{ .scalar = .scalable } };
344 pub const z16: Register = .{ .alias = .v16, .format = .{ .scalar = .scalable } };
345 pub const z17: Register = .{ .alias = .v17, .format = .{ .scalar = .scalable } };
346 pub const z18: Register = .{ .alias = .v18, .format = .{ .scalar = .scalable } };
347 pub const z19: Register = .{ .alias = .v19, .format = .{ .scalar = .scalable } };
348 pub const z20: Register = .{ .alias = .v20, .format = .{ .scalar = .scalable } };
349 pub const z21: Register = .{ .alias = .v21, .format = .{ .scalar = .scalable } };
350 pub const z22: Register = .{ .alias = .v22, .format = .{ .scalar = .scalable } };
351 pub const z23: Register = .{ .alias = .v23, .format = .{ .scalar = .scalable } };
352 pub const z24: Register = .{ .alias = .v24, .format = .{ .scalar = .scalable } };
353 pub const z25: Register = .{ .alias = .v25, .format = .{ .scalar = .scalable } };
354 pub const z26: Register = .{ .alias = .v26, .format = .{ .scalar = .scalable } };
355 pub const z27: Register = .{ .alias = .v27, .format = .{ .scalar = .scalable } };
356 pub const z28: Register = .{ .alias = .v28, .format = .{ .scalar = .scalable } };
357 pub const z29: Register = .{ .alias = .v29, .format = .{ .scalar = .scalable } };
358 pub const z30: Register = .{ .alias = .v30, .format = .{ .scalar = .scalable } };
359 pub const z31: Register = .{ .alias = .v31, .format = .{ .scalar = .scalable } };
360
361 pub const p0: Register = .{ .alias = .v0, .format = .{ .scalar = .predicate } };
362 pub const p1: Register = .{ .alias = .v1, .format = .{ .scalar = .predicate } };
363 pub const p2: Register = .{ .alias = .v2, .format = .{ .scalar = .predicate } };
364 pub const p3: Register = .{ .alias = .v3, .format = .{ .scalar = .predicate } };
365 pub const p4: Register = .{ .alias = .v4, .format = .{ .scalar = .predicate } };
366 pub const p5: Register = .{ .alias = .v5, .format = .{ .scalar = .predicate } };
367 pub const p6: Register = .{ .alias = .v6, .format = .{ .scalar = .predicate } };
368 pub const p7: Register = .{ .alias = .v7, .format = .{ .scalar = .predicate } };
369 pub const p8: Register = .{ .alias = .v8, .format = .{ .scalar = .predicate } };
370 pub const p9: Register = .{ .alias = .v9, .format = .{ .scalar = .predicate } };
371 pub const p10: Register = .{ .alias = .v10, .format = .{ .scalar = .predicate } };
372 pub const p11: Register = .{ .alias = .v11, .format = .{ .scalar = .predicate } };
373 pub const p12: Register = .{ .alias = .v12, .format = .{ .scalar = .predicate } };
374 pub const p13: Register = .{ .alias = .v13, .format = .{ .scalar = .predicate } };
375 pub const p14: Register = .{ .alias = .v14, .format = .{ .scalar = .predicate } };
376 pub const p15: Register = .{ .alias = .v15, .format = .{ .scalar = .predicate } };
377
378 pub const ffr: Register = .{ .alias = .ffr, .format = .{ .integer = .doubleword } };
379
380 pub const Encoded = enum(u5) {
381 _,
382
383 pub fn decodeInteger(enc: Encoded, sf_enc: IntegerSize, opts: struct { sp: bool = false }) Register {
384 return switch (sf_enc) {
385 .word => switch (@intFromEnum(enc)) {
386 0 => .w0,
387 1 => .w1,
388 2 => .w2,
389 3 => .w3,
390 4 => .w4,
391 5 => .w5,
392 6 => .w6,
393 7 => .w7,
394 8 => .w8,
395 9 => .w9,
396 10 => .w10,
397 11 => .w11,
398 12 => .w12,
399 13 => .w13,
400 14 => .w14,
401 15 => .w15,
402 16 => .w16,
403 17 => .w17,
404 18 => .w18,
405 19 => .w19,
406 20 => .w20,
407 21 => .w21,
408 22 => .w22,
409 23 => .w23,
410 24 => .w24,
411 25 => .w25,
412 26 => .w26,
413 27 => .w27,
414 28 => .w28,
415 29 => .w29,
416 30 => .w30,
417 31 => if (opts.sp) .wsp else .wzr,
418 },
419 .doubleword => switch (@intFromEnum(enc)) {
420 0 => .x0,
421 1 => .x1,
422 2 => .x2,
423 3 => .x3,
424 4 => .x4,
425 5 => .x5,
426 6 => .x6,
427 7 => .x7,
428 8 => .x8,
429 9 => .x9,
430 10 => .x10,
431 11 => .x11,
432 12 => .x12,
433 13 => .x13,
434 14 => .x14,
435 15 => .x15,
436 16 => .x16,
437 17 => .x17,
438 18 => .x18,
439 19 => .x19,
440 20 => .x20,
441 21 => .x21,
442 22 => .x22,
443 23 => .x23,
444 24 => .x24,
445 25 => .x25,
446 26 => .x26,
447 27 => .x27,
448 28 => .x28,
449 29 => .x29,
450 30 => .x30,
451 31 => if (opts.sp) .sp else .xzr,
452 },
453 };
454 }
455
456 pub fn decodeVector(enc: Encoded, vs_enc: VectorSize) Register {
457 return switch (vs_enc) {
458 .byte => switch (@intFromEnum(enc)) {
459 0 => .b0,
460 1 => .b1,
461 2 => .b2,
462 3 => .b3,
463 4 => .b4,
464 5 => .b5,
465 6 => .b6,
466 7 => .b7,
467 8 => .b8,
468 9 => .b9,
469 10 => .b10,
470 11 => .b11,
471 12 => .b12,
472 13 => .b13,
473 14 => .b14,
474 15 => .b15,
475 16 => .b16,
476 17 => .b17,
477 18 => .b18,
478 19 => .b19,
479 20 => .b20,
480 21 => .b21,
481 22 => .b22,
482 23 => .b23,
483 24 => .b24,
484 25 => .b25,
485 26 => .b26,
486 27 => .b27,
487 28 => .b28,
488 29 => .b29,
489 30 => .b30,
490 31 => .b31,
491 },
492 .half => switch (@intFromEnum(enc)) {
493 0 => .h0,
494 1 => .h1,
495 2 => .h2,
496 3 => .h3,
497 4 => .h4,
498 5 => .h5,
499 6 => .h6,
500 7 => .h7,
501 8 => .h8,
502 9 => .h9,
503 10 => .h10,
504 11 => .h11,
505 12 => .h12,
506 13 => .h13,
507 14 => .h14,
508 15 => .h15,
509 16 => .h16,
510 17 => .h17,
511 18 => .h18,
512 19 => .h19,
513 20 => .h20,
514 21 => .h21,
515 22 => .h22,
516 23 => .h23,
517 24 => .h24,
518 25 => .h25,
519 26 => .h26,
520 27 => .h27,
521 28 => .h28,
522 29 => .h29,
523 30 => .h30,
524 31 => .h31,
525 },
526 .single => switch (@intFromEnum(enc)) {
527 0 => .s0,
528 1 => .s1,
529 2 => .s2,
530 3 => .s3,
531 4 => .s4,
532 5 => .s5,
533 6 => .s6,
534 7 => .s7,
535 8 => .s8,
536 9 => .s9,
537 10 => .s10,
538 11 => .s11,
539 12 => .s12,
540 13 => .s13,
541 14 => .s14,
542 15 => .s15,
543 16 => .s16,
544 17 => .s17,
545 18 => .s18,
546 19 => .s19,
547 20 => .s20,
548 21 => .s21,
549 22 => .s22,
550 23 => .s23,
551 24 => .s24,
552 25 => .s25,
553 26 => .s26,
554 27 => .s27,
555 28 => .s28,
556 29 => .s29,
557 30 => .s30,
558 31 => .s31,
559 },
560 .double => switch (@intFromEnum(enc)) {
561 0 => .d0,
562 1 => .d1,
563 2 => .d2,
564 3 => .d3,
565 4 => .d4,
566 5 => .d5,
567 6 => .d6,
568 7 => .d7,
569 8 => .d8,
570 9 => .d9,
571 10 => .d10,
572 11 => .d11,
573 12 => .d12,
574 13 => .d13,
575 14 => .d14,
576 15 => .d15,
577 16 => .d16,
578 17 => .d17,
579 18 => .d18,
580 19 => .d19,
581 20 => .d20,
582 21 => .d21,
583 22 => .d22,
584 23 => .d23,
585 24 => .d24,
586 25 => .d25,
587 26 => .d26,
588 27 => .d27,
589 28 => .d28,
590 29 => .d29,
591 30 => .d30,
592 31 => .d31,
593 },
594 .quad => switch (@intFromEnum(enc)) {
595 0 => .q0,
596 1 => .q1,
597 2 => .q2,
598 3 => .q3,
599 4 => .q4,
600 5 => .q5,
601 6 => .q6,
602 7 => .q7,
603 8 => .q8,
604 9 => .q9,
605 10 => .q10,
606 11 => .q11,
607 12 => .q12,
608 13 => .q13,
609 14 => .q14,
610 15 => .q15,
611 16 => .q16,
612 17 => .q17,
613 18 => .q18,
614 19 => .q19,
615 20 => .q20,
616 21 => .q21,
617 22 => .q22,
618 23 => .q23,
619 24 => .q24,
620 25 => .q25,
621 26 => .q26,
622 27 => .q27,
623 28 => .q28,
624 29 => .q29,
625 30 => .q30,
626 31 => .q31,
627 },
628 .scalable => switch (@intFromEnum(enc)) {
629 0 => .z0,
630 1 => .z1,
631 2 => .z2,
632 3 => .z3,
633 4 => .z4,
634 5 => .z5,
635 6 => .z6,
636 7 => .z7,
637 8 => .z8,
638 9 => .z9,
639 10 => .z10,
640 11 => .z11,
641 12 => .z12,
642 13 => .z13,
643 14 => .z14,
644 15 => .z15,
645 16 => .z16,
646 17 => .z17,
647 18 => .z18,
648 19 => .z19,
649 20 => .z20,
650 21 => .z21,
651 22 => .z22,
652 23 => .z23,
653 24 => .z24,
654 25 => .z25,
655 26 => .z26,
656 27 => .z27,
657 28 => .z28,
658 29 => .z29,
659 30 => .z30,
660 31 => .z31,
661 },
662 .predicate => switch (@as(u4, @intCast(@intFromEnum(enc)))) {
663 0 => .p0,
664 1 => .p1,
665 2 => .p2,
666 3 => .p3,
667 4 => .p4,
668 5 => .p5,
669 6 => .p6,
670 7 => .p7,
671 8 => .p8,
672 9 => .p9,
673 10 => .p10,
674 11 => .p11,
675 12 => .p12,
676 13 => .p13,
677 14 => .p14,
678 15 => .p15,
679 },
680 };
681 }
682 };
683
684 /// One tag per set of aliasing registers.
685 pub const Alias = enum(u7) {
686 r0,
687 r1,
688 r2,
689 r3,
690 r4,
691 r5,
692 r6,
693 r7,
694 r8,
695 r9,
696 r10,
697 r11,
698 r12,
699 r13,
700 r14,
701 r15,
702 r16,
703 r17,
704 r18,
705 r19,
706 r20,
707 r21,
708 r22,
709 r23,
710 r24,
711 r25,
712 r26,
713 r27,
714 r28,
715 r29,
716 r30,
717 zr,
718 sp,
719
720 pc,
721
722 v0,
723 v1,
724 v2,
725 v3,
726 v4,
727 v5,
728 v6,
729 v7,
730 v8,
731 v9,
732 v10,
733 v11,
734 v12,
735 v13,
736 v14,
737 v15,
738 v16,
739 v17,
740 v18,
741 v19,
742 v20,
743 v21,
744 v22,
745 v23,
746 v24,
747 v25,
748 v26,
749 v27,
750 v28,
751 v29,
752 v30,
753 v31,
754
755 fpcr,
756 fpsr,
757
758 p0,
759 p1,
760 p2,
761 p3,
762 p4,
763 p5,
764 p6,
765 p7,
766 p8,
767 p9,
768 p10,
769 p11,
770 p12,
771 p13,
772 p14,
773 p15,
774
775 ffr,
776
777 pub const ip0: Alias = .r16;
778 pub const ip1: Alias = .r17;
779 pub const fp: Alias = .r29;
780 pub const lr: Alias = .r30;
781
782 pub fn r(ra: Alias) Register {
783 assert(@intFromEnum(ra) >= @intFromEnum(Alias.r0) and @intFromEnum(ra) <= @intFromEnum(Alias.pc));
784 return .{ .alias = ra, .format = .alias };
785 }
786 pub fn x(ra: Alias) Register {
787 assert(@intFromEnum(ra) >= @intFromEnum(Alias.r0) and @intFromEnum(ra) <= @intFromEnum(Alias.sp));
788 return .{ .alias = ra, .format = .{ .integer = .doubleword } };
789 }
790 pub fn w(ra: Alias) Register {
791 assert(@intFromEnum(ra) >= @intFromEnum(Alias.r0) and @intFromEnum(ra) <= @intFromEnum(Alias.sp));
792 return .{ .alias = ra, .format = .{ .integer = .word } };
793 }
794 pub fn v(ra: Alias) Register {
795 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
796 return .{ .alias = ra, .format = .alias };
797 }
798 pub fn q(ra: Alias) Register {
799 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
800 return .{ .alias = ra, .format = .{ .scalar = .quad } };
801 }
802 pub fn d(ra: Alias) Register {
803 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
804 return .{ .alias = ra, .format = .{ .scalar = .double } };
805 }
806 pub fn s(ra: Alias) Register {
807 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
808 return .{ .alias = ra, .format = .{ .scalar = .single } };
809 }
810 pub fn h(ra: Alias) Register {
811 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
812 return .{ .alias = ra, .format = .{ .scalar = .half } };
813 }
814 pub fn b(ra: Alias) Register {
815 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
816 return .{ .alias = ra, .format = .{ .scalar = .byte } };
817 }
818 pub fn z(ra: Alias) Register {
819 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
820 return .{ .alias = ra, .format = .{ .scalar = .scalable } };
821 }
822 pub fn p(ra: Alias) Register {
823 assert(@intFromEnum(ra) >= @intFromEnum(Alias.p0) and @intFromEnum(ra) <= @intFromEnum(Alias.p15));
824 return .{ .alias = ra, .format = .{ .scalar = .predicate } };
825 }
826 pub fn @"2d"(ra: Alias) Register {
827 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
828 return .{ .alias = ra, .format = .{ .vector = .@"2d" } };
829 }
830 pub fn @"4s"(ra: Alias) Register {
831 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
832 return .{ .alias = ra, .format = .{ .vector = .@"4s" } };
833 }
834 pub fn @"8h"(ra: Alias) Register {
835 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
836 return .{ .alias = ra, .format = .{ .vector = .@"8h" } };
837 }
838 pub fn @"16b"(ra: Alias) Register {
839 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
840 return .{ .alias = ra, .format = .{ .vector = .@"16b" } };
841 }
842 pub fn @"1d"(ra: Alias) Register {
843 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
844 return .{ .alias = ra, .format = .{ .vector = .@"1d" } };
845 }
846 pub fn @"2s"(ra: Alias) Register {
847 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
848 return .{ .alias = ra, .format = .{ .vector = .@"2s" } };
849 }
850 pub fn @"4h"(ra: Alias) Register {
851 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
852 return .{ .alias = ra, .format = .{ .vector = .@"4h" } };
853 }
854 pub fn @"8b"(ra: Alias) Register {
855 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
856 return .{ .alias = ra, .format = .{ .vector = .@"8b" } };
857 }
858 pub fn @"d[]"(ra: Alias, index: u1) Register {
859 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
860 return .{ .alias = ra, .format = .{ .element = .{ .size = .double, .index = index } } };
861 }
862 pub fn @"s[]"(ra: Alias, index: u2) Register {
863 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
864 return .{ .alias = ra, .format = .{ .element = .{ .size = .single, .index = index } } };
865 }
866 pub fn @"h[]"(ra: Alias, index: u3) Register {
867 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
868 return .{ .alias = ra, .format = .{ .element = .{ .size = .half, .index = index } } };
869 }
870 pub fn @"b[]"(ra: Alias, index: u4) Register {
871 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
872 return .{ .alias = ra, .format = .{ .element = .{ .size = .byte, .index = index } } };
873 }
874
875 pub fn isVector(ra: Alias) bool {
876 return switch (ra) {
877 .r0,
878 .r1,
879 .r2,
880 .r3,
881 .r4,
882 .r5,
883 .r6,
884 .r7,
885 .r8,
886 .r9,
887 .r10,
888 .r11,
889 .r12,
890 .r13,
891 .r14,
892 .r15,
893 .r16,
894 .r17,
895 .r18,
896 .r19,
897 .r20,
898 .r21,
899 .r22,
900 .r23,
901 .r24,
902 .r25,
903 .r26,
904 .r27,
905 .r28,
906 .r29,
907 .r30,
908 .zr,
909 .sp,
910
911 .pc,
912
913 .fpcr,
914 .fpsr,
915
916 .ffr,
917 => false,
918
919 .v0,
920 .v1,
921 .v2,
922 .v3,
923 .v4,
924 .v5,
925 .v6,
926 .v7,
927 .v8,
928 .v9,
929 .v10,
930 .v11,
931 .v12,
932 .v13,
933 .v14,
934 .v15,
935 .v16,
936 .v17,
937 .v18,
938 .v19,
939 .v20,
940 .v21,
941 .v22,
942 .v23,
943 .v24,
944 .v25,
945 .v26,
946 .v27,
947 .v28,
948 .v29,
949 .v30,
950 .v31,
951
952 .p0,
953 .p1,
954 .p2,
955 .p3,
956 .p4,
957 .p5,
958 .p6,
959 .p7,
960 .p8,
961 .p9,
962 .p10,
963 .p11,
964 .p12,
965 .p13,
966 .p14,
967 .p15,
968 => true,
969 };
970 }
971
972 pub fn encode(ra: Alias, comptime opts: struct { sp: bool = false, V: bool = false }) Encoded {
973 return @enumFromInt(@as(u5, switch (ra) {
974 .r0 => if (opts.V) unreachable else 0,
975 .r1 => if (opts.V) unreachable else 1,
976 .r2 => if (opts.V) unreachable else 2,
977 .r3 => if (opts.V) unreachable else 3,
978 .r4 => if (opts.V) unreachable else 4,
979 .r5 => if (opts.V) unreachable else 5,
980 .r6 => if (opts.V) unreachable else 6,
981 .r7 => if (opts.V) unreachable else 7,
982 .r8 => if (opts.V) unreachable else 8,
983 .r9 => if (opts.V) unreachable else 9,
984 .r10 => if (opts.V) unreachable else 10,
985 .r11 => if (opts.V) unreachable else 11,
986 .r12 => if (opts.V) unreachable else 12,
987 .r13 => if (opts.V) unreachable else 13,
988 .r14 => if (opts.V) unreachable else 14,
989 .r15 => if (opts.V) unreachable else 15,
990 .r16 => if (opts.V) unreachable else 16,
991 .r17 => if (opts.V) unreachable else 17,
992 .r18 => if (opts.V) unreachable else 18,
993 .r19 => if (opts.V) unreachable else 19,
994 .r20 => if (opts.V) unreachable else 20,
995 .r21 => if (opts.V) unreachable else 21,
996 .r22 => if (opts.V) unreachable else 22,
997 .r23 => if (opts.V) unreachable else 23,
998 .r24 => if (opts.V) unreachable else 24,
999 .r25 => if (opts.V) unreachable else 25,
1000 .r26 => if (opts.V) unreachable else 26,
1001 .r27 => if (opts.V) unreachable else 27,
1002 .r28 => if (opts.V) unreachable else 28,
1003 .r29 => if (opts.V) unreachable else 29,
1004 .r30 => if (opts.V) unreachable else 30,
1005 .zr => if (opts.sp or opts.V) unreachable else 31,
1006 .sp => if (opts.sp and !opts.V) 31 else unreachable,
1007 .pc => unreachable,
1008 .v0 => if (opts.V) 0 else unreachable,
1009 .v1 => if (opts.V) 1 else unreachable,
1010 .v2 => if (opts.V) 2 else unreachable,
1011 .v3 => if (opts.V) 3 else unreachable,
1012 .v4 => if (opts.V) 4 else unreachable,
1013 .v5 => if (opts.V) 5 else unreachable,
1014 .v6 => if (opts.V) 6 else unreachable,
1015 .v7 => if (opts.V) 7 else unreachable,
1016 .v8 => if (opts.V) 8 else unreachable,
1017 .v9 => if (opts.V) 9 else unreachable,
1018 .v10 => if (opts.V) 10 else unreachable,
1019 .v11 => if (opts.V) 11 else unreachable,
1020 .v12 => if (opts.V) 12 else unreachable,
1021 .v13 => if (opts.V) 13 else unreachable,
1022 .v14 => if (opts.V) 14 else unreachable,
1023 .v15 => if (opts.V) 15 else unreachable,
1024 .v16 => if (opts.V) 16 else unreachable,
1025 .v17 => if (opts.V) 17 else unreachable,
1026 .v18 => if (opts.V) 18 else unreachable,
1027 .v19 => if (opts.V) 19 else unreachable,
1028 .v20 => if (opts.V) 20 else unreachable,
1029 .v21 => if (opts.V) 21 else unreachable,
1030 .v22 => if (opts.V) 22 else unreachable,
1031 .v23 => if (opts.V) 23 else unreachable,
1032 .v24 => if (opts.V) 24 else unreachable,
1033 .v25 => if (opts.V) 25 else unreachable,
1034 .v26 => if (opts.V) 26 else unreachable,
1035 .v27 => if (opts.V) 27 else unreachable,
1036 .v28 => if (opts.V) 28 else unreachable,
1037 .v29 => if (opts.V) 29 else unreachable,
1038 .v30 => if (opts.V) 30 else unreachable,
1039 .v31 => if (opts.V) 31 else unreachable,
1040 .fpcr, .fpsr => unreachable,
1041 .p0, .p1, .p2, .p3, .p4, .p5, .p6, .p7, .p8, .p9, .p10, .p11, .p12, .p13, .p14, .p15 => unreachable,
1042 .ffr => unreachable,
1043 }));
1044 }
1045 };
1046
1047 pub fn isVector(reg: Register) bool {
1048 return reg.alias.isVector();
1049 }
1050
1051 pub fn size(reg: Register) ?u5 {
1052 return format: switch (reg.format) {
1053 .alias => unreachable,
1054 .integer => |sf| switch (sf) {
1055 .word => 4,
1056 .doubleword => 8,
1057 },
1058 .vector => |vs| switch (vs) {
1059 .byte => 1,
1060 .word => 2,
1061 .single => 4,
1062 .double => 8,
1063 .quad => 16,
1064 .scalable, .predicate => null,
1065 },
1066 .arrangement => |arrangement| switch (arrangement) {
1067 .@"2d", .@"4s", .@"8h", .@"16b" => 16,
1068 .@"1d", .@"2s", .@"4h", .@"8b" => 8,
1069 },
1070 .element => |element| continue :format .{ .vector = element.size },
1071 };
1072 }
1073
1074 pub fn parse(reg: []const u8) ?Register {
1075 return if (reg.len == 0) null else switch (reg[0]) {
1076 else => null,
1077 'r' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| switch (n) {
1078 0...30 => .{
1079 .alias = @enumFromInt(@intFromEnum(Alias.r0) + n),
1080 .format = .alias,
1081 },
1082 31 => null,
1083 } else |_| null,
1084 'x' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| switch (n) {
1085 0...30 => .{
1086 .alias = @enumFromInt(@intFromEnum(Alias.r0) + n),
1087 .format = .{ .integer = .doubleword },
1088 },
1089 31 => null,
1090 } else |_| if (std.mem.eql(u8, reg, "xzr")) .xzr else null,
1091 'w' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| switch (n) {
1092 0...30 => .{
1093 .alias = @enumFromInt(@intFromEnum(Alias.r0) + n),
1094 .format = .{ .integer = .word },
1095 },
1096 31 => null,
1097 } else |_| if (std.mem.eql(u8, reg, "wzr"))
1098 .wzr
1099 else if (std.mem.eql(u8, reg, "wsp"))
1100 .wsp
1101 else
1102 null,
1103 'i' => return if (std.mem.eql(u8, reg, "ip") or std.mem.eql(u8, reg, "ip0"))
1104 .ip0
1105 else if (std.mem.eql(u8, reg, "ip1"))
1106 .ip1
1107 else
1108 null,
1109 'f' => return if (std.mem.eql(u8, reg, "fp")) .fp else null,
1110 'p' => return if (std.mem.eql(u8, reg, "pc")) .pc else null,
1111 'v' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{
1112 .alias = @enumFromInt(@intFromEnum(Alias.v0) + n),
1113 .format = .alias,
1114 } else |_| null,
1115 'q' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{
1116 .alias = @enumFromInt(@intFromEnum(Alias.v0) + n),
1117 .format = .{ .scalar = .quad },
1118 } else |_| null,
1119 'd' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{
1120 .alias = @enumFromInt(@intFromEnum(Alias.v0) + n),
1121 .format = .{ .scalar = .double },
1122 } else |_| null,
1123 's' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{
1124 .alias = @enumFromInt(@intFromEnum(Alias.v0) + n),
1125 .format = .{ .scalar = .single },
1126 } else |_| if (std.mem.eql(u8, reg, "sp")) .sp else null,
1127 'h' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{
1128 .alias = @enumFromInt(@intFromEnum(Alias.v0) + n),
1129 .format = .{ .scalar = .half },
1130 } else |_| null,
1131 'b' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{
1132 .alias = @enumFromInt(@intFromEnum(Alias.v0) + n),
1133 .format = .{ .scalar = .byte },
1134 } else |_| null,
1135 };
1136 }
1137
1138 pub fn fmt(reg: Register) aarch64.Disassemble.RegisterFormatter {
1139 return reg.fmtCase(.lower);
1140 }
1141 pub fn fmtCase(reg: Register, case: aarch64.Disassemble.Case) aarch64.Disassemble.RegisterFormatter {
1142 return .{ .reg = reg, .case = case };
1143 }
1144};
1145
1146/// C1.2.4 Condition code
1147pub const ConditionCode = enum(u4) {
1148 /// integer: Equal
1149 /// floating-point: Equal
1150 /// Z == 1
1151 eq = 0b0000,
1152 /// integer: Not equal
1153 /// floating-point: Not equal or unordered
1154 /// Z == 0
1155 ne = 0b0001,
1156 /// integer: Unsigned higher or same
1157 /// floating-point: Greater than, equal, or unordered
1158 /// C == 1
1159 hs = 0b0010,
1160 /// integer: Unsigned lower
1161 /// floating-point: Less than
1162 /// C == 0
1163 lo = 0b0011,
1164 /// integer: Minus, negative
1165 /// floating-point: Less than
1166 /// N == 1
1167 mi = 0b0100,
1168 /// integer: Plus, positive or zero
1169 /// floating-point: Greater than, equal, or unordered
1170 /// N == 0
1171 pl = 0b0101,
1172 /// integer: Overflow
1173 /// floating-point: Unordered
1174 /// V == 1
1175 vs = 0b0110,
1176 /// integer: No overflow
1177 /// floating-point: Ordered
1178 /// V == 0
1179 vc = 0b0111,
1180 /// integer: Unsigned higher
1181 /// floating-point: Greater than, or unordered
1182 /// C == 1 and Z == 0
1183 hi = 0b1000,
1184 /// integer: Unsigned lower or same
1185 /// floating-point: Less than or equal
1186 /// C == 0 or Z == 1
1187 ls = 0b1001,
1188 /// integer: Signed greater than or equal
1189 /// floating-point: Greater than or equal
1190 /// N == V
1191 ge = 0b1010,
1192 /// integer: Signed less than
1193 /// floating-point: Less than, or unordered
1194 /// N != V
1195 lt = 0b1011,
1196 /// integer: Signed greater than
1197 /// floating-point: Greater than
1198 /// Z == 0 and N == V
1199 gt = 0b1100,
1200 /// integer: Signed less than or equal
1201 /// floating-point: Less than, equal, or unordered
1202 /// Z == 1 or N != V
1203 le = 0b1101,
1204 /// integer: Always
1205 /// floating-point: Always
1206 /// true
1207 al = 0b1110,
1208 /// integer: Always
1209 /// floating-point: Always
1210 /// true
1211 nv = 0b1111,
1212 /// Carry set
1213 /// C == 1
1214 pub const cs: ConditionCode = .hs;
1215 /// Carry clear
1216 /// C == 0
1217 pub const cc: ConditionCode = .lo;
1218
1219 pub fn invert(cond: ConditionCode) ConditionCode {
1220 return @enumFromInt(@intFromEnum(cond) ^ 0b0001);
1221 }
1222};
1223
1224/// C4.1 A64 instruction set encoding
1225pub const Instruction = packed union {
1226 group: Group,
1227 reserved: Reserved,
1228 sme: Sme,
1229 sve: Sve,
1230 data_processing_immediate: DataProcessingImmediate,
1231 branch_exception_generating_system: BranchExceptionGeneratingSystem,
1232 load_store: LoadStore,
1233 data_processing_register: DataProcessingRegister,
1234 data_processing_vector: DataProcessingVector,
1235
1236 /// Table C4-1 Main encoding table for the A64 instruction set
1237 pub const Group = packed struct {
1238 encoded0: u25,
1239 op1: u4,
1240 encoded29: u2,
1241 op0: u1,
1242 };
1243
1244 /// C4.1.1 Reserved
1245 pub const Reserved = packed union {
1246 group: @This().Group,
1247 udf: Udf,
1248
1249 /// Table C4-2 Encoding table for the Reserved group
1250 pub const Group = packed struct {
1251 encoded0: u16,
1252 op1: u9,
1253 decoded25: u4 = 0b0000,
1254 op0: u2,
1255 decoded31: u1 = 0b0,
1256 };
1257
1258 /// C6.2.387 UDF
1259 pub const Udf = packed struct {
1260 imm16: u16,
1261 decoded16: u16 = 0b0000000000000000,
1262 };
1263
1264 pub const Decoded = union(enum) {
1265 unallocated,
1266 udf: Udf,
1267 };
1268 pub fn decode(inst: @This()) @This().Decoded {
1269 return switch (inst.group.op0) {
1270 0b00 => switch (inst.group.op1) {
1271 0b000000000 => .{ .udf = inst.udf },
1272 else => .unallocated,
1273 },
1274 else => .unallocated,
1275 };
1276 }
1277 };
1278
1279 /// C4.1.2 SME encodings
1280 pub const Sme = packed union {
1281 group: @This().Group,
1282
1283 /// Table C4-3 Encodings table for the SME encodings group
1284 pub const Group = packed struct {
1285 encoded0: u2,
1286 op2: u3,
1287 encoded5: u5,
1288 op1: u15,
1289 decoded25: u4 = 0b0000,
1290 op0: u2,
1291 decoded31: u1 = 0b1,
1292 };
1293 };
1294
1295 /// C4.1.30 SVE encodings
1296 pub const Sve = packed union {
1297 group: @This().Group,
1298
1299 /// Table C4-31 Encoding table for the SVE encodings group
1300 pub const Group = packed struct {
1301 encoded0: u4,
1302 op2: u1,
1303 encoded5: u5,
1304 op1: u15,
1305 decoded25: u4 = 0b0010,
1306 op0: u3,
1307 };
1308 };
1309
1310 /// C4.1.86 Data Processing -- Immediate
1311 pub const DataProcessingImmediate = packed union {
1312 group: @This().Group,
1313 pc_relative_addressing: PcRelativeAddressing,
1314 add_subtract_immediate: AddSubtractImmediate,
1315 add_subtract_immediate_with_tags: AddSubtractImmediateWithTags,
1316 logical_immediate: LogicalImmediate,
1317 move_wide_immediate: MoveWideImmediate,
1318 bitfield: Bitfield,
1319 extract: Extract,
1320
1321 /// Table C4-87 Encoding table for the Data Processing -- Immediate group
1322 pub const Group = packed struct {
1323 encoded0: u23,
1324 op0: u3,
1325 decoded26: u3 = 0b100,
1326 encoded29: u3,
1327 };
1328
1329 /// PC-rel. addressing
1330 pub const PcRelativeAddressing = packed union {
1331 group: @This().Group,
1332 adr: Adr,
1333 adrp: Adrp,
1334
1335 pub const Group = packed struct {
1336 Rd: Register.Encoded,
1337 immhi: i19,
1338 decoded24: u5 = 0b10000,
1339 immlo: u2,
1340 op: Op,
1341 };
1342
1343 /// C6.2.10 ADR
1344 pub const Adr = packed struct {
1345 Rd: Register.Encoded,
1346 immhi: i19,
1347 decoded24: u5 = 0b10000,
1348 immlo: u2,
1349 op: Op = .adr,
1350 };
1351
1352 /// C6.2.11 ADRP
1353 pub const Adrp = packed struct {
1354 Rd: Register.Encoded,
1355 immhi: i19,
1356 decoded24: u5 = 0b10000,
1357 immlo: u2,
1358 op: Op = .adrp,
1359 };
1360
1361 pub const Op = enum(u1) {
1362 adr = 0b0,
1363 adrp = 0b1,
1364 };
1365 };
1366
1367 /// Add/subtract (immediate)
1368 pub const AddSubtractImmediate = packed union {
1369 group: @This().Group,
1370 add: Add,
1371 adds: Adds,
1372 sub: Sub,
1373 subs: Subs,
1374
1375 pub const Group = packed struct {
1376 Rd: Register.Encoded,
1377 Rn: Register.Encoded,
1378 imm12: u12,
1379 sh: Shift,
1380 decoded23: u6 = 0b100010,
1381 S: bool,
1382 op: AddSubtractOp,
1383 sf: Register.IntegerSize,
1384 };
1385
1386 /// C6.2.4 ADD (immediate)
1387 pub const Add = packed struct {
1388 Rd: Register.Encoded,
1389 Rn: Register.Encoded,
1390 imm12: u12,
1391 sh: Shift,
1392 decoded23: u6 = 0b100010,
1393 S: bool = false,
1394 op: AddSubtractOp = .add,
1395 sf: Register.IntegerSize,
1396 };
1397
1398 /// C6.2.8 ADDS (immediate)
1399 pub const Adds = packed struct {
1400 Rd: Register.Encoded,
1401 Rn: Register.Encoded,
1402 imm12: u12,
1403 sh: Shift,
1404 decoded23: u6 = 0b100010,
1405 S: bool = true,
1406 op: AddSubtractOp = .add,
1407 sf: Register.IntegerSize,
1408 };
1409
1410 /// C6.2.357 SUB (immediate)
1411 pub const Sub = packed struct {
1412 Rd: Register.Encoded,
1413 Rn: Register.Encoded,
1414 imm12: u12,
1415 sh: Shift,
1416 decoded23: u6 = 0b100010,
1417 S: bool = false,
1418 op: AddSubtractOp = .sub,
1419 sf: Register.IntegerSize,
1420 };
1421
1422 /// C6.2.363 SUBS (immediate)
1423 pub const Subs = packed struct {
1424 Rd: Register.Encoded,
1425 Rn: Register.Encoded,
1426 imm12: u12,
1427 sh: Shift,
1428 decoded23: u6 = 0b100010,
1429 S: bool = true,
1430 op: AddSubtractOp = .sub,
1431 sf: Register.IntegerSize,
1432 };
1433
1434 pub const Shift = enum(u1) {
1435 @"0" = 0b0,
1436 @"12" = 0b1,
1437 };
1438 };
1439
1440 /// Add/subtract (immediate, with tags)
1441 pub const AddSubtractImmediateWithTags = packed union {
1442 group: @This().Group,
1443
1444 pub const Group = packed struct {
1445 Rd: Register.Encoded,
1446 Rn: Register.Encoded,
1447 uimm4: u4,
1448 op3: u2,
1449 uimm6: u6,
1450 o2: u1,
1451 decoded23: u6 = 0b100011,
1452 S: bool,
1453 op: AddSubtractOp,
1454 sf: Register.IntegerSize,
1455 };
1456 };
1457
1458 /// Logical (immediate)
1459 pub const LogicalImmediate = packed union {
1460 group: @This().Group,
1461 @"and": And,
1462 orr: Orr,
1463 eor: Eor,
1464 ands: Ands,
1465
1466 pub const Group = packed struct {
1467 Rd: Register.Encoded,
1468 Rn: Register.Encoded,
1469 imm: Bitmask,
1470 decoded23: u6 = 0b100100,
1471 opc: LogicalOpc,
1472 sf: Register.IntegerSize,
1473 };
1474
1475 /// C6.2.12 AND (immediate)
1476 pub const And = packed struct {
1477 Rd: Register.Encoded,
1478 Rn: Register.Encoded,
1479 imm: Bitmask,
1480 decoded23: u6 = 0b100100,
1481 opc: LogicalOpc = .@"and",
1482 sf: Register.IntegerSize,
1483 };
1484
1485 /// C6.2.240 ORR (immediate)
1486 pub const Orr = packed struct {
1487 Rd: Register.Encoded,
1488 Rn: Register.Encoded,
1489 imm: Bitmask,
1490 decoded23: u6 = 0b100100,
1491 opc: LogicalOpc = .orr,
1492 sf: Register.IntegerSize,
1493 };
1494
1495 /// C6.2.119 EOR (immediate)
1496 pub const Eor = packed struct {
1497 Rd: Register.Encoded,
1498 Rn: Register.Encoded,
1499 imm: Bitmask,
1500 decoded23: u6 = 0b100100,
1501 opc: LogicalOpc = .eor,
1502 sf: Register.IntegerSize,
1503 };
1504
1505 /// C6.2.14 ANDS (immediate)
1506 pub const Ands = packed struct {
1507 Rd: Register.Encoded,
1508 Rn: Register.Encoded,
1509 imm: Bitmask,
1510 decoded23: u6 = 0b100100,
1511 opc: LogicalOpc = .ands,
1512 sf: Register.IntegerSize,
1513 };
1514
1515 pub const Decoded = union(enum) {
1516 unallocated,
1517 @"and": And,
1518 orr: Orr,
1519 eor: Eor,
1520 ands: Ands,
1521 };
1522 pub fn decode(inst: @This()) @This().Decoded {
1523 return if (!inst.group.imm.validImmediate(inst.group.sf))
1524 .unallocated
1525 else switch (inst.group.opc) {
1526 .@"and" => .{ .@"and" = inst.@"and" },
1527 .orr => .{ .orr = inst.orr },
1528 .eor => .{ .eor = inst.eor },
1529 .ands => .{ .ands = inst.ands },
1530 };
1531 }
1532 };
1533
1534 /// Move wide (immediate)
1535 pub const MoveWideImmediate = packed union {
1536 group: @This().Group,
1537 movn: Movn,
1538 movz: Movz,
1539 movk: Movk,
1540
1541 pub const Group = packed struct {
1542 Rd: Register.Encoded,
1543 imm16: u16,
1544 hw: Hw,
1545 decoded23: u6 = 0b100101,
1546 opc: Opc,
1547 sf: Register.IntegerSize,
1548 };
1549
1550 /// C6.2.226 MOVN
1551 pub const Movn = packed struct {
1552 Rd: Register.Encoded,
1553 imm16: u16,
1554 hw: Hw,
1555 decoded23: u6 = 0b100101,
1556 opc: Opc = .movn,
1557 sf: Register.IntegerSize,
1558 };
1559
1560 /// C6.2.227 MOVZ
1561 pub const Movz = packed struct {
1562 Rd: Register.Encoded,
1563 imm16: u16,
1564 hw: Hw,
1565 decoded23: u6 = 0b100101,
1566 opc: Opc = .movz,
1567 sf: Register.IntegerSize,
1568 };
1569
1570 /// C6.2.225 MOVK
1571 pub const Movk = packed struct {
1572 Rd: Register.Encoded,
1573 imm16: u16,
1574 hw: Hw,
1575 decoded23: u6 = 0b100101,
1576 opc: Opc = .movk,
1577 sf: Register.IntegerSize,
1578 };
1579
1580 pub const Hw = enum(u2) {
1581 @"0" = 0b00,
1582 @"16" = 0b01,
1583 @"32" = 0b10,
1584 @"48" = 0b11,
1585
1586 pub fn int(hw: Hw) u6 {
1587 return switch (hw) {
1588 .@"0" => 0,
1589 .@"16" => 16,
1590 .@"32" => 32,
1591 .@"48" => 48,
1592 };
1593 }
1594
1595 pub fn sf(hw: Hw) Register.IntegerSize {
1596 return switch (hw) {
1597 .@"0", .@"16" => .word,
1598 .@"32", .@"48" => .doubleword,
1599 };
1600 }
1601 };
1602
1603 pub const Opc = enum(u2) {
1604 movn = 0b00,
1605 movz = 0b10,
1606 movk = 0b11,
1607 _,
1608 };
1609
1610 pub const Decoded = union(enum) {
1611 unallocated,
1612 movn: Movn,
1613 movz: Movz,
1614 movk: Movk,
1615 };
1616 pub fn decode(inst: @This()) @This().Decoded {
1617 return if (inst.group.sf == .word and inst.group.hw.sf() == .doubleword)
1618 .unallocated
1619 else switch (inst.group.opc) {
1620 _ => .unallocated,
1621 .movn => .{ .movn = inst.movn },
1622 .movz => .{ .movz = inst.movz },
1623 .movk => .{ .movk = inst.movk },
1624 };
1625 }
1626 };
1627
1628 /// Bitfield
1629 pub const Bitfield = packed union {
1630 group: @This().Group,
1631 sbfm: Sbfm,
1632 bfm: Bfm,
1633 ubfm: Ubfm,
1634
1635 pub const Group = packed struct {
1636 Rd: Register.Encoded,
1637 Rn: Register.Encoded,
1638 imm: Bitmask,
1639 decoded23: u6 = 0b100110,
1640 opc: Opc,
1641 sf: Register.IntegerSize,
1642 };
1643
1644 pub const Sbfm = packed struct {
1645 Rd: Register.Encoded,
1646 Rn: Register.Encoded,
1647 imm: Bitmask,
1648 decoded23: u6 = 0b100110,
1649 opc: Opc = .sbfm,
1650 sf: Register.IntegerSize,
1651 };
1652
1653 pub const Bfm = packed struct {
1654 Rd: Register.Encoded,
1655 Rn: Register.Encoded,
1656 imm: Bitmask,
1657 decoded23: u6 = 0b100110,
1658 opc: Opc = .bfm,
1659 sf: Register.IntegerSize,
1660 };
1661
1662 pub const Ubfm = packed struct {
1663 Rd: Register.Encoded,
1664 Rn: Register.Encoded,
1665 imm: Bitmask,
1666 decoded23: u6 = 0b100110,
1667 opc: Opc = .ubfm,
1668 sf: Register.IntegerSize,
1669 };
1670
1671 pub const Opc = enum(u2) {
1672 sbfm = 0b00,
1673 bfm = 0b01,
1674 ubfm = 0b10,
1675 _,
1676 };
1677
1678 pub const Decoded = union(enum) {
1679 unallocated,
1680 sbfm: Sbfm,
1681 bfm: Bfm,
1682 ubfm: Ubfm,
1683 };
1684 pub fn decode(inst: @This()) @This().Decoded {
1685 return if (!inst.group.imm.validBitfield(inst.group.sf))
1686 .unallocated
1687 else switch (inst.group.opc) {
1688 _ => .unallocated,
1689 .sbfm => .{ .sbfm = inst.sbfm },
1690 .bfm => .{ .bfm = inst.bfm },
1691 .ubfm => .{ .ubfm = inst.ubfm },
1692 };
1693 }
1694 };
1695
1696 /// Extract
1697 pub const Extract = packed union {
1698 group: @This().Group,
1699 extr: Extr,
1700
1701 pub const Group = packed struct {
1702 Rd: Register.Encoded,
1703 Rn: Register.Encoded,
1704 imms: u6,
1705 Rm: Register.Encoded,
1706 o0: u1,
1707 N: Register.IntegerSize,
1708 decoded23: u6 = 0b100111,
1709 op21: u2,
1710 sf: Register.IntegerSize,
1711 };
1712
1713 pub const Extr = packed struct {
1714 Rd: Register.Encoded,
1715 Rn: Register.Encoded,
1716 imms: u6,
1717 Rm: Register.Encoded,
1718 o0: u1 = 0b0,
1719 N: Register.IntegerSize,
1720 decoded23: u6 = 0b100111,
1721 op21: u2 = 0b00,
1722 sf: Register.IntegerSize,
1723 };
1724
1725 pub const Decoded = union(enum) {
1726 unallocated,
1727 extr: Extr,
1728 };
1729 pub fn decode(inst: @This()) @This().Decoded {
1730 return switch (inst.group.op21) {
1731 0b01, 0b10...0b11 => .unallocated,
1732 0b00 => switch (inst.group.o0) {
1733 0b1 => .unallocated,
1734 0b0 => if ((inst.group.sf == .word and @as(u1, @truncate(inst.group.imms >> 5)) == 0b1) or
1735 inst.group.sf != inst.group.N)
1736 .unallocated
1737 else
1738 .{ .extr = inst.extr },
1739 },
1740 };
1741 }
1742 };
1743
1744 pub const Bitmask = packed struct {
1745 imms: u6,
1746 immr: u6,
1747 N: Register.IntegerSize,
1748
1749 fn lenHsb(bitmask: Bitmask) u7 {
1750 return @bitCast(packed struct {
1751 not_imms: u6,
1752 N: Register.IntegerSize,
1753 }{ .not_imms = ~bitmask.imms, .N = bitmask.N });
1754 }
1755
1756 fn validImmediate(bitmask: Bitmask, sf: Register.IntegerSize) bool {
1757 if (sf == .word and bitmask.N == .doubleword) return false;
1758 const len_hsb = bitmask.lenHsb();
1759 return (len_hsb -% 1) & len_hsb != 0b0_000000;
1760 }
1761
1762 fn validBitfield(bitmask: Bitmask, sf: Register.IntegerSize) bool {
1763 if (sf != bitmask.N) return false;
1764 if (sf == .word and (@as(u1, @truncate(bitmask.immr >> 5)) != 0b0 or
1765 @as(u1, @truncate(bitmask.imms >> 5)) != 0b0)) return false;
1766 const len_hsb = bitmask.lenHsb();
1767 return len_hsb >= 0b0_000010;
1768 }
1769
1770 fn decode(bitmask: Bitmask, sf: Register.IntegerSize) struct { u64, u64 } {
1771 const esize = @as(u7, 1 << 6) >> @clz(bitmask.lenHsb());
1772 const levels: u6 = @intCast(esize - 1);
1773 const s = bitmask.imms & levels;
1774 const r = bitmask.immr & levels;
1775 const d = (s -% r) & levels;
1776 const welem = @as(u64, std.math.maxInt(u64)) >> (63 - s);
1777 const telem = @as(u64, std.math.maxInt(u64)) >> (63 - d);
1778 const emask = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - esize);
1779 const rmask = @divExact(std.math.maxInt(u64), emask);
1780 const wmask = std.math.rotr(u64, welem * rmask, r);
1781 const tmask = telem * rmask;
1782 return switch (sf) {
1783 .word => .{ @as(u32, @truncate(wmask)), @as(u32, @truncate(tmask)) },
1784 .doubleword => .{ wmask, tmask },
1785 };
1786 }
1787
1788 pub fn decodeImmediate(bitmask: Bitmask, sf: Register.IntegerSize) u64 {
1789 assert(bitmask.validImmediate(sf));
1790 const imm, _ = bitmask.decode(sf);
1791 return imm;
1792 }
1793
1794 pub fn decodeBitfield(bitmask: Bitmask, sf: Register.IntegerSize) struct { u64, u64 } {
1795 assert(bitmask.validBitfield(sf));
1796 return bitmask.decode(sf);
1797 }
1798
1799 pub fn moveWidePreferred(bitmask: Bitmask, sf: Register.IntegerSize) bool {
1800 const s = bitmask.imms;
1801 const r = bitmask.immr;
1802 const width: u7 = switch (sf) {
1803 .word => 32,
1804 .doubleword => 64,
1805 };
1806 if (sf != bitmask.N) return false;
1807 if (sf == .word and @as(u1, @truncate(s >> 5)) != 0b0) return false;
1808 if (s < 16) return (-%r % 16) <= (15 - s);
1809 if (s >= width - 15) return (r % 16) <= (s - (width - 15));
1810 return false;
1811 }
1812 };
1813
1814 pub const Decoded = union(enum) {
1815 unallocated,
1816 pc_relative_addressing: PcRelativeAddressing,
1817 add_subtract_immediate: AddSubtractImmediate,
1818 add_subtract_immediate_with_tags: AddSubtractImmediateWithTags,
1819 logical_immediate: LogicalImmediate,
1820 move_wide_immediate: MoveWideImmediate,
1821 bitfield: Bitfield,
1822 extract: Extract,
1823 };
1824 pub fn decode(inst: @This()) @This().Decoded {
1825 return switch (inst.group.op0) {
1826 0b000, 0b001 => .{ .pc_relative_addressing = inst.pc_relative_addressing },
1827 0b010 => .{ .add_subtract_immediate = inst.add_subtract_immediate },
1828 0b011 => .{ .add_subtract_immediate_with_tags = inst.add_subtract_immediate_with_tags },
1829 0b100 => .{ .logical_immediate = inst.logical_immediate },
1830 0b101 => .{ .move_wide_immediate = inst.move_wide_immediate },
1831 0b110 => .{ .bitfield = inst.bitfield },
1832 0b111 => .{ .extract = inst.extract },
1833 };
1834 }
1835 };
1836
1837 /// C4.1.87 Branches, Exception Generating and System instructions
1838 pub const BranchExceptionGeneratingSystem = packed union {
1839 group: @This().Group,
1840 conditional_branch_immediate: ConditionalBranchImmediate,
1841 exception_generating: ExceptionGenerating,
1842 system_register_argument: SystemRegisterArgument,
1843 hints: Hints,
1844 barriers: Barriers,
1845 pstate: Pstate,
1846 system_result: SystemResult,
1847 system: System,
1848 system_register_move: SystemRegisterMove,
1849 unconditional_branch_register: UnconditionalBranchRegister,
1850 unconditional_branch_immediate: UnconditionalBranchImmediate,
1851 compare_branch_immediate: CompareBranchImmediate,
1852 test_branch_immediate: TestBranchImmediate,
1853
1854 /// Table C4-88 Encoding table for the Branches, Exception Generating and System instructions group
1855 pub const Group = packed struct {
1856 op2: u5,
1857 encoded5: u7,
1858 op1: u14,
1859 decoded26: u3 = 0b101,
1860 op0: u3,
1861 };
1862
1863 /// Conditional branch (immediate)
1864 pub const ConditionalBranchImmediate = packed union {
1865 group: @This().Group,
1866 b: B,
1867 bc: Bc,
1868
1869 pub const Group = packed struct {
1870 cond: ConditionCode,
1871 o0: u1,
1872 imm19: i19,
1873 o1: u1,
1874 decoded25: u7 = 0b0101010,
1875 };
1876
1877 /// C6.2.26 B.cond
1878 pub const B = packed struct {
1879 cond: ConditionCode,
1880 o0: u1 = 0b0,
1881 imm19: i19,
1882 o1: u1 = 0b0,
1883 decoded25: u7 = 0b0101010,
1884 };
1885
1886 /// C6.2.27 BC.cond
1887 pub const Bc = packed struct {
1888 cond: ConditionCode,
1889 o0: u1 = 0b1,
1890 imm19: i19,
1891 o1: u1 = 0b0,
1892 decoded25: u7 = 0b0101010,
1893 };
1894
1895 pub const Decoded = union(enum) {
1896 unallocated,
1897 b: B,
1898 bc: Bc,
1899 };
1900 pub fn decode(inst: @This()) @This().Decoded {
1901 return switch (inst.group.o1) {
1902 0b0 => switch (inst.group.o0) {
1903 0b0 => .{ .b = inst.b },
1904 0b1 => .{ .bc = inst.bc },
1905 },
1906 0b1 => .unallocated,
1907 };
1908 }
1909 };
1910
1911 /// Exception generating
1912 pub const ExceptionGenerating = packed union {
1913 group: @This().Group,
1914 svc: Svc,
1915 hvc: Hvc,
1916 smc: Smc,
1917 brk: Brk,
1918 hlt: Hlt,
1919 tcancel: Tcancel,
1920 dcps1: Dcps1,
1921 dcps2: Dcps2,
1922 dcps3: Dcps3,
1923
1924 pub const Group = packed struct {
1925 LL: u2,
1926 op2: u3,
1927 imm16: u16,
1928 opc: u3,
1929 decoded24: u8 = 0b11010100,
1930 };
1931
1932 /// C6.2.365 SVC
1933 pub const Svc = packed struct {
1934 decoded0: u2 = 0b01,
1935 decoded2: u3 = 0b000,
1936 imm16: u16,
1937 decoded21: u3 = 0b000,
1938 decoded24: u8 = 0b11010100,
1939 };
1940
1941 /// C6.2.128 HVC
1942 pub const Hvc = packed struct {
1943 decoded0: u2 = 0b10,
1944 decoded2: u3 = 0b000,
1945 imm16: u16,
1946 decoded21: u3 = 0b000,
1947 decoded24: u8 = 0b11010100,
1948 };
1949
1950 /// C6.2.283 SMC
1951 pub const Smc = packed struct {
1952 decoded0: u2 = 0b11,
1953 decoded2: u3 = 0b000,
1954 imm16: u16,
1955 decoded21: u3 = 0b000,
1956 decoded24: u8 = 0b11010100,
1957 };
1958
1959 /// C6.2.40 BRK
1960 pub const Brk = packed struct {
1961 decoded0: u2 = 0b00,
1962 decoded2: u3 = 0b000,
1963 imm16: u16,
1964 decoded21: u3 = 0b001,
1965 decoded24: u8 = 0b11010100,
1966 };
1967
1968 /// C6.2.127 HLT
1969 pub const Hlt = packed struct {
1970 decoded0: u2 = 0b00,
1971 decoded2: u3 = 0b000,
1972 imm16: u16,
1973 decoded21: u3 = 0b010,
1974 decoded24: u8 = 0b11010100,
1975 };
1976
1977 /// C6.2.376 TCANCEL
1978 pub const Tcancel = packed struct {
1979 decoded0: u2 = 0b00,
1980 decoded2: u3 = 0b000,
1981 imm16: u16,
1982 decoded21: u3 = 0b011,
1983 decoded24: u8 = 0b11010100,
1984 };
1985
1986 /// C6.2.110 DCPS1
1987 pub const Dcps1 = packed struct {
1988 LL: u2 = 0b01,
1989 decoded2: u3 = 0b000,
1990 imm16: u16,
1991 decoded21: u3 = 0b101,
1992 decoded24: u8 = 0b11010100,
1993 };
1994
1995 /// C6.2.110 DCPS2
1996 pub const Dcps2 = packed struct {
1997 LL: u2 = 0b10,
1998 decoded2: u3 = 0b000,
1999 imm16: u16,
2000 decoded21: u3 = 0b101,
2001 decoded24: u8 = 0b11010100,
2002 };
2003
2004 /// C6.2.110 DCPS3
2005 pub const Dcps3 = packed struct {
2006 LL: u2 = 0b11,
2007 decoded2: u3 = 0b000,
2008 imm16: u16,
2009 decoded21: u3 = 0b101,
2010 decoded24: u8 = 0b11010100,
2011 };
2012
2013 pub const Decoded = union(enum) {
2014 unallocated,
2015 svc: Svc,
2016 hvc: Hvc,
2017 smc: Smc,
2018 brk: Brk,
2019 hlt: Hlt,
2020 tcancel: Tcancel,
2021 dcps1: Dcps1,
2022 dcps2: Dcps2,
2023 dcps3: Dcps3,
2024 };
2025 pub fn decode(inst: @This()) @This().Decoded {
2026 return switch (inst.group.op2) {
2027 0b001 => .unallocated,
2028 0b010...0b011 => .unallocated,
2029 0b100...0b111 => .unallocated,
2030 0b000 => switch (inst.group.opc) {
2031 0b000 => switch (inst.group.LL) {
2032 0b00 => .unallocated,
2033 0b01 => .{ .svc = inst.svc },
2034 0b10 => .{ .hvc = inst.hvc },
2035 0b11 => .{ .smc = inst.smc },
2036 },
2037 0b001 => switch (inst.group.LL) {
2038 0b01 => .unallocated,
2039 0b00 => .{ .brk = inst.brk },
2040 0b10...0b11 => .unallocated,
2041 },
2042 0b010 => switch (inst.group.LL) {
2043 0b01 => .unallocated,
2044 0b00 => .{ .hlt = inst.hlt },
2045 0b10...0b11 => .unallocated,
2046 },
2047 0b011 => switch (inst.group.LL) {
2048 0b00 => .{ .tcancel = inst.tcancel },
2049 0b01 => .unallocated,
2050 0b10...0b11 => .unallocated,
2051 },
2052 0b100 => .unallocated,
2053 0b101 => switch (inst.group.LL) {
2054 0b00 => .unallocated,
2055 0b01 => .{ .dcps1 = inst.dcps1 },
2056 0b10 => .{ .dcps2 = inst.dcps2 },
2057 0b11 => .{ .dcps3 = inst.dcps3 },
2058 },
2059 0b110 => .unallocated,
2060 0b111 => .unallocated,
2061 },
2062 };
2063 }
2064 };
2065
2066 /// System instructions with register argument
2067 pub const SystemRegisterArgument = packed struct {
2068 Rt: Register.Encoded,
2069 op2: u3,
2070 CRm: u4,
2071 decoded12: u20 = 0b11010101000000110001,
2072 };
2073
2074 /// Hints
2075 pub const Hints = packed union {
2076 group: @This().Group,
2077 hint: Hint,
2078 nop: Nop,
2079 yield: Yield,
2080 wfe: Wfe,
2081 wfi: Wfi,
2082 sev: Sev,
2083 sevl: Sevl,
2084
2085 pub const Group = packed struct {
2086 decoded0: u5 = 0b11111,
2087 op2: u3,
2088 CRm: u4,
2089 decoded12: u20 = 0b11010101000000110010,
2090 };
2091
2092 /// C6.2.126 HINT
2093 pub const Hint = packed struct {
2094 decoded0: u5 = 0b11111,
2095 op2: u3,
2096 CRm: u4,
2097 decoded12: u4 = 0b0010,
2098 decoded16: u3 = 0b011,
2099 decoded19: u2 = 0b00,
2100 decoded21: u1 = 0b0,
2101 decoded22: u10 = 0b1101010100,
2102 };
2103
2104 /// C6.2.238 NOP
2105 pub const Nop = packed struct {
2106 decoded0: u5 = 0b11111,
2107 op2: u3 = 0b000,
2108 CRm: u4 = 0b0000,
2109 decoded12: u4 = 0b0010,
2110 decoded16: u3 = 0b011,
2111 decoded19: u2 = 0b00,
2112 decoded21: u1 = 0b0,
2113 decoded22: u10 = 0b1101010100,
2114 };
2115
2116 /// C6.2.402 YIELD
2117 pub const Yield = packed struct {
2118 decoded0: u5 = 0b11111,
2119 op2: u3 = 0b001,
2120 CRm: u4 = 0b0000,
2121 decoded12: u4 = 0b0010,
2122 decoded16: u3 = 0b011,
2123 decoded19: u2 = 0b00,
2124 decoded21: u1 = 0b0,
2125 decoded22: u10 = 0b1101010100,
2126 };
2127
2128 /// C6.2.396 WFE
2129 pub const Wfe = packed struct {
2130 decoded0: u5 = 0b11111,
2131 op2: u3 = 0b010,
2132 CRm: u4 = 0b0000,
2133 decoded12: u4 = 0b0010,
2134 decoded16: u3 = 0b011,
2135 decoded19: u2 = 0b00,
2136 decoded21: u1 = 0b0,
2137 decoded22: u10 = 0b1101010100,
2138 };
2139
2140 /// C6.2.398 WFI
2141 pub const Wfi = packed struct {
2142 decoded0: u5 = 0b11111,
2143 op2: u3 = 0b011,
2144 CRm: u4 = 0b0000,
2145 decoded12: u4 = 0b0010,
2146 decoded16: u3 = 0b011,
2147 decoded19: u2 = 0b00,
2148 decoded21: u1 = 0b0,
2149 decoded22: u10 = 0b1101010100,
2150 };
2151
2152 /// C6.2.280 SEV
2153 pub const Sev = packed struct {
2154 decoded0: u5 = 0b11111,
2155 op2: u3 = 0b100,
2156 CRm: u4 = 0b0000,
2157 decoded12: u4 = 0b0010,
2158 decoded16: u3 = 0b011,
2159 decoded19: u2 = 0b00,
2160 decoded21: u1 = 0b0,
2161 decoded22: u10 = 0b1101010100,
2162 };
2163
2164 /// C6.2.280 SEVL
2165 pub const Sevl = packed struct {
2166 decoded0: u5 = 0b11111,
2167 op2: u3 = 0b101,
2168 CRm: u4 = 0b0000,
2169 decoded12: u4 = 0b0010,
2170 decoded16: u3 = 0b011,
2171 decoded19: u2 = 0b00,
2172 decoded21: u1 = 0b0,
2173 decoded22: u10 = 0b1101010100,
2174 };
2175
2176 pub const Decoded = union(enum) {
2177 hint: Hint,
2178 nop: Nop,
2179 yield: Yield,
2180 wfe: Wfe,
2181 wfi: Wfi,
2182 sev: Sev,
2183 sevl: Sevl,
2184 };
2185 pub fn decode(inst: @This()) @This().Decoded {
2186 return switch (inst.group.CRm) {
2187 else => .{ .hint = inst.hint },
2188 0b0000 => switch (inst.group.op2) {
2189 else => .{ .hint = inst.hint },
2190 0b000 => .{ .nop = inst.nop },
2191 0b001 => .{ .yield = inst.yield },
2192 0b010 => .{ .wfe = inst.wfe },
2193 0b011 => .{ .wfi = inst.wfi },
2194 0b100 => .{ .sev = inst.sev },
2195 0b101 => .{ .sevl = inst.sevl },
2196 },
2197 };
2198 }
2199 };
2200
2201 /// Barriers
2202 pub const Barriers = packed union {
2203 group: @This().Group,
2204 clrex: Clrex,
2205 dsb: Dsb,
2206 dmb: Dmb,
2207 isb: Isb,
2208 sb: Sb,
2209
2210 pub const Group = packed struct {
2211 Rt: Register.Encoded,
2212 op2: u3,
2213 CRm: u4,
2214 decoded12: u4 = 0b0011,
2215 decoded16: u3 = 0b011,
2216 decoded19: u2 = 0b00,
2217 decoded21: u1 = 0b0,
2218 decoded22: u10 = 0b1101010100,
2219 };
2220
2221 /// C6.2.56 CLREX
2222 pub const Clrex = packed struct {
2223 Rt: Register.Encoded = @enumFromInt(0b11111),
2224 op2: u3 = 0b010,
2225 CRm: u4,
2226 decoded12: u4 = 0b0011,
2227 decoded16: u3 = 0b011,
2228 decoded19: u2 = 0b00,
2229 decoded21: u1 = 0b0,
2230 decoded22: u10 = 0b1101010100,
2231 };
2232
2233 /// C6.2.116 DSB
2234 pub const Dsb = packed struct {
2235 Rt: Register.Encoded = @enumFromInt(0b11111),
2236 opc: u2 = 0b00,
2237 decoded7: u1 = 0b1,
2238 CRm: Option,
2239 decoded12: u4 = 0b0011,
2240 decoded16: u3 = 0b011,
2241 decoded19: u2 = 0b00,
2242 decoded21: u1 = 0b0,
2243 decoded22: u10 = 0b1101010100,
2244 };
2245
2246 /// C6.2.114 DMB
2247 pub const Dmb = packed struct {
2248 Rt: Register.Encoded = @enumFromInt(0b11111),
2249 opc: u2 = 0b01,
2250 decoded7: u1 = 0b1,
2251 CRm: Option,
2252 decoded12: u4 = 0b0011,
2253 decoded16: u3 = 0b011,
2254 decoded19: u2 = 0b00,
2255 decoded21: u1 = 0b0,
2256 decoded22: u10 = 0b1101010100,
2257 };
2258
2259 /// C6.2.131 ISB
2260 pub const Isb = packed struct {
2261 Rt: Register.Encoded = @enumFromInt(0b11111),
2262 opc: u2 = 0b10,
2263 decoded7: u1 = 0b1,
2264 CRm: Option,
2265 decoded12: u4 = 0b0011,
2266 decoded16: u3 = 0b011,
2267 decoded19: u2 = 0b00,
2268 decoded21: u1 = 0b0,
2269 decoded22: u10 = 0b1101010100,
2270 };
2271
2272 /// C6.2.264 SB
2273 pub const Sb = packed struct {
2274 Rt: Register.Encoded = @enumFromInt(0b11111),
2275 opc: u2 = 0b11,
2276 decoded7: u1 = 0b1,
2277 CRm: u4 = 0b0000,
2278 decoded12: u4 = 0b0011,
2279 decoded16: u3 = 0b011,
2280 decoded19: u2 = 0b00,
2281 decoded21: u1 = 0b0,
2282 decoded22: u10 = 0b1101010100,
2283 };
2284
2285 pub const Option = enum(u4) {
2286 oshld = 0b0001,
2287 oshst = 0b0010,
2288 osh = 0b0011,
2289 nshld = 0b0101,
2290 nshst = 0b0110,
2291 nsh = 0b0111,
2292 ishld = 0b1001,
2293 ishst = 0b1010,
2294 ish = 0b1011,
2295 ld = 0b1101,
2296 st = 0b1110,
2297 sy = 0b1111,
2298 _,
2299 };
2300 };
2301
2302 /// PSTATE
2303 pub const Pstate = packed struct {
2304 Rt: Register.Encoded,
2305 op2: u3,
2306 CRm: u4,
2307 decoded12: u4 = 0b0100,
2308 op1: u3,
2309 decoded19: u13 = 0b1101010100000,
2310 };
2311
2312 /// System with result
2313 pub const SystemResult = packed struct {
2314 Rt: Register.Encoded,
2315 op2: u3,
2316 CRm: u4,
2317 CRn: u4,
2318 op1: u3,
2319 decoded19: u13 = 0b1101010100100,
2320 };
2321
2322 /// System instructions
2323 pub const System = packed union {
2324 group: @This().Group,
2325 sys: Sys,
2326 sysl: Sysl,
2327
2328 pub const Group = packed struct {
2329 Rt: Register.Encoded,
2330 op2: u3,
2331 CRm: u4,
2332 CRn: u4,
2333 op1: u3,
2334 decoded19: u2 = 0b01,
2335 L: L,
2336 decoded22: u10 = 0b1101010100,
2337 };
2338
2339 /// C6.2.372 SYS
2340 pub const Sys = packed struct {
2341 Rt: Register.Encoded,
2342 op2: u3,
2343 CRm: u4,
2344 CRn: u4,
2345 op1: u3,
2346 decoded19: u2 = 0b01,
2347 L: L = .sys,
2348 decoded22: u10 = 0b1101010100,
2349 };
2350
2351 /// C6.2.373 SYSL
2352 pub const Sysl = packed struct {
2353 Rt: Register.Encoded,
2354 op2: u3,
2355 CRm: u4,
2356 CRn: u4,
2357 op1: u3,
2358 decoded19: u2 = 0b01,
2359 L: L = .sysl,
2360 decoded22: u10 = 0b1101010100,
2361 };
2362
2363 const L = enum(u1) {
2364 sys = 0b0,
2365 sysl = 0b1,
2366 };
2367
2368 pub const Decoded = union(enum) {
2369 sys: Sys,
2370 sysl: Sysl,
2371 };
2372 pub fn decode(inst: @This()) @This().Decoded {
2373 return switch (inst.group.L) {
2374 .sys => .{ .sys = inst.sys },
2375 .sysl => .{ .sysl = inst.sysl },
2376 };
2377 }
2378 };
2379
2380 /// System register move
2381 pub const SystemRegisterMove = packed union {
2382 group: @This().Group,
2383 msr: Msr,
2384 mrs: Mrs,
2385
2386 pub const Group = packed struct {
2387 Rt: Register.Encoded,
2388 op2: u3,
2389 CRm: u4,
2390 CRn: u4,
2391 op1: u3,
2392 o0: u1,
2393 decoded20: u1 = 0b1,
2394 L: L,
2395 decoded22: u10 = 0b1101010100,
2396 };
2397
2398 /// C6.2.230 MSR (register)
2399 pub const Msr = packed struct {
2400 Rt: Register.Encoded,
2401 op2: u3,
2402 CRm: u4,
2403 CRn: u4,
2404 op1: u3,
2405 o0: u1,
2406 decoded20: u1 = 0b1,
2407 L: L = .msr,
2408 decoded22: u10 = 0b1101010100,
2409 };
2410
2411 /// C6.2.228 MRS
2412 pub const Mrs = packed struct {
2413 Rt: Register.Encoded,
2414 op2: u3,
2415 CRm: u4,
2416 CRn: u4,
2417 op1: u3,
2418 o0: u1,
2419 decoded20: u1 = 0b1,
2420 L: L = .mrs,
2421 decoded22: u10 = 0b1101010100,
2422 };
2423
2424 pub const L = enum(u1) {
2425 msr = 0b0,
2426 mrs = 0b1,
2427 };
2428
2429 pub const Decoded = union(enum) {
2430 msr: Msr,
2431 mrs: Mrs,
2432 };
2433 pub fn decode(inst: @This()) @This().Decoded {
2434 return switch (inst.group.L) {
2435 .msr => .{ .msr = inst.msr },
2436 .mrs => .{ .mrs = inst.mrs },
2437 };
2438 }
2439 };
2440
2441 /// Unconditional branch (register)
2442 pub const UnconditionalBranchRegister = packed union {
2443 group: @This().Group,
2444 br: Br,
2445 blr: Blr,
2446 ret: Ret,
2447
2448 pub const Group = packed struct {
2449 op4: u5,
2450 Rn: Register.Encoded,
2451 op3: u6,
2452 op2: u5,
2453 opc: u4,
2454 decoded25: u7 = 0b1101011,
2455 };
2456
2457 /// C6.2.37 BR
2458 pub const Br = packed struct {
2459 Rm: Register.Encoded = @enumFromInt(0),
2460 Rn: Register.Encoded,
2461 M: bool = false,
2462 A: bool = false,
2463 decoded12: u4 = 0b0000,
2464 decoded16: u5 = 0b11111,
2465 op: u2 = 0b00,
2466 decoded23: u1 = 0b0,
2467 Z: bool = false,
2468 decoded25: u7 = 0b1101011,
2469 };
2470
2471 /// C6.2.35 BLR
2472 pub const Blr = packed struct {
2473 Rm: Register.Encoded = @enumFromInt(0),
2474 Rn: Register.Encoded,
2475 M: bool = false,
2476 A: bool = false,
2477 decoded12: u4 = 0b0000,
2478 decoded16: u5 = 0b11111,
2479 op: u2 = 0b01,
2480 decoded23: u1 = 0b0,
2481 Z: bool = false,
2482 decoded25: u7 = 0b1101011,
2483 };
2484
2485 /// C6.2.254 RET
2486 pub const Ret = packed struct {
2487 Rm: Register.Encoded = @enumFromInt(0),
2488 Rn: Register.Encoded,
2489 M: bool = false,
2490 A: bool = false,
2491 decoded12: u4 = 0b0000,
2492 decoded16: u5 = 0b11111,
2493 op: u2 = 0b10,
2494 decoded23: u1 = 0b0,
2495 Z: bool = false,
2496 decoded25: u7 = 0b1101011,
2497 };
2498
2499 pub const Decoded = union(enum) {
2500 unallocated,
2501 br: Br,
2502 blr: Blr,
2503 ret: Ret,
2504 };
2505 pub fn decode(inst: @This()) @This().Decoded {
2506 return switch (inst.group.op2) {
2507 else => .unallocated,
2508 0b11111 => switch (inst.group.opc) {
2509 0b0000 => switch (inst.group.op4) {
2510 else => .unallocated,
2511 0b00000 => .{ .br = inst.br },
2512 },
2513 0b0001 => switch (inst.group.op4) {
2514 else => .unallocated,
2515 0b00000 => .{ .blr = inst.blr },
2516 },
2517 0b0010 => switch (inst.group.op4) {
2518 else => .unallocated,
2519 0b00000 => .{ .ret = inst.ret },
2520 },
2521 else => .unallocated,
2522 },
2523 };
2524 }
2525 };
2526
2527 /// Unconditional branch (immediate)
2528 pub const UnconditionalBranchImmediate = packed union {
2529 group: @This().Group,
2530 b: B,
2531 bl: Bl,
2532
2533 pub const Group = packed struct {
2534 imm26: i26,
2535 decoded26: u5 = 0b00101,
2536 op: Op,
2537 };
2538
2539 /// C6.2.25 B
2540 pub const B = packed struct {
2541 imm26: i26,
2542 decoded26: u5 = 0b00101,
2543 op: Op = .b,
2544 };
2545
2546 /// C6.2.34 BL
2547 pub const Bl = packed struct {
2548 imm26: i26,
2549 decoded26: u5 = 0b00101,
2550 op: Op = .bl,
2551 };
2552
2553 pub const Op = enum(u1) {
2554 b = 0b0,
2555 bl = 0b1,
2556 };
2557 };
2558
2559 /// Compare and branch (immediate)
2560 pub const CompareBranchImmediate = packed union {
2561 group: @This().Group,
2562 cbz: Cbz,
2563 cbnz: Cbnz,
2564
2565 pub const Group = packed struct {
2566 Rt: Register.Encoded,
2567 imm19: i19,
2568 op: Op,
2569 decoded25: u6 = 0b011010,
2570 sf: Register.IntegerSize,
2571 };
2572
2573 /// C6.2.47 CBZ
2574 pub const Cbz = packed struct {
2575 Rt: Register.Encoded,
2576 imm19: i19,
2577 op: Op = .cbz,
2578 decoded25: u6 = 0b011010,
2579 sf: Register.IntegerSize,
2580 };
2581
2582 /// C6.2.46 CBNZ
2583 pub const Cbnz = packed struct {
2584 Rt: Register.Encoded,
2585 imm19: i19,
2586 op: Op = .cbnz,
2587 decoded25: u6 = 0b011010,
2588 sf: Register.IntegerSize,
2589 };
2590
2591 pub const Op = enum(u1) {
2592 cbz = 0b0,
2593 cbnz = 0b1,
2594 };
2595 };
2596
2597 /// Test and branch (immediate)
2598 pub const TestBranchImmediate = packed union {
2599 group: @This().Group,
2600 tbz: Tbz,
2601 tbnz: Tbnz,
2602
2603 pub const Group = packed struct {
2604 Rt: Register.Encoded,
2605 imm14: i14,
2606 b40: u5,
2607 op: Op,
2608 decoded25: u6 = 0b011011,
2609 b5: u1,
2610 };
2611
2612 /// C6.2.375 TBZ
2613 pub const Tbz = packed struct {
2614 Rt: Register.Encoded,
2615 imm14: i14,
2616 b40: u5,
2617 op: Op = .tbz,
2618 decoded25: u6 = 0b011011,
2619 b5: u1,
2620 };
2621
2622 /// C6.2.374 TBNZ
2623 pub const Tbnz = packed struct {
2624 Rt: Register.Encoded,
2625 imm14: i14,
2626 b40: u5,
2627 op: Op = .tbnz,
2628 decoded25: u6 = 0b011011,
2629 b5: u1,
2630 };
2631
2632 pub const Op = enum(u1) {
2633 tbz = 0b0,
2634 tbnz = 0b1,
2635 };
2636 };
2637
2638 pub const Decoded = union(enum) {
2639 unallocated,
2640 conditional_branch_immediate: ConditionalBranchImmediate,
2641 exception_generating: ExceptionGenerating,
2642 system_register_argument: SystemRegisterArgument,
2643 hints: Hints,
2644 barriers: Barriers,
2645 pstate: Pstate,
2646 system_result: SystemResult,
2647 system: System,
2648 system_register_move: SystemRegisterMove,
2649 unconditional_branch_register: UnconditionalBranchRegister,
2650 unconditional_branch_immediate: UnconditionalBranchImmediate,
2651 compare_branch_immediate: CompareBranchImmediate,
2652 test_branch_immediate: TestBranchImmediate,
2653 };
2654 pub fn decode(inst: @This()) @This().Decoded {
2655 return switch (inst.group.op0) {
2656 0b010 => switch (inst.group.op1) {
2657 0b000000000000000...0b01111111111111 => .{ .conditional_branch_immediate = inst.conditional_branch_immediate },
2658 else => .unallocated,
2659 },
2660 0b110 => switch (inst.group.op1) {
2661 0b00000000000000...0b00111111111111 => .{ .exception_generating = inst.exception_generating },
2662 0b01000000110001 => .{ .system_register_argument = inst.system_register_argument },
2663 0b01000000110010 => switch (inst.group.op2) {
2664 0b11111 => .{ .hints = inst.hints },
2665 else => .unallocated,
2666 },
2667 0b01000000110011 => .{ .barriers = inst.barriers },
2668 0b01000000000100,
2669 0b01000000010100,
2670 0b01000000100100,
2671 0b01000000110100,
2672 0b01000001000100,
2673 0b01000001010100,
2674 0b01000001100100,
2675 0b01000001110100,
2676 => .{ .pstate = inst.pstate },
2677 0b01001000000000...0b01001001111111 => .{ .system_result = inst.system_result },
2678 0b01000010000000...0b01000011111111, 0b01001010000000...0b01001011111111 => .{ .system = inst.system },
2679 0b01000100000000...0b01000111111111, 0b01001100000000...0b01001111111111 => .{ .system_register_move = inst.system_register_move },
2680 0b10000000000000...0b11111111111111 => .{ .unconditional_branch_register = inst.unconditional_branch_register },
2681 else => .unallocated,
2682 },
2683 0b000, 0b100 => .{ .unconditional_branch_immediate = inst.unconditional_branch_immediate },
2684 0b001, 0b101 => switch (inst.group.op1) {
2685 0b00000000000000...0b01111111111111 => .{ .compare_branch_immediate = inst.compare_branch_immediate },
2686 0b10000000000000...0b11111111111111 => .{ .test_branch_immediate = inst.test_branch_immediate },
2687 },
2688 else => .unallocated,
2689 };
2690 }
2691 };
2692
2693 /// C4.1.88 Loads and Stores
2694 pub const LoadStore = packed union {
2695 group: @This().Group,
2696 register_literal: RegisterLiteral,
2697 memory: Memory,
2698 no_allocate_pair_offset: NoAllocatePairOffset,
2699 register_pair_post_indexed: RegisterPairPostIndexed,
2700 register_pair_offset: RegisterPairOffset,
2701 register_pair_pre_indexed: RegisterPairPreIndexed,
2702 register_unscaled_immediate: RegisterUnscaledImmediate,
2703 register_immediate_post_indexed: RegisterImmediatePostIndexed,
2704 register_unprivileged: RegisterUnprivileged,
2705 register_immediate_pre_indexed: RegisterImmediatePreIndexed,
2706 register_register_offset: RegisterRegisterOffset,
2707 register_unsigned_immediate: RegisterUnsignedImmediate,
2708
2709 /// Table C4-89 Encoding table for the Loads and Stores group
2710 pub const Group = packed struct {
2711 encoded0: u10,
2712 op4: u2,
2713 encoded12: u4,
2714 op3: u6,
2715 encoded22: u1,
2716 op2: u2,
2717 decoded25: u1 = 0b0,
2718 op1: bool,
2719 decoded27: u1 = 0b1,
2720 op0: u4,
2721 };
2722
2723 /// Load register (literal)
2724 pub const RegisterLiteral = packed union {
2725 group: @This().Group,
2726 integer: Integer,
2727 vector: Vector,
2728
2729 pub const Group = packed struct {
2730 Rt: Register.Encoded,
2731 imm19: i19,
2732 decoded24: u2 = 0b00,
2733 V: bool,
2734 decoded27: u3 = 0b011,
2735 opc: u2,
2736 };
2737
2738 pub const Integer = packed union {
2739 group: @This().Group,
2740 ldr: Ldr,
2741 ldrsw: Ldrsw,
2742 prfm: Prfm,
2743
2744 pub const Group = packed struct {
2745 Rt: Register.Encoded,
2746 imm19: i19,
2747 decoded24: u2 = 0b00,
2748 V: bool = false,
2749 decoded27: u3 = 0b011,
2750 opc: u2,
2751 };
2752
2753 /// C6.2.167 LDR (literal)
2754 pub const Ldr = packed struct {
2755 Rt: Register.Encoded,
2756 imm19: i19,
2757 decoded24: u2 = 0b00,
2758 V: bool = false,
2759 decoded27: u3 = 0b011,
2760 sf: Register.IntegerSize,
2761 opc1: u1 = 0b0,
2762 };
2763
2764 /// C6.2.179 LDRSW (literal)
2765 pub const Ldrsw = packed struct {
2766 Rt: Register.Encoded,
2767 imm19: i19,
2768 decoded24: u2 = 0b00,
2769 V: bool = false,
2770 decoded27: u3 = 0b011,
2771 opc: u2 = 0b10,
2772 };
2773
2774 /// C6.2.248 PRFM (literal)
2775 pub const Prfm = packed struct {
2776 prfop: PrfOp,
2777 imm19: i19,
2778 decoded24: u2 = 0b00,
2779 V: bool = false,
2780 decoded27: u3 = 0b011,
2781 opc: u2 = 0b11,
2782 };
2783 };
2784
2785 pub const Vector = packed union {
2786 group: @This().Group,
2787 ldr: Ldr,
2788
2789 pub const Group = packed struct {
2790 Rt: Register.Encoded,
2791 imm19: i19,
2792 decoded24: u2 = 0b00,
2793 V: bool = true,
2794 decoded27: u3 = 0b011,
2795 opc: VectorSize,
2796 };
2797
2798 /// C7.2.192 LDR (literal, SIMD&FP)
2799 pub const Ldr = packed struct {
2800 Rt: Register.Encoded,
2801 imm19: i19,
2802 decoded24: u2 = 0b00,
2803 V: bool = true,
2804 decoded27: u3 = 0b011,
2805 opc: VectorSize,
2806 };
2807 };
2808
2809 pub const Decoded = union(enum) {
2810 integer: Integer,
2811 vector: Vector,
2812 };
2813 pub fn decode(inst: @This()) @This().Decoded {
2814 return switch (inst.group.V) {
2815 false => .{ .integer = inst.integer },
2816 true => .{ .vector = inst.vector },
2817 };
2818 }
2819 };
2820
2821 /// Memory Copy and Memory Set
2822 pub const Memory = packed struct {
2823 Rd: Register.Encoded,
2824 Rn: Register.Encoded,
2825 decoded10: u2 = 0b01,
2826 op2: u4,
2827 Rs: Register.Encoded,
2828 decoded21: u1 = 0b0,
2829 op1: u2,
2830 decoded24: u2 = 0b01,
2831 o0: u1,
2832 decoded27: u3 = 0b011,
2833 size: IntegerSize,
2834 };
2835
2836 /// Load/store no-allocate pair (offset)
2837 pub const NoAllocatePairOffset = packed struct {
2838 Rt: Register.Encoded,
2839 Rn: Register.Encoded,
2840 Rt2: Register.Encoded,
2841 imm7: i7,
2842 L: L,
2843 decoded23: u3 = 0b000,
2844 V: bool,
2845 decoded27: u3 = 0b101,
2846 opc: u2,
2847 };
2848
2849 /// Load/store register pair (post-indexed)
2850 pub const RegisterPairPostIndexed = packed union {
2851 group: @This().Group,
2852 integer: Integer,
2853 vector: Vector,
2854
2855 pub const Group = packed struct {
2856 Rt: Register.Encoded,
2857 Rn: Register.Encoded,
2858 Rt2: Register.Encoded,
2859 imm7: i7,
2860 L: L,
2861 decoded23: u3 = 0b001,
2862 V: bool,
2863 decoded27: u3 = 0b101,
2864 opc: u2,
2865 };
2866
2867 pub const Integer = packed union {
2868 group: @This().Group,
2869 stp: Stp,
2870 ldp: Ldp,
2871 ldpsw: Ldpsw,
2872
2873 pub const Group = packed struct {
2874 Rt: Register.Encoded,
2875 Rn: Register.Encoded,
2876 Rt2: Register.Encoded,
2877 imm7: i7,
2878 L: L,
2879 decoded23: u3 = 0b001,
2880 V: bool = false,
2881 decoded27: u3 = 0b101,
2882 opc: u2,
2883 };
2884
2885 /// C6.2.321 STP
2886 pub const Stp = packed struct {
2887 Rt: Register.Encoded,
2888 Rn: Register.Encoded,
2889 Rt2: Register.Encoded,
2890 imm7: i7,
2891 L: L = .store,
2892 decoded23: u3 = 0b001,
2893 V: bool = false,
2894 decoded27: u3 = 0b101,
2895 opc0: u1 = 0b0,
2896 sf: Register.IntegerSize,
2897 };
2898
2899 /// C6.2.164 LDP
2900 pub const Ldp = packed struct {
2901 Rt: Register.Encoded,
2902 Rn: Register.Encoded,
2903 Rt2: Register.Encoded,
2904 imm7: i7,
2905 L: L = .load,
2906 decoded23: u3 = 0b001,
2907 V: bool = false,
2908 decoded27: u3 = 0b101,
2909 opc0: u1 = 0b0,
2910 sf: Register.IntegerSize,
2911 };
2912
2913 /// C6.2.165 LDPSW
2914 pub const Ldpsw = packed struct {
2915 Rt: Register.Encoded,
2916 Rn: Register.Encoded,
2917 Rt2: Register.Encoded,
2918 imm7: i7,
2919 L: L = .load,
2920 decoded23: u3 = 0b001,
2921 V: bool = false,
2922 decoded27: u3 = 0b101,
2923 opc: u2 = 0b01,
2924 };
2925
2926 pub const Decoded = union(enum) {
2927 unallocated,
2928 stp: Stp,
2929 ldp: Ldp,
2930 ldpsw: Ldpsw,
2931 };
2932 pub fn decode(inst: @This()) @This().Decoded {
2933 return switch (inst.group.opc) {
2934 0b00, 0b10 => switch (inst.group.L) {
2935 .store => .{ .stp = inst.stp },
2936 .load => .{ .ldp = inst.ldp },
2937 },
2938 0b01 => switch (inst.group.L) {
2939 else => .unallocated,
2940 .load => .{ .ldpsw = inst.ldpsw },
2941 },
2942 else => .unallocated,
2943 };
2944 }
2945 };
2946
2947 pub const Vector = packed union {
2948 group: @This().Group,
2949 stp: Stp,
2950 ldp: Ldp,
2951
2952 pub const Group = packed struct {
2953 Rt: Register.Encoded,
2954 Rn: Register.Encoded,
2955 Rt2: Register.Encoded,
2956 imm7: i7,
2957 L: L,
2958 decoded23: u3 = 0b001,
2959 V: bool = true,
2960 decoded27: u3 = 0b101,
2961 opc: VectorSize,
2962 };
2963
2964 /// C7.2.330 STP (SIMD&FP)
2965 pub const Stp = packed struct {
2966 Rt: Register.Encoded,
2967 Rn: Register.Encoded,
2968 Rt2: Register.Encoded,
2969 imm7: i7,
2970 L: L = .store,
2971 decoded23: u3 = 0b001,
2972 V: bool = true,
2973 decoded27: u3 = 0b101,
2974 opc: VectorSize,
2975 };
2976
2977 /// C7.2.190 LDP (SIMD&FP)
2978 pub const Ldp = packed struct {
2979 Rt: Register.Encoded,
2980 Rn: Register.Encoded,
2981 Rt2: Register.Encoded,
2982 imm7: i7,
2983 L: L = .load,
2984 decoded23: u3 = 0b001,
2985 V: bool = true,
2986 decoded27: u3 = 0b101,
2987 opc: VectorSize,
2988 };
2989
2990 pub const Decoded = union(enum) {
2991 unallocated,
2992 stp: Stp,
2993 ldp: Ldp,
2994 };
2995 pub fn decode(inst: @This()) @This().Decoded {
2996 return switch (inst.group.opc) {
2997 .single, .double, .quad => switch (inst.group.L) {
2998 .store => .{ .stp = inst.stp },
2999 .load => .{ .ldp = inst.ldp },
3000 },
3001 _ => .unallocated,
3002 };
3003 }
3004 };
3005
3006 pub const Decoded = union(enum) {
3007 integer: Integer,
3008 vector: Vector,
3009 };
3010 pub fn decode(inst: @This()) @This().Decoded {
3011 return switch (inst.group.V) {
3012 false => .{ .integer = inst.integer },
3013 true => .{ .vector = inst.vector },
3014 };
3015 }
3016 };
3017
3018 /// Load/store register pair (offset)
3019 pub const RegisterPairOffset = packed union {
3020 group: @This().Group,
3021 integer: Integer,
3022 vector: Vector,
3023
3024 pub const Group = packed struct {
3025 Rt: Register.Encoded,
3026 Rn: Register.Encoded,
3027 Rt2: Register.Encoded,
3028 imm7: i7,
3029 L: L,
3030 decoded23: u3 = 0b010,
3031 V: bool,
3032 decoded27: u3 = 0b101,
3033 opc: u2,
3034 };
3035
3036 pub const Integer = packed union {
3037 group: @This().Group,
3038 stp: Stp,
3039 ldp: Ldp,
3040 ldpsw: Ldpsw,
3041
3042 pub const Group = packed struct {
3043 Rt: Register.Encoded,
3044 Rn: Register.Encoded,
3045 Rt2: Register.Encoded,
3046 imm7: i7,
3047 L: L,
3048 decoded23: u3 = 0b010,
3049 V: bool = false,
3050 decoded27: u3 = 0b101,
3051 opc: u2,
3052 };
3053
3054 /// C6.2.321 STP
3055 pub const Stp = packed struct {
3056 Rt: Register.Encoded,
3057 Rn: Register.Encoded,
3058 Rt2: Register.Encoded,
3059 imm7: i7,
3060 L: L = .store,
3061 decoded23: u3 = 0b010,
3062 V: bool = false,
3063 decoded27: u3 = 0b101,
3064 opc0: u1 = 0b0,
3065 sf: Register.IntegerSize,
3066 };
3067
3068 /// C6.2.164 LDP
3069 pub const Ldp = packed struct {
3070 Rt: Register.Encoded,
3071 Rn: Register.Encoded,
3072 Rt2: Register.Encoded,
3073 imm7: i7,
3074 L: L = .load,
3075 decoded23: u3 = 0b010,
3076 V: bool = false,
3077 decoded27: u3 = 0b101,
3078 opc0: u1 = 0b0,
3079 sf: Register.IntegerSize,
3080 };
3081
3082 /// C6.2.165 LDPSW
3083 pub const Ldpsw = packed struct {
3084 Rt: Register.Encoded,
3085 Rn: Register.Encoded,
3086 Rt2: Register.Encoded,
3087 imm7: i7,
3088 L: L = .load,
3089 decoded23: u3 = 0b010,
3090 V: bool = false,
3091 decoded27: u3 = 0b101,
3092 opc: u2 = 0b01,
3093 };
3094
3095 pub const Decoded = union(enum) {
3096 unallocated,
3097 stp: Stp,
3098 ldp: Ldp,
3099 ldpsw: Ldpsw,
3100 };
3101 pub fn decode(inst: @This()) @This().Decoded {
3102 return switch (inst.group.opc) {
3103 0b00, 0b10 => switch (inst.group.L) {
3104 .store => .{ .stp = inst.stp },
3105 .load => .{ .ldp = inst.ldp },
3106 },
3107 0b01 => switch (inst.group.L) {
3108 else => .unallocated,
3109 .load => .{ .ldpsw = inst.ldpsw },
3110 },
3111 else => .unallocated,
3112 };
3113 }
3114 };
3115
3116 pub const Vector = packed union {
3117 group: @This().Group,
3118 stp: Stp,
3119 ldp: Ldp,
3120
3121 pub const Group = packed struct {
3122 Rt: Register.Encoded,
3123 Rn: Register.Encoded,
3124 Rt2: Register.Encoded,
3125 imm7: i7,
3126 L: L,
3127 decoded23: u3 = 0b010,
3128 V: bool = true,
3129 decoded27: u3 = 0b101,
3130 opc: VectorSize,
3131 };
3132
3133 /// C7.2.330 STP (SIMD&FP)
3134 pub const Stp = packed struct {
3135 Rt: Register.Encoded,
3136 Rn: Register.Encoded,
3137 Rt2: Register.Encoded,
3138 imm7: i7,
3139 L: L = .store,
3140 decoded23: u3 = 0b010,
3141 V: bool = true,
3142 decoded27: u3 = 0b101,
3143 opc: VectorSize,
3144 };
3145
3146 /// C7.2.190 LDP (SIMD&FP)
3147 pub const Ldp = packed struct {
3148 Rt: Register.Encoded,
3149 Rn: Register.Encoded,
3150 Rt2: Register.Encoded,
3151 imm7: i7,
3152 L: L = .load,
3153 decoded23: u3 = 0b010,
3154 V: bool = true,
3155 decoded27: u3 = 0b101,
3156 opc: VectorSize,
3157 };
3158
3159 pub const Decoded = union(enum) {
3160 unallocated,
3161 stp: Stp,
3162 ldp: Ldp,
3163 };
3164 pub fn decode(inst: @This()) @This().Decoded {
3165 return switch (inst.group.opc) {
3166 .single, .double, .quad => switch (inst.group.L) {
3167 .store => .{ .stp = inst.stp },
3168 .load => .{ .ldp = inst.ldp },
3169 },
3170 _ => .unallocated,
3171 };
3172 }
3173 };
3174
3175 pub const Decoded = union(enum) {
3176 integer: Integer,
3177 vector: Vector,
3178 };
3179 pub fn decode(inst: @This()) @This().Decoded {
3180 return switch (inst.group.V) {
3181 false => .{ .integer = inst.integer },
3182 true => .{ .vector = inst.vector },
3183 };
3184 }
3185 };
3186
3187 /// Load/store register pair (pre-indexed)
3188 pub const RegisterPairPreIndexed = packed union {
3189 group: @This().Group,
3190 integer: Integer,
3191 vector: Vector,
3192
3193 pub const Group = packed struct {
3194 Rt: Register.Encoded,
3195 Rn: Register.Encoded,
3196 Rt2: Register.Encoded,
3197 imm7: i7,
3198 L: L,
3199 decoded23: u3 = 0b011,
3200 V: bool,
3201 decoded27: u3 = 0b101,
3202 opc: u2,
3203 };
3204
3205 pub const Integer = packed union {
3206 group: @This().Group,
3207 stp: Stp,
3208 ldp: Ldp,
3209 ldpsw: Ldpsw,
3210
3211 pub const Group = packed struct {
3212 Rt: Register.Encoded,
3213 Rn: Register.Encoded,
3214 Rt2: Register.Encoded,
3215 imm7: i7,
3216 L: L,
3217 decoded23: u3 = 0b011,
3218 V: bool = false,
3219 decoded27: u3 = 0b101,
3220 opc: u2,
3221 };
3222
3223 /// C6.2.321 STP
3224 pub const Stp = packed struct {
3225 Rt: Register.Encoded,
3226 Rn: Register.Encoded,
3227 Rt2: Register.Encoded,
3228 imm7: i7,
3229 L: L = .store,
3230 decoded23: u3 = 0b011,
3231 V: bool = false,
3232 decoded27: u3 = 0b101,
3233 opc0: u1 = 0b0,
3234 sf: Register.IntegerSize,
3235 };
3236
3237 /// C6.2.164 LDP
3238 pub const Ldp = packed struct {
3239 Rt: Register.Encoded,
3240 Rn: Register.Encoded,
3241 Rt2: Register.Encoded,
3242 imm7: i7,
3243 L: L = .load,
3244 decoded23: u3 = 0b011,
3245 V: bool = false,
3246 decoded27: u3 = 0b101,
3247 opc0: u1 = 0b0,
3248 sf: Register.IntegerSize,
3249 };
3250
3251 /// C6.2.165 LDPSW
3252 pub const Ldpsw = packed struct {
3253 Rt: Register.Encoded,
3254 Rn: Register.Encoded,
3255 Rt2: Register.Encoded,
3256 imm7: i7,
3257 L: L = .load,
3258 decoded23: u3 = 0b011,
3259 V: bool = false,
3260 decoded27: u3 = 0b101,
3261 opc0: u2 = 0b01,
3262 };
3263
3264 pub const Decoded = union(enum) {
3265 unallocated,
3266 stp: Stp,
3267 ldp: Ldp,
3268 ldpsw: Ldpsw,
3269 };
3270 pub fn decode(inst: @This()) @This().Decoded {
3271 return switch (inst.group.opc) {
3272 0b00, 0b10 => switch (inst.group.L) {
3273 .store => .{ .stp = inst.stp },
3274 .load => .{ .ldp = inst.ldp },
3275 },
3276 0b01 => switch (inst.group.L) {
3277 else => .unallocated,
3278 .load => .{ .ldpsw = inst.ldpsw },
3279 },
3280 else => .unallocated,
3281 };
3282 }
3283 };
3284
3285 pub const Vector = packed union {
3286 group: @This().Group,
3287 stp: Stp,
3288 ldp: Ldp,
3289
3290 pub const Group = packed struct {
3291 Rt: Register.Encoded,
3292 Rn: Register.Encoded,
3293 Rt2: Register.Encoded,
3294 imm7: i7,
3295 L: L,
3296 decoded23: u3 = 0b011,
3297 V: bool = true,
3298 decoded27: u3 = 0b101,
3299 opc: VectorSize,
3300 };
3301
3302 /// C7.2.330 STP (SIMD&FP)
3303 pub const Stp = packed struct {
3304 Rt: Register.Encoded,
3305 Rn: Register.Encoded,
3306 Rt2: Register.Encoded,
3307 imm7: i7,
3308 L: L = .store,
3309 decoded23: u3 = 0b011,
3310 V: bool = true,
3311 decoded27: u3 = 0b101,
3312 opc: VectorSize,
3313 };
3314
3315 /// C7.2.190 LDP (SIMD&FP)
3316 pub const Ldp = packed struct {
3317 Rt: Register.Encoded,
3318 Rn: Register.Encoded,
3319 Rt2: Register.Encoded,
3320 imm7: i7,
3321 L: L = .load,
3322 decoded23: u3 = 0b011,
3323 V: bool = true,
3324 decoded27: u3 = 0b101,
3325 opc: VectorSize,
3326 };
3327
3328 pub const Decoded = union(enum) {
3329 unallocated,
3330 stp: Stp,
3331 ldp: Ldp,
3332 };
3333 pub fn decode(inst: @This()) @This().Decoded {
3334 return switch (inst.group.opc) {
3335 .single, .double, .quad => switch (inst.group.L) {
3336 .store => .{ .stp = inst.stp },
3337 .load => .{ .ldp = inst.ldp },
3338 },
3339 _ => .unallocated,
3340 };
3341 }
3342 };
3343
3344 pub const Decoded = union(enum) {
3345 integer: Integer,
3346 vector: Vector,
3347 };
3348 pub fn decode(inst: @This()) @This().Decoded {
3349 return switch (inst.group.V) {
3350 false => .{ .integer = inst.integer },
3351 true => .{ .vector = inst.vector },
3352 };
3353 }
3354 };
3355
3356 /// Load/store register (unscaled immediate)
3357 pub const RegisterUnscaledImmediate = packed union {
3358 group: @This().Group,
3359 integer: Integer,
3360 vector: Vector,
3361
3362 pub const Group = packed struct {
3363 Rt: Register.Encoded,
3364 Rn: Register.Encoded,
3365 decoded10: u2 = 0b00,
3366 imm9: i9,
3367 decoded21: u1 = 0b0,
3368 opc: u2,
3369 decoded24: u2 = 0b00,
3370 V: bool,
3371 decoded27: u3 = 0b111,
3372 size: u2,
3373 };
3374
3375 pub const Integer = packed union {
3376 group: @This().Group,
3377 sturb: Sturb,
3378 ldurb: Ldurb,
3379 ldursb: Ldursb,
3380 sturh: Sturh,
3381 ldurh: Ldurh,
3382 ldursh: Ldursh,
3383 stur: Stur,
3384 ldur: Ldur,
3385 ldursw: Ldursw,
3386 prfum: Prfum,
3387
3388 pub const Group = packed struct {
3389 Rt: Register.Encoded,
3390 Rn: Register.Encoded,
3391 decoded10: u2 = 0b00,
3392 imm9: i9,
3393 decoded21: u1 = 0b0,
3394 opc: u2,
3395 decoded24: u2 = 0b00,
3396 V: bool = false,
3397 decoded27: u3 = 0b111,
3398 size: IntegerSize,
3399 };
3400
3401 /// C6.2.347 STURB
3402 pub const Sturb = packed struct {
3403 Rt: Register.Encoded,
3404 Rn: Register.Encoded,
3405 decoded10: u2 = 0b00,
3406 imm9: i9,
3407 decoded21: u1 = 0b0,
3408 opc: u2 = 0b00,
3409 decoded24: u2 = 0b00,
3410 V: bool = false,
3411 decoded27: u3 = 0b111,
3412 size: IntegerSize = .byte,
3413 };
3414
3415 /// C6.2.203 LDURB
3416 pub const Ldurb = packed struct {
3417 Rt: Register.Encoded,
3418 Rn: Register.Encoded,
3419 decoded10: u2 = 0b00,
3420 imm9: i9,
3421 decoded21: u1 = 0b0,
3422 opc: u2 = 0b01,
3423 decoded24: u2 = 0b00,
3424 V: bool = false,
3425 decoded27: u3 = 0b111,
3426 size: IntegerSize = .byte,
3427 };
3428
3429 /// C6.2.205 LDURSB
3430 pub const Ldursb = packed struct {
3431 Rt: Register.Encoded,
3432 Rn: Register.Encoded,
3433 decoded10: u2 = 0b00,
3434 imm9: i9,
3435 decoded21: u1 = 0b0,
3436 opc0: u1,
3437 opc1: u1 = 0b1,
3438 decoded24: u2 = 0b00,
3439 V: bool = false,
3440 decoded27: u3 = 0b111,
3441 size: IntegerSize = .byte,
3442 };
3443
3444 /// C6.2.348 STURH
3445 pub const Sturh = packed struct {
3446 Rt: Register.Encoded,
3447 Rn: Register.Encoded,
3448 decoded10: u2 = 0b00,
3449 imm9: i9,
3450 decoded21: u1 = 0b0,
3451 opc: u2 = 0b00,
3452 decoded24: u2 = 0b00,
3453 V: bool = false,
3454 decoded27: u3 = 0b111,
3455 size: IntegerSize = .halfword,
3456 };
3457
3458 /// C6.2.204 LDURH
3459 pub const Ldurh = packed struct {
3460 Rt: Register.Encoded,
3461 Rn: Register.Encoded,
3462 decoded10: u2 = 0b00,
3463 imm9: i9,
3464 decoded21: u1 = 0b0,
3465 opc: u2 = 0b01,
3466 decoded24: u2 = 0b00,
3467 V: bool = false,
3468 decoded27: u3 = 0b111,
3469 size: IntegerSize = .halfword,
3470 };
3471
3472 /// C6.2.206 LDURSH
3473 pub const Ldursh = packed struct {
3474 Rt: Register.Encoded,
3475 Rn: Register.Encoded,
3476 decoded10: u2 = 0b00,
3477 imm9: i9,
3478 decoded21: u1 = 0b0,
3479 opc0: u1,
3480 opc1: u1 = 0b1,
3481 decoded24: u2 = 0b00,
3482 V: bool = false,
3483 decoded27: u3 = 0b111,
3484 size: IntegerSize = .halfword,
3485 };
3486
3487 /// C6.2.346 STUR
3488 pub const Stur = packed struct {
3489 Rt: Register.Encoded,
3490 Rn: Register.Encoded,
3491 decoded10: u2 = 0b00,
3492 imm9: i9,
3493 decoded21: u1 = 0b0,
3494 opc: u2 = 0b00,
3495 decoded24: u2 = 0b00,
3496 V: bool = false,
3497 decoded27: u3 = 0b111,
3498 sf: Register.IntegerSize,
3499 size1: u1 = 0b1,
3500 };
3501
3502 /// C6.2.202 LDUR
3503 pub const Ldur = packed struct {
3504 Rt: Register.Encoded,
3505 Rn: Register.Encoded,
3506 decoded10: u2 = 0b00,
3507 imm9: i9,
3508 decoded21: u1 = 0b0,
3509 opc: u2 = 0b01,
3510 decoded24: u2 = 0b00,
3511 V: bool = false,
3512 decoded27: u3 = 0b111,
3513 sf: Register.IntegerSize,
3514 size1: u1 = 0b1,
3515 };
3516
3517 /// C6.2.207 LDURSW
3518 pub const Ldursw = packed struct {
3519 Rt: Register.Encoded,
3520 Rn: Register.Encoded,
3521 decoded10: u2 = 0b00,
3522 imm9: i9,
3523 decoded21: u1 = 0b0,
3524 opc: u2 = 0b10,
3525 decoded24: u2 = 0b00,
3526 V: bool = false,
3527 decoded27: u3 = 0b111,
3528 size: IntegerSize = .word,
3529 };
3530
3531 /// C6.2.250 PRFUM
3532 pub const Prfum = packed struct {
3533 prfop: PrfOp,
3534 Rn: Register.Encoded,
3535 decoded10: u2 = 0b00,
3536 imm9: i9,
3537 decoded21: u1 = 0b0,
3538 opc: u2 = 0b10,
3539 decoded24: u2 = 0b00,
3540 V: bool = false,
3541 decoded27: u3 = 0b111,
3542 size: IntegerSize = .doubleword,
3543 };
3544
3545 pub const Decoded = union(enum) {
3546 unallocated,
3547 sturb: Sturb,
3548 ldurb: Ldurb,
3549 ldursb: Ldursb,
3550 sturh: Sturh,
3551 ldurh: Ldurh,
3552 ldursh: Ldursh,
3553 stur: Stur,
3554 ldur: Ldur,
3555 ldursw: Ldursw,
3556 prfum: Prfum,
3557 };
3558 pub fn decode(inst: @This()) @This().Decoded {
3559 return switch (inst.group.size) {
3560 .byte => switch (inst.group.V) {
3561 false => switch (inst.group.opc) {
3562 0b00 => .{ .sturb = inst.sturb },
3563 0b01 => .{ .ldurb = inst.ldurb },
3564 0b10, 0b11 => .{ .ldursb = inst.ldursb },
3565 },
3566 true => .unallocated,
3567 },
3568 .halfword => switch (inst.group.V) {
3569 false => switch (inst.group.opc) {
3570 0b00 => .{ .sturh = inst.sturh },
3571 0b01 => .{ .ldurh = inst.ldurh },
3572 0b10, 0b11 => .{ .ldursh = inst.ldursh },
3573 },
3574 true => .unallocated,
3575 },
3576 .word => switch (inst.group.V) {
3577 false => switch (inst.group.opc) {
3578 0b00 => .{ .stur = inst.stur },
3579 0b01 => .{ .ldur = inst.ldur },
3580 0b10 => .{ .ldursw = inst.ldursw },
3581 0b11 => .unallocated,
3582 },
3583 true => .unallocated,
3584 },
3585 .doubleword => switch (inst.group.V) {
3586 false => switch (inst.group.opc) {
3587 0b00 => .{ .stur = inst.stur },
3588 0b01 => .{ .ldur = inst.ldur },
3589 0b10 => .{ .prfum = inst.prfum },
3590 0b11 => .unallocated,
3591 },
3592 true => .unallocated,
3593 },
3594 };
3595 }
3596 };
3597
3598 pub const Vector = packed union {
3599 group: @This().Group,
3600 stur: Stur,
3601 ldur: Ldur,
3602
3603 pub const Group = packed struct {
3604 Rt: Register.Encoded,
3605 Rn: Register.Encoded,
3606 decoded10: u2 = 0b00,
3607 imm9: i9,
3608 decoded21: u1 = 0b0,
3609 opc0: L,
3610 opc1: Opc1,
3611 decoded24: u2 = 0b00,
3612 V: bool = true,
3613 decoded27: u3 = 0b111,
3614 size: Size,
3615 };
3616
3617 /// C7.2.333 STUR (SIMD&FP)
3618 pub const Stur = packed struct {
3619 Rt: Register.Encoded,
3620 Rn: Register.Encoded,
3621 decoded10: u2 = 0b00,
3622 imm9: i9,
3623 decoded21: u1 = 0b0,
3624 opc0: L = .store,
3625 opc1: Opc1,
3626 decoded24: u2 = 0b00,
3627 V: bool = true,
3628 decoded27: u3 = 0b111,
3629 size: Size,
3630 };
3631
3632 /// C7.2.194 LDUR (SIMD&FP)
3633 pub const Ldur = packed struct {
3634 Rt: Register.Encoded,
3635 Rn: Register.Encoded,
3636 decoded10: u2 = 0b00,
3637 imm9: i9,
3638 decoded21: u1 = 0b0,
3639 opc0: L = .load,
3640 opc1: Opc1,
3641 decoded24: u2 = 0b00,
3642 V: bool = true,
3643 decoded27: u3 = 0b111,
3644 size: Size,
3645 };
3646
3647 pub const Opc1 = packed struct {
3648 encoded: u1,
3649
3650 pub fn encode(vs: Register.VectorSize) Opc1 {
3651 return .{ .encoded = switch (vs) {
3652 .byte, .half, .single, .double => 0b0,
3653 .quad => 0b1,
3654 else => unreachable,
3655 } };
3656 }
3657
3658 pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize {
3659 return switch (enc_size.encoded) {
3660 0b00 => switch (enc_opc1.encoded) {
3661 0b0 => .byte,
3662 0b1 => .quad,
3663 },
3664 0b01 => switch (enc_opc1.encoded) {
3665 0b0 => .half,
3666 0b1 => unreachable,
3667 },
3668 0b10 => switch (enc_opc1.encoded) {
3669 0b0 => .single,
3670 0b1 => unreachable,
3671 },
3672 0b11 => switch (enc_opc1.encoded) {
3673 0b0 => .double,
3674 0b1 => unreachable,
3675 },
3676 };
3677 }
3678 };
3679
3680 pub const Size = packed struct {
3681 encoded: u2,
3682
3683 pub fn encode(vs: Register.VectorSize) Size {
3684 return .{ .encoded = switch (vs) {
3685 .byte, .quad => 0b00,
3686 .half => 0b01,
3687 .single => 0b10,
3688 .double => 0b11,
3689 else => unreachable,
3690 } };
3691 }
3692 };
3693
3694 pub const Decoded = union(enum) {
3695 unallocated,
3696 stur: Stur,
3697 ldur: Ldur,
3698 };
3699 pub fn decode(inst: @This()) @This().Decoded {
3700 return switch (inst.group.size.encoded) {
3701 0b00 => switch (inst.group.opc0) {
3702 .store => .{ .stur = inst.stur },
3703 .load => .{ .ldur = inst.ldur },
3704 },
3705 0b01, 0b10, 0b11 => switch (inst.group.opc1.encoded) {
3706 0b0 => switch (inst.group.opc0) {
3707 .store => .{ .stur = inst.stur },
3708 .load => .{ .ldur = inst.ldur },
3709 },
3710 0b1 => .unallocated,
3711 },
3712 };
3713 }
3714 };
3715
3716 pub const Decoded = union(enum) {
3717 integer: Integer,
3718 vector: Vector,
3719 };
3720 pub fn decode(inst: @This()) @This().Decoded {
3721 return switch (inst.group.V) {
3722 false => .{ .integer = inst.integer },
3723 true => .{ .vector = inst.vector },
3724 };
3725 }
3726 };
3727
3728 /// Load/store register (immediate post-indexed)
3729 pub const RegisterImmediatePostIndexed = packed union {
3730 group: @This().Group,
3731 integer: Integer,
3732 vector: Vector,
3733
3734 pub const Group = packed struct {
3735 Rt: Register.Encoded,
3736 Rn: Register.Encoded,
3737 decoded10: u2 = 0b01,
3738 imm9: i9,
3739 decoded21: u1 = 0b0,
3740 opc: u2,
3741 decoded24: u2 = 0b00,
3742 V: bool,
3743 decoded27: u3 = 0b111,
3744 size: u2,
3745 };
3746
3747 pub const Integer = packed union {
3748 group: @This().Group,
3749 strb: Strb,
3750 ldrb: Ldrb,
3751 ldrsb: Ldrsb,
3752 strh: Strh,
3753 ldrh: Ldrh,
3754 ldrsh: Ldrsh,
3755 str: Str,
3756 ldr: Ldr,
3757 ldrsw: Ldrsw,
3758
3759 pub const Group = packed struct {
3760 Rt: Register.Encoded,
3761 Rn: Register.Encoded,
3762 decoded10: u2 = 0b01,
3763 imm9: i9,
3764 decoded21: u1 = 0b0,
3765 opc: u2,
3766 decoded24: u2 = 0b00,
3767 V: bool = false,
3768 decoded27: u3 = 0b111,
3769 size: IntegerSize,
3770 };
3771
3772 /// C6.2.324 STRB (immediate)
3773 pub const Strb = packed struct {
3774 Rt: Register.Encoded,
3775 Rn: Register.Encoded,
3776 decoded10: u2 = 0b01,
3777 imm9: i9,
3778 decoded21: u1 = 0b0,
3779 opc: u2 = 0b00,
3780 decoded24: u2 = 0b00,
3781 V: bool = false,
3782 decoded27: u3 = 0b111,
3783 size: IntegerSize = .byte,
3784 };
3785
3786 /// C6.2.170 LDRB (immediate)
3787 pub const Ldrb = packed struct {
3788 Rt: Register.Encoded,
3789 Rn: Register.Encoded,
3790 decoded10: u2 = 0b01,
3791 imm9: i9,
3792 decoded21: u1 = 0b0,
3793 opc: u2 = 0b01,
3794 decoded24: u2 = 0b00,
3795 V: bool = false,
3796 decoded27: u3 = 0b111,
3797 size: IntegerSize = .byte,
3798 };
3799
3800 /// C6.2.174 LDRSB (immediate)
3801 pub const Ldrsb = packed struct {
3802 Rt: Register.Encoded,
3803 Rn: Register.Encoded,
3804 decoded10: u2 = 0b01,
3805 imm9: i9,
3806 decoded21: u1 = 0b0,
3807 opc0: u1,
3808 opc1: u1 = 0b1,
3809 decoded24: u2 = 0b00,
3810 V: bool = false,
3811 decoded27: u3 = 0b111,
3812 size: IntegerSize = .byte,
3813 };
3814
3815 /// C6.2.326 STRH (immediate)
3816 pub const Strh = packed struct {
3817 Rt: Register.Encoded,
3818 Rn: Register.Encoded,
3819 decoded10: u2 = 0b01,
3820 imm9: i9,
3821 decoded21: u1 = 0b0,
3822 opc: u2 = 0b00,
3823 decoded24: u2 = 0b00,
3824 V: bool = false,
3825 decoded27: u3 = 0b111,
3826 size: IntegerSize = .halfword,
3827 };
3828
3829 /// C6.2.172 LDRH (immediate)
3830 pub const Ldrh = packed struct {
3831 Rt: Register.Encoded,
3832 Rn: Register.Encoded,
3833 decoded10: u2 = 0b01,
3834 imm9: i9,
3835 decoded21: u1 = 0b0,
3836 opc: u2 = 0b01,
3837 decoded24: u2 = 0b00,
3838 V: bool = false,
3839 decoded27: u3 = 0b111,
3840 size: IntegerSize = .halfword,
3841 };
3842
3843 /// C6.2.176 LDRSH (immediate)
3844 pub const Ldrsh = packed struct {
3845 Rt: Register.Encoded,
3846 Rn: Register.Encoded,
3847 decoded10: u2 = 0b01,
3848 imm9: i9,
3849 decoded21: u1 = 0b0,
3850 opc0: u1,
3851 opc1: u1 = 0b1,
3852 decoded24: u2 = 0b00,
3853 V: bool = false,
3854 decoded27: u3 = 0b111,
3855 size: IntegerSize = .halfword,
3856 };
3857
3858 /// C6.2.322 STR (immediate)
3859 pub const Str = packed struct {
3860 Rt: Register.Encoded,
3861 Rn: Register.Encoded,
3862 decoded10: u2 = 0b01,
3863 imm9: i9,
3864 decoded21: u1 = 0b0,
3865 opc: u2 = 0b00,
3866 decoded24: u2 = 0b00,
3867 V: bool = false,
3868 decoded27: u3 = 0b111,
3869 sf: Register.IntegerSize,
3870 size1: u1 = 0b1,
3871 };
3872
3873 /// C6.2.166 LDR (immediate)
3874 pub const Ldr = packed struct {
3875 Rt: Register.Encoded,
3876 Rn: Register.Encoded,
3877 decoded10: u2 = 0b01,
3878 imm9: i9,
3879 decoded21: u1 = 0b0,
3880 opc: u2 = 0b01,
3881 decoded24: u2 = 0b00,
3882 V: bool = false,
3883 decoded27: u3 = 0b111,
3884 sf: Register.IntegerSize,
3885 size1: u1 = 0b1,
3886 };
3887
3888 /// C6.2.178 LDRSW (immediate)
3889 pub const Ldrsw = packed struct {
3890 Rt: Register.Encoded,
3891 Rn: Register.Encoded,
3892 decoded10: u2 = 0b01,
3893 imm9: i9,
3894 decoded21: u1 = 0b0,
3895 opc: u2 = 0b10,
3896 decoded24: u2 = 0b00,
3897 V: bool = false,
3898 decoded27: u3 = 0b111,
3899 size: IntegerSize = .word,
3900 };
3901
3902 pub const Decoded = union(enum) {
3903 unallocated,
3904 strb: Strb,
3905 ldrb: Ldrb,
3906 ldrsb: Ldrsb,
3907 strh: Strh,
3908 ldrh: Ldrh,
3909 ldrsh: Ldrsh,
3910 str: Str,
3911 ldr: Ldr,
3912 ldrsw: Ldrsw,
3913 };
3914 pub fn decode(inst: @This()) @This().Decoded {
3915 return switch (inst.group.size) {
3916 .byte => switch (inst.group.V) {
3917 false => switch (inst.group.opc) {
3918 0b00 => .{ .strb = inst.strb },
3919 0b01 => .{ .ldrb = inst.ldrb },
3920 0b10, 0b11 => .{ .ldrsb = inst.ldrsb },
3921 },
3922 true => .unallocated,
3923 },
3924 .halfword => switch (inst.group.V) {
3925 false => switch (inst.group.opc) {
3926 0b00 => .{ .strh = inst.strh },
3927 0b01 => .{ .ldrh = inst.ldrh },
3928 0b10, 0b11 => .{ .ldrsh = inst.ldrsh },
3929 },
3930 true => .unallocated,
3931 },
3932 .word => switch (inst.group.V) {
3933 false => switch (inst.group.opc) {
3934 0b00 => .{ .str = inst.str },
3935 0b01 => .{ .ldr = inst.ldr },
3936 0b10 => .{ .ldrsw = inst.ldrsw },
3937 0b11 => .unallocated,
3938 },
3939 true => .unallocated,
3940 },
3941 .doubleword => switch (inst.group.V) {
3942 false => switch (inst.group.opc) {
3943 0b00 => .{ .str = inst.str },
3944 0b01 => .{ .ldr = inst.ldr },
3945 0b10, 0b11 => .unallocated,
3946 },
3947 true => .unallocated,
3948 },
3949 };
3950 }
3951 };
3952
3953 pub const Vector = packed union {
3954 group: @This().Group,
3955 str: Str,
3956 ldr: Ldr,
3957
3958 pub const Group = packed struct {
3959 Rt: Register.Encoded,
3960 Rn: Register.Encoded,
3961 decoded10: u2 = 0b01,
3962 imm9: i9,
3963 decoded21: u1 = 0b0,
3964 opc0: L,
3965 opc1: Opc1,
3966 decoded24: u2 = 0b00,
3967 V: bool = true,
3968 decoded27: u3 = 0b111,
3969 size: Size,
3970 };
3971
3972 /// C7.2.331 STR (immediate, SIMD&FP)
3973 pub const Str = packed struct {
3974 Rt: Register.Encoded,
3975 Rn: Register.Encoded,
3976 decoded10: u2 = 0b01,
3977 imm9: i9,
3978 decoded21: u1 = 0b0,
3979 opc0: L = .store,
3980 opc1: Opc1,
3981 decoded24: u2 = 0b00,
3982 V: bool = true,
3983 decoded27: u3 = 0b111,
3984 size: Size,
3985 };
3986
3987 /// C7.2.191 LDR (immediate, SIMD&FP)
3988 pub const Ldr = packed struct {
3989 Rt: Register.Encoded,
3990 Rn: Register.Encoded,
3991 decoded10: u2 = 0b01,
3992 imm9: i9,
3993 decoded21: u1 = 0b0,
3994 opc0: L = .load,
3995 opc1: Opc1,
3996 decoded24: u2 = 0b00,
3997 V: bool = true,
3998 decoded27: u3 = 0b111,
3999 size: Size,
4000 };
4001
4002 pub const Opc1 = packed struct {
4003 encoded: u1,
4004
4005 pub fn encode(vs: Register.VectorSize) Opc1 {
4006 return .{ .encoded = switch (vs) {
4007 .byte, .half, .single, .double => 0b0,
4008 .quad => 0b1,
4009 else => unreachable,
4010 } };
4011 }
4012
4013 pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize {
4014 return switch (enc_size.encoded) {
4015 0b00 => switch (enc_opc1.encoded) {
4016 0b0 => .byte,
4017 0b1 => .quad,
4018 },
4019 0b01 => switch (enc_opc1.encoded) {
4020 0b0 => .half,
4021 0b1 => unreachable,
4022 },
4023 0b10 => switch (enc_opc1.encoded) {
4024 0b0 => .single,
4025 0b1 => unreachable,
4026 },
4027 0b11 => switch (enc_opc1.encoded) {
4028 0b0 => .double,
4029 0b1 => unreachable,
4030 },
4031 };
4032 }
4033 };
4034
4035 pub const Size = packed struct {
4036 encoded: u2,
4037
4038 pub fn encode(vs: Register.VectorSize) Size {
4039 return .{ .encoded = switch (vs) {
4040 .byte, .quad => 0b00,
4041 .half => 0b01,
4042 .single => 0b10,
4043 .double => 0b11,
4044 else => unreachable,
4045 } };
4046 }
4047 };
4048
4049 pub const Decoded = union(enum) {
4050 unallocated,
4051 str: Str,
4052 ldr: Ldr,
4053 };
4054 pub fn decode(inst: @This()) @This().Decoded {
4055 return switch (inst.group.size.encoded) {
4056 0b00 => switch (inst.group.opc0) {
4057 .store => .{ .str = inst.str },
4058 .load => .{ .ldr = inst.ldr },
4059 },
4060 0b01, 0b10, 0b11 => switch (inst.group.opc1.encoded) {
4061 0b0 => switch (inst.group.opc0) {
4062 .store => .{ .str = inst.str },
4063 .load => .{ .ldr = inst.ldr },
4064 },
4065 0b1 => .unallocated,
4066 },
4067 };
4068 }
4069 };
4070
4071 pub const Decoded = union(enum) {
4072 integer: Integer,
4073 vector: Vector,
4074 };
4075 pub fn decode(inst: @This()) @This().Decoded {
4076 return switch (inst.group.V) {
4077 false => .{ .integer = inst.integer },
4078 true => .{ .vector = inst.vector },
4079 };
4080 }
4081 };
4082
4083 /// Load/store register (unprivileged)
4084 pub const RegisterUnprivileged = packed struct {
4085 Rt: Register.Encoded,
4086 Rn: Register.Encoded,
4087 decoded10: u2 = 0b10,
4088 imm9: i9,
4089 decoded21: u1 = 0b0,
4090 opc: u2,
4091 decoded24: u2 = 0b00,
4092 V: bool,
4093 decoded27: u3 = 0b111,
4094 size: IntegerSize,
4095 };
4096
4097 /// Load/store register (immediate pre-indexed)
4098 pub const RegisterImmediatePreIndexed = packed union {
4099 group: @This().Group,
4100 integer: Integer,
4101 vector: Vector,
4102
4103 pub const Group = packed struct {
4104 Rt: Register.Encoded,
4105 Rn: Register.Encoded,
4106 decoded10: u2 = 0b11,
4107 imm9: i9,
4108 decoded21: u1 = 0b0,
4109 opc: u2,
4110 decoded24: u2 = 0b00,
4111 V: bool,
4112 decoded27: u3 = 0b111,
4113 size: u2,
4114 };
4115
4116 pub const Integer = packed union {
4117 group: @This().Group,
4118 strb: Strb,
4119 ldrb: Ldrb,
4120 ldrsb: Ldrsb,
4121 strh: Strh,
4122 ldrh: Ldrh,
4123 ldrsh: Ldrsh,
4124 str: Str,
4125 ldr: Ldr,
4126 ldrsw: Ldrsw,
4127
4128 pub const Group = packed struct {
4129 Rt: Register.Encoded,
4130 Rn: Register.Encoded,
4131 decoded10: u2 = 0b11,
4132 imm9: i9,
4133 decoded21: u1 = 0b0,
4134 opc: u2,
4135 decoded24: u2 = 0b00,
4136 V: bool = false,
4137 decoded27: u3 = 0b111,
4138 size: IntegerSize,
4139 };
4140
4141 /// C6.2.324 STRB (immediate)
4142 pub const Strb = packed struct {
4143 Rt: Register.Encoded,
4144 Rn: Register.Encoded,
4145 decoded10: u2 = 0b11,
4146 imm9: i9,
4147 decoded21: u1 = 0b0,
4148 opc: u2 = 0b00,
4149 decoded24: u2 = 0b00,
4150 V: bool = false,
4151 decoded27: u3 = 0b111,
4152 size: IntegerSize = .byte,
4153 };
4154
4155 /// C6.2.170 LDRB (immediate)
4156 pub const Ldrb = packed struct {
4157 Rt: Register.Encoded,
4158 Rn: Register.Encoded,
4159 decoded10: u2 = 0b11,
4160 imm9: i9,
4161 decoded21: u1 = 0b0,
4162 opc: u2 = 0b01,
4163 decoded24: u2 = 0b00,
4164 V: bool = false,
4165 decoded27: u3 = 0b111,
4166 size: IntegerSize = .byte,
4167 };
4168
4169 /// C6.2.174 LDRSB (immediate)
4170 pub const Ldrsb = packed struct {
4171 Rt: Register.Encoded,
4172 Rn: Register.Encoded,
4173 decoded10: u2 = 0b11,
4174 imm9: i9,
4175 decoded21: u1 = 0b0,
4176 opc0: u1,
4177 opc1: u1 = 0b1,
4178 decoded24: u2 = 0b00,
4179 V: bool = false,
4180 decoded27: u3 = 0b111,
4181 size: IntegerSize = .byte,
4182 };
4183
4184 /// C6.2.326 STRH (immediate)
4185 pub const Strh = packed struct {
4186 Rt: Register.Encoded,
4187 Rn: Register.Encoded,
4188 decoded10: u2 = 0b11,
4189 imm9: i9,
4190 decoded21: u1 = 0b0,
4191 opc: u2 = 0b00,
4192 decoded24: u2 = 0b00,
4193 V: bool = false,
4194 decoded27: u3 = 0b111,
4195 size: IntegerSize = .halfword,
4196 };
4197
4198 /// C6.2.172 LDRH (immediate)
4199 pub const Ldrh = packed struct {
4200 Rt: Register.Encoded,
4201 Rn: Register.Encoded,
4202 decoded10: u2 = 0b11,
4203 imm9: i9,
4204 decoded21: u1 = 0b0,
4205 opc: u2 = 0b01,
4206 decoded24: u2 = 0b00,
4207 V: bool = false,
4208 decoded27: u3 = 0b111,
4209 size: IntegerSize = .halfword,
4210 };
4211
4212 /// C6.2.176 LDRSH (immediate)
4213 pub const Ldrsh = packed struct {
4214 Rt: Register.Encoded,
4215 Rn: Register.Encoded,
4216 decoded10: u2 = 0b11,
4217 imm9: i9,
4218 decoded21: u1 = 0b0,
4219 opc0: u1,
4220 opc1: u1 = 0b1,
4221 decoded24: u2 = 0b00,
4222 V: bool = false,
4223 decoded27: u3 = 0b111,
4224 size: IntegerSize = .halfword,
4225 };
4226
4227 /// C6.2.322 STR (immediate)
4228 pub const Str = packed struct {
4229 Rt: Register.Encoded,
4230 Rn: Register.Encoded,
4231 decoded10: u2 = 0b11,
4232 imm9: i9,
4233 decoded21: u1 = 0b0,
4234 opc: u2 = 0b00,
4235 decoded24: u2 = 0b00,
4236 V: bool = false,
4237 decoded27: u3 = 0b111,
4238 sf: Register.IntegerSize,
4239 size1: u1 = 0b1,
4240 };
4241
4242 /// C6.2.166 LDR (immediate)
4243 pub const Ldr = packed struct {
4244 Rt: Register.Encoded,
4245 Rn: Register.Encoded,
4246 decoded10: u2 = 0b11,
4247 imm9: i9,
4248 decoded21: u1 = 0b0,
4249 opc: u2 = 0b01,
4250 decoded24: u2 = 0b00,
4251 V: bool = false,
4252 decoded27: u3 = 0b111,
4253 sf: Register.IntegerSize,
4254 size1: u1 = 0b1,
4255 };
4256
4257 /// C6.2.178 LDRSW (immediate)
4258 pub const Ldrsw = packed struct {
4259 Rt: Register.Encoded,
4260 Rn: Register.Encoded,
4261 decoded10: u2 = 0b11,
4262 imm9: i9,
4263 decoded21: u1 = 0b0,
4264 opc: u2 = 0b10,
4265 decoded24: u2 = 0b00,
4266 V: bool = false,
4267 decoded27: u3 = 0b111,
4268 size: IntegerSize = .word,
4269 };
4270
4271 pub const Decoded = union(enum) {
4272 unallocated,
4273 strb: Strb,
4274 ldrb: Ldrb,
4275 ldrsb: Ldrsb,
4276 strh: Strh,
4277 ldrh: Ldrh,
4278 ldrsh: Ldrsh,
4279 str: Str,
4280 ldr: Ldr,
4281 ldrsw: Ldrsw,
4282 };
4283 pub fn decode(inst: @This()) @This().Decoded {
4284 return switch (inst.group.size) {
4285 .byte => switch (inst.group.opc) {
4286 0b00 => .{ .strb = inst.strb },
4287 0b01 => .{ .ldrb = inst.ldrb },
4288 0b10, 0b11 => .{ .ldrsb = inst.ldrsb },
4289 },
4290 .halfword => switch (inst.group.opc) {
4291 0b00 => .{ .strh = inst.strh },
4292 0b01 => .{ .ldrh = inst.ldrh },
4293 0b10, 0b11 => .{ .ldrsh = inst.ldrsh },
4294 },
4295 .word => switch (inst.group.opc) {
4296 0b00 => .{ .str = inst.str },
4297 0b01 => .{ .ldr = inst.ldr },
4298 0b10 => .{ .ldrsw = inst.ldrsw },
4299 0b11 => .unallocated,
4300 },
4301 .doubleword => switch (inst.group.opc) {
4302 0b00 => .{ .str = inst.str },
4303 0b01 => .{ .ldr = inst.ldr },
4304 0b10, 0b11 => .unallocated,
4305 },
4306 };
4307 }
4308 };
4309
4310 pub const Vector = packed union {
4311 group: @This().Group,
4312 str: Str,
4313 ldr: Ldr,
4314
4315 pub const Group = packed struct {
4316 Rt: Register.Encoded,
4317 Rn: Register.Encoded,
4318 decoded10: u2 = 0b11,
4319 imm9: i9,
4320 decoded21: u1 = 0b0,
4321 opc0: L,
4322 opc1: Opc1,
4323 decoded24: u2 = 0b00,
4324 V: bool = true,
4325 decoded27: u3 = 0b111,
4326 size: Size,
4327 };
4328
4329 /// C7.2.331 STR (immediate, SIMD&FP)
4330 pub const Str = packed struct {
4331 Rt: Register.Encoded,
4332 Rn: Register.Encoded,
4333 decoded10: u2 = 0b11,
4334 imm9: i9,
4335 decoded21: u1 = 0b0,
4336 opc0: L = .store,
4337 opc1: Opc1,
4338 decoded24: u2 = 0b00,
4339 V: bool = true,
4340 decoded27: u3 = 0b111,
4341 size: Size,
4342 };
4343
4344 /// C7.2.191 LDR (immediate, SIMD&FP)
4345 pub const Ldr = packed struct {
4346 Rt: Register.Encoded,
4347 Rn: Register.Encoded,
4348 decoded10: u2 = 0b11,
4349 imm9: i9,
4350 decoded21: u1 = 0b0,
4351 opc0: L = .load,
4352 opc1: Opc1,
4353 decoded24: u2 = 0b00,
4354 V: bool = true,
4355 decoded27: u3 = 0b111,
4356 size: Size,
4357 };
4358
4359 pub const Opc1 = packed struct {
4360 encoded: u1,
4361
4362 pub fn encode(vs: Register.VectorSize) Opc1 {
4363 return .{ .encoded = switch (vs) {
4364 .byte, .half, .single, .double => 0b0,
4365 .quad => 0b1,
4366 else => unreachable,
4367 } };
4368 }
4369
4370 pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize {
4371 return switch (enc_size.encoded) {
4372 0b00 => switch (enc_opc1.encoded) {
4373 0b0 => .byte,
4374 0b1 => .quad,
4375 },
4376 0b01 => switch (enc_opc1.encoded) {
4377 0b0 => .half,
4378 0b1 => unreachable,
4379 },
4380 0b10 => switch (enc_opc1.encoded) {
4381 0b0 => .single,
4382 0b1 => unreachable,
4383 },
4384 0b11 => switch (enc_opc1.encoded) {
4385 0b0 => .double,
4386 0b1 => unreachable,
4387 },
4388 };
4389 }
4390 };
4391
4392 pub const Size = packed struct {
4393 encoded: u2,
4394
4395 pub fn encode(vs: Register.VectorSize) Size {
4396 return .{ .encoded = switch (vs) {
4397 .byte, .quad => 0b00,
4398 .half => 0b01,
4399 .single => 0b10,
4400 .double => 0b11,
4401 else => unreachable,
4402 } };
4403 }
4404 };
4405
4406 pub const Decoded = union(enum) {
4407 unallocated,
4408 str: Str,
4409 ldr: Ldr,
4410 };
4411 pub fn decode(inst: @This()) @This().Decoded {
4412 return switch (inst.group.size.encoded) {
4413 0b00 => switch (inst.group.opc0) {
4414 .store => .{ .str = inst.str },
4415 .load => .{ .ldr = inst.ldr },
4416 },
4417 0b01, 0b10, 0b11 => switch (inst.group.opc1.encoded) {
4418 0b0 => switch (inst.group.opc0) {
4419 .store => .{ .str = inst.str },
4420 .load => .{ .ldr = inst.ldr },
4421 },
4422 0b1 => .unallocated,
4423 },
4424 };
4425 }
4426 };
4427
4428 pub const Decoded = union(enum) {
4429 integer: Integer,
4430 vector: Vector,
4431 };
4432 pub fn decode(inst: @This()) @This().Decoded {
4433 return switch (inst.group.V) {
4434 false => .{ .integer = inst.integer },
4435 true => .{ .vector = inst.vector },
4436 };
4437 }
4438 };
4439
4440 /// Load/store register (register offset)
4441 pub const RegisterRegisterOffset = packed union {
4442 group: @This().Group,
4443 integer: Integer,
4444 vector: Vector,
4445
4446 pub const Group = packed struct {
4447 Rt: Register.Encoded,
4448 Rn: Register.Encoded,
4449 decoded10: u2 = 0b10,
4450 S: bool,
4451 option: Option,
4452 Rm: Register.Encoded,
4453 decoded21: u1 = 0b1,
4454 opc: u2,
4455 decoded24: u2 = 0b00,
4456 V: bool,
4457 decoded27: u3 = 0b111,
4458 size: u2,
4459 };
4460
4461 pub const Integer = packed union {
4462 group: @This().Group,
4463 strb: Strb,
4464 ldrb: Ldrb,
4465 ldrsb: Ldrsb,
4466 strh: Strh,
4467 ldrh: Ldrh,
4468 ldrsh: Ldrsh,
4469 str: Str,
4470 ldr: Ldr,
4471 ldrsw: Ldrsw,
4472 prfm: Prfm,
4473
4474 pub const Group = packed struct {
4475 Rt: Register.Encoded,
4476 Rn: Register.Encoded,
4477 decoded10: u2 = 0b10,
4478 S: bool,
4479 option: Option,
4480 Rm: Register.Encoded,
4481 decoded21: u1 = 0b1,
4482 opc: u2,
4483 decoded24: u2 = 0b00,
4484 V: bool = false,
4485 decoded27: u3 = 0b111,
4486 size: IntegerSize,
4487 };
4488
4489 /// C6.2.325 STRB (register)
4490 pub const Strb = packed struct {
4491 Rt: Register.Encoded,
4492 Rn: Register.Encoded,
4493 decoded10: u2 = 0b10,
4494 S: bool,
4495 option: Option,
4496 Rm: Register.Encoded,
4497 decoded21: u1 = 0b1,
4498 opc: u2 = 0b00,
4499 decoded24: u2 = 0b00,
4500 V: bool = false,
4501 decoded27: u3 = 0b111,
4502 size: IntegerSize = .byte,
4503 };
4504
4505 /// C6.2.171 LDRB (register)
4506 pub const Ldrb = packed struct {
4507 Rt: Register.Encoded,
4508 Rn: Register.Encoded,
4509 decoded10: u2 = 0b10,
4510 S: bool,
4511 option: Option,
4512 Rm: Register.Encoded,
4513 decoded21: u1 = 0b1,
4514 opc: u2 = 0b01,
4515 decoded24: u2 = 0b00,
4516 V: bool = false,
4517 decoded27: u3 = 0b111,
4518 size: IntegerSize = .byte,
4519 };
4520
4521 /// C6.2.175 LDRSB (register)
4522 pub const Ldrsb = packed struct {
4523 Rt: Register.Encoded,
4524 Rn: Register.Encoded,
4525 decoded10: u2 = 0b10,
4526 S: bool,
4527 option: Option,
4528 Rm: Register.Encoded,
4529 decoded21: u1 = 0b1,
4530 opc0: u1,
4531 opc1: u1 = 0b1,
4532 decoded24: u2 = 0b00,
4533 V: bool = false,
4534 decoded27: u3 = 0b111,
4535 size: IntegerSize = .byte,
4536 };
4537
4538 /// C6.2.327 STRH (register)
4539 pub const Strh = packed struct {
4540 Rt: Register.Encoded,
4541 Rn: Register.Encoded,
4542 decoded10: u2 = 0b10,
4543 S: bool,
4544 option: Option,
4545 Rm: Register.Encoded,
4546 decoded21: u1 = 0b1,
4547 opc: u2 = 0b00,
4548 decoded24: u2 = 0b00,
4549 V: bool = false,
4550 decoded27: u3 = 0b111,
4551 size: IntegerSize = .halfword,
4552 };
4553
4554 /// C6.2.173 LDRH (register)
4555 pub const Ldrh = packed struct {
4556 Rt: Register.Encoded,
4557 Rn: Register.Encoded,
4558 decoded10: u2 = 0b10,
4559 S: bool,
4560 option: Option,
4561 Rm: Register.Encoded,
4562 decoded21: u1 = 0b1,
4563 opc: u2 = 0b01,
4564 decoded24: u2 = 0b00,
4565 V: bool = false,
4566 decoded27: u3 = 0b111,
4567 size: IntegerSize = .halfword,
4568 };
4569
4570 /// C6.2.177 LDRSH (register)
4571 pub const Ldrsh = packed struct {
4572 Rt: Register.Encoded,
4573 Rn: Register.Encoded,
4574 decoded10: u2 = 0b10,
4575 S: bool,
4576 option: Option,
4577 Rm: Register.Encoded,
4578 decoded21: u1 = 0b1,
4579 opc0: u1,
4580 opc1: u1 = 0b1,
4581 decoded24: u2 = 0b00,
4582 V: bool = false,
4583 decoded27: u3 = 0b111,
4584 size: IntegerSize = .halfword,
4585 };
4586
4587 /// C6.2.323 STR (register)
4588 pub const Str = packed struct {
4589 Rt: Register.Encoded,
4590 Rn: Register.Encoded,
4591 decoded10: u2 = 0b10,
4592 S: bool,
4593 option: Option,
4594 Rm: Register.Encoded,
4595 decoded21: u1 = 0b1,
4596 opc: u2 = 0b00,
4597 decoded24: u2 = 0b00,
4598 V: bool = false,
4599 decoded27: u3 = 0b111,
4600 sf: Register.IntegerSize,
4601 size1: u1 = 0b1,
4602 };
4603
4604 /// C6.2.168 LDR (register)
4605 pub const Ldr = packed struct {
4606 Rt: Register.Encoded,
4607 Rn: Register.Encoded,
4608 decoded10: u2 = 0b10,
4609 S: bool,
4610 option: Option,
4611 Rm: Register.Encoded,
4612 decoded21: u1 = 0b1,
4613 opc: u2 = 0b01,
4614 decoded24: u2 = 0b00,
4615 V: bool = false,
4616 decoded27: u3 = 0b111,
4617 sf: Register.IntegerSize,
4618 size1: u1 = 0b1,
4619 };
4620
4621 /// C6.2.180 LDRSW (register)
4622 pub const Ldrsw = packed struct {
4623 Rt: Register.Encoded,
4624 Rn: Register.Encoded,
4625 decoded10: u2 = 0b10,
4626 S: bool,
4627 option: Option,
4628 Rm: Register.Encoded,
4629 decoded21: u1 = 0b1,
4630 opc: u2 = 0b10,
4631 decoded24: u2 = 0b00,
4632 V: bool = false,
4633 decoded27: u3 = 0b111,
4634 size: IntegerSize = .word,
4635 };
4636
4637 /// C6.2.249 PRFM (register)
4638 pub const Prfm = packed struct {
4639 prfop: PrfOp,
4640 Rn: Register.Encoded,
4641 decoded10: u2 = 0b10,
4642 S: bool,
4643 option: Option,
4644 Rm: Register.Encoded,
4645 decoded21: u1 = 0b1,
4646 opc: u2 = 0b10,
4647 decoded24: u2 = 0b00,
4648 V: bool = false,
4649 decoded27: u3 = 0b111,
4650 size: IntegerSize = .doubleword,
4651 };
4652
4653 pub const Decoded = union(enum) {
4654 unallocated,
4655 strb: Strb,
4656 ldrb: Ldrb,
4657 ldrsb: Ldrsb,
4658 strh: Strh,
4659 ldrh: Ldrh,
4660 ldrsh: Ldrsh,
4661 str: Str,
4662 ldr: Ldr,
4663 ldrsw: Ldrsw,
4664 prfm: Prfm,
4665 };
4666 pub fn decode(inst: @This()) @This().Decoded {
4667 return switch (inst.group.size) {
4668 .byte => switch (inst.group.V) {
4669 false => switch (inst.group.opc) {
4670 0b00 => .{ .strb = inst.strb },
4671 0b01 => .{ .ldrb = inst.ldrb },
4672 0b10, 0b11 => .{ .ldrsb = inst.ldrsb },
4673 },
4674 true => .unallocated,
4675 },
4676 .halfword => switch (inst.group.V) {
4677 false => switch (inst.group.opc) {
4678 0b00 => .{ .strh = inst.strh },
4679 0b01 => .{ .ldrh = inst.ldrh },
4680 0b10, 0b11 => .{ .ldrsh = inst.ldrsh },
4681 },
4682 true => .unallocated,
4683 },
4684 .word => switch (inst.group.V) {
4685 false => switch (inst.group.opc) {
4686 0b00 => .{ .str = inst.str },
4687 0b01 => .{ .ldr = inst.ldr },
4688 0b10 => .{ .ldrsw = inst.ldrsw },
4689 0b11 => .unallocated,
4690 },
4691 true => .unallocated,
4692 },
4693 .doubleword => switch (inst.group.V) {
4694 false => switch (inst.group.opc) {
4695 0b00 => .{ .str = inst.str },
4696 0b01 => .{ .ldr = inst.ldr },
4697 0b10 => .{ .prfm = inst.prfm },
4698 0b11 => .unallocated,
4699 },
4700 true => .unallocated,
4701 },
4702 };
4703 }
4704 };
4705
4706 pub const Vector = packed union {
4707 group: @This().Group,
4708 str: Str,
4709 ldr: Ldr,
4710
4711 pub const Group = packed struct {
4712 Rt: Register.Encoded,
4713 Rn: Register.Encoded,
4714 decoded10: u2 = 0b10,
4715 S: bool,
4716 option: Option,
4717 Rm: Register.Encoded,
4718 decoded21: u1 = 0b1,
4719 opc: u2,
4720 decoded24: u2 = 0b00,
4721 V: bool = true,
4722 decoded27: u3 = 0b111,
4723 size: Size,
4724 };
4725
4726 /// C7.2.332 STR (register, SIMD&FP)
4727 pub const Str = packed struct {
4728 Rt: Register.Encoded,
4729 Rn: Register.Encoded,
4730 decoded10: u2 = 0b10,
4731 S: bool,
4732 option: Option,
4733 Rm: Register.Encoded,
4734 decoded21: u1 = 0b1,
4735 opc0: L = .store,
4736 opc1: Opc1,
4737 decoded24: u2 = 0b00,
4738 V: bool = true,
4739 decoded27: u3 = 0b111,
4740 size: Size,
4741 };
4742
4743 /// C7.2.193 LDR (register, SIMD&FP)
4744 pub const Ldr = packed struct {
4745 Rt: Register.Encoded,
4746 Rn: Register.Encoded,
4747 decoded10: u2 = 0b10,
4748 S: bool,
4749 option: Option,
4750 Rm: Register.Encoded,
4751 decoded21: u1 = 0b1,
4752 opc0: L = .load,
4753 opc1: Opc1,
4754 decoded24: u2 = 0b00,
4755 V: bool = true,
4756 decoded27: u3 = 0b111,
4757 size: Size,
4758 };
4759
4760 pub const Opc1 = packed struct {
4761 encoded: u1,
4762
4763 pub fn encode(vs: Register.VectorSize) Opc1 {
4764 return .{ .encoded = switch (vs) {
4765 .byte, .half, .single, .double => 0b0,
4766 .quad => 0b1,
4767 else => unreachable,
4768 } };
4769 }
4770
4771 pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize {
4772 return switch (enc_size.encoded) {
4773 0b00 => switch (enc_opc1.encoded) {
4774 0b0 => .byte,
4775 0b1 => .quad,
4776 },
4777 0b01 => switch (enc_opc1.encoded) {
4778 0b0 => .half,
4779 0b1 => unreachable,
4780 },
4781 0b10 => switch (enc_opc1.encoded) {
4782 0b0 => .single,
4783 0b1 => unreachable,
4784 },
4785 0b11 => switch (enc_opc1.encoded) {
4786 0b0 => .double,
4787 0b1 => unreachable,
4788 },
4789 };
4790 }
4791 };
4792
4793 pub const Size = packed struct {
4794 encoded: u2,
4795
4796 pub fn encode(vs: Register.VectorSize) Size {
4797 return .{ .encoded = switch (vs) {
4798 .byte, .quad => 0b00,
4799 .half => 0b01,
4800 .single => 0b10,
4801 .double => 0b11,
4802 else => unreachable,
4803 } };
4804 }
4805 };
4806 };
4807
4808 pub const Option = enum(u3) {
4809 uxtw = 0b010,
4810 lsl = 0b011,
4811 sxtw = 0b110,
4812 sxtx = 0b111,
4813 _,
4814
4815 pub fn sf(option: Option) Register.IntegerSize {
4816 return switch (option) {
4817 .uxtw, .sxtw => .word,
4818 .lsl, .sxtx => .doubleword,
4819 _ => unreachable,
4820 };
4821 }
4822 };
4823
4824 pub const Extend = union(Option) {
4825 uxtw: Amount,
4826 lsl: Amount,
4827 sxtw: Amount,
4828 sxtx: Amount,
4829
4830 pub const Amount = u3;
4831 };
4832
4833 pub const Decoded = union(enum) {
4834 integer: Integer,
4835 vector: Vector,
4836 };
4837 pub fn decode(inst: @This()) @This().Decoded {
4838 return switch (inst.group.V) {
4839 false => .{ .integer = inst.integer },
4840 true => .{ .vector = inst.vector },
4841 };
4842 }
4843 };
4844
4845 /// Load/store register (unsigned immediate)
4846 pub const RegisterUnsignedImmediate = packed union {
4847 group: @This().Group,
4848 integer: Integer,
4849 vector: Vector,
4850
4851 pub const Group = packed struct {
4852 Rt: Register.Encoded,
4853 Rn: Register.Encoded,
4854 imm12: u12,
4855 opc: u2,
4856 decoded24: u2 = 0b01,
4857 V: bool,
4858 decoded27: u3 = 0b111,
4859 size: u2,
4860 };
4861
4862 pub const Integer = packed union {
4863 group: @This().Group,
4864 strb: Strb,
4865 ldrb: Ldrb,
4866 ldrsb: Ldrsb,
4867 strh: Strh,
4868 ldrh: Ldrh,
4869 ldrsh: Ldrsh,
4870 str: Str,
4871 ldr: Ldr,
4872 ldrsw: Ldrsw,
4873 prfm: Prfm,
4874
4875 pub const Group = packed struct {
4876 Rt: Register.Encoded,
4877 Rn: Register.Encoded,
4878 imm12: u12,
4879 opc: u2,
4880 decoded24: u2 = 0b01,
4881 V: bool = false,
4882 decoded27: u3 = 0b111,
4883 size: IntegerSize,
4884 };
4885
4886 /// C6.2.324 STRB (immediate)
4887 pub const Strb = packed struct {
4888 Rt: Register.Encoded,
4889 Rn: Register.Encoded,
4890 imm12: u12,
4891 opc: u2 = 0b00,
4892 decoded24: u2 = 0b01,
4893 V: bool = false,
4894 decoded27: u3 = 0b111,
4895 size: IntegerSize = .byte,
4896 };
4897
4898 /// C6.2.170 LDRB (immediate)
4899 pub const Ldrb = packed struct {
4900 Rt: Register.Encoded,
4901 Rn: Register.Encoded,
4902 imm12: u12,
4903 opc: u2 = 0b01,
4904 decoded24: u2 = 0b01,
4905 V: bool = false,
4906 decoded27: u3 = 0b111,
4907 size: IntegerSize = .byte,
4908 };
4909
4910 /// C6.2.174 LDRSB (immediate)
4911 pub const Ldrsb = packed struct {
4912 Rt: Register.Encoded,
4913 Rn: Register.Encoded,
4914 imm12: u12,
4915 opc0: u1,
4916 opc1: u1 = 0b1,
4917 decoded24: u2 = 0b01,
4918 V: bool = false,
4919 decoded27: u3 = 0b111,
4920 size: IntegerSize = .byte,
4921 };
4922
4923 /// C6.2.326 STRH (immediate)
4924 pub const Strh = packed struct {
4925 Rt: Register.Encoded,
4926 Rn: Register.Encoded,
4927 imm12: u12,
4928 opc: u2 = 0b00,
4929 decoded24: u2 = 0b01,
4930 V: bool = false,
4931 decoded27: u3 = 0b111,
4932 size: IntegerSize = .halfword,
4933 };
4934
4935 /// C6.2.172 LDRH (immediate)
4936 pub const Ldrh = packed struct {
4937 Rt: Register.Encoded,
4938 Rn: Register.Encoded,
4939 imm12: u12,
4940 opc: u2 = 0b01,
4941 decoded24: u2 = 0b01,
4942 V: bool = false,
4943 decoded27: u3 = 0b111,
4944 size: IntegerSize = .halfword,
4945 };
4946
4947 /// C6.2.176 LDRSH (immediate)
4948 pub const Ldrsh = packed struct {
4949 Rt: Register.Encoded,
4950 Rn: Register.Encoded,
4951 imm12: u12,
4952 opc0: u1,
4953 opc1: u1 = 0b1,
4954 decoded24: u2 = 0b01,
4955 V: bool = false,
4956 decoded27: u3 = 0b111,
4957 size: IntegerSize = .halfword,
4958 };
4959
4960 /// C6.2.322 STR (immediate)
4961 pub const Str = packed struct {
4962 Rt: Register.Encoded,
4963 Rn: Register.Encoded,
4964 imm12: u12,
4965 opc: u2 = 0b00,
4966 decoded24: u2 = 0b01,
4967 V: bool = false,
4968 decoded27: u3 = 0b111,
4969 sf: Register.IntegerSize,
4970 size1: u1 = 0b1,
4971 };
4972
4973 /// C6.2.166 LDR (immediate)
4974 pub const Ldr = packed struct {
4975 Rt: Register.Encoded,
4976 Rn: Register.Encoded,
4977 imm12: u12,
4978 opc: u2 = 0b01,
4979 decoded24: u2 = 0b01,
4980 V: bool = false,
4981 decoded27: u3 = 0b111,
4982 sf: Register.IntegerSize,
4983 size1: u1 = 0b1,
4984 };
4985
4986 /// C6.2.178 LDRSW (immediate)
4987 pub const Ldrsw = packed struct {
4988 Rt: Register.Encoded,
4989 Rn: Register.Encoded,
4990 imm12: u12,
4991 opc: u2 = 0b10,
4992 decoded24: u2 = 0b01,
4993 V: bool = false,
4994 decoded27: u3 = 0b111,
4995 size: IntegerSize = .word,
4996 };
4997
4998 /// C6.2.247 PRFM (immediate)
4999 pub const Prfm = packed struct {
5000 prfop: PrfOp,
5001 Rn: Register.Encoded,
5002 imm12: u12,
5003 opc: u2 = 0b10,
5004 decoded24: u2 = 0b01,
5005 V: bool = false,
5006 decoded27: u3 = 0b111,
5007 size: IntegerSize = .doubleword,
5008 };
5009
5010 pub const Decoded = union(enum) {
5011 unallocated,
5012 strb: Strb,
5013 ldrb: Ldrb,
5014 ldrsb: Ldrsb,
5015 strh: Strh,
5016 ldrh: Ldrh,
5017 ldrsh: Ldrsh,
5018 str: Str,
5019 ldr: Ldr,
5020 ldrsw: Ldrsw,
5021 prfm: Prfm,
5022 };
5023 pub fn decode(inst: @This()) @This().Decoded {
5024 return switch (inst.group.size) {
5025 .byte => switch (inst.group.V) {
5026 false => switch (inst.group.opc) {
5027 0b00 => .{ .strb = inst.strb },
5028 0b01 => .{ .ldrb = inst.ldrb },
5029 0b10, 0b11 => .{ .ldrsb = inst.ldrsb },
5030 },
5031 true => .unallocated,
5032 },
5033 .halfword => switch (inst.group.V) {
5034 false => switch (inst.group.opc) {
5035 0b00 => .{ .strh = inst.strh },
5036 0b01 => .{ .ldrh = inst.ldrh },
5037 0b10, 0b11 => .{ .ldrsh = inst.ldrsh },
5038 },
5039 true => .unallocated,
5040 },
5041 .word => switch (inst.group.V) {
5042 false => switch (inst.group.opc) {
5043 0b00 => .{ .str = inst.str },
5044 0b01 => .{ .ldr = inst.ldr },
5045 0b10 => .{ .ldrsw = inst.ldrsw },
5046 0b11 => .unallocated,
5047 },
5048 true => .unallocated,
5049 },
5050 .doubleword => switch (inst.group.V) {
5051 false => switch (inst.group.opc) {
5052 0b00 => .{ .str = inst.str },
5053 0b01 => .{ .ldr = inst.ldr },
5054 0b10 => .{ .prfm = inst.prfm },
5055 0b11 => .unallocated,
5056 },
5057 true => .unallocated,
5058 },
5059 };
5060 }
5061 };
5062
5063 pub const Vector = packed union {
5064 group: @This().Group,
5065 str: Str,
5066 ldr: Ldr,
5067
5068 pub const Group = packed struct {
5069 Rt: Register.Encoded,
5070 Rn: Register.Encoded,
5071 imm12: u12,
5072 opc0: L,
5073 opc1: Opc1,
5074 decoded24: u2 = 0b01,
5075 V: bool = true,
5076 decoded27: u3 = 0b111,
5077 size: Size,
5078 };
5079
5080 /// C7.2.331 STR (immediate, SIMD&FP)
5081 pub const Str = packed struct {
5082 Rt: Register.Encoded,
5083 Rn: Register.Encoded,
5084 imm12: u12,
5085 opc0: L = .store,
5086 opc1: Opc1,
5087 decoded24: u2 = 0b01,
5088 V: bool = true,
5089 decoded27: u3 = 0b111,
5090 size: Size,
5091 };
5092
5093 /// C7.2.191 LDR (immediate, SIMD&FP)
5094 pub const Ldr = packed struct {
5095 Rt: Register.Encoded,
5096 Rn: Register.Encoded,
5097 imm12: u12,
5098 opc0: L = .load,
5099 opc1: Opc1,
5100 decoded24: u2 = 0b01,
5101 V: bool = true,
5102 decoded27: u3 = 0b111,
5103 size: Size,
5104 };
5105
5106 pub const Opc1 = packed struct {
5107 encoded: u1,
5108
5109 pub fn encode(vs: Register.VectorSize) Opc1 {
5110 return .{ .encoded = switch (vs) {
5111 .byte, .half, .single, .double => 0b0,
5112 .quad => 0b1,
5113 else => unreachable,
5114 } };
5115 }
5116
5117 pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize {
5118 return switch (enc_size.encoded) {
5119 0b00 => switch (enc_opc1.encoded) {
5120 0b0 => .byte,
5121 0b1 => .quad,
5122 },
5123 0b01 => switch (enc_opc1.encoded) {
5124 0b0 => .half,
5125 0b1 => unreachable,
5126 },
5127 0b10 => switch (enc_opc1.encoded) {
5128 0b0 => .single,
5129 0b1 => unreachable,
5130 },
5131 0b11 => switch (enc_opc1.encoded) {
5132 0b0 => .double,
5133 0b1 => unreachable,
5134 },
5135 };
5136 }
5137 };
5138
5139 pub const Size = packed struct {
5140 encoded: u2,
5141
5142 pub fn encode(vs: Register.VectorSize) Size {
5143 return .{ .encoded = switch (vs) {
5144 .byte, .quad => 0b00,
5145 .half => 0b01,
5146 .single => 0b10,
5147 .double => 0b11,
5148 else => unreachable,
5149 } };
5150 }
5151 };
5152
5153 pub const Decoded = union(enum) {
5154 unallocated,
5155 str: Str,
5156 ldr: Ldr,
5157 };
5158 pub fn decode(inst: @This()) @This().Decoded {
5159 return switch (inst.group.size.encoded) {
5160 0b00 => switch (inst.group.opc0) {
5161 .store => .{ .str = inst.str },
5162 .load => .{ .ldr = inst.ldr },
5163 },
5164 0b01, 0b10, 0b11 => switch (inst.group.opc1.encoded) {
5165 0b0 => switch (inst.group.opc0) {
5166 .store => .{ .str = inst.str },
5167 .load => .{ .ldr = inst.ldr },
5168 },
5169 0b1 => .unallocated,
5170 },
5171 };
5172 }
5173 };
5174
5175 pub const Decoded = union(enum) {
5176 integer: Integer,
5177 vector: Vector,
5178 };
5179 pub fn decode(inst: @This()) @This().Decoded {
5180 return switch (inst.group.V) {
5181 false => .{ .integer = inst.integer },
5182 true => .{ .vector = inst.vector },
5183 };
5184 }
5185 };
5186
5187 pub const L = enum(u1) {
5188 store = 0b0,
5189 load = 0b1,
5190 };
5191
5192 pub const IntegerSize = enum(u2) {
5193 byte = 0b00,
5194 halfword = 0b01,
5195 word = 0b10,
5196 doubleword = 0b11,
5197 };
5198
5199 pub const VectorSize = enum(u2) {
5200 single = 0b00,
5201 double = 0b01,
5202 quad = 0b10,
5203 _,
5204
5205 pub fn decode(vs: VectorSize) Register.VectorSize {
5206 return switch (vs) {
5207 .single => .single,
5208 .double => .double,
5209 .quad => .quad,
5210 _ => unreachable,
5211 };
5212 }
5213
5214 pub fn encode(vs: Register.VectorSize) VectorSize {
5215 return switch (vs) {
5216 else => unreachable,
5217 .single => .single,
5218 .double => .double,
5219 .quad => .quad,
5220 };
5221 }
5222 };
5223
5224 pub const PrfOp = packed struct {
5225 policy: Policy,
5226 target: Target,
5227 type: Type,
5228
5229 pub const Policy = enum(u1) {
5230 keep = 0b0,
5231 strm = 0b1,
5232 };
5233
5234 pub const Target = enum(u2) {
5235 l1 = 0b00,
5236 l2 = 0b01,
5237 l3 = 0b10,
5238 _,
5239 };
5240
5241 pub const Type = enum(u2) {
5242 pld = 0b00,
5243 pli = 0b01,
5244 pst = 0b10,
5245 _,
5246 };
5247
5248 pub const pldl1keep: PrfOp = .{ .type = .pld, .target = .l1, .policy = .keep };
5249 pub const pldl1strm: PrfOp = .{ .type = .pld, .target = .l1, .policy = .strm };
5250 pub const pldl2keep: PrfOp = .{ .type = .pld, .target = .l2, .policy = .keep };
5251 pub const pldl2strm: PrfOp = .{ .type = .pld, .target = .l2, .policy = .strm };
5252 pub const pldl3keep: PrfOp = .{ .type = .pld, .target = .l3, .policy = .keep };
5253 pub const pldl3strm: PrfOp = .{ .type = .pld, .target = .l3, .policy = .strm };
5254 pub const plil1keep: PrfOp = .{ .type = .pli, .target = .l1, .policy = .keep };
5255 pub const plil1strm: PrfOp = .{ .type = .pli, .target = .l1, .policy = .strm };
5256 pub const plil2keep: PrfOp = .{ .type = .pli, .target = .l2, .policy = .keep };
5257 pub const plil2strm: PrfOp = .{ .type = .pli, .target = .l2, .policy = .strm };
5258 pub const plil3keep: PrfOp = .{ .type = .pli, .target = .l3, .policy = .keep };
5259 pub const plil3strm: PrfOp = .{ .type = .pli, .target = .l3, .policy = .strm };
5260 pub const pstl1keep: PrfOp = .{ .type = .pst, .target = .l1, .policy = .keep };
5261 pub const pstl1strm: PrfOp = .{ .type = .pst, .target = .l1, .policy = .strm };
5262 pub const pstl2keep: PrfOp = .{ .type = .pst, .target = .l2, .policy = .keep };
5263 pub const pstl2strm: PrfOp = .{ .type = .pst, .target = .l2, .policy = .strm };
5264 pub const pstl3keep: PrfOp = .{ .type = .pst, .target = .l3, .policy = .keep };
5265 pub const pstl3strm: PrfOp = .{ .type = .pst, .target = .l3, .policy = .strm_ };
5266 };
5267
5268 pub const Decoded = union(enum) {
5269 unallocated,
5270 register_literal: RegisterLiteral,
5271 memory: Memory,
5272 no_allocate_pair_offset: NoAllocatePairOffset,
5273 register_pair_post_indexed: RegisterPairPostIndexed,
5274 register_pair_offset: RegisterPairOffset,
5275 register_pair_pre_indexed: RegisterPairPreIndexed,
5276 register_unscaled_immediate: RegisterUnscaledImmediate,
5277 register_immediate_post_indexed: RegisterImmediatePostIndexed,
5278 register_unprivileged: RegisterUnprivileged,
5279 register_immediate_pre_indexed: RegisterImmediatePreIndexed,
5280 register_register_offset: RegisterRegisterOffset,
5281 register_unsigned_immediate: RegisterUnsignedImmediate,
5282 };
5283 pub fn decode(inst: @This()) @This().Decoded {
5284 return switch (inst.group.op0) {
5285 else => .unallocated,
5286 0b0010, 0b0110, 0b1010, 0b1110 => switch (inst.group.op2) {
5287 0b00 => .{ .no_allocate_pair_offset = inst.no_allocate_pair_offset },
5288 0b01 => .{ .register_pair_post_indexed = inst.register_pair_post_indexed },
5289 0b10 => .{ .register_pair_offset = inst.register_pair_offset },
5290 0b11 => .{ .register_pair_pre_indexed = inst.register_pair_pre_indexed },
5291 },
5292 0b0011, 0b0111, 0b1011, 0b1111 => switch (inst.group.op2) {
5293 0b00...0b01 => switch (inst.group.op3) {
5294 0b000000...0b011111 => switch (inst.group.op4) {
5295 0b00 => .{ .register_unscaled_immediate = inst.register_unscaled_immediate },
5296 0b01 => .{ .register_immediate_post_indexed = inst.register_immediate_post_indexed },
5297 0b10 => .{ .register_unprivileged = inst.register_unprivileged },
5298 0b11 => .{ .register_immediate_pre_indexed = inst.register_immediate_pre_indexed },
5299 },
5300 0b100000...0b111111 => switch (inst.group.op4) {
5301 0b00 => .unallocated,
5302 0b10 => .{ .register_register_offset = inst.register_register_offset },
5303 0b01, 0b11 => .unallocated,
5304 },
5305 },
5306 0b10...0b11 => .{ .register_unsigned_immediate = inst.register_unsigned_immediate },
5307 },
5308 };
5309 }
5310 };
5311
5312 /// C4.1.89 Data Processing -- Register
5313 pub const DataProcessingRegister = packed union {
5314 group: @This().Group,
5315 data_processing_two_source: DataProcessingTwoSource,
5316 data_processing_one_source: DataProcessingOneSource,
5317 logical_shifted_register: LogicalShiftedRegister,
5318 add_subtract_shifted_register: AddSubtractShiftedRegister,
5319 add_subtract_extended_register: AddSubtractExtendedRegister,
5320 add_subtract_with_carry: AddSubtractWithCarry,
5321 rotate_right_into_flags: RotateRightIntoFlags,
5322 evaluate_into_flags: EvaluateIntoFlags,
5323 conditional_compare_register: ConditionalCompareRegister,
5324 conditional_compare_immediate: ConditionalCompareImmediate,
5325 conditional_select: ConditionalSelect,
5326 data_processing_three_source: DataProcessingThreeSource,
5327
5328 /// Table C4-90 Encoding table for the Data Processing -- Register group
5329 pub const Group = packed struct {
5330 encoded0: u10,
5331 op3: u6,
5332 encoded16: u5,
5333 op2: u4,
5334 decoded25: u3 = 0b101,
5335 op1: u1,
5336 encoded29: u1,
5337 op0: u1,
5338 encoded31: u1,
5339 };
5340
5341 /// Data-processing (2 source)
5342 pub const DataProcessingTwoSource = packed union {
5343 group: @This().Group,
5344 udiv: Udiv,
5345 sdiv: Sdiv,
5346 lslv: Lslv,
5347 lsrv: Lsrv,
5348 asrv: Asrv,
5349 rorv: Rorv,
5350
5351 pub const Group = packed struct {
5352 Rd: Register.Encoded,
5353 Rn: Register.Encoded,
5354 opcode: u6,
5355 Rm: Register.Encoded,
5356 decoded21: u8 = 0b11010110,
5357 S: bool,
5358 decoded30: u1 = 0b0,
5359 sf: Register.IntegerSize,
5360 };
5361
5362 /// C6.2.388 UDIV
5363 pub const Udiv = packed struct {
5364 Rd: Register.Encoded,
5365 Rn: Register.Encoded,
5366 o1: DivOp = .udiv,
5367 decoded11: u5 = 0b00001,
5368 Rm: Register.Encoded,
5369 decoded21: u8 = 0b11010110,
5370 S: bool = false,
5371 decoded30: u1 = 0b0,
5372 sf: Register.IntegerSize,
5373 };
5374
5375 /// C6.2.270 SDIV
5376 pub const Sdiv = packed struct {
5377 Rd: Register.Encoded,
5378 Rn: Register.Encoded,
5379 o1: DivOp = .sdiv,
5380 decoded11: u5 = 0b00001,
5381 Rm: Register.Encoded,
5382 decoded21: u8 = 0b11010110,
5383 S: bool = false,
5384 decoded30: u1 = 0b0,
5385 sf: Register.IntegerSize,
5386 };
5387
5388 /// C6.2.214 LSLV
5389 pub const Lslv = packed struct {
5390 Rd: Register.Encoded,
5391 Rn: Register.Encoded,
5392 op2: ShiftOp = .lslv,
5393 decoded12: u4 = 0b0010,
5394 Rm: Register.Encoded,
5395 decoded21: u8 = 0b11010110,
5396 S: bool = false,
5397 decoded30: u1 = 0b0,
5398 sf: Register.IntegerSize,
5399 };
5400
5401 /// C6.2.217 LSRV
5402 pub const Lsrv = packed struct {
5403 Rd: Register.Encoded,
5404 Rn: Register.Encoded,
5405 op2: ShiftOp = .lsrv,
5406 decoded12: u4 = 0b0010,
5407 Rm: Register.Encoded,
5408 decoded21: u8 = 0b11010110,
5409 S: bool = false,
5410 decoded30: u1 = 0b0,
5411 sf: Register.IntegerSize,
5412 };
5413
5414 /// C6.2.18 ASRV
5415 pub const Asrv = packed struct {
5416 Rd: Register.Encoded,
5417 Rn: Register.Encoded,
5418 op2: ShiftOp = .asrv,
5419 decoded12: u4 = 0b0010,
5420 Rm: Register.Encoded,
5421 decoded21: u8 = 0b11010110,
5422 S: bool = false,
5423 decoded30: u1 = 0b0,
5424 sf: Register.IntegerSize,
5425 };
5426
5427 /// C6.2.263 RORV
5428 pub const Rorv = packed struct {
5429 Rd: Register.Encoded,
5430 Rn: Register.Encoded,
5431 op2: ShiftOp = .rorv,
5432 decoded12: u4 = 0b0010,
5433 Rm: Register.Encoded,
5434 decoded21: u8 = 0b11010110,
5435 S: bool = false,
5436 decoded30: u1 = 0b0,
5437 sf: Register.IntegerSize,
5438 };
5439
5440 pub const DivOp = enum(u1) {
5441 udiv = 0b0,
5442 sdiv = 0b1,
5443 };
5444
5445 pub const ShiftOp = enum(u2) {
5446 lslv = 0b00,
5447 lsrv = 0b01,
5448 asrv = 0b10,
5449 rorv = 0b11,
5450 };
5451
5452 pub const Decoded = union(enum) {
5453 unallocated,
5454 udiv: Udiv,
5455 sdiv: Sdiv,
5456 lslv: Lslv,
5457 lsrv: Lsrv,
5458 asrv: Asrv,
5459 rorv: Rorv,
5460 };
5461 pub fn decode(inst: @This()) @This().Decoded {
5462 return switch (inst.group.S) {
5463 false => switch (inst.group.opcode) {
5464 else => .unallocated,
5465 0b000010 => .{ .udiv = inst.udiv },
5466 0b000011 => .{ .sdiv = inst.sdiv },
5467 0b001000 => .{ .lslv = inst.lslv },
5468 0b001001 => .{ .lsrv = inst.lsrv },
5469 0b001010 => .{ .asrv = inst.asrv },
5470 0b001011 => .{ .rorv = inst.rorv },
5471 },
5472 true => .unallocated,
5473 };
5474 }
5475 };
5476
5477 /// Data-processing (1 source)
5478 pub const DataProcessingOneSource = packed union {
5479 group: @This().Group,
5480 rbit: Rbit,
5481 rev16: Rev16,
5482 rev32: Rev32,
5483 rev: Rev,
5484 clz: Clz,
5485 cls: Cls,
5486
5487 pub const Group = packed struct {
5488 Rd: Register.Encoded,
5489 Rn: Register.Encoded,
5490 opcode: u6,
5491 opcode2: u5,
5492 decoded21: u8 = 0b11010110,
5493 S: bool,
5494 decoded30: u1 = 0b1,
5495 sf: Register.IntegerSize,
5496 };
5497
5498 /// C6.2.253 RBIT
5499 pub const Rbit = packed struct {
5500 Rd: Register.Encoded,
5501 Rn: Register.Encoded,
5502 decoded10: u2 = 0b00,
5503 decoded12: u4 = 0b0000,
5504 decoded16: u5 = 0b00000,
5505 decoded21: u8 = 0b11010110,
5506 S: bool = false,
5507 decoded30: u1 = 0b1,
5508 sf: Register.IntegerSize,
5509 };
5510
5511 /// C6.2.257 REV16
5512 pub const Rev16 = packed struct {
5513 Rd: Register.Encoded,
5514 Rn: Register.Encoded,
5515 opc: u2 = 0b01,
5516 decoded12: u4 = 0b0000,
5517 decoded16: u5 = 0b00000,
5518 decoded21: u8 = 0b11010110,
5519 S: bool = false,
5520 decoded30: u1 = 0b1,
5521 sf: Register.IntegerSize,
5522 };
5523
5524 /// C6.2.258 REV32
5525 pub const Rev32 = packed struct {
5526 Rd: Register.Encoded,
5527 Rn: Register.Encoded,
5528 opc: u2 = 0b10,
5529 decoded12: u4 = 0b0000,
5530 decoded16: u5 = 0b00000,
5531 decoded21: u8 = 0b11010110,
5532 S: bool = false,
5533 decoded30: u1 = 0b1,
5534 sf: Register.IntegerSize = .doubleword,
5535 };
5536
5537 /// C6.2.256 REV
5538 pub const Rev = packed struct {
5539 Rd: Register.Encoded,
5540 Rn: Register.Encoded,
5541 opc0: Register.IntegerSize,
5542 opc1: u1 = 0b1,
5543 decoded12: u4 = 0b0000,
5544 decoded16: u5 = 0b00000,
5545 decoded21: u8 = 0b11010110,
5546 S: bool = false,
5547 decoded30: u1 = 0b1,
5548 sf: Register.IntegerSize,
5549 };
5550
5551 /// C6.2.58 CLZ
5552 pub const Clz = packed struct {
5553 Rd: Register.Encoded,
5554 Rn: Register.Encoded,
5555 op: u1 = 0b0,
5556 decoded11: u5 = 0b00010,
5557 decoded16: u5 = 0b00000,
5558 decoded21: u8 = 0b11010110,
5559 S: bool = false,
5560 decoded30: u1 = 0b1,
5561 sf: Register.IntegerSize,
5562 };
5563
5564 /// C6.2.57 CLS
5565 pub const Cls = packed struct {
5566 Rd: Register.Encoded,
5567 Rn: Register.Encoded,
5568 op: u1 = 0b1,
5569 decoded11: u5 = 0b00010,
5570 decoded16: u5 = 0b00000,
5571 decoded21: u8 = 0b11010110,
5572 S: bool = false,
5573 decoded30: u1 = 0b1,
5574 sf: Register.IntegerSize,
5575 };
5576
5577 pub const Decoded = union(enum) {
5578 unallocated,
5579 rbit: Rbit,
5580 rev16: Rev16,
5581 rev32: Rev32,
5582 rev: Rev,
5583 clz: Clz,
5584 cls: Cls,
5585 };
5586 pub fn decode(inst: @This()) @This().Decoded {
5587 return switch (inst.group.S) {
5588 true => .unallocated,
5589 false => switch (inst.group.opcode2) {
5590 else => .unallocated,
5591 0b00000 => switch (inst.group.opcode) {
5592 else => .unallocated,
5593 0b000000 => .{ .rbit = inst.rbit },
5594 0b000001 => .{ .rev16 = inst.rev16 },
5595 0b000010 => switch (inst.group.sf) {
5596 .word => .{ .rev = inst.rev },
5597 .doubleword => .{ .rev32 = inst.rev32 },
5598 },
5599 0b000011 => switch (inst.group.sf) {
5600 .word => .unallocated,
5601 .doubleword => .{ .rev = inst.rev },
5602 },
5603 0b000100 => .{ .clz = inst.clz },
5604 0b000101 => .{ .cls = inst.cls },
5605 },
5606 },
5607 };
5608 }
5609 };
5610
5611 /// Logical (shifted register)
5612 pub const LogicalShiftedRegister = packed union {
5613 group: @This().Group,
5614 @"and": And,
5615 bic: Bic,
5616 orr: Orr,
5617 orn: Orn,
5618 eor: Eor,
5619 eon: Eon,
5620 ands: Ands,
5621 bics: Bics,
5622
5623 pub const Group = packed struct {
5624 Rd: Register.Encoded,
5625 Rn: Register.Encoded,
5626 imm6: Shift.Amount,
5627 Rm: Register.Encoded,
5628 N: bool,
5629 shift: Shift.Op,
5630 decoded24: u5 = 0b01010,
5631 opc: LogicalOpc,
5632 sf: Register.IntegerSize,
5633 };
5634
5635 /// C6.2.13 AND (shifted register)
5636 pub const And = packed struct {
5637 Rd: Register.Encoded,
5638 Rn: Register.Encoded,
5639 imm6: Shift.Amount,
5640 Rm: Register.Encoded,
5641 N: bool = false,
5642 shift: Shift.Op,
5643 decoded24: u5 = 0b01010,
5644 opc: LogicalOpc = .@"and",
5645 sf: Register.IntegerSize,
5646 };
5647
5648 /// C6.2.32 BIC (shifted register)
5649 pub const Bic = packed struct {
5650 Rd: Register.Encoded,
5651 Rn: Register.Encoded,
5652 imm6: Shift.Amount,
5653 Rm: Register.Encoded,
5654 N: bool = true,
5655 shift: Shift.Op,
5656 decoded24: u5 = 0b01010,
5657 opc: LogicalOpc = .@"and",
5658 sf: Register.IntegerSize,
5659 };
5660
5661 /// C6.2.241 ORR (shifted register)
5662 pub const Orr = packed struct {
5663 Rd: Register.Encoded,
5664 Rn: Register.Encoded,
5665 imm6: Shift.Amount,
5666 Rm: Register.Encoded,
5667 N: bool = false,
5668 shift: Shift.Op,
5669 decoded24: u5 = 0b01010,
5670 opc: LogicalOpc = .orr,
5671 sf: Register.IntegerSize,
5672 };
5673
5674 /// C6.2.239 ORN (shifted register)
5675 pub const Orn = packed struct {
5676 Rd: Register.Encoded,
5677 Rn: Register.Encoded,
5678 imm6: Shift.Amount,
5679 Rm: Register.Encoded,
5680 N: bool = true,
5681 shift: Shift.Op,
5682 decoded24: u5 = 0b01010,
5683 opc: LogicalOpc = .orr,
5684 sf: Register.IntegerSize,
5685 };
5686
5687 /// C6.2.120 EOR (shifted register)
5688 pub const Eor = packed struct {
5689 Rd: Register.Encoded,
5690 Rn: Register.Encoded,
5691 imm6: Shift.Amount,
5692 Rm: Register.Encoded,
5693 N: bool = false,
5694 shift: Shift.Op,
5695 decoded24: u5 = 0b01010,
5696 opc: LogicalOpc = .eor,
5697 sf: Register.IntegerSize,
5698 };
5699
5700 /// C6.2.118 EON (shifted register)
5701 pub const Eon = packed struct {
5702 Rd: Register.Encoded,
5703 Rn: Register.Encoded,
5704 imm6: Shift.Amount,
5705 Rm: Register.Encoded,
5706 N: bool = true,
5707 shift: Shift.Op,
5708 decoded24: u5 = 0b01010,
5709 opc: LogicalOpc = .eor,
5710 sf: Register.IntegerSize,
5711 };
5712
5713 /// C6.2.15 ANDS (shifted register)
5714 pub const Ands = packed struct {
5715 Rd: Register.Encoded,
5716 Rn: Register.Encoded,
5717 imm6: Shift.Amount,
5718 Rm: Register.Encoded,
5719 N: bool = false,
5720 shift: Shift.Op,
5721 decoded24: u5 = 0b01010,
5722 opc: LogicalOpc = .ands,
5723 sf: Register.IntegerSize,
5724 };
5725
5726 /// C6.2.33 BICS (shifted register)
5727 pub const Bics = packed struct {
5728 Rd: Register.Encoded,
5729 Rn: Register.Encoded,
5730 imm6: Shift.Amount,
5731 Rm: Register.Encoded,
5732 N: bool = true,
5733 shift: Shift.Op,
5734 decoded24: u5 = 0b01010,
5735 opc: LogicalOpc = .ands,
5736 sf: Register.IntegerSize,
5737 };
5738
5739 pub const Decoded = union(enum) {
5740 unallocated,
5741 @"and": And,
5742 bic: Bic,
5743 orr: Orr,
5744 orn: Orn,
5745 eor: Eor,
5746 eon: Eon,
5747 ands: Ands,
5748 bics: Bics,
5749 };
5750 pub fn decode(inst: @This()) @This().Decoded {
5751 return if (inst.group.sf == .word and @as(u1, @truncate(inst.group.imm6 >> 5)) == 0b1)
5752 .unallocated
5753 else switch (inst.group.opc) {
5754 .@"and" => switch (inst.group.N) {
5755 false => .{ .@"and" = inst.@"and" },
5756 true => .{ .bic = inst.bic },
5757 },
5758 .orr => switch (inst.group.N) {
5759 false => .{ .orr = inst.orr },
5760 true => .{ .orn = inst.orn },
5761 },
5762 .eor => switch (inst.group.N) {
5763 false => .{ .eor = inst.eor },
5764 true => .{ .eon = inst.eon },
5765 },
5766 .ands => switch (inst.group.N) {
5767 false => .{ .ands = inst.ands },
5768 true => .{ .bics = inst.bics },
5769 },
5770 };
5771 }
5772 };
5773
5774 /// Add/subtract (shifted register)
5775 pub const AddSubtractShiftedRegister = packed union {
5776 group: @This().Group,
5777 add: Add,
5778 adds: Adds,
5779 sub: Sub,
5780 subs: Subs,
5781
5782 pub const Group = packed struct {
5783 Rd: Register.Encoded,
5784 Rn: Register.Encoded,
5785 imm6: Shift.Amount,
5786 Rm: Register.Encoded,
5787 decoded21: u1 = 0b0,
5788 shift: Shift.Op,
5789 decoded24: u5 = 0b01011,
5790 S: bool,
5791 op: AddSubtractOp,
5792 sf: Register.IntegerSize,
5793 };
5794
5795 /// C6.2.5 ADD (shifted register)
5796 pub const Add = packed struct {
5797 Rd: Register.Encoded,
5798 Rn: Register.Encoded,
5799 imm6: Shift.Amount,
5800 Rm: Register.Encoded,
5801 decoded21: u1 = 0b0,
5802 shift: Shift.Op,
5803 decoded24: u5 = 0b01011,
5804 S: bool = false,
5805 op: AddSubtractOp = .add,
5806 sf: Register.IntegerSize,
5807 };
5808
5809 /// C6.2.9 ADDS (shifted register)
5810 pub const Adds = packed struct {
5811 Rd: Register.Encoded,
5812 Rn: Register.Encoded,
5813 imm6: Shift.Amount,
5814 Rm: Register.Encoded,
5815 decoded21: u1 = 0b0,
5816 shift: Shift.Op,
5817 decoded24: u5 = 0b01011,
5818 S: bool = true,
5819 op: AddSubtractOp = .add,
5820 sf: Register.IntegerSize,
5821 };
5822
5823 /// C6.2.5 SUB (shifted register)
5824 pub const Sub = packed struct {
5825 Rd: Register.Encoded,
5826 Rn: Register.Encoded,
5827 imm6: Shift.Amount,
5828 Rm: Register.Encoded,
5829 decoded21: u1 = 0b0,
5830 shift: Shift.Op,
5831 decoded24: u5 = 0b01011,
5832 S: bool = false,
5833 op: AddSubtractOp = .sub,
5834 sf: Register.IntegerSize,
5835 };
5836
5837 /// C6.2.9 SUBS (shifted register)
5838 pub const Subs = packed struct {
5839 Rd: Register.Encoded,
5840 Rn: Register.Encoded,
5841 imm6: Shift.Amount,
5842 Rm: Register.Encoded,
5843 decoded21: u1 = 0b0,
5844 shift: Shift.Op,
5845 decoded24: u5 = 0b01011,
5846 S: bool = true,
5847 op: AddSubtractOp = .sub,
5848 sf: Register.IntegerSize,
5849 };
5850
5851 pub const Decoded = union(enum) {
5852 unallocated,
5853 add: Add,
5854 adds: Adds,
5855 sub: Sub,
5856 subs: Subs,
5857 };
5858 pub fn decode(inst: @This()) @This().Decoded {
5859 return switch (inst.group.shift) {
5860 .ror => .unallocated,
5861 .lsl, .lsr, .asr => if (inst.group.sf == .word and @as(u1, @truncate(inst.group.imm6 >> 5)) == 0b1)
5862 .unallocated
5863 else switch (inst.group.op) {
5864 .add => switch (inst.group.S) {
5865 false => .{ .add = inst.add },
5866 true => .{ .adds = inst.adds },
5867 },
5868 .sub => switch (inst.group.S) {
5869 false => .{ .sub = inst.sub },
5870 true => .{ .subs = inst.subs },
5871 },
5872 },
5873 };
5874 }
5875 };
5876
5877 /// Add/subtract (extended register)
5878 pub const AddSubtractExtendedRegister = packed union {
5879 group: @This().Group,
5880 add: Add,
5881 adds: Adds,
5882 sub: Sub,
5883 subs: Subs,
5884
5885 pub const Group = packed struct {
5886 Rd: Register.Encoded,
5887 Rn: Register.Encoded,
5888 imm3: Extend.Amount,
5889 option: Option,
5890 Rm: Register.Encoded,
5891 decoded21: u1 = 0b1,
5892 opt: u2,
5893 decoded24: u5 = 0b01011,
5894 S: bool,
5895 op: AddSubtractOp,
5896 sf: Register.IntegerSize,
5897 };
5898
5899 /// C6.2.3 ADD (extended register)
5900 pub const Add = packed struct {
5901 Rd: Register.Encoded,
5902 Rn: Register.Encoded,
5903 imm3: Extend.Amount,
5904 option: Option,
5905 Rm: Register.Encoded,
5906 decoded21: u1 = 0b1,
5907 opt: u2 = 0b00,
5908 decoded24: u5 = 0b01011,
5909 S: bool = false,
5910 op: AddSubtractOp = .add,
5911 sf: Register.IntegerSize,
5912 };
5913
5914 /// C6.2.7 ADDS (extended register)
5915 pub const Adds = packed struct {
5916 Rd: Register.Encoded,
5917 Rn: Register.Encoded,
5918 imm3: Extend.Amount,
5919 option: Option,
5920 Rm: Register.Encoded,
5921 decoded21: u1 = 0b1,
5922 opt: u2 = 0b00,
5923 decoded24: u5 = 0b01011,
5924 S: bool = true,
5925 op: AddSubtractOp = .add,
5926 sf: Register.IntegerSize,
5927 };
5928
5929 /// C6.2.356 SUB (extended register)
5930 pub const Sub = packed struct {
5931 Rd: Register.Encoded,
5932 Rn: Register.Encoded,
5933 imm3: Extend.Amount,
5934 option: Option,
5935 Rm: Register.Encoded,
5936 decoded21: u1 = 0b1,
5937 opt: u2 = 0b00,
5938 decoded24: u5 = 0b01011,
5939 S: bool = false,
5940 op: AddSubtractOp = .sub,
5941 sf: Register.IntegerSize,
5942 };
5943
5944 /// C6.2.362 SUBS (extended register)
5945 pub const Subs = packed struct {
5946 Rd: Register.Encoded,
5947 Rn: Register.Encoded,
5948 imm3: Extend.Amount,
5949 option: Option,
5950 Rm: Register.Encoded,
5951 decoded21: u1 = 0b1,
5952 opt: u2 = 0b00,
5953 decoded24: u5 = 0b01011,
5954 S: bool = true,
5955 op: AddSubtractOp = .sub,
5956 sf: Register.IntegerSize,
5957 };
5958
5959 pub const Option = enum(u3) {
5960 uxtb = 0b000,
5961 uxth = 0b001,
5962 uxtw = 0b010,
5963 uxtx = 0b011,
5964 sxtb = 0b100,
5965 sxth = 0b101,
5966 sxtw = 0b110,
5967 sxtx = 0b111,
5968
5969 pub fn sf(option: Option) Register.IntegerSize {
5970 return switch (option) {
5971 .uxtb, .uxth, .uxtw, .sxtb, .sxth, .sxtw => .word,
5972 .uxtx, .sxtx => .doubleword,
5973 };
5974 }
5975 };
5976
5977 pub const Extend = union(Option) {
5978 uxtb: Amount,
5979 uxth: Amount,
5980 uxtw: Amount,
5981 uxtx: Amount,
5982 sxtb: Amount,
5983 sxth: Amount,
5984 sxtw: Amount,
5985 sxtx: Amount,
5986
5987 pub const Amount = u3;
5988 };
5989
5990 pub const Decoded = union(enum) {
5991 unallocated,
5992 add: Add,
5993 adds: Adds,
5994 sub: Sub,
5995 subs: Subs,
5996 };
5997 pub fn decode(inst: @This()) @This().Decoded {
5998 return switch (inst.group.imm3) {
5999 0b101 => .unallocated,
6000 0b110...0b111 => .unallocated,
6001 0b000...0b100 => switch (inst.group.opt) {
6002 0b01 => .unallocated,
6003 0b10...0b11 => .unallocated,
6004 0b00 => switch (inst.group.op) {
6005 .add => switch (inst.group.S) {
6006 false => .{ .add = inst.add },
6007 true => .{ .adds = inst.adds },
6008 },
6009 .sub => switch (inst.group.S) {
6010 false => .{ .sub = inst.sub },
6011 true => .{ .subs = inst.subs },
6012 },
6013 },
6014 },
6015 };
6016 }
6017 };
6018
6019 /// Add/subtract (with carry)
6020 pub const AddSubtractWithCarry = packed union {
6021 group: @This().Group,
6022 adc: Adc,
6023 adcs: Adcs,
6024 sbc: Sbc,
6025 sbcs: Sbcs,
6026
6027 pub const Group = packed struct {
6028 Rd: Register.Encoded,
6029 Rn: Register.Encoded,
6030 decoded10: u6 = 0b000000,
6031 Rm: Register.Encoded,
6032 decoded21: u8 = 0b11010000,
6033 S: bool,
6034 op: Op,
6035 sf: Register.IntegerSize,
6036 };
6037
6038 /// C6.2.1 ADC
6039 pub const Adc = packed struct {
6040 Rd: Register.Encoded,
6041 Rn: Register.Encoded,
6042 decoded10: u6 = 0b000000,
6043 Rm: Register.Encoded,
6044 decoded21: u8 = 0b11010000,
6045 S: bool = false,
6046 op: Op = .adc,
6047 sf: Register.IntegerSize,
6048 };
6049
6050 /// C6.2.2 ADCS
6051 pub const Adcs = packed struct {
6052 Rd: Register.Encoded,
6053 Rn: Register.Encoded,
6054 decoded10: u6 = 0b000000,
6055 Rm: Register.Encoded,
6056 decoded21: u8 = 0b11010000,
6057 S: bool = true,
6058 op: Op = .adc,
6059 sf: Register.IntegerSize,
6060 };
6061
6062 /// C6.2.265 SBC
6063 pub const Sbc = packed struct {
6064 Rd: Register.Encoded,
6065 Rn: Register.Encoded,
6066 decoded10: u6 = 0b000000,
6067 Rm: Register.Encoded,
6068 decoded21: u8 = 0b11010000,
6069 S: bool = false,
6070 op: Op = .sbc,
6071 sf: Register.IntegerSize,
6072 };
6073
6074 /// C6.2.266 SBCS
6075 pub const Sbcs = packed struct {
6076 Rd: Register.Encoded,
6077 Rn: Register.Encoded,
6078 decoded10: u6 = 0b000000,
6079 Rm: Register.Encoded,
6080 decoded21: u8 = 0b11010000,
6081 S: bool = true,
6082 op: Op = .sbc,
6083 sf: Register.IntegerSize,
6084 };
6085
6086 pub const Op = enum(u1) {
6087 adc = 0b0,
6088 sbc = 0b1,
6089 };
6090
6091 pub const Decoded = union(enum) {
6092 adc: Adc,
6093 adcs: Adcs,
6094 sbc: Sbc,
6095 sbcs: Sbcs,
6096 };
6097 pub fn decode(inst: @This()) @This().Decoded {
6098 return switch (inst.group.op) {
6099 .adc => switch (inst.group.S) {
6100 false => .{ .adc = inst.adc },
6101 true => .{ .adcs = inst.adcs },
6102 },
6103 .sbc => switch (inst.group.S) {
6104 false => .{ .sbc = inst.sbc },
6105 true => .{ .sbcs = inst.sbcs },
6106 },
6107 };
6108 }
6109 };
6110
6111 /// Rotate right into flags
6112 pub const RotateRightIntoFlags = packed union {
6113 group: @This().Group,
6114
6115 pub const Group = packed struct {
6116 mask: Nzcv,
6117 o2: u1,
6118 Rn: Register.Encoded,
6119 decoded10: u5 = 0b0001,
6120 imm6: u6,
6121 decoded21: u8 = 0b11010000,
6122 S: bool,
6123 op: u1,
6124 sf: Register.IntegerSize,
6125 };
6126 };
6127
6128 /// Evaluate into flags
6129 pub const EvaluateIntoFlags = packed union {
6130 group: @This().Group,
6131
6132 pub const Group = packed struct {
6133 mask: Nzcv,
6134 o3: u1,
6135 Rn: Register.Encoded,
6136 decoded10: u4 = 0b0010,
6137 sz: enum(u1) {
6138 byte = 0b0,
6139 word = 0b1,
6140 },
6141 opcode2: u6,
6142 decoded21: u8 = 0b11010000,
6143 S: bool,
6144 op: u1,
6145 sf: Register.IntegerSize,
6146 };
6147 };
6148
6149 /// Conditional compare (register)
6150 pub const ConditionalCompareRegister = packed union {
6151 group: @This().Group,
6152 ccmn: Ccmn,
6153 ccmp: Ccmp,
6154
6155 pub const Group = packed struct {
6156 nzcv: Nzcv,
6157 o3: u1,
6158 Rn: Register.Encoded,
6159 o2: u1,
6160 decoded11: u1 = 0b0,
6161 cond: ConditionCode,
6162 Rm: Register.Encoded,
6163 decoded21: u8 = 0b11010010,
6164 S: bool,
6165 op: Op,
6166 sf: Register.IntegerSize,
6167 };
6168
6169 /// C6.2.49 CCMN (register)
6170 pub const Ccmn = packed struct {
6171 nzcv: Nzcv,
6172 o3: u1 = 0b0,
6173 Rn: Register.Encoded,
6174 o2: u1 = 0b0,
6175 decoded11: u1 = 0b0,
6176 cond: ConditionCode,
6177 Rm: Register.Encoded,
6178 decoded21: u8 = 0b11010010,
6179 S: bool = true,
6180 op: Op = .ccmn,
6181 sf: Register.IntegerSize,
6182 };
6183
6184 /// C6.2.51 CCMP (register)
6185 pub const Ccmp = packed struct {
6186 nzcv: Nzcv,
6187 o3: u1 = 0b0,
6188 Rn: Register.Encoded,
6189 o2: u1 = 0b0,
6190 decoded11: u1 = 0b0,
6191 cond: ConditionCode,
6192 Rm: Register.Encoded,
6193 decoded21: u8 = 0b11010010,
6194 S: bool = true,
6195 op: Op = .ccmp,
6196 sf: Register.IntegerSize,
6197 };
6198
6199 pub const Op = enum(u1) {
6200 ccmn = 0b0,
6201 ccmp = 0b1,
6202 };
6203 };
6204
6205 /// Conditional compare (immediate)
6206 pub const ConditionalCompareImmediate = packed union {
6207 group: @This().Group,
6208 ccmn: Ccmn,
6209 ccmp: Ccmp,
6210
6211 pub const Group = packed struct {
6212 nzcv: Nzcv,
6213 o3: u1,
6214 Rn: Register.Encoded,
6215 o2: u1,
6216 decoded11: u1 = 0b1,
6217 cond: ConditionCode,
6218 imm5: u5,
6219 decoded21: u8 = 0b11010010,
6220 S: bool,
6221 op: Op,
6222 sf: Register.IntegerSize,
6223 };
6224
6225 /// C6.2.48 CCMN (immediate)
6226 pub const Ccmn = packed struct {
6227 nzcv: Nzcv,
6228 o3: u1 = 0b0,
6229 Rn: Register.Encoded,
6230 o2: u1 = 0b0,
6231 decoded11: u1 = 0b1,
6232 cond: ConditionCode,
6233 imm5: u5,
6234 decoded21: u8 = 0b11010010,
6235 S: bool = true,
6236 op: Op = .ccmn,
6237 sf: Register.IntegerSize,
6238 };
6239
6240 /// C6.2.50 CCMP (immediate)
6241 pub const Ccmp = packed struct {
6242 nzcv: Nzcv,
6243 o3: u1 = 0b0,
6244 Rn: Register.Encoded,
6245 o2: u1 = 0b0,
6246 decoded11: u1 = 0b1,
6247 cond: ConditionCode,
6248 imm5: u5,
6249 decoded21: u8 = 0b11010010,
6250 S: bool = true,
6251 op: Op = .ccmp,
6252 sf: Register.IntegerSize,
6253 };
6254
6255 pub const Op = enum(u1) {
6256 ccmn = 0b0,
6257 ccmp = 0b1,
6258 };
6259 };
6260
6261 /// Conditional select
6262 pub const ConditionalSelect = packed union {
6263 group: @This().Group,
6264 csel: Csel,
6265 csinc: Csinc,
6266 csinv: Csinv,
6267 csneg: Csneg,
6268
6269 pub const Group = packed struct {
6270 Rd: Register.Encoded,
6271 Rn: Register.Encoded,
6272 op2: u2,
6273 cond: ConditionCode,
6274 Rm: Register.Encoded,
6275 decoded21: u8 = 0b11010100,
6276 S: bool,
6277 op: u1,
6278 sf: Register.IntegerSize,
6279 };
6280
6281 /// C6.2.103 CSEL
6282 pub const Csel = packed struct {
6283 Rd: Register.Encoded,
6284 Rn: Register.Encoded,
6285 op2: u2 = 0b00,
6286 cond: ConditionCode,
6287 Rm: Register.Encoded,
6288 decoded21: u8 = 0b11010100,
6289 S: bool = false,
6290 op: u1 = 0b0,
6291 sf: Register.IntegerSize,
6292 };
6293
6294 /// C6.2.106 CSINC
6295 pub const Csinc = packed struct {
6296 Rd: Register.Encoded,
6297 Rn: Register.Encoded,
6298 op2: u2 = 0b01,
6299 cond: ConditionCode,
6300 Rm: Register.Encoded,
6301 decoded21: u8 = 0b11010100,
6302 S: bool = false,
6303 op: u1 = 0b0,
6304 sf: Register.IntegerSize,
6305 };
6306
6307 /// C6.2.107 CSINV
6308 pub const Csinv = packed struct {
6309 Rd: Register.Encoded,
6310 Rn: Register.Encoded,
6311 op2: u2 = 0b00,
6312 cond: ConditionCode,
6313 Rm: Register.Encoded,
6314 decoded21: u8 = 0b11010100,
6315 S: bool = false,
6316 op: u1 = 0b1,
6317 sf: Register.IntegerSize,
6318 };
6319
6320 /// C6.2.108 CSNEG
6321 pub const Csneg = packed struct {
6322 Rd: Register.Encoded,
6323 Rn: Register.Encoded,
6324 op2: u2 = 0b01,
6325 cond: ConditionCode,
6326 Rm: Register.Encoded,
6327 decoded21: u8 = 0b11010100,
6328 S: bool = false,
6329 op: u1 = 0b1,
6330 sf: Register.IntegerSize,
6331 };
6332
6333 pub const Decoded = union(enum) {
6334 unallocated,
6335 csel: Csel,
6336 csinc: Csinc,
6337 csinv: Csinv,
6338 csneg: Csneg,
6339 };
6340 pub fn decode(inst: @This()) @This().Decoded {
6341 return switch (inst.group.S) {
6342 true => .unallocated,
6343 false => switch (inst.group.op) {
6344 0b0 => switch (inst.group.op2) {
6345 0b10...0b11 => .unallocated,
6346 0b00 => .{ .csel = inst.csel },
6347 0b01 => .{ .csinc = inst.csinc },
6348 },
6349 0b1 => switch (inst.group.op2) {
6350 0b10...0b11 => .unallocated,
6351 0b00 => .{ .csinv = inst.csinv },
6352 0b01 => .{ .csneg = inst.csneg },
6353 },
6354 },
6355 };
6356 }
6357 };
6358
6359 /// Data-processing (3 source)
6360 pub const DataProcessingThreeSource = packed union {
6361 group: @This().Group,
6362 madd: Madd,
6363 msub: Msub,
6364 smaddl: Smaddl,
6365 smsubl: Smsubl,
6366 smulh: Smulh,
6367 umaddl: Umaddl,
6368 umsubl: Umsubl,
6369 umulh: Umulh,
6370
6371 pub const Group = packed struct {
6372 Rd: Register.Encoded,
6373 Rn: Register.Encoded,
6374 Ra: Register.Encoded,
6375 o0: AddSubtractOp,
6376 Rm: Register.Encoded,
6377 op31: u3,
6378 decoded24: u5 = 0b11011,
6379 op54: u2,
6380 sf: Register.IntegerSize,
6381 };
6382
6383 /// C6.2.218 MADD
6384 pub const Madd = packed struct {
6385 Rd: Register.Encoded,
6386 Rn: Register.Encoded,
6387 Ra: Register.Encoded,
6388 o0: AddSubtractOp = .add,
6389 Rm: Register.Encoded,
6390 op31: u3 = 0b000,
6391 decoded24: u5 = 0b11011,
6392 op54: u2 = 0b00,
6393 sf: Register.IntegerSize,
6394 };
6395
6396 /// C6.2.231 MSUB
6397 pub const Msub = packed struct {
6398 Rd: Register.Encoded,
6399 Rn: Register.Encoded,
6400 Ra: Register.Encoded,
6401 o0: AddSubtractOp = .sub,
6402 Rm: Register.Encoded,
6403 op31: u3 = 0b000,
6404 decoded24: u5 = 0b11011,
6405 op54: u2 = 0b00,
6406 sf: Register.IntegerSize,
6407 };
6408
6409 /// C6.2.282 SMADDL
6410 pub const Smaddl = packed struct {
6411 Rd: Register.Encoded,
6412 Rn: Register.Encoded,
6413 Ra: Register.Encoded,
6414 o0: AddSubtractOp = .add,
6415 Rm: Register.Encoded,
6416 op21: u2 = 0b01,
6417 U: bool = false,
6418 decoded24: u5 = 0b11011,
6419 op54: u2 = 0b00,
6420 sf: Register.IntegerSize = .doubleword,
6421 };
6422
6423 /// C6.2.287 SMSUBL
6424 pub const Smsubl = packed struct {
6425 Rd: Register.Encoded,
6426 Rn: Register.Encoded,
6427 Ra: Register.Encoded,
6428 o0: AddSubtractOp = .sub,
6429 Rm: Register.Encoded,
6430 op21: u2 = 0b01,
6431 U: bool = false,
6432 decoded24: u5 = 0b11011,
6433 op54: u2 = 0b00,
6434 sf: Register.IntegerSize = .doubleword,
6435 };
6436
6437 /// C6.2.288 SMULH
6438 pub const Smulh = packed struct {
6439 Rd: Register.Encoded,
6440 Rn: Register.Encoded,
6441 Ra: Register.Encoded = @enumFromInt(0b11111),
6442 o0: AddSubtractOp = .add,
6443 Rm: Register.Encoded,
6444 op21: u2 = 0b10,
6445 U: bool = false,
6446 decoded24: u5 = 0b11011,
6447 op54: u2 = 0b00,
6448 sf: Register.IntegerSize = .doubleword,
6449 };
6450
6451 /// C6.2.389 UMADDL
6452 pub const Umaddl = packed struct {
6453 Rd: Register.Encoded,
6454 Rn: Register.Encoded,
6455 Ra: Register.Encoded,
6456 o0: AddSubtractOp = .add,
6457 Rm: Register.Encoded,
6458 op21: u2 = 0b01,
6459 U: bool = true,
6460 decoded24: u5 = 0b11011,
6461 op54: u2 = 0b00,
6462 sf: Register.IntegerSize = .doubleword,
6463 };
6464
6465 /// C6.2.391 UMSUBL
6466 pub const Umsubl = packed struct {
6467 Rd: Register.Encoded,
6468 Rn: Register.Encoded,
6469 Ra: Register.Encoded,
6470 o0: AddSubtractOp = .sub,
6471 Rm: Register.Encoded,
6472 op21: u2 = 0b01,
6473 U: bool = true,
6474 decoded24: u5 = 0b11011,
6475 op54: u2 = 0b00,
6476 sf: Register.IntegerSize = .doubleword,
6477 };
6478
6479 /// C6.2.392 UMULH
6480 pub const Umulh = packed struct {
6481 Rd: Register.Encoded,
6482 Rn: Register.Encoded,
6483 Ra: Register.Encoded = @enumFromInt(0b11111),
6484 o0: AddSubtractOp = .add,
6485 Rm: Register.Encoded,
6486 op21: u2 = 0b10,
6487 U: bool = true,
6488 decoded24: u5 = 0b11011,
6489 op54: u2 = 0b00,
6490 sf: Register.IntegerSize = .doubleword,
6491 };
6492
6493 pub const Decoded = union(enum) {
6494 unallocated,
6495 madd: Madd,
6496 msub: Msub,
6497 smaddl: Smaddl,
6498 smsubl: Smsubl,
6499 smulh: Smulh,
6500 umaddl: Umaddl,
6501 umsubl: Umsubl,
6502 umulh: Umulh,
6503 };
6504 pub fn decode(inst: @This()) @This().Decoded {
6505 return switch (inst.group.op54) {
6506 0b01, 0b10...0b11 => .unallocated,
6507 0b00 => switch (inst.group.op31) {
6508 0b011, 0b100, 0b111 => .unallocated,
6509 0b000 => switch (inst.group.o0) {
6510 .add => .{ .madd = inst.madd },
6511 .sub => .{ .msub = inst.msub },
6512 },
6513 0b001 => switch (inst.group.sf) {
6514 .word => .unallocated,
6515 .doubleword => switch (inst.group.o0) {
6516 .add => .{ .smaddl = inst.smaddl },
6517 .sub => .{ .smsubl = inst.smsubl },
6518 },
6519 },
6520 0b010 => switch (inst.group.sf) {
6521 .word => .unallocated,
6522 .doubleword => switch (inst.group.o0) {
6523 .add => .{ .smulh = inst.smulh },
6524 .sub => .unallocated,
6525 },
6526 },
6527 0b101 => switch (inst.group.sf) {
6528 .word => .unallocated,
6529 .doubleword => switch (inst.group.o0) {
6530 .add => .{ .umaddl = inst.umaddl },
6531 .sub => .{ .umsubl = inst.umsubl },
6532 },
6533 },
6534 0b110 => switch (inst.group.sf) {
6535 .word => .unallocated,
6536 .doubleword => switch (inst.group.o0) {
6537 .add => .{ .umulh = inst.umulh },
6538 .sub => .unallocated,
6539 },
6540 },
6541 },
6542 };
6543 }
6544 };
6545
6546 pub const Shift = union(enum(u2)) {
6547 lsl: Amount = 0b00,
6548 lsr: Amount = 0b01,
6549 asr: Amount = 0b10,
6550 ror: Amount = 0b11,
6551
6552 pub const Op = @typeInfo(Shift).@"union".tag_type.?;
6553 pub const Amount = u6;
6554 pub const none: Shift = .{ .lsl = 0 };
6555 };
6556
6557 pub const Nzcv = packed struct { v: bool, c: bool, z: bool, n: bool };
6558
6559 pub const Decoded = union(enum) {
6560 unallocated,
6561 data_processing_two_source: DataProcessingTwoSource,
6562 data_processing_one_source: DataProcessingOneSource,
6563 logical_shifted_register: LogicalShiftedRegister,
6564 add_subtract_shifted_register: AddSubtractShiftedRegister,
6565 add_subtract_extended_register: AddSubtractExtendedRegister,
6566 add_subtract_with_carry: AddSubtractWithCarry,
6567 rotate_right_into_flags: RotateRightIntoFlags,
6568 evaluate_into_flags: EvaluateIntoFlags,
6569 conditional_compare_register: ConditionalCompareRegister,
6570 conditional_compare_immediate: ConditionalCompareImmediate,
6571 conditional_select: ConditionalSelect,
6572 data_processing_three_source: DataProcessingThreeSource,
6573 };
6574 pub fn decode(inst: @This()) @This().Decoded {
6575 return switch (inst.group.op1) {
6576 0b0 => switch (@as(u1, @truncate(inst.group.op2 >> 3))) {
6577 0b0 => .{ .logical_shifted_register = inst.logical_shifted_register },
6578 0b1 => switch (@as(u1, @truncate(inst.group.op2 >> 0))) {
6579 0b0 => .{ .add_subtract_shifted_register = inst.add_subtract_shifted_register },
6580 0b1 => .{ .add_subtract_extended_register = inst.add_subtract_extended_register },
6581 },
6582 },
6583 0b1 => switch (inst.group.op2) {
6584 0b0000 => switch (inst.group.op3) {
6585 0b000000 => .{ .add_subtract_with_carry = inst.add_subtract_with_carry },
6586 0b000001, 0b100001 => .{ .rotate_right_into_flags = inst.rotate_right_into_flags },
6587 0b000010, 0b010010, 0b100010, 0b110010 => .{ .evaluate_into_flags = inst.evaluate_into_flags },
6588 else => .unallocated,
6589 },
6590 0b0010 => switch (@as(u1, @truncate(inst.group.op3 >> 1))) {
6591 0b0 => .{ .conditional_compare_register = inst.conditional_compare_register },
6592 0b1 => .{ .conditional_compare_immediate = inst.conditional_compare_immediate },
6593 },
6594 0b0100 => .{ .conditional_select = inst.conditional_select },
6595 0b0110 => switch (inst.group.op0) {
6596 0b0 => .{ .data_processing_two_source = inst.data_processing_two_source },
6597 0b1 => .{ .data_processing_one_source = inst.data_processing_one_source },
6598 },
6599 0b1000...0b1111 => .{ .data_processing_three_source = inst.data_processing_three_source },
6600 else => .unallocated,
6601 },
6602 };
6603 }
6604 };
6605
6606 /// C4.1.90 Data Processing -- Scalar Floating-Point and Advanced SIMD
6607 pub const DataProcessingVector = packed union {
6608 group: @This().Group,
6609 simd_scalar_pairwise: SimdScalarPairwise,
6610 simd_copy: SimdCopy,
6611 simd_two_register_miscellaneous: SimdTwoRegisterMiscellaneous,
6612 simd_across_lanes: SimdAcrossLanes,
6613 simd_three_same: SimdThreeSame,
6614 simd_modified_immediate: SimdModifiedImmediate,
6615 convert_float_integer: ConvertFloatInteger,
6616 float_data_processing_one_source: FloatDataProcessingOneSource,
6617 float_compare: FloatCompare,
6618 float_immediate: FloatImmediate,
6619 float_data_processing_two_source: FloatDataProcessingTwoSource,
6620 float_data_processing_three_source: FloatDataProcessingThreeSource,
6621
6622 /// Table C4-91 Encoding table for the Data Processing -- Scalar Floating-Point and Advanced SIMD group
6623 pub const Group = packed struct {
6624 encoded0: u10,
6625 op3: u9,
6626 op2: u4,
6627 op1: u2,
6628 decoded25: u3 = 0b111,
6629 op0: u4,
6630 };
6631
6632 /// Advanced SIMD scalar pairwise
6633 pub const SimdScalarPairwise = packed union {
6634 group: @This().Group,
6635 addp: Addp,
6636
6637 pub const Group = packed struct {
6638 Rd: Register.Encoded,
6639 Rn: Register.Encoded,
6640 decoded10: u2 = 0b10,
6641 opcode: u5,
6642 decoded17: u5 = 0b11000,
6643 size: Size,
6644 decoded24: u5 = 0b11110,
6645 U: u1,
6646 decoded30: u2 = 0b01,
6647 };
6648
6649 /// C7.2.4 ADDP (scalar)
6650 pub const Addp = packed struct {
6651 Rd: Register.Encoded,
6652 Rn: Register.Encoded,
6653 decoded10: u2 = 0b10,
6654 opcode: u5 = 0b11011,
6655 decoded17: u5 = 0b11000,
6656 size: Size,
6657 decoded24: u5 = 0b11110,
6658 U: u1 = 0b0,
6659 decoded30: u2 = 0b01,
6660 };
6661 };
6662
6663 /// Advanced SIMD copy
6664 pub const SimdCopy = packed union {
6665 group: @This().Group,
6666 smov: Smov,
6667 umov: Umov,
6668
6669 pub const Group = packed struct {
6670 Rd: Register.Encoded,
6671 Rn: Register.Encoded,
6672 decoded10: u1 = 0b1,
6673 imm4: u4,
6674 decoded15: u1 = 0b0,
6675 imm5: u5,
6676 decoded21: u8 = 0b01110000,
6677 op: u1,
6678 Q: Register.IntegerSize,
6679 decoded31: u1 = 0b0,
6680 };
6681
6682 /// C7.2.279 SMOV
6683 pub const Smov = packed struct {
6684 Rd: Register.Encoded,
6685 Rn: Register.Encoded,
6686 decoded10: u1 = 0b1,
6687 decoded11: u1 = 0b1,
6688 decoded12: u1 = 0b0,
6689 decoded13: u2 = 0b01,
6690 decoded15: u1 = 0b0,
6691 imm5: u5,
6692 decoded21: u8 = 0b01110000,
6693 decoded29: u1 = 0b0,
6694 Q: Register.IntegerSize,
6695 decoded31: u1 = 0b0,
6696 };
6697
6698 /// C7.2.371 UMOV
6699 pub const Umov = packed struct {
6700 Rd: Register.Encoded,
6701 Rn: Register.Encoded,
6702 decoded10: u1 = 0b1,
6703 decoded11: u1 = 0b1,
6704 decoded12: u1 = 0b1,
6705 decoded13: u2 = 0b01,
6706 decoded15: u1 = 0b0,
6707 imm5: u5,
6708 decoded21: u8 = 0b01110000,
6709 decoded29: u1 = 0b0,
6710 Q: Register.IntegerSize,
6711 decoded31: u1 = 0b0,
6712 };
6713 };
6714
6715 /// Advanced SIMD two-register miscellaneous
6716 pub const SimdTwoRegisterMiscellaneous = packed union {
6717 group: @This().Group,
6718 cnt: Cnt,
6719
6720 pub const Group = packed struct {
6721 Rd: Register.Encoded,
6722 Rn: Register.Encoded,
6723 decoded10: u2 = 0b10,
6724 opcode: u5,
6725 decoded17: u5 = 0b10000,
6726 size: Size,
6727 decoded24: u5 = 0b01110,
6728 U: u1,
6729 Q: Q,
6730 decoded31: u1 = 0b0,
6731 };
6732
6733 /// C7.2.38 CNT
6734 pub const Cnt = packed struct {
6735 Rd: Register.Encoded,
6736 Rn: Register.Encoded,
6737 decoded10: u2 = 0b10,
6738 opcode: u5 = 0b00101,
6739 decoded17: u5 = 0b10000,
6740 size: Size,
6741 decoded24: u5 = 0b01110,
6742 U: u1 = 0b0,
6743 Q: Q,
6744 decoded31: u1 = 0b0,
6745 };
6746 };
6747
6748 /// Advanced SIMD across lanes
6749 pub const SimdAcrossLanes = packed union {
6750 group: @This().Group,
6751 addv: Addv,
6752
6753 pub const Group = packed struct {
6754 Rd: Register.Encoded,
6755 Rn: Register.Encoded,
6756 decoded10: u2 = 0b10,
6757 opcode: u5,
6758 decoded17: u5 = 0b11000,
6759 size: Size,
6760 decoded24: u5 = 0b01110,
6761 U: u1,
6762 Q: Q,
6763 decoded31: u1 = 0b0,
6764 };
6765
6766 /// C7.2.6 ADDV
6767 pub const Addv = packed struct {
6768 Rd: Register.Encoded,
6769 Rn: Register.Encoded,
6770 decoded10: u2 = 0b10,
6771 opcode: u5 = 0b11011,
6772 decoded17: u5 = 0b11000,
6773 size: Size,
6774 decoded24: u5 = 0b01110,
6775 U: u1 = 0b0,
6776 Q: Q,
6777 decoded31: u1 = 0b0,
6778 };
6779 };
6780
6781 /// Advanced SIMD three same
6782 pub const SimdThreeSame = packed union {
6783 group: @This().Group,
6784 addp: Addp,
6785 @"and": And,
6786 bic: Bic,
6787 orr: Orr,
6788 orn: Orn,
6789 eor: Eor,
6790
6791 pub const Group = packed struct {
6792 Rd: Register.Encoded,
6793 Rn: Register.Encoded,
6794 decoded10: u1 = 0b1,
6795 opcode: u5,
6796 Rm: Register.Encoded,
6797 decoded21: u1 = 0b1,
6798 size: Size,
6799 decoded24: u5 = 0b01110,
6800 U: u1,
6801 Q: Q,
6802 decoded31: u1 = 0b0,
6803 };
6804
6805 /// C7.2.5 ADDP (vector)
6806 pub const Addp = packed struct {
6807 Rd: Register.Encoded,
6808 Rn: Register.Encoded,
6809 decoded10: u1 = 0b1,
6810 opcode: u5 = 0b10111,
6811 Rm: Register.Encoded,
6812 decoded21: u1 = 0b1,
6813 size: Size,
6814 decoded24: u5 = 0b01110,
6815 U: u1 = 0b0,
6816 Q: Q,
6817 decoded31: u1 = 0b0,
6818 };
6819
6820 /// C7.2.11 AND (vector)
6821 pub const And = packed struct {
6822 Rd: Register.Encoded,
6823 Rn: Register.Encoded,
6824 decoded10: u1 = 0b1,
6825 opcode: u5 = 0b00011,
6826 Rm: Register.Encoded,
6827 decoded21: u1 = 0b1,
6828 size: Size = .byte,
6829 decoded24: u5 = 0b01110,
6830 U: u1 = 0b0,
6831 Q: Q,
6832 decoded31: u1 = 0b0,
6833 };
6834
6835 /// C7.2.21 BIC (vector, register)
6836 pub const Bic = packed struct {
6837 Rd: Register.Encoded,
6838 Rn: Register.Encoded,
6839 decoded10: u1 = 0b1,
6840 opcode: u5 = 0b00011,
6841 Rm: Register.Encoded,
6842 decoded21: u1 = 0b1,
6843 size: Size = .half,
6844 decoded24: u5 = 0b01110,
6845 U: u1 = 0b0,
6846 Q: Q,
6847 decoded31: u1 = 0b0,
6848 };
6849
6850 /// C7.2.213 ORR (vector, register)
6851 pub const Orr = packed struct {
6852 Rd: Register.Encoded,
6853 Rn: Register.Encoded,
6854 decoded10: u1 = 0b1,
6855 opcode: u5 = 0b00011,
6856 Rm: Register.Encoded,
6857 decoded21: u1 = 0b1,
6858 size: Size = .single,
6859 decoded24: u5 = 0b01110,
6860 U: u1 = 0b0,
6861 Q: Q,
6862 decoded31: u1 = 0b0,
6863 };
6864
6865 /// C7.2.211 ORN (vector)
6866 pub const Orn = packed struct {
6867 Rd: Register.Encoded,
6868 Rn: Register.Encoded,
6869 decoded10: u1 = 0b1,
6870 opcode: u5 = 0b00011,
6871 Rm: Register.Encoded,
6872 decoded21: u1 = 0b1,
6873 size: Size = .double,
6874 decoded24: u5 = 0b01110,
6875 U: u1 = 0b0,
6876 Q: Q,
6877 decoded31: u1 = 0b0,
6878 };
6879
6880 /// C7.2.41 EOR (vector)
6881 pub const Eor = packed struct {
6882 Rd: Register.Encoded,
6883 Rn: Register.Encoded,
6884 decoded10: u1 = 0b1,
6885 opcode: u5 = 0b00011,
6886 Rm: Register.Encoded,
6887 decoded21: u1 = 0b1,
6888 size: Size = .byte,
6889 decoded24: u5 = 0b01110,
6890 U: u1 = 0b1,
6891 Q: Q,
6892 decoded31: u1 = 0b0,
6893 };
6894 };
6895
6896 /// Advanced SIMD modified immediate
6897 pub const SimdModifiedImmediate = packed union {
6898 group: @This().Group,
6899 movi: Movi,
6900 orr: Orr,
6901 fmov: Fmov,
6902 mvni: Mvni,
6903 bic: Bic,
6904
6905 pub const Group = packed struct {
6906 Rd: Register.Encoded,
6907 imm5: u5,
6908 decoded10: u1 = 0b1,
6909 o2: u1,
6910 cmode: u4,
6911 imm3: u3,
6912 decoded19: u10 = 0b0111100000,
6913 op: u1,
6914 Q: Q,
6915 decoded31: u1 = 0b0,
6916 };
6917
6918 /// C7.2.204 MOVI
6919 pub const Movi = packed struct {
6920 Rd: Register.Encoded,
6921 imm5: u5,
6922 decoded10: u1 = 0b1,
6923 o2: u1 = 0b0,
6924 cmode: u4,
6925 imm3: u3,
6926 decoded19: u10 = 0b0111100000,
6927 op: u1,
6928 Q: Q,
6929 decoded31: u1 = 0b0,
6930 };
6931
6932 /// C7.2.212 ORR (vector, immediate)
6933 pub const Orr = packed struct {
6934 Rd: Register.Encoded,
6935 imm5: u5,
6936 decoded10: u1 = 0b1,
6937 o2: u1 = 0b0,
6938 cmode0: u1 = 0b1,
6939 cmode: u3,
6940 imm3: u3,
6941 decoded19: u10 = 0b0111100000,
6942 op: u1 = 0b0,
6943 Q: Q,
6944 decoded31: u1 = 0b0,
6945 };
6946
6947 /// C7.2.129 FMOV (vector, immediate)
6948 pub const Fmov = packed struct {
6949 Rd: Register.Encoded,
6950 imm5: u5,
6951 decoded10: u1 = 0b1,
6952 o2: u1 = 0b1,
6953 cmode: u4 = 0b1111,
6954 imm3: u3,
6955 decoded19: u10 = 0b0111100000,
6956 op: u1 = 0b0,
6957 Q: Q,
6958 decoded31: u1 = 0b0,
6959 };
6960
6961 /// C7.2.208 MVNI
6962 pub const Mvni = packed struct {
6963 Rd: Register.Encoded,
6964 imm5: u5,
6965 decoded10: u1 = 0b1,
6966 o2: u1 = 0b0,
6967 cmode: u4,
6968 imm3: u3,
6969 decoded19: u10 = 0b0111100000,
6970 op: u1 = 0b1,
6971 Q: Q,
6972 decoded31: u1 = 0b0,
6973 };
6974
6975 /// C7.2.20 BIC (vector, immediate)
6976 pub const Bic = packed struct {
6977 Rd: Register.Encoded,
6978 imm5: u5,
6979 decoded10: u1 = 0b1,
6980 o2: u1 = 0b0,
6981 cmode0: u1 = 0b1,
6982 cmode: u3,
6983 imm3: u3,
6984 decoded19: u10 = 0b0111100000,
6985 op: u1 = 0b1,
6986 Q: Q,
6987 decoded31: u1 = 0b0,
6988 };
6989 };
6990
6991 /// Conversion between floating-point and integer
6992 pub const ConvertFloatInteger = packed union {
6993 group: @This().Group,
6994 fcvtns: Fcvtns,
6995 fcvtnu: Fcvtnu,
6996 scvtf: Scvtf,
6997 ucvtf: Ucvtf,
6998 fcvtas: Fcvtas,
6999 fcvtau: Fcvtau,
7000 fmov: Fmov,
7001 fcvtps: Fcvtps,
7002 fcvtpu: Fcvtpu,
7003 fcvtms: Fcvtms,
7004 fcvtmu: Fcvtmu,
7005 fcvtzs: Fcvtzs,
7006 fcvtzu: Fcvtzu,
7007 fjcvtzs: Fjcvtzs,
7008
7009 pub const Group = packed struct {
7010 Rd: Register.Encoded,
7011 Rn: Register.Encoded,
7012 decoded10: u6 = 0b000000,
7013 opcode: u3,
7014 rmode: u2,
7015 decoded21: u1 = 0b1,
7016 ptype: Ftype,
7017 decoded24: u5 = 0b11110,
7018 S: bool,
7019 decoded30: u1 = 0b0,
7020 sf: Register.IntegerSize,
7021 };
7022
7023 /// C7.2.81 FCVTNS (scalar)
7024 pub const Fcvtns = packed struct {
7025 Rd: Register.Encoded,
7026 Rn: Register.Encoded,
7027 decoded10: u6 = 0b000000,
7028 opcode: u3 = 0b000,
7029 rmode: Rmode = .n,
7030 decoded21: u1 = 0b1,
7031 ftype: Ftype,
7032 decoded24: u5 = 0b11110,
7033 S: bool = false,
7034 decoded30: u1 = 0b0,
7035 sf: Register.IntegerSize,
7036 };
7037
7038 /// C7.2.83 FCVTNU (scalar)
7039 pub const Fcvtnu = packed struct {
7040 Rd: Register.Encoded,
7041 Rn: Register.Encoded,
7042 decoded10: u6 = 0b000000,
7043 opcode: u3 = 0b001,
7044 rmode: Rmode = .n,
7045 decoded21: u1 = 0b1,
7046 ftype: Ftype,
7047 decoded24: u5 = 0b11110,
7048 S: bool = false,
7049 decoded30: u1 = 0b0,
7050 sf: Register.IntegerSize,
7051 };
7052
7053 /// C7.2.236 SCVTF (scalar, integer)
7054 pub const Scvtf = packed struct {
7055 Rd: Register.Encoded,
7056 Rn: Register.Encoded,
7057 decoded10: u6 = 0b000000,
7058 opcode: u3 = 0b010,
7059 rmode: Rmode = .n,
7060 decoded21: u1 = 0b1,
7061 ftype: Ftype,
7062 decoded24: u5 = 0b11110,
7063 S: bool = false,
7064 decoded30: u1 = 0b0,
7065 sf: Register.IntegerSize,
7066 };
7067
7068 /// C7.2.355 UCVTF (scalar, integer)
7069 pub const Ucvtf = packed struct {
7070 Rd: Register.Encoded,
7071 Rn: Register.Encoded,
7072 decoded10: u6 = 0b000000,
7073 opcode: u3 = 0b011,
7074 rmode: Rmode = .n,
7075 decoded21: u1 = 0b1,
7076 ftype: Ftype,
7077 decoded24: u5 = 0b11110,
7078 S: bool = false,
7079 decoded30: u1 = 0b0,
7080 sf: Register.IntegerSize,
7081 };
7082
7083 /// C7.2.71 FCVTAS (scalar)
7084 pub const Fcvtas = packed struct {
7085 Rd: Register.Encoded,
7086 Rn: Register.Encoded,
7087 decoded10: u6 = 0b000000,
7088 opcode: u3 = 0b100,
7089 rmode: Rmode = .n,
7090 decoded21: u1 = 0b1,
7091 ftype: Ftype,
7092 decoded24: u5 = 0b11110,
7093 S: bool = false,
7094 decoded30: u1 = 0b0,
7095 sf: Register.IntegerSize,
7096 };
7097
7098 /// C7.2.73 FCVTAU (scalar)
7099 pub const Fcvtau = packed struct {
7100 Rd: Register.Encoded,
7101 Rn: Register.Encoded,
7102 decoded10: u6 = 0b000000,
7103 opcode: u3 = 0b101,
7104 rmode: Rmode = .n,
7105 decoded21: u1 = 0b1,
7106 ftype: Ftype,
7107 decoded24: u5 = 0b11110,
7108 S: bool = false,
7109 decoded30: u1 = 0b0,
7110 sf: Register.IntegerSize,
7111 };
7112
7113 /// C7.2.131 FMOV (general)
7114 pub const Fmov = packed struct {
7115 Rd: Register.Encoded,
7116 Rn: Register.Encoded,
7117 decoded10: u6 = 0b000000,
7118 opcode: Opcode,
7119 rmode: Fmov.Rmode,
7120 decoded21: u1 = 0b1,
7121 ftype: Ftype,
7122 decoded24: u5 = 0b11110,
7123 S: bool = false,
7124 decoded30: u1 = 0b0,
7125 sf: Register.IntegerSize,
7126
7127 pub const Opcode = enum(u3) {
7128 float_to_integer = 0b110,
7129 integer_to_float = 0b111,
7130 _,
7131 };
7132
7133 pub const Rmode = enum(u2) {
7134 @"0" = 0b00,
7135 @"1" = 0b01,
7136 _,
7137 };
7138 };
7139
7140 /// C7.2.85 FCVTPS (scalar)
7141 pub const Fcvtps = packed struct {
7142 Rd: Register.Encoded,
7143 Rn: Register.Encoded,
7144 decoded10: u6 = 0b000000,
7145 opcode: u3 = 0b000,
7146 rmode: Rmode = .p,
7147 decoded21: u1 = 0b1,
7148 ftype: Ftype,
7149 decoded24: u5 = 0b11110,
7150 S: bool = false,
7151 decoded30: u1 = 0b0,
7152 sf: Register.IntegerSize,
7153 };
7154
7155 /// C7.2.87 FCVTPU (scalar)
7156 pub const Fcvtpu = packed struct {
7157 Rd: Register.Encoded,
7158 Rn: Register.Encoded,
7159 decoded10: u6 = 0b000000,
7160 opcode: u3 = 0b001,
7161 rmode: Rmode = .p,
7162 decoded21: u1 = 0b1,
7163 ftype: Ftype,
7164 decoded24: u5 = 0b11110,
7165 S: bool = false,
7166 decoded30: u1 = 0b0,
7167 sf: Register.IntegerSize,
7168 };
7169
7170 /// C7.2.76 FCVTMS (scalar)
7171 pub const Fcvtms = packed struct {
7172 Rd: Register.Encoded,
7173 Rn: Register.Encoded,
7174 decoded10: u6 = 0b000000,
7175 opcode: u3 = 0b000,
7176 rmode: Rmode = .m,
7177 decoded21: u1 = 0b1,
7178 ftype: Ftype,
7179 decoded24: u5 = 0b11110,
7180 S: bool = false,
7181 decoded30: u1 = 0b0,
7182 sf: Register.IntegerSize,
7183 };
7184
7185 /// C7.2.78 FCVTMU (scalar)
7186 pub const Fcvtmu = packed struct {
7187 Rd: Register.Encoded,
7188 Rn: Register.Encoded,
7189 decoded10: u6 = 0b000000,
7190 opcode: u3 = 0b001,
7191 rmode: Rmode = .m,
7192 decoded21: u1 = 0b1,
7193 ftype: Ftype,
7194 decoded24: u5 = 0b11110,
7195 S: bool = false,
7196 decoded30: u1 = 0b0,
7197 sf: Register.IntegerSize,
7198 };
7199
7200 /// C7.2.92 FCVTZS (scalar, integer)
7201 pub const Fcvtzs = packed struct {
7202 Rd: Register.Encoded,
7203 Rn: Register.Encoded,
7204 decoded10: u6 = 0b000000,
7205 opcode: u3 = 0b000,
7206 rmode: Rmode = .z,
7207 decoded21: u1 = 0b1,
7208 ftype: Ftype,
7209 decoded24: u5 = 0b11110,
7210 S: bool = false,
7211 decoded30: u1 = 0b0,
7212 sf: Register.IntegerSize,
7213 };
7214
7215 /// C7.2.96 FCVTZU (scalar, integer)
7216 pub const Fcvtzu = packed struct {
7217 Rd: Register.Encoded,
7218 Rn: Register.Encoded,
7219 decoded10: u6 = 0b000000,
7220 opcode: u3 = 0b001,
7221 rmode: Rmode = .z,
7222 decoded21: u1 = 0b1,
7223 ftype: Ftype,
7224 decoded24: u5 = 0b11110,
7225 S: bool = false,
7226 decoded30: u1 = 0b0,
7227 sf: Register.IntegerSize,
7228 };
7229
7230 /// C7.2.99 FJCVTZS
7231 pub const Fjcvtzs = packed struct {
7232 Rd: Register.Encoded,
7233 Rn: Register.Encoded,
7234 decoded10: u6 = 0b000000,
7235 opcode: u3 = 0b110,
7236 rmode: Rmode = .z,
7237 decoded21: u1 = 0b1,
7238 ftype: Ftype = .double,
7239 decoded24: u5 = 0b11110,
7240 S: bool = false,
7241 decoded30: u1 = 0b0,
7242 sf: Register.IntegerSize = .word,
7243 };
7244
7245 pub const Rmode = enum(u2) {
7246 /// to nearest
7247 n = 0b00,
7248 /// toward plus infinity
7249 p = 0b01,
7250 /// toward minus infinity
7251 m = 0b10,
7252 /// toward zero
7253 z = 0b11,
7254 };
7255 };
7256
7257 /// Floating-point data-processing (1 source)
7258 pub const FloatDataProcessingOneSource = packed union {
7259 group: @This().Group,
7260 fmov: Fmov,
7261 fabs: Fabs,
7262 fneg: Fneg,
7263 fsqrt: Fsqrt,
7264 fcvt: Fcvt,
7265 frintn: Frintn,
7266 frintp: Frintp,
7267 frintm: Frintm,
7268 frintz: Frintz,
7269 frinta: Frinta,
7270 frintx: Frintx,
7271 frinti: Frinti,
7272
7273 pub const Group = packed struct {
7274 Rd: Register.Encoded,
7275 Rn: Register.Encoded,
7276 decoded10: u5 = 0b10000,
7277 opcode: u6,
7278 decoded21: u1 = 0b1,
7279 ptype: Ftype,
7280 decoded24: u5 = 0b11110,
7281 S: bool,
7282 decoded30: u1 = 0b0,
7283 M: u1,
7284 };
7285
7286 /// C7.2.130 FMOV (register)
7287 pub const Fmov = packed struct {
7288 Rd: Register.Encoded,
7289 Rn: Register.Encoded,
7290 decoded10: u5 = 0b10000,
7291 opc: u2 = 0b00,
7292 decoded17: u4 = 0b0000,
7293 decoded21: u1 = 0b1,
7294 ftype: Ftype,
7295 decoded24: u5 = 0b11110,
7296 S: bool = false,
7297 decoded30: u1 = 0b0,
7298 M: u1 = 0b0,
7299 };
7300
7301 /// C7.2.46 FABS (scalar)
7302 pub const Fabs = packed struct {
7303 Rd: Register.Encoded,
7304 Rn: Register.Encoded,
7305 decoded10: u5 = 0b10000,
7306 opc: u2 = 0b01,
7307 decoded17: u4 = 0b0000,
7308 decoded21: u1 = 0b1,
7309 ftype: Ftype,
7310 decoded24: u5 = 0b11110,
7311 S: bool = false,
7312 decoded30: u1 = 0b0,
7313 M: u1 = 0b0,
7314 };
7315
7316 /// C7.2.140 FNEG (scalar)
7317 pub const Fneg = packed struct {
7318 Rd: Register.Encoded,
7319 Rn: Register.Encoded,
7320 decoded10: u5 = 0b10000,
7321 opc: u2 = 0b10,
7322 decoded17: u4 = 0b0000,
7323 decoded21: u1 = 0b1,
7324 ftype: Ftype,
7325 decoded24: u5 = 0b11110,
7326 S: bool = false,
7327 decoded30: u1 = 0b0,
7328 M: u1 = 0b0,
7329 };
7330
7331 /// C7.2.172 FSQRT (scalar)
7332 pub const Fsqrt = packed struct {
7333 Rd: Register.Encoded,
7334 Rn: Register.Encoded,
7335 decoded10: u5 = 0b10000,
7336 opc: u2 = 0b11,
7337 decoded17: u4 = 0b0000,
7338 decoded21: u1 = 0b1,
7339 ftype: Ftype,
7340 decoded24: u5 = 0b11110,
7341 S: bool = false,
7342 decoded30: u1 = 0b0,
7343 M: u1 = 0b0,
7344 };
7345
7346 /// C7.2.69 FCVT
7347 pub const Fcvt = packed struct {
7348 Rd: Register.Encoded,
7349 Rn: Register.Encoded,
7350 decoded10: u5 = 0b10000,
7351 opc: Ftype,
7352 decoded17: u4 = 0b0001,
7353 decoded21: u1 = 0b1,
7354 ftype: Ftype,
7355 decoded24: u5 = 0b11110,
7356 S: bool = false,
7357 decoded30: u1 = 0b0,
7358 M: u1 = 0b0,
7359 };
7360
7361 /// C7.2.162 FRINTN (scalar)
7362 pub const Frintn = packed struct {
7363 Rd: Register.Encoded,
7364 Rn: Register.Encoded,
7365 decoded10: u5 = 0b10000,
7366 rmode: Rmode = .n,
7367 decoded18: u3 = 0b001,
7368 decoded21: u1 = 0b1,
7369 ftype: Ftype,
7370 decoded24: u5 = 0b11110,
7371 S: bool = false,
7372 decoded30: u1 = 0b0,
7373 M: u1 = 0b0,
7374 };
7375
7376 /// C7.2.164 FRINTP (scalar)
7377 pub const Frintp = packed struct {
7378 Rd: Register.Encoded,
7379 Rn: Register.Encoded,
7380 decoded10: u5 = 0b10000,
7381 rmode: Rmode = .p,
7382 decoded18: u3 = 0b001,
7383 decoded21: u1 = 0b1,
7384 ftype: Ftype,
7385 decoded24: u5 = 0b11110,
7386 S: bool = false,
7387 decoded30: u1 = 0b0,
7388 M: u1 = 0b0,
7389 };
7390
7391 /// C7.2.160 FRINTM (scalar)
7392 pub const Frintm = packed struct {
7393 Rd: Register.Encoded,
7394 Rn: Register.Encoded,
7395 decoded10: u5 = 0b10000,
7396 rmode: Rmode = .m,
7397 decoded18: u3 = 0b001,
7398 decoded21: u1 = 0b1,
7399 ftype: Ftype,
7400 decoded24: u5 = 0b11110,
7401 S: bool = false,
7402 decoded30: u1 = 0b0,
7403 M: u1 = 0b0,
7404 };
7405
7406 /// C7.2.168 FRINTZ (scalar)
7407 pub const Frintz = packed struct {
7408 Rd: Register.Encoded,
7409 Rn: Register.Encoded,
7410 decoded10: u5 = 0b10000,
7411 rmode: Rmode = .z,
7412 decoded18: u3 = 0b001,
7413 decoded21: u1 = 0b1,
7414 ftype: Ftype,
7415 decoded24: u5 = 0b11110,
7416 S: bool = false,
7417 decoded30: u1 = 0b0,
7418 M: u1 = 0b0,
7419 };
7420
7421 /// C7.2.156 FRINTA (scalar)
7422 pub const Frinta = packed struct {
7423 Rd: Register.Encoded,
7424 Rn: Register.Encoded,
7425 decoded10: u5 = 0b10000,
7426 rmode: Rmode = .a,
7427 decoded18: u3 = 0b001,
7428 decoded21: u1 = 0b1,
7429 ftype: Ftype,
7430 decoded24: u5 = 0b11110,
7431 S: bool = false,
7432 decoded30: u1 = 0b0,
7433 M: u1 = 0b0,
7434 };
7435
7436 /// C7.2.166 FRINTX (scalar)
7437 pub const Frintx = packed struct {
7438 Rd: Register.Encoded,
7439 Rn: Register.Encoded,
7440 decoded10: u5 = 0b10000,
7441 rmode: Rmode = .x,
7442 decoded18: u3 = 0b001,
7443 decoded21: u1 = 0b1,
7444 ftype: Ftype,
7445 decoded24: u5 = 0b11110,
7446 S: bool = false,
7447 decoded30: u1 = 0b0,
7448 M: u1 = 0b0,
7449 };
7450
7451 /// C7.2.158 FRINTI (scalar)
7452 pub const Frinti = packed struct {
7453 Rd: Register.Encoded,
7454 Rn: Register.Encoded,
7455 decoded10: u5 = 0b10000,
7456 rmode: Rmode = .i,
7457 decoded18: u3 = 0b001,
7458 decoded21: u1 = 0b1,
7459 ftype: Ftype,
7460 decoded24: u5 = 0b11110,
7461 S: bool = false,
7462 decoded30: u1 = 0b0,
7463 M: u1 = 0b0,
7464 };
7465
7466 pub const Rmode = enum(u3) {
7467 /// to nearest with ties to even
7468 n = 0b000,
7469 /// toward plus infinity
7470 p = 0b001,
7471 /// toward minus infinity
7472 m = 0b010,
7473 /// toward zero
7474 z = 0b011,
7475 /// to nearest with ties to away
7476 a = 0b100,
7477 /// exact, using current rounding mode
7478 x = 0b110,
7479 /// using current rounding mode
7480 i = 0b111,
7481 _,
7482 };
7483 };
7484
7485 /// Floating-point compare
7486 pub const FloatCompare = packed union {
7487 group: @This().Group,
7488 fcmp: Fcmp,
7489 fcmpe: Fcmpe,
7490
7491 pub const Group = packed struct {
7492 opcode2: u5,
7493 Rn: Register.Encoded,
7494 decoded10: u4 = 0b1000,
7495 op: u2,
7496 Rm: Register.Encoded,
7497 decoded21: u1 = 0b1,
7498 ptype: Ftype,
7499 decoded24: u5 = 0b11110,
7500 S: bool,
7501 decoded30: u1 = 0b0,
7502 M: u1,
7503 };
7504
7505 /// C7.2.66 FCMP
7506 pub const Fcmp = packed struct {
7507 decoded0: u3 = 0b000,
7508 opc0: Opc0,
7509 opc1: u1 = 0b0,
7510 Rn: Register.Encoded,
7511 decoded10: u4 = 0b1000,
7512 op: u2 = 0b00,
7513 Rm: Register.Encoded,
7514 decoded21: u1 = 0b1,
7515 ftype: Ftype,
7516 decoded24: u5 = 0b11110,
7517 S: bool = false,
7518 decoded30: u1 = 0b0,
7519 M: u1 = 0b0,
7520 };
7521
7522 /// C7.2.67 FCMPE
7523 pub const Fcmpe = packed struct {
7524 decoded0: u3 = 0b000,
7525 opc0: Opc0,
7526 opc1: u1 = 0b1,
7527 Rn: Register.Encoded,
7528 decoded10: u4 = 0b1000,
7529 op: u2 = 0b00,
7530 Rm: Register.Encoded,
7531 decoded21: u1 = 0b1,
7532 ftype: Ftype,
7533 decoded24: u5 = 0b11110,
7534 S: bool = false,
7535 decoded30: u1 = 0b0,
7536 M: u1 = 0b0,
7537 };
7538
7539 pub const Opc0 = enum(u1) {
7540 register = 0b00,
7541 zero = 0b01,
7542 };
7543 };
7544
7545 /// Floating-point immediate
7546 pub const FloatImmediate = packed union {
7547 group: @This().Group,
7548 fmov: Fmov,
7549
7550 pub const Group = packed struct {
7551 Rd: Register.Encoded,
7552 imm5: u5,
7553 decoded10: u3 = 0b100,
7554 imm8: u8,
7555 decoded21: u1 = 0b1,
7556 ptype: Ftype,
7557 decoded24: u5 = 0b11110,
7558 S: bool,
7559 decoded30: u1 = 0b0,
7560 M: u1,
7561 };
7562
7563 /// C7.2.132 FMOV (scalar, immediate)
7564 pub const Fmov = packed struct {
7565 Rd: Register.Encoded,
7566 imm5: u5 = 0b00000,
7567 decoded10: u3 = 0b100,
7568 imm8: u8,
7569 decoded21: u1 = 0b1,
7570 ftype: Ftype,
7571 decoded24: u5 = 0b11110,
7572 S: bool = false,
7573 decoded30: u1 = 0b0,
7574 M: u1 = 0b0,
7575 };
7576 };
7577
7578 /// Floating-point data-processing (2 source)
7579 pub const FloatDataProcessingTwoSource = packed union {
7580 group: @This().Group,
7581 fmul: Fmul,
7582 fdiv: Fdiv,
7583 fadd: Fadd,
7584 fsub: Fsub,
7585 fmax: Fmax,
7586 fmin: Fmin,
7587 fmaxnm: Fmaxnm,
7588 fminnm: Fminnm,
7589 fnmul: Fnmul,
7590
7591 pub const Group = packed struct {
7592 Rd: Register.Encoded,
7593 Rn: Register.Encoded,
7594 decoded10: u2 = 0b10,
7595 opcode: Opcode,
7596 Rm: Register.Encoded,
7597 decoded21: u1 = 0b1,
7598 ptype: Ftype,
7599 decoded24: u5 = 0b11110,
7600 S: bool,
7601 decoded30: u1 = 0b0,
7602 M: u1,
7603 };
7604
7605 /// C7.2.136 FMUL (scalar)
7606 pub const Fmul = packed struct {
7607 Rd: Register.Encoded,
7608 Rn: Register.Encoded,
7609 decoded10: u2 = 0b10,
7610 opcode: Opcode = .fmul,
7611 Rm: Register.Encoded,
7612 decoded21: u1 = 0b1,
7613 ftype: Ftype,
7614 decoded24: u5 = 0b11110,
7615 S: bool = false,
7616 decoded30: u1 = 0b0,
7617 M: u1 = 0b0,
7618 };
7619
7620 /// C7.2.98 FDIV (scalar)
7621 pub const Fdiv = packed struct {
7622 Rd: Register.Encoded,
7623 Rn: Register.Encoded,
7624 decoded10: u2 = 0b10,
7625 opcode: Opcode = .fdiv,
7626 Rm: Register.Encoded,
7627 decoded21: u1 = 0b1,
7628 ftype: Ftype,
7629 decoded24: u5 = 0b11110,
7630 S: bool = false,
7631 decoded30: u1 = 0b0,
7632 M: u1 = 0b0,
7633 };
7634
7635 /// C7.2.50 FADD (scalar)
7636 pub const Fadd = packed struct {
7637 Rd: Register.Encoded,
7638 Rn: Register.Encoded,
7639 decoded10: u2 = 0b10,
7640 opcode: Opcode = .fadd,
7641 Rm: Register.Encoded,
7642 decoded21: u1 = 0b1,
7643 ftype: Ftype,
7644 decoded24: u5 = 0b11110,
7645 S: bool = false,
7646 decoded30: u1 = 0b0,
7647 M: u1 = 0b0,
7648 };
7649
7650 /// C7.2.174 FSUB (scalar)
7651 pub const Fsub = packed struct {
7652 Rd: Register.Encoded,
7653 Rn: Register.Encoded,
7654 decoded10: u2 = 0b10,
7655 opcode: Opcode = .fsub,
7656 Rm: Register.Encoded,
7657 decoded21: u1 = 0b1,
7658 ftype: Ftype,
7659 decoded24: u5 = 0b11110,
7660 S: bool = false,
7661 decoded30: u1 = 0b0,
7662 M: u1 = 0b0,
7663 };
7664
7665 /// C7.2.102 FMAX (scalar)
7666 pub const Fmax = packed struct {
7667 Rd: Register.Encoded,
7668 Rn: Register.Encoded,
7669 decoded10: u2 = 0b10,
7670 opcode: Opcode = .fmax,
7671 Rm: Register.Encoded,
7672 decoded21: u1 = 0b1,
7673 ftype: Ftype,
7674 decoded24: u5 = 0b11110,
7675 S: bool = false,
7676 decoded30: u1 = 0b0,
7677 M: u1 = 0b0,
7678 };
7679
7680 /// C7.2.112 FMIN (scalar)
7681 pub const Fmin = packed struct {
7682 Rd: Register.Encoded,
7683 Rn: Register.Encoded,
7684 decoded10: u2 = 0b10,
7685 opcode: Opcode = .fmin,
7686 Rm: Register.Encoded,
7687 decoded21: u1 = 0b1,
7688 ftype: Ftype,
7689 decoded24: u5 = 0b11110,
7690 S: bool = false,
7691 decoded30: u1 = 0b0,
7692 M: u1 = 0b0,
7693 };
7694
7695 /// C7.2.104 FMAXNM (scalar)
7696 pub const Fmaxnm = packed struct {
7697 Rd: Register.Encoded,
7698 Rn: Register.Encoded,
7699 decoded10: u2 = 0b10,
7700 opcode: Opcode = .fmaxnm,
7701 Rm: Register.Encoded,
7702 decoded21: u1 = 0b1,
7703 ftype: Ftype,
7704 decoded24: u5 = 0b11110,
7705 S: bool = false,
7706 decoded30: u1 = 0b0,
7707 M: u1 = 0b0,
7708 };
7709
7710 /// C7.2.114 FMINNM (scalar)
7711 pub const Fminnm = packed struct {
7712 Rd: Register.Encoded,
7713 Rn: Register.Encoded,
7714 decoded10: u2 = 0b10,
7715 opcode: Opcode = .fminnm,
7716 Rm: Register.Encoded,
7717 decoded21: u1 = 0b1,
7718 ftype: Ftype,
7719 decoded24: u5 = 0b11110,
7720 S: bool = false,
7721 decoded30: u1 = 0b0,
7722 M: u1 = 0b0,
7723 };
7724
7725 /// C7.2.143 FNMUL (scalar)
7726 pub const Fnmul = packed struct {
7727 Rd: Register.Encoded,
7728 Rn: Register.Encoded,
7729 decoded10: u2 = 0b10,
7730 opcode: Opcode = .fnmul,
7731 Rm: Register.Encoded,
7732 decoded21: u1 = 0b1,
7733 ftype: Ftype,
7734 decoded24: u5 = 0b11110,
7735 S: bool = false,
7736 decoded30: u1 = 0b0,
7737 M: u1 = 0b0,
7738 };
7739
7740 pub const Opcode = enum(u4) {
7741 fmul = 0b0000,
7742 fdiv = 0b0001,
7743 fadd = 0b0010,
7744 fsub = 0b0011,
7745 fmax = 0b0100,
7746 fmin = 0b0101,
7747 fmaxnm = 0b0110,
7748 fminnm = 0b0111,
7749 fnmul = 0b1000,
7750 _,
7751 };
7752 };
7753
7754 /// Floating-point data-processing (3 source)
7755 pub const FloatDataProcessingThreeSource = packed union {
7756 group: @This().Group,
7757 fmadd: Fmadd,
7758 fmsub: Fmsub,
7759 fnmadd: Fnmadd,
7760 fnmsub: Fnmsub,
7761
7762 pub const Group = packed struct {
7763 Rd: Register.Encoded,
7764 Rn: Register.Encoded,
7765 Ra: Register.Encoded,
7766 o0: AddSubtractOp,
7767 Rm: Register.Encoded,
7768 o1: u1,
7769 ptype: Ftype,
7770 decoded24: u5 = 0b11111,
7771 S: bool,
7772 decoded30: u1 = 0b0,
7773 M: u1,
7774 };
7775
7776 /// C7.2.100 FMADD
7777 pub const Fmadd = packed struct {
7778 Rd: Register.Encoded,
7779 Rn: Register.Encoded,
7780 Ra: Register.Encoded,
7781 o0: AddSubtractOp = .add,
7782 Rm: Register.Encoded,
7783 o1: O1 = .fm,
7784 ftype: Ftype,
7785 decoded24: u5 = 0b11111,
7786 S: bool = false,
7787 decoded30: u1 = 0b0,
7788 M: u1 = 0b0,
7789 };
7790
7791 /// C7.2.133 FMSUB
7792 pub const Fmsub = packed struct {
7793 Rd: Register.Encoded,
7794 Rn: Register.Encoded,
7795 Ra: Register.Encoded,
7796 o0: AddSubtractOp = .sub,
7797 Rm: Register.Encoded,
7798 o1: O1 = .fm,
7799 ftype: Ftype,
7800 decoded24: u5 = 0b11111,
7801 S: bool = false,
7802 decoded30: u1 = 0b0,
7803 M: u1 = 0b0,
7804 };
7805
7806 /// C7.2.141 FNMADD
7807 pub const Fnmadd = packed struct {
7808 Rd: Register.Encoded,
7809 Rn: Register.Encoded,
7810 Ra: Register.Encoded,
7811 o0: AddSubtractOp = .add,
7812 Rm: Register.Encoded,
7813 o1: O1 = .fnm,
7814 ftype: Ftype,
7815 decoded24: u5 = 0b11111,
7816 S: bool = false,
7817 decoded30: u1 = 0b0,
7818 M: u1 = 0b0,
7819 };
7820
7821 /// C7.2.142 FNMSUB
7822 pub const Fnmsub = packed struct {
7823 Rd: Register.Encoded,
7824 Rn: Register.Encoded,
7825 Ra: Register.Encoded,
7826 o0: AddSubtractOp = .sub,
7827 Rm: Register.Encoded,
7828 o1: O1 = .fnm,
7829 ftype: Ftype,
7830 decoded24: u5 = 0b11111,
7831 S: bool = false,
7832 decoded30: u1 = 0b0,
7833 M: u1 = 0b0,
7834 };
7835
7836 pub const O1 = enum(u1) {
7837 fm = 0b0,
7838 fnm = 0b1,
7839 };
7840 };
7841
7842 pub const Q = enum(u1) {
7843 double = 0b0,
7844 quad = 0b1,
7845 };
7846
7847 pub const Size = enum(u2) {
7848 byte = 0b00,
7849 half = 0b01,
7850 single = 0b10,
7851 double = 0b11,
7852
7853 pub fn toVectorSize(s: Size) Register.VectorSize {
7854 return switch (s) {
7855 .byte => .byte,
7856 .half => .half,
7857 .single => .single,
7858 .double => .double,
7859 };
7860 }
7861
7862 pub fn fromVectorSize(vs: Register.VectorSize) Size {
7863 return switch (vs) {
7864 .byte => .byte,
7865 .half => .half,
7866 .single => .single,
7867 .double => .double,
7868 };
7869 }
7870 };
7871
7872 pub const Ftype = enum(u2) {
7873 single = 0b00,
7874 double = 0b01,
7875 quad = 0b10,
7876 half = 0b11,
7877 };
7878 };
7879
7880 pub const AddSubtractOp = enum(u1) {
7881 add = 0b0,
7882 sub = 0b1,
7883 };
7884
7885 pub const LogicalOpc = enum(u2) {
7886 @"and" = 0b00,
7887 orr = 0b01,
7888 eor = 0b10,
7889 ands = 0b11,
7890 };
7891
7892 pub const Decoded = union(enum) {
7893 unallocated,
7894 reserved: Reserved,
7895 sme: Sme,
7896 sve: Sve,
7897 data_processing_immediate: DataProcessingImmediate,
7898 branch_exception_generating_system: BranchExceptionGeneratingSystem,
7899 load_store: LoadStore,
7900 data_processing_register: DataProcessingRegister,
7901 data_processing_vector: DataProcessingVector,
7902 };
7903 pub fn decode(inst: @This()) @This().Decoded {
7904 return switch (inst.group.op1) {
7905 0b0000 => switch (inst.group.op0) {
7906 0b0 => .{ .reserved = inst.reserved },
7907 0b1 => .{ .sme = inst.sme },
7908 },
7909 0b0001 => .unallocated,
7910 0b0010 => .{ .sve = inst.sve },
7911 0b0011 => .unallocated,
7912 0b1000, 0b1001 => .{ .data_processing_immediate = inst.data_processing_immediate },
7913 0b1010, 0b1011 => .{ .branch_exception_generating_system = inst.branch_exception_generating_system },
7914 0b0100, 0b0110, 0b1100, 0b1110 => .{ .load_store = inst.load_store },
7915 0b0101, 0b1101 => .{ .data_processing_register = inst.data_processing_register },
7916 0b0111, 0b1111 => .{ .data_processing_vector = inst.data_processing_vector },
7917 };
7918 }
7919
7920 /// C6.2.1 ADC
7921 pub fn adc(d: Register, n: Register, m: Register) Instruction {
7922 const sf = d.format.integer;
7923 assert(n.format.integer == sf and m.format.integer == sf);
7924 return .{ .data_processing_register = .{ .add_subtract_with_carry = .{
7925 .adc = .{
7926 .Rd = d.alias.encode(.{}),
7927 .Rn = n.alias.encode(.{}),
7928 .Rm = m.alias.encode(.{}),
7929 .sf = sf,
7930 },
7931 } } };
7932 }
7933 /// C6.2.2 ADCS
7934 pub fn adcs(d: Register, n: Register, m: Register) Instruction {
7935 const sf = d.format.integer;
7936 assert(n.format.integer == sf and m.format.integer == sf);
7937 return .{ .data_processing_register = .{ .add_subtract_with_carry = .{
7938 .adcs = .{
7939 .Rd = d.alias.encode(.{}),
7940 .Rn = n.alias.encode(.{}),
7941 .Rm = m.alias.encode(.{}),
7942 .sf = sf,
7943 },
7944 } } };
7945 }
7946 /// C6.2.3 ADD (extended register)
7947 /// C6.2.4 ADD (immediate)
7948 /// C6.2.5 ADD (shifted register)
7949 pub fn add(d: Register, n: Register, form: union(enum) {
7950 extended_register_explicit: struct {
7951 register: Register,
7952 option: DataProcessingRegister.AddSubtractExtendedRegister.Option,
7953 amount: DataProcessingRegister.AddSubtractExtendedRegister.Extend.Amount,
7954 },
7955 extended_register: struct { register: Register, extend: DataProcessingRegister.AddSubtractExtendedRegister.Extend },
7956 immediate: u12,
7957 shifted_immediate: struct { immediate: u12, lsl: DataProcessingImmediate.AddSubtractImmediate.Shift = .@"0" },
7958 register: Register,
7959 shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
7960 shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
7961 }) Instruction {
7962 const sf = d.format.integer;
7963 assert(n.format.integer == sf);
7964 form: switch (form) {
7965 .extended_register_explicit => |extended_register_explicit| {
7966 assert(extended_register_explicit.register.format.integer == extended_register_explicit.option.sf());
7967 return .{ .data_processing_register = .{ .add_subtract_extended_register = .{
7968 .add = .{
7969 .Rd = d.alias.encode(.{ .sp = true }),
7970 .Rn = n.alias.encode(.{ .sp = true }),
7971 .imm3 = switch (extended_register_explicit.amount) {
7972 0...4 => |amount| amount,
7973 else => unreachable,
7974 },
7975 .option = extended_register_explicit.option,
7976 .Rm = extended_register_explicit.register.alias.encode(.{}),
7977 .sf = sf,
7978 },
7979 } } };
7980 },
7981 .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
7982 .register = extended_register.register,
7983 .option = extended_register.extend,
7984 .amount = switch (extended_register.extend) {
7985 .uxtb, .uxth, .uxtw, .uxtx, .sxtb, .sxth, .sxtw, .sxtx => |amount| amount,
7986 },
7987 } },
7988 .immediate => |immediate| continue :form .{ .shifted_immediate = .{ .immediate = immediate } },
7989 .shifted_immediate => |shifted_immediate| {
7990 return .{ .data_processing_immediate = .{ .add_subtract_immediate = .{
7991 .add = .{
7992 .Rd = d.alias.encode(.{ .sp = true }),
7993 .Rn = n.alias.encode(.{ .sp = true }),
7994 .imm12 = shifted_immediate.immediate,
7995 .sh = shifted_immediate.lsl,
7996 .sf = sf,
7997 },
7998 } } };
7999 },
8000 .register => |register| continue :form if (d.alias == .sp or n.alias == .sp or register.alias == .sp)
8001 .{ .extended_register = .{ .register = register, .extend = switch (sf) {
8002 .word => .{ .uxtw = 0 },
8003 .doubleword => .{ .uxtx = 0 },
8004 } } }
8005 else
8006 .{ .shifted_register = .{ .register = register } },
8007 .shifted_register_explicit => |shifted_register_explicit| {
8008 assert(shifted_register_explicit.register.format.integer == sf);
8009 return .{ .data_processing_register = .{ .add_subtract_shifted_register = .{
8010 .add = .{
8011 .Rd = d.alias.encode(.{}),
8012 .Rn = n.alias.encode(.{}),
8013 .imm6 = switch (sf) {
8014 .word => @as(u5, @intCast(shifted_register_explicit.amount)),
8015 .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
8016 },
8017 .Rm = shifted_register_explicit.register.alias.encode(.{}),
8018 .shift = switch (shifted_register_explicit.shift) {
8019 .lsl, .lsr, .asr => |shift| shift,
8020 .ror => unreachable,
8021 },
8022 .sf = sf,
8023 },
8024 } } };
8025 },
8026 .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
8027 .register = shifted_register.register,
8028 .shift = shifted_register.shift,
8029 .amount = switch (shifted_register.shift) {
8030 .lsl, .lsr, .asr => |amount| amount,
8031 .ror => unreachable,
8032 },
8033 } },
8034 }
8035 }
8036 /// C7.2.4 ADDP (scalar)
8037 /// C7.2.5 ADDP (vector)
8038 pub fn addp(d: Register, n: Register, form: union(enum) {
8039 scalar,
8040 vector: Register,
8041 }) Instruction {
8042 switch (form) {
8043 .scalar => {
8044 assert(d.format.scalar == .double and n.format.vector == .@"2d");
8045 return .{ .data_processing_vector = .{ .simd_scalar_pairwise = .{
8046 .addp = .{
8047 .Rd = d.alias.encode(.{ .V = true }),
8048 .Rn = n.alias.encode(.{ .V = true }),
8049 .size = .double,
8050 },
8051 } } };
8052 },
8053 .vector => |m| {
8054 const arrangement = d.format.vector;
8055 assert(arrangement != .@"1d" and n.format.vector == arrangement and m.format.vector == arrangement);
8056 return .{ .data_processing_vector = .{ .simd_three_same = .{
8057 .addp = .{
8058 .Rd = d.alias.encode(.{ .V = true }),
8059 .Rn = n.alias.encode(.{ .V = true }),
8060 .Rm = m.alias.encode(.{ .V = true }),
8061 .size = arrangement.elemSize(),
8062 .Q = arrangement.size(),
8063 },
8064 } } };
8065 },
8066 }
8067 }
8068 /// C6.2.7 ADDS (extended register)
8069 /// C6.2.8 ADDS (immediate)
8070 /// C6.2.9 ADDS (shifted register)
8071 pub fn adds(d: Register, n: Register, form: union(enum) {
8072 extended_register_explicit: struct {
8073 register: Register,
8074 option: DataProcessingRegister.AddSubtractExtendedRegister.Option,
8075 amount: DataProcessingRegister.AddSubtractExtendedRegister.Extend.Amount,
8076 },
8077 extended_register: struct { register: Register, extend: DataProcessingRegister.AddSubtractExtendedRegister.Extend },
8078 immediate: u12,
8079 shifted_immediate: struct { immediate: u12, lsl: DataProcessingImmediate.AddSubtractImmediate.Shift = .@"0" },
8080 register: Register,
8081 shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
8082 shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
8083 }) Instruction {
8084 const sf = d.format.integer;
8085 assert(n.format.integer == sf);
8086 form: switch (form) {
8087 .extended_register_explicit => |extended_register_explicit| {
8088 assert(extended_register_explicit.register.format.integer == extended_register_explicit.option.sf());
8089 return .{ .data_processing_register = .{ .add_subtract_extended_register = .{
8090 .adds = .{
8091 .Rd = d.alias.encode(.{}),
8092 .Rn = n.alias.encode(.{ .sp = true }),
8093 .imm3 = switch (extended_register_explicit.amount) {
8094 0...4 => |amount| amount,
8095 else => unreachable,
8096 },
8097 .option = extended_register_explicit.option,
8098 .Rm = extended_register_explicit.register.alias.encode(.{}),
8099 .sf = sf,
8100 },
8101 } } };
8102 },
8103 .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
8104 .register = extended_register.register,
8105 .option = extended_register.extend,
8106 .amount = switch (extended_register.extend) {
8107 .uxtb, .uxth, .uxtw, .uxtx, .sxtb, .sxth, .sxtw, .sxtx => |amount| amount,
8108 },
8109 } },
8110 .immediate => |immediate| continue :form .{ .shifted_immediate = .{ .immediate = immediate } },
8111 .shifted_immediate => |shifted_immediate| {
8112 return .{ .data_processing_immediate = .{ .add_subtract_immediate = .{
8113 .adds = .{
8114 .Rd = d.alias.encode(.{}),
8115 .Rn = n.alias.encode(.{ .sp = true }),
8116 .imm12 = shifted_immediate.immediate,
8117 .sh = shifted_immediate.lsl,
8118 .sf = sf,
8119 },
8120 } } };
8121 },
8122 .register => |register| continue :form if (d.alias == .sp or n.alias == .sp or register.alias == .sp)
8123 .{ .extended_register = .{ .register = register, .extend = switch (sf) {
8124 .word => .{ .uxtw = 0 },
8125 .doubleword => .{ .uxtx = 0 },
8126 } } }
8127 else
8128 .{ .shifted_register = .{ .register = register } },
8129 .shifted_register_explicit => |shifted_register_explicit| {
8130 assert(shifted_register_explicit.register.format.integer == sf);
8131 return .{ .data_processing_register = .{ .add_subtract_shifted_register = .{
8132 .adds = .{
8133 .Rd = d.alias.encode(.{}),
8134 .Rn = n.alias.encode(.{}),
8135 .imm6 = switch (sf) {
8136 .word => @as(u5, @intCast(shifted_register_explicit.amount)),
8137 .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
8138 },
8139 .Rm = shifted_register_explicit.register.alias.encode(.{}),
8140 .shift = switch (shifted_register_explicit.shift) {
8141 .lsl, .lsr, .asr => |shift| shift,
8142 .ror => unreachable,
8143 },
8144 .sf = sf,
8145 },
8146 } } };
8147 },
8148 .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
8149 .register = shifted_register.register,
8150 .shift = shifted_register.shift,
8151 .amount = switch (shifted_register.shift) {
8152 .lsl, .lsr, .asr => |amount| amount,
8153 .ror => unreachable,
8154 },
8155 } },
8156 }
8157 }
8158 /// C7.2.6 ADDV
8159 pub fn addv(d: Register, n: Register) Instruction {
8160 const arrangement = n.format.vector;
8161 assert(arrangement.len() > 2 and d.format.scalar == arrangement.elemSize().toVectorSize());
8162 return .{ .data_processing_vector = .{ .simd_across_lanes = .{
8163 .addv = .{
8164 .Rd = d.alias.encode(.{ .V = true }),
8165 .Rn = n.alias.encode(.{ .V = true }),
8166 .size = arrangement.elemSize(),
8167 .Q = arrangement.size(),
8168 },
8169 } } };
8170 }
8171 /// C6.2.10 ADR
8172 pub fn adr(d: Register, label: i21) Instruction {
8173 assert(d.format.integer == .doubleword);
8174 return .{ .data_processing_immediate = .{ .pc_relative_addressing = .{
8175 .adr = .{
8176 .Rd = d.alias.encode(.{}),
8177 .immhi = @intCast(label >> 2),
8178 .immlo = @truncate(@as(u21, @bitCast(label))),
8179 },
8180 } } };
8181 }
8182 /// C6.2.11 ADRP
8183 pub fn adrp(d: Register, label: i33) Instruction {
8184 assert(d.format.integer == .doubleword);
8185 const imm: i21 = @intCast(@shrExact(label, 12));
8186 return .{ .data_processing_immediate = .{ .pc_relative_addressing = .{
8187 .adrp = .{
8188 .Rd = d.alias.encode(.{}),
8189 .immhi = @intCast(imm >> 2),
8190 .immlo = @truncate(@as(u21, @bitCast(imm))),
8191 },
8192 } } };
8193 }
8194 /// C6.2.12 AND (immediate)
8195 /// C6.2.13 AND (shifted register)
8196 /// C7.2.11 AND (vector)
8197 pub fn @"and"(d: Register, n: Register, form: union(enum) {
8198 immediate: DataProcessingImmediate.Bitmask,
8199 register: Register,
8200 shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
8201 shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
8202 }) Instruction {
8203 switch (d.format) {
8204 else => unreachable,
8205 .integer => |sf| {
8206 assert(n.format.integer == sf);
8207 form: switch (form) {
8208 .immediate => |bitmask| {
8209 assert(bitmask.validImmediate(sf));
8210 return .{ .data_processing_immediate = .{ .logical_immediate = .{
8211 .@"and" = .{
8212 .Rd = d.alias.encode(.{ .sp = true }),
8213 .Rn = n.alias.encode(.{}),
8214 .imm = bitmask,
8215 .sf = sf,
8216 },
8217 } } };
8218 },
8219 .register => |register| continue :form .{ .shifted_register = .{ .register = register } },
8220 .shifted_register_explicit => |shifted_register_explicit| {
8221 assert(shifted_register_explicit.register.format.integer == sf);
8222 return .{ .data_processing_register = .{ .logical_shifted_register = .{
8223 .@"and" = .{
8224 .Rd = d.alias.encode(.{}),
8225 .Rn = n.alias.encode(.{}),
8226 .imm6 = switch (sf) {
8227 .word => @as(u5, @intCast(shifted_register_explicit.amount)),
8228 .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
8229 },
8230 .Rm = shifted_register_explicit.register.alias.encode(.{}),
8231 .shift = shifted_register_explicit.shift,
8232 .sf = sf,
8233 },
8234 } } };
8235 },
8236 .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
8237 .register = shifted_register.register,
8238 .shift = shifted_register.shift,
8239 .amount = switch (shifted_register.shift) {
8240 .lsl, .lsr, .asr, .ror => |amount| amount,
8241 },
8242 } },
8243 }
8244 },
8245 .vector => |arrangement| {
8246 const m = form.register;
8247 assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement);
8248 return .{ .data_processing_vector = .{ .simd_three_same = .{
8249 .@"and" = .{
8250 .Rd = d.alias.encode(.{ .V = true }),
8251 .Rn = n.alias.encode(.{ .V = true }),
8252 .Rm = m.alias.encode(.{ .V = true }),
8253 .Q = arrangement.size(),
8254 },
8255 } } };
8256 },
8257 }
8258 }
8259 /// C6.2.14 ANDS (immediate)
8260 /// C6.2.15 ANDS (shifted register)
8261 pub fn ands(d: Register, n: Register, form: union(enum) {
8262 immediate: DataProcessingImmediate.Bitmask,
8263 register: Register,
8264 shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
8265 shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
8266 }) Instruction {
8267 const sf = d.format.integer;
8268 assert(n.format.integer == sf);
8269 form: switch (form) {
8270 .immediate => |bitmask| {
8271 assert(bitmask.validImmediate(sf));
8272 return .{ .data_processing_immediate = .{ .logical_immediate = .{
8273 .ands = .{
8274 .Rd = d.alias.encode(.{}),
8275 .Rn = n.alias.encode(.{}),
8276 .imm = bitmask,
8277 .sf = sf,
8278 },
8279 } } };
8280 },
8281 .register => |register| continue :form .{ .shifted_register = .{ .register = register } },
8282 .shifted_register_explicit => |shifted_register_explicit| {
8283 assert(shifted_register_explicit.register.format.integer == sf);
8284 return .{ .data_processing_register = .{ .logical_shifted_register = .{
8285 .ands = .{
8286 .Rd = d.alias.encode(.{}),
8287 .Rn = n.alias.encode(.{}),
8288 .imm6 = switch (sf) {
8289 .word => @as(u5, @intCast(shifted_register_explicit.amount)),
8290 .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
8291 },
8292 .Rm = shifted_register_explicit.register.alias.encode(.{}),
8293 .shift = shifted_register_explicit.shift,
8294 .sf = sf,
8295 },
8296 } } };
8297 },
8298 .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
8299 .register = shifted_register.register,
8300 .shift = shifted_register.shift,
8301 .amount = switch (shifted_register.shift) {
8302 .lsl, .lsr, .asr, .ror => |amount| amount,
8303 },
8304 } },
8305 }
8306 }
8307 /// C6.2.18 ASRV
8308 pub fn asrv(d: Register, n: Register, m: Register) Instruction {
8309 const sf = d.format.integer;
8310 assert(n.format.integer == sf and m.format.integer == sf);
8311 return .{ .data_processing_register = .{ .data_processing_two_source = .{
8312 .asrv = .{
8313 .Rd = d.alias.encode(.{}),
8314 .Rn = n.alias.encode(.{}),
8315 .Rm = m.alias.encode(.{}),
8316 .sf = sf,
8317 },
8318 } } };
8319 }
8320 /// C6.2.25 B
8321 pub fn b(label: i28) Instruction {
8322 return .{ .branch_exception_generating_system = .{ .unconditional_branch_immediate = .{
8323 .b = .{ .imm26 = @intCast(@shrExact(label, 2)) },
8324 } } };
8325 }
8326 /// C6.2.26 B.cond
8327 pub fn @"b."(cond: ConditionCode, label: i21) Instruction {
8328 return .{ .branch_exception_generating_system = .{ .conditional_branch_immediate = .{
8329 .b = .{
8330 .cond = cond,
8331 .imm19 = @intCast(@shrExact(label, 2)),
8332 },
8333 } } };
8334 }
8335 /// C6.2.27 BC.cond
8336 pub fn @"bc."(cond: ConditionCode, label: i21) Instruction {
8337 return .{ .branch_exception_generating_system = .{ .conditional_branch_immediate = .{
8338 .bc = .{
8339 .cond = cond,
8340 .imm19 = @intCast(@shrExact(label, 2)),
8341 },
8342 } } };
8343 }
8344 /// C6.2.30 BFM
8345 pub fn bfm(d: Register, n: Register, bitmask: DataProcessingImmediate.Bitmask) Instruction {
8346 const sf = d.format.integer;
8347 assert(n.format.integer == sf and bitmask.validBitfield(sf));
8348 return .{ .data_processing_immediate = .{ .bitfield = .{
8349 .bfm = .{
8350 .Rd = d.alias.encode(.{}),
8351 .Rn = n.alias.encode(.{}),
8352 .imm = bitmask,
8353 .sf = sf,
8354 },
8355 } } };
8356 }
8357 /// C6.2.32 BIC (shifted register)
8358 /// C7.2.20 BIC (vector, immediate)
8359 /// C7.2.21 BIC (vector, register)
8360 pub fn bic(d: Register, n: Register, form: union(enum) {
8361 shifted_immediate: struct { immediate: u8, lsl: u5 = 0 },
8362 register: Register,
8363 shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
8364 shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
8365 }) Instruction {
8366 switch (d.format) {
8367 else => unreachable,
8368 .integer => |sf| {
8369 assert(n.format.integer == sf);
8370 form: switch (form) {
8371 else => unreachable,
8372 .register => |register| continue :form .{ .shifted_register = .{ .register = register } },
8373 .shifted_register_explicit => |shifted_register_explicit| {
8374 assert(shifted_register_explicit.register.format.integer == sf);
8375 return .{ .data_processing_register = .{ .logical_shifted_register = .{
8376 .bic = .{
8377 .Rd = d.alias.encode(.{}),
8378 .Rn = n.alias.encode(.{}),
8379 .imm6 = switch (sf) {
8380 .word => @as(u5, @intCast(shifted_register_explicit.amount)),
8381 .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
8382 },
8383 .Rm = shifted_register_explicit.register.alias.encode(.{}),
8384 .shift = shifted_register_explicit.shift,
8385 .sf = sf,
8386 },
8387 } } };
8388 },
8389 .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
8390 .register = shifted_register.register,
8391 .shift = shifted_register.shift,
8392 .amount = switch (shifted_register.shift) {
8393 .lsl, .lsr, .asr, .ror => |amount| amount,
8394 },
8395 } },
8396 }
8397 },
8398 .vector => |arrangement| switch (form) {
8399 else => unreachable,
8400 .shifted_immediate => |shifted_immediate| {
8401 assert(n.alias == d.alias and n.format.vector == arrangement);
8402 return .{ .data_processing_vector = .{ .simd_modified_immediate = .{
8403 .bic = .{
8404 .Rd = d.alias.encode(.{ .V = true }),
8405 .imm5 = @truncate(shifted_immediate.immediate >> 0),
8406 .cmode = switch (arrangement) {
8407 else => unreachable,
8408 .@"4h", .@"8h" => @as(u3, 0b100) |
8409 @as(u3, @as(u1, @intCast(@shrExact(shifted_immediate.lsl, 3)))) << 0,
8410 .@"2s", .@"4s" => @as(u3, 0b000) |
8411 @as(u3, @as(u2, @intCast(@shrExact(shifted_immediate.lsl, 3)))) << 0,
8412 },
8413 .imm3 = @intCast(shifted_immediate.immediate >> 5),
8414 .Q = arrangement.size(),
8415 },
8416 } } };
8417 },
8418 .register => |m| {
8419 assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement);
8420 return .{ .data_processing_vector = .{ .simd_three_same = .{
8421 .bic = .{
8422 .Rd = d.alias.encode(.{ .V = true }),
8423 .Rn = n.alias.encode(.{ .V = true }),
8424 .Rm = m.alias.encode(.{ .V = true }),
8425 .Q = arrangement.size(),
8426 },
8427 } } };
8428 },
8429 },
8430 }
8431 }
8432 /// C6.2.33 BICS (shifted register)
8433 pub fn bics(d: Register, n: Register, form: union(enum) {
8434 register: Register,
8435 shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
8436 shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
8437 }) Instruction {
8438 const sf = d.format.integer;
8439 assert(n.format.integer == sf);
8440 form: switch (form) {
8441 .register => |register| continue :form .{ .shifted_register = .{ .register = register } },
8442 .shifted_register_explicit => |shifted_register_explicit| {
8443 assert(shifted_register_explicit.register.format.integer == sf);
8444 return .{ .data_processing_register = .{ .logical_shifted_register = .{
8445 .bics = .{
8446 .Rd = d.alias.encode(.{}),
8447 .Rn = n.alias.encode(.{}),
8448 .imm6 = switch (sf) {
8449 .word => @as(u5, @intCast(shifted_register_explicit.amount)),
8450 .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
8451 },
8452 .Rm = shifted_register_explicit.register.alias.encode(.{}),
8453 .shift = shifted_register_explicit.shift,
8454 .sf = sf,
8455 },
8456 } } };
8457 },
8458 .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
8459 .register = shifted_register.register,
8460 .shift = shifted_register.shift,
8461 .amount = switch (shifted_register.shift) {
8462 .lsl, .lsr, .asr, .ror => |amount| amount,
8463 },
8464 } },
8465 }
8466 }
8467 /// C6.2.34 BL
8468 pub fn bl(label: i28) Instruction {
8469 return .{ .branch_exception_generating_system = .{ .unconditional_branch_immediate = .{
8470 .bl = .{ .imm26 = @intCast(@shrExact(label, 2)) },
8471 } } };
8472 }
8473 /// C6.2.35 BLR
8474 pub fn blr(n: Register) Instruction {
8475 assert(n.format.integer == .doubleword);
8476 return .{ .branch_exception_generating_system = .{ .unconditional_branch_register = .{
8477 .blr = .{ .Rn = n.alias.encode(.{}) },
8478 } } };
8479 }
8480 /// C6.2.37 BR
8481 pub fn br(n: Register) Instruction {
8482 assert(n.format.integer == .doubleword);
8483 return .{ .branch_exception_generating_system = .{ .unconditional_branch_register = .{
8484 .br = .{ .Rn = n.alias.encode(.{}) },
8485 } } };
8486 }
8487 /// C6.2.40 BRK
8488 pub fn brk(imm: u16) Instruction {
8489 return .{ .branch_exception_generating_system = .{ .exception_generating = .{
8490 .brk = .{ .imm16 = imm },
8491 } } };
8492 }
8493 /// C6.2.46 CBNZ
8494 pub fn cbnz(t: Register, label: i21) Instruction {
8495 return .{ .branch_exception_generating_system = .{ .compare_branch_immediate = .{
8496 .cbnz = .{
8497 .Rt = t.alias.encode(.{}),
8498 .imm19 = @intCast(@shrExact(label, 2)),
8499 .sf = t.format.integer,
8500 },
8501 } } };
8502 }
8503 /// C6.2.47 CBZ
8504 pub fn cbz(t: Register, label: i21) Instruction {
8505 return .{ .branch_exception_generating_system = .{ .compare_branch_immediate = .{
8506 .cbz = .{
8507 .Rt = t.alias.encode(.{}),
8508 .imm19 = @intCast(@shrExact(label, 2)),
8509 .sf = t.format.integer,
8510 },
8511 } } };
8512 }
8513 /// C6.2.48 CCMN (immediate)
8514 /// C6.2.49 CCMN (register)
8515 pub fn ccmn(
8516 n: Register,
8517 form: union(enum) { register: Register, immediate: u5 },
8518 nzcv: DataProcessingRegister.Nzcv,
8519 cond: ConditionCode,
8520 ) Instruction {
8521 const sf = n.format.integer;
8522 switch (form) {
8523 .register => |m| {
8524 assert(m.format.integer == sf);
8525 return .{ .data_processing_register = .{ .conditional_compare_register = .{
8526 .ccmn = .{
8527 .nzcv = nzcv,
8528 .Rn = n.alias.encode(.{}),
8529 .cond = cond,
8530 .Rm = m.alias.encode(.{}),
8531 .sf = sf,
8532 },
8533 } } };
8534 },
8535 .immediate => |imm| return .{ .data_processing_register = .{ .conditional_compare_immediate = .{
8536 .ccmn = .{
8537 .nzcv = nzcv,
8538 .Rn = n.alias.encode(.{}),
8539 .cond = cond,
8540 .imm5 = imm,
8541 .sf = sf,
8542 },
8543 } } },
8544 }
8545 }
8546 /// C6.2.50 CCMP (immediate)
8547 /// C6.2.51 CCMP (register)
8548 pub fn ccmp(
8549 n: Register,
8550 form: union(enum) { register: Register, immediate: u5 },
8551 nzcv: DataProcessingRegister.Nzcv,
8552 cond: ConditionCode,
8553 ) Instruction {
8554 const sf = n.format.integer;
8555 switch (form) {
8556 .register => |m| {
8557 assert(m.format.integer == sf);
8558 return .{ .data_processing_register = .{ .conditional_compare_register = .{
8559 .ccmp = .{
8560 .nzcv = nzcv,
8561 .Rn = n.alias.encode(.{}),
8562 .cond = cond,
8563 .Rm = m.alias.encode(.{}),
8564 .sf = sf,
8565 },
8566 } } };
8567 },
8568 .immediate => |imm| return .{ .data_processing_register = .{ .conditional_compare_immediate = .{
8569 .ccmp = .{
8570 .nzcv = nzcv,
8571 .Rn = n.alias.encode(.{}),
8572 .cond = cond,
8573 .imm5 = imm,
8574 .sf = sf,
8575 },
8576 } } },
8577 }
8578 }
8579 /// C6.2.56 CLREX
8580 pub fn clrex(imm: u4) Instruction {
8581 return .{ .branch_exception_generating_system = .{ .barriers = .{
8582 .clrex = .{
8583 .CRm = imm,
8584 },
8585 } } };
8586 }
8587 /// C6.2.58 CLZ
8588 pub fn clz(d: Register, n: Register) Instruction {
8589 const sf = d.format.integer;
8590 assert(n.format.integer == sf);
8591 return .{ .data_processing_register = .{ .data_processing_one_source = .{
8592 .clz = .{
8593 .Rd = d.alias.encode(.{}),
8594 .Rn = n.alias.encode(.{}),
8595 .sf = sf,
8596 },
8597 } } };
8598 }
8599 /// C7.2.38 CNT
8600 pub fn cnt(d: Register, n: Register) Instruction {
8601 const arrangement = d.format.vector;
8602 assert(arrangement.elemSize() == .byte and n.format.vector == arrangement);
8603 return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
8604 .cnt = .{
8605 .Rd = d.alias.encode(.{ .V = true }),
8606 .Rn = n.alias.encode(.{ .V = true }),
8607 .size = arrangement.elemSize(),
8608 .Q = arrangement.size(),
8609 },
8610 } } };
8611 }
8612 /// C6.2.103 CSEL
8613 pub fn csel(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction {
8614 const sf = d.format.integer;
8615 assert(n.format.integer == sf and m.format.integer == sf);
8616 return .{ .data_processing_register = .{ .conditional_select = .{
8617 .csel = .{
8618 .Rd = d.alias.encode(.{}),
8619 .Rn = n.alias.encode(.{}),
8620 .cond = cond,
8621 .Rm = m.alias.encode(.{}),
8622 .sf = sf,
8623 },
8624 } } };
8625 }
8626 /// C6.2.106 CSINC
8627 pub fn csinc(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction {
8628 const sf = d.format.integer;
8629 assert(n.format.integer == sf and m.format.integer == sf);
8630 return .{ .data_processing_register = .{ .conditional_select = .{
8631 .csinc = .{
8632 .Rd = d.alias.encode(.{}),
8633 .Rn = n.alias.encode(.{}),
8634 .cond = cond,
8635 .Rm = m.alias.encode(.{}),
8636 .sf = sf,
8637 },
8638 } } };
8639 }
8640 /// C6.2.107 CSINV
8641 pub fn csinv(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction {
8642 const sf = d.format.integer;
8643 assert(n.format.integer == sf and m.format.integer == sf);
8644 return .{ .data_processing_register = .{ .conditional_select = .{
8645 .csinv = .{
8646 .Rd = d.alias.encode(.{}),
8647 .Rn = n.alias.encode(.{}),
8648 .cond = cond,
8649 .Rm = m.alias.encode(.{}),
8650 .sf = sf,
8651 },
8652 } } };
8653 }
8654 /// C6.2.108 CSNEG
8655 pub fn csneg(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction {
8656 const sf = d.format.integer;
8657 assert(n.format.integer == sf and m.format.integer == sf);
8658 return .{ .data_processing_register = .{ .conditional_select = .{
8659 .csneg = .{
8660 .Rd = d.alias.encode(.{}),
8661 .Rn = n.alias.encode(.{}),
8662 .cond = cond,
8663 .Rm = m.alias.encode(.{}),
8664 .sf = sf,
8665 },
8666 } } };
8667 }
8668 /// C6.2.110 DCPS1
8669 pub fn dcps1(imm: u16) Instruction {
8670 return .{ .branch_exception_generating_system = .{ .exception_generating = .{
8671 .dcps1 = .{ .imm16 = imm },
8672 } } };
8673 }
8674 /// C6.2.111 DCPS2
8675 pub fn dcps2(imm: u16) Instruction {
8676 return .{ .branch_exception_generating_system = .{ .exception_generating = .{
8677 .dcps2 = .{ .imm16 = imm },
8678 } } };
8679 }
8680 /// C6.2.112 DCPS3
8681 pub fn dcps3(imm: u16) Instruction {
8682 return .{ .branch_exception_generating_system = .{ .exception_generating = .{
8683 .dcps3 = .{ .imm16 = imm },
8684 } } };
8685 }
8686 /// C6.2.116 DSB
8687 pub fn dsb(option: BranchExceptionGeneratingSystem.Barriers.Option) Instruction {
8688 return .{ .branch_exception_generating_system = .{ .barriers = .{
8689 .dsb = .{
8690 .CRm = option,
8691 },
8692 } } };
8693 }
8694 /// C6.2.118 EON (shifted register)
8695 pub fn eon(d: Register, n: Register, form: union(enum) {
8696 register: Register,
8697 shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
8698 shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
8699 }) Instruction {
8700 const sf = d.format.integer;
8701 assert(n.format.integer == sf);
8702 form: switch (form) {
8703 .register => |register| continue :form .{ .shifted_register = .{ .register = register } },
8704 .shifted_register_explicit => |shifted_register_explicit| {
8705 assert(shifted_register_explicit.register.format.integer == sf);
8706 return .{ .data_processing_register = .{ .logical_shifted_register = .{
8707 .eon = .{
8708 .Rd = d.alias.encode(.{}),
8709 .Rn = n.alias.encode(.{}),
8710 .imm6 = switch (sf) {
8711 .word => @as(u5, @intCast(shifted_register_explicit.amount)),
8712 .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
8713 },
8714 .Rm = shifted_register_explicit.register.alias.encode(.{}),
8715 .shift = shifted_register_explicit.shift,
8716 .sf = sf,
8717 },
8718 } } };
8719 },
8720 .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
8721 .register = shifted_register.register,
8722 .shift = shifted_register.shift,
8723 .amount = switch (shifted_register.shift) {
8724 .lsl, .lsr, .asr, .ror => |amount| amount,
8725 },
8726 } },
8727 }
8728 }
8729 /// C6.2.119 EOR (immediate)
8730 /// C6.2.120 EOR (shifted register)
8731 /// C7.2.41 EOR (vector)
8732 pub fn eor(d: Register, n: Register, form: union(enum) {
8733 immediate: DataProcessingImmediate.Bitmask,
8734 register: Register,
8735 shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
8736 shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
8737 }) Instruction {
8738 switch (d.format) {
8739 else => unreachable,
8740 .integer => |sf| {
8741 assert(n.format.integer == sf);
8742 form: switch (form) {
8743 .immediate => |bitmask| {
8744 assert(bitmask.validImmediate(sf));
8745 return .{ .data_processing_immediate = .{ .logical_immediate = .{
8746 .eor = .{
8747 .Rd = d.alias.encode(.{ .sp = true }),
8748 .Rn = n.alias.encode(.{}),
8749 .imm = bitmask,
8750 .sf = sf,
8751 },
8752 } } };
8753 },
8754 .register => |register| continue :form .{ .shifted_register = .{ .register = register } },
8755 .shifted_register_explicit => |shifted_register_explicit| {
8756 assert(shifted_register_explicit.register.format.integer == sf);
8757 return .{ .data_processing_register = .{ .logical_shifted_register = .{
8758 .eor = .{
8759 .Rd = d.alias.encode(.{}),
8760 .Rn = n.alias.encode(.{}),
8761 .imm6 = switch (sf) {
8762 .word => @as(u5, @intCast(shifted_register_explicit.amount)),
8763 .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
8764 },
8765 .Rm = shifted_register_explicit.register.alias.encode(.{}),
8766 .shift = shifted_register_explicit.shift,
8767 .sf = sf,
8768 },
8769 } } };
8770 },
8771 .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
8772 .register = shifted_register.register,
8773 .shift = shifted_register.shift,
8774 .amount = switch (shifted_register.shift) {
8775 .lsl, .lsr, .asr, .ror => |amount| amount,
8776 },
8777 } },
8778 }
8779 },
8780 .vector => |arrangement| {
8781 const m = form.register;
8782 assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement);
8783 return .{ .data_processing_vector = .{ .simd_three_same = .{
8784 .eor = .{
8785 .Rd = d.alias.encode(.{ .V = true }),
8786 .Rn = n.alias.encode(.{ .V = true }),
8787 .Rm = m.alias.encode(.{ .V = true }),
8788 .Q = arrangement.size(),
8789 },
8790 } } };
8791 },
8792 }
8793 }
8794 /// C6.2.124 EXTR
8795 pub fn extr(d: Register, n: Register, m: Register, lsb: u6) Instruction {
8796 const sf = d.format.integer;
8797 assert(n.format.integer == sf and m.format.integer == sf);
8798 return .{ .data_processing_immediate = .{ .extract = .{
8799 .extr = .{
8800 .Rd = d.alias.encode(.{}),
8801 .Rn = n.alias.encode(.{}),
8802 .imms = switch (sf) {
8803 .word => @as(u5, @intCast(lsb)),
8804 .doubleword => @as(u6, @intCast(lsb)),
8805 },
8806 .Rm = m.alias.encode(.{}),
8807 .N = sf,
8808 .sf = sf,
8809 },
8810 } } };
8811 }
8812 /// C7.2.46 FABS (scalar)
8813 pub fn fabs(d: Register, n: Register) Instruction {
8814 const ftype = d.format.scalar;
8815 assert(n.format.scalar == ftype);
8816 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
8817 .fabs = .{
8818 .Rd = d.alias.encode(.{ .V = true }),
8819 .Rn = n.alias.encode(.{ .V = true }),
8820 .ftype = switch (ftype) {
8821 else => unreachable,
8822 .single => .single,
8823 .double => .double,
8824 .half => .half,
8825 },
8826 },
8827 } } };
8828 }
8829 /// C7.2.50 FADD (scalar)
8830 pub fn fadd(d: Register, n: Register, m: Register) Instruction {
8831 const ftype = d.format.scalar;
8832 assert(n.format.scalar == ftype and m.format.scalar == ftype);
8833 return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
8834 .fadd = .{
8835 .Rd = d.alias.encode(.{ .V = true }),
8836 .Rn = n.alias.encode(.{ .V = true }),
8837 .Rm = m.alias.encode(.{ .V = true }),
8838 .ftype = switch (ftype) {
8839 else => unreachable,
8840 .single => .single,
8841 .double => .double,
8842 .half => .half,
8843 },
8844 },
8845 } } };
8846 }
8847 /// C7.2.66 FCMP
8848 pub fn fcmp(n: Register, form: union(enum) { register: Register, zero }) Instruction {
8849 const ftype = n.format.scalar;
8850 switch (form) {
8851 .register => |m| {
8852 assert(m.format.scalar == ftype);
8853 return .{ .data_processing_vector = .{ .float_compare = .{
8854 .fcmp = .{
8855 .opc0 = .register,
8856 .Rn = n.alias.encode(.{ .V = true }),
8857 .Rm = m.alias.encode(.{ .V = true }),
8858 .ftype = switch (ftype) {
8859 else => unreachable,
8860 .single => .single,
8861 .double => .double,
8862 .half => .half,
8863 },
8864 },
8865 } } };
8866 },
8867 .zero => return .{ .data_processing_vector = .{ .float_compare = .{
8868 .fcmp = .{
8869 .opc0 = .register,
8870 .Rn = n.alias.encode(.{ .V = true }),
8871 .Rm = @enumFromInt(0b00000),
8872 .ftype = switch (ftype) {
8873 else => unreachable,
8874 .single => .single,
8875 .double => .double,
8876 .half => .half,
8877 },
8878 },
8879 } } },
8880 }
8881 }
8882 /// C7.2.67 FCMPE
8883 pub fn fcmpe(n: Register, form: union(enum) { register: Register, zero }) Instruction {
8884 const ftype = n.format.scalar;
8885 switch (form) {
8886 .register => |m| {
8887 assert(m.format.scalar == ftype);
8888 return .{ .data_processing_vector = .{ .float_compare = .{
8889 .fcmpe = .{
8890 .opc0 = .zero,
8891 .Rn = n.alias.encode(.{ .V = true }),
8892 .Rm = m.alias.encode(.{ .V = true }),
8893 .ftype = switch (ftype) {
8894 else => unreachable,
8895 .single => .single,
8896 .double => .double,
8897 .half => .half,
8898 },
8899 },
8900 } } };
8901 },
8902 .zero => return .{ .data_processing_vector = .{ .float_compare = .{
8903 .fcmpe = .{
8904 .opc0 = .zero,
8905 .Rn = n.alias.encode(.{ .V = true }),
8906 .Rm = @enumFromInt(0b00000),
8907 .ftype = switch (ftype) {
8908 else => unreachable,
8909 .single => .single,
8910 .double => .double,
8911 .half => .half,
8912 },
8913 },
8914 } } },
8915 }
8916 }
8917 /// C7.2.69 FCVT
8918 pub fn fcvt(d: Register, n: Register) Instruction {
8919 assert(d.format.scalar != n.format.scalar);
8920 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
8921 .fcvt = .{
8922 .Rd = d.alias.encode(.{ .V = true }),
8923 .Rn = n.alias.encode(.{ .V = true }),
8924 .opc = switch (d.format.scalar) {
8925 else => unreachable,
8926 .single => .single,
8927 .double => .double,
8928 .half => .half,
8929 },
8930 .ftype = switch (n.format.scalar) {
8931 else => unreachable,
8932 .single => .single,
8933 .double => .double,
8934 .half => .half,
8935 },
8936 },
8937 } } };
8938 }
8939 /// C7.2.71 FCVTAS (scalar)
8940 pub fn fcvtas(d: Register, n: Register) Instruction {
8941 return .{ .data_processing_vector = .{ .convert_float_integer = .{
8942 .fcvtas = .{
8943 .Rd = d.alias.encode(.{}),
8944 .Rn = n.alias.encode(.{ .V = true }),
8945 .ftype = switch (n.format.scalar) {
8946 else => unreachable,
8947 .single => .single,
8948 .double => .double,
8949 .half => .half,
8950 },
8951 .sf = d.format.integer,
8952 },
8953 } } };
8954 }
8955 /// C7.2.73 FCVTAU (scalar)
8956 pub fn fcvtau(d: Register, n: Register) Instruction {
8957 return .{ .data_processing_vector = .{ .convert_float_integer = .{
8958 .fcvtau = .{
8959 .Rd = d.alias.encode(.{}),
8960 .Rn = n.alias.encode(.{ .V = true }),
8961 .ftype = switch (n.format.scalar) {
8962 else => unreachable,
8963 .single => .single,
8964 .double => .double,
8965 .half => .half,
8966 },
8967 .sf = d.format.integer,
8968 },
8969 } } };
8970 }
8971 /// C7.2.76 FCVTMS (scalar)
8972 pub fn fcvtms(d: Register, n: Register) Instruction {
8973 return .{ .data_processing_vector = .{ .convert_float_integer = .{
8974 .fcvtms = .{
8975 .Rd = d.alias.encode(.{}),
8976 .Rn = n.alias.encode(.{ .V = true }),
8977 .ftype = switch (n.format.scalar) {
8978 else => unreachable,
8979 .single => .single,
8980 .double => .double,
8981 .half => .half,
8982 },
8983 .sf = d.format.integer,
8984 },
8985 } } };
8986 }
8987 /// C7.2.78 FCVTMU (scalar)
8988 pub fn fcvtmu(d: Register, n: Register) Instruction {
8989 return .{ .data_processing_vector = .{ .convert_float_integer = .{
8990 .fcvtmu = .{
8991 .Rd = d.alias.encode(.{}),
8992 .Rn = n.alias.encode(.{ .V = true }),
8993 .ftype = switch (n.format.scalar) {
8994 else => unreachable,
8995 .single => .single,
8996 .double => .double,
8997 .half => .half,
8998 },
8999 .sf = d.format.integer,
9000 },
9001 } } };
9002 }
9003 /// C7.2.81 FCVTNS (scalar)
9004 pub fn fcvtns(d: Register, n: Register) Instruction {
9005 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9006 .fcvtns = .{
9007 .Rd = d.alias.encode(.{}),
9008 .Rn = n.alias.encode(.{ .V = true }),
9009 .ftype = switch (n.format.scalar) {
9010 else => unreachable,
9011 .single => .single,
9012 .double => .double,
9013 .half => .half,
9014 },
9015 .sf = d.format.integer,
9016 },
9017 } } };
9018 }
9019 /// C7.2.83 FCVTNU (scalar)
9020 pub fn fcvtnu(d: Register, n: Register) Instruction {
9021 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9022 .fcvtnu = .{
9023 .Rd = d.alias.encode(.{}),
9024 .Rn = n.alias.encode(.{ .V = true }),
9025 .ftype = switch (n.format.scalar) {
9026 else => unreachable,
9027 .single => .single,
9028 .double => .double,
9029 .half => .half,
9030 },
9031 .sf = d.format.integer,
9032 },
9033 } } };
9034 }
9035 /// C7.2.85 FCVTPS (scalar)
9036 pub fn fcvtps(d: Register, n: Register) Instruction {
9037 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9038 .fcvtps = .{
9039 .Rd = d.alias.encode(.{}),
9040 .Rn = n.alias.encode(.{ .V = true }),
9041 .ftype = switch (n.format.scalar) {
9042 else => unreachable,
9043 .single => .single,
9044 .double => .double,
9045 .half => .half,
9046 },
9047 .sf = d.format.integer,
9048 },
9049 } } };
9050 }
9051 /// C7.2.87 FCVTPU (scalar)
9052 pub fn fcvtpu(d: Register, n: Register) Instruction {
9053 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9054 .fcvtpu = .{
9055 .Rd = d.alias.encode(.{}),
9056 .Rn = n.alias.encode(.{ .V = true }),
9057 .ftype = switch (n.format.scalar) {
9058 else => unreachable,
9059 .single => .single,
9060 .double => .double,
9061 .half => .half,
9062 },
9063 .sf = d.format.integer,
9064 },
9065 } } };
9066 }
9067 /// C7.2.92 FCVTZS (scalar, integer)
9068 pub fn fcvtzs(d: Register, n: Register) Instruction {
9069 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9070 .fcvtzs = .{
9071 .Rd = d.alias.encode(.{}),
9072 .Rn = n.alias.encode(.{ .V = true }),
9073 .ftype = switch (n.format.scalar) {
9074 else => unreachable,
9075 .single => .single,
9076 .double => .double,
9077 .half => .half,
9078 },
9079 .sf = d.format.integer,
9080 },
9081 } } };
9082 }
9083 /// C7.2.96 FCVTZU (scalar, integer)
9084 pub fn fcvtzu(d: Register, n: Register) Instruction {
9085 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9086 .fcvtzu = .{
9087 .Rd = d.alias.encode(.{}),
9088 .Rn = n.alias.encode(.{ .V = true }),
9089 .ftype = switch (n.format.scalar) {
9090 else => unreachable,
9091 .single => .single,
9092 .double => .double,
9093 .half => .half,
9094 },
9095 .sf = d.format.integer,
9096 },
9097 } } };
9098 }
9099 /// C7.2.98 FDIV (scalar)
9100 pub fn fdiv(d: Register, n: Register, m: Register) Instruction {
9101 const ftype = d.format.scalar;
9102 assert(n.format.scalar == ftype and m.format.scalar == ftype);
9103 return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
9104 .fdiv = .{
9105 .Rd = d.alias.encode(.{ .V = true }),
9106 .Rn = n.alias.encode(.{ .V = true }),
9107 .Rm = m.alias.encode(.{ .V = true }),
9108 .ftype = switch (ftype) {
9109 else => unreachable,
9110 .single => .single,
9111 .double => .double,
9112 .half => .half,
9113 },
9114 },
9115 } } };
9116 }
9117 /// C7.2.99 FJCVTZS
9118 pub fn fjcvtzs(d: Register, n: Register) Instruction {
9119 assert(d.format.integer == .word);
9120 assert(n.format.scalar == .double);
9121 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9122 .fjcvtzs = .{
9123 .Rd = d.alias.encode(.{}),
9124 .Rn = n.alias.encode(.{ .V = true }),
9125 },
9126 } } };
9127 }
9128 /// C7.2.100 FMADD
9129 pub fn fmadd(d: Register, n: Register, m: Register, a: Register) Instruction {
9130 const ftype = d.format.scalar;
9131 assert(n.format.scalar == ftype and m.format.scalar == ftype and a.format.scalar == ftype);
9132 return .{ .data_processing_vector = .{ .float_data_processing_three_source = .{
9133 .fmadd = .{
9134 .Rd = d.alias.encode(.{ .V = true }),
9135 .Rn = n.alias.encode(.{ .V = true }),
9136 .Rm = m.alias.encode(.{ .V = true }),
9137 .Ra = a.alias.encode(.{ .V = true }),
9138 .ftype = switch (ftype) {
9139 else => unreachable,
9140 .single => .single,
9141 .double => .double,
9142 .half => .half,
9143 },
9144 },
9145 } } };
9146 }
9147 /// C7.2.102 FMAX (scalar)
9148 pub fn fmax(d: Register, n: Register, m: Register) Instruction {
9149 const ftype = d.format.scalar;
9150 assert(n.format.scalar == ftype and m.format.scalar == ftype);
9151 return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
9152 .fmax = .{
9153 .Rd = d.alias.encode(.{ .V = true }),
9154 .Rn = n.alias.encode(.{ .V = true }),
9155 .Rm = m.alias.encode(.{ .V = true }),
9156 .ftype = switch (ftype) {
9157 else => unreachable,
9158 .single => .single,
9159 .double => .double,
9160 .half => .half,
9161 },
9162 },
9163 } } };
9164 }
9165 /// C7.2.104 FMAXNM (scalar)
9166 pub fn fmaxnm(d: Register, n: Register, m: Register) Instruction {
9167 const ftype = d.format.scalar;
9168 assert(n.format.scalar == ftype and m.format.scalar == ftype);
9169 return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
9170 .fmaxnm = .{
9171 .Rd = d.alias.encode(.{ .V = true }),
9172 .Rn = n.alias.encode(.{ .V = true }),
9173 .Rm = m.alias.encode(.{ .V = true }),
9174 .ftype = switch (ftype) {
9175 else => unreachable,
9176 .single => .single,
9177 .double => .double,
9178 .half => .half,
9179 },
9180 },
9181 } } };
9182 }
9183 /// C7.2.112 FMIN (scalar)
9184 pub fn fmin(d: Register, n: Register, m: Register) Instruction {
9185 const ftype = d.format.scalar;
9186 assert(n.format.scalar == ftype and m.format.scalar == ftype);
9187 return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
9188 .fmin = .{
9189 .Rd = d.alias.encode(.{ .V = true }),
9190 .Rn = n.alias.encode(.{ .V = true }),
9191 .Rm = m.alias.encode(.{ .V = true }),
9192 .ftype = switch (ftype) {
9193 else => unreachable,
9194 .single => .single,
9195 .double => .double,
9196 .half => .half,
9197 },
9198 },
9199 } } };
9200 }
9201 /// C7.2.114 FMINNM (scalar)
9202 pub fn fminnm(d: Register, n: Register, m: Register) Instruction {
9203 const ftype = d.format.scalar;
9204 assert(n.format.scalar == ftype and m.format.scalar == ftype);
9205 return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
9206 .fminnm = .{
9207 .Rd = d.alias.encode(.{ .V = true }),
9208 .Rn = n.alias.encode(.{ .V = true }),
9209 .Rm = m.alias.encode(.{ .V = true }),
9210 .ftype = switch (ftype) {
9211 else => unreachable,
9212 .single => .single,
9213 .double => .double,
9214 .half => .half,
9215 },
9216 },
9217 } } };
9218 }
9219 /// C7.2.129 FMOV (vector, immediate)
9220 /// C7.2.130 FMOV (register)
9221 /// C7.2.131 FMOV (general)
9222 /// C7.2.132 FMOV (scalar, immediate)
9223 pub fn fmov(d: Register, form: union(enum) { immediate: f16, register: Register }) Instruction {
9224 switch (form) {
9225 .immediate => |immediate| {
9226 const repr: std.math.FloatRepr(f16) = @bitCast(immediate);
9227 const imm: u8 = @bitCast(@as(packed struct(u8) {
9228 mantissa: u4,
9229 exponent: i3,
9230 sign: std.math.Sign,
9231 }, .{
9232 .mantissa = @intCast(@shrExact(repr.mantissa, 6)),
9233 .exponent = @intCast(repr.exponent.unbias() - 1),
9234 .sign = repr.sign,
9235 }));
9236 switch (d.format) {
9237 else => unreachable,
9238 .scalar => |ftype| return .{ .data_processing_vector = .{ .float_immediate = .{
9239 .fmov = .{
9240 .Rd = d.alias.encode(.{ .V = true }),
9241 .imm8 = imm,
9242 .ftype = switch (ftype) {
9243 else => unreachable,
9244 .single => .single,
9245 .double => .double,
9246 .half => .half,
9247 },
9248 },
9249 } } },
9250 .vector => |arrangement| {
9251 assert(arrangement.len() > 1 and arrangement.elemSize() != .byte);
9252 return .{ .data_processing_vector = .{ .simd_modified_immediate = .{
9253 .fmov = .{
9254 .Rd = d.alias.encode(.{ .V = true }),
9255 .imm5 = @truncate(imm >> 0),
9256 .imm3 = @intCast(imm >> 5),
9257 .Q = arrangement.size(),
9258 },
9259 } } };
9260 },
9261 }
9262 },
9263 .register => |n| switch (d.format) {
9264 else => unreachable,
9265 .integer => |sf| switch (n.format) {
9266 else => unreachable,
9267 .scalar => |ftype| {
9268 switch (ftype) {
9269 else => unreachable,
9270 .half => {},
9271 .single => assert(sf == .word),
9272 .double => assert(sf == .doubleword),
9273 }
9274 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9275 .fmov = .{
9276 .Rd = d.alias.encode(.{}),
9277 .Rn = n.alias.encode(.{ .V = true }),
9278 .opcode = .float_to_integer,
9279 .rmode = .@"0",
9280 .ftype = switch (ftype) {
9281 else => unreachable,
9282 .single => .single,
9283 .double => .double,
9284 .half => .half,
9285 },
9286 .sf = sf,
9287 },
9288 } } };
9289 },
9290 .element => |element| return .{ .data_processing_vector = .{ .convert_float_integer = .{
9291 .fmov = .{
9292 .Rd = d.alias.encode(.{}),
9293 .Rn = n.alias.encode(.{ .V = true }),
9294 .opcode = .float_to_integer,
9295 .rmode = switch (element.index) {
9296 else => unreachable,
9297 1 => .@"1",
9298 },
9299 .ftype = switch (element.size) {
9300 else => unreachable,
9301 .double => .quad,
9302 },
9303 .sf = sf,
9304 },
9305 } } },
9306 },
9307 .scalar => |ftype| switch (n.format) {
9308 else => unreachable,
9309 .integer => {
9310 const sf = n.format.integer;
9311 switch (ftype) {
9312 else => unreachable,
9313 .half => {},
9314 .single => assert(sf == .word),
9315 .double => assert(sf == .doubleword),
9316 }
9317 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9318 .fmov = .{
9319 .Rd = d.alias.encode(.{ .V = true }),
9320 .Rn = n.alias.encode(.{}),
9321 .opcode = .integer_to_float,
9322 .rmode = .@"0",
9323 .ftype = switch (ftype) {
9324 else => unreachable,
9325 .single => .single,
9326 .double => .double,
9327 .half => .half,
9328 },
9329 .sf = sf,
9330 },
9331 } } };
9332 },
9333 .scalar => {
9334 assert(n.format.scalar == ftype);
9335 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9336 .fmov = .{
9337 .Rd = d.alias.encode(.{ .V = true }),
9338 .Rn = n.alias.encode(.{ .V = true }),
9339 .ftype = switch (ftype) {
9340 else => unreachable,
9341 .single => .single,
9342 .double => .double,
9343 .half => .half,
9344 },
9345 },
9346 } } };
9347 },
9348 },
9349 .element => |element| switch (n.format) {
9350 else => unreachable,
9351 .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
9352 .fmov = .{
9353 .Rd = d.alias.encode(.{ .V = true }),
9354 .Rn = n.alias.encode(.{}),
9355 .opcode = .integer_to_float,
9356 .rmode = switch (element.index) {
9357 else => unreachable,
9358 1 => .@"1",
9359 },
9360 .ftype = switch (element.size) {
9361 else => unreachable,
9362 .double => .quad,
9363 },
9364 .sf = sf,
9365 },
9366 } } },
9367 },
9368 },
9369 }
9370 }
9371 /// C7.2.133 FMSUB
9372 pub fn fmsub(d: Register, n: Register, m: Register, a: Register) Instruction {
9373 const ftype = d.format.scalar;
9374 assert(n.format.scalar == ftype and m.format.scalar == ftype and a.format.scalar == ftype);
9375 return .{ .data_processing_vector = .{ .float_data_processing_three_source = .{
9376 .fmsub = .{
9377 .Rd = d.alias.encode(.{ .V = true }),
9378 .Rn = n.alias.encode(.{ .V = true }),
9379 .Rm = m.alias.encode(.{ .V = true }),
9380 .Ra = a.alias.encode(.{ .V = true }),
9381 .ftype = switch (ftype) {
9382 else => unreachable,
9383 .single => .single,
9384 .double => .double,
9385 .half => .half,
9386 },
9387 },
9388 } } };
9389 }
9390 /// C7.2.136 FMUL (scalar)
9391 pub fn fmul(d: Register, n: Register, m: Register) Instruction {
9392 const ftype = d.format.scalar;
9393 assert(n.format.scalar == ftype and m.format.scalar == ftype);
9394 return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
9395 .fmul = .{
9396 .Rd = d.alias.encode(.{ .V = true }),
9397 .Rn = n.alias.encode(.{ .V = true }),
9398 .Rm = m.alias.encode(.{ .V = true }),
9399 .ftype = switch (ftype) {
9400 else => unreachable,
9401 .single => .single,
9402 .double => .double,
9403 .half => .half,
9404 },
9405 },
9406 } } };
9407 }
9408 /// C7.2.140 FNEG (scalar)
9409 pub fn fneg(d: Register, n: Register) Instruction {
9410 const ftype = d.format.scalar;
9411 assert(n.format.scalar == ftype);
9412 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9413 .fneg = .{
9414 .Rd = d.alias.encode(.{ .V = true }),
9415 .Rn = n.alias.encode(.{ .V = true }),
9416 .ftype = switch (ftype) {
9417 else => unreachable,
9418 .single => .single,
9419 .double => .double,
9420 .half => .half,
9421 },
9422 },
9423 } } };
9424 }
9425 /// C7.2.141 FNMADD
9426 pub fn fnmadd(d: Register, n: Register, m: Register, a: Register) Instruction {
9427 const ftype = d.format.scalar;
9428 assert(n.format.scalar == ftype and m.format.scalar == ftype and a.format.scalar == ftype);
9429 return .{ .data_processing_vector = .{ .float_data_processing_three_source = .{
9430 .fnmadd = .{
9431 .Rd = d.alias.encode(.{ .V = true }),
9432 .Rn = n.alias.encode(.{ .V = true }),
9433 .Rm = m.alias.encode(.{ .V = true }),
9434 .Ra = a.alias.encode(.{ .V = true }),
9435 .ftype = switch (ftype) {
9436 else => unreachable,
9437 .single => .single,
9438 .double => .double,
9439 .half => .half,
9440 },
9441 },
9442 } } };
9443 }
9444 /// C7.2.142 FNMSUB
9445 pub fn fnmsub(d: Register, n: Register, m: Register, a: Register) Instruction {
9446 const ftype = d.format.scalar;
9447 assert(n.format.scalar == ftype and m.format.scalar == ftype and a.format.scalar == ftype);
9448 return .{ .data_processing_vector = .{ .float_data_processing_three_source = .{
9449 .fnmsub = .{
9450 .Rd = d.alias.encode(.{ .V = true }),
9451 .Rn = n.alias.encode(.{ .V = true }),
9452 .Rm = m.alias.encode(.{ .V = true }),
9453 .Ra = a.alias.encode(.{ .V = true }),
9454 .ftype = switch (ftype) {
9455 else => unreachable,
9456 .single => .single,
9457 .double => .double,
9458 .half => .half,
9459 },
9460 },
9461 } } };
9462 }
9463 /// C7.2.143 FNMUL (scalar)
9464 pub fn fnmul(d: Register, n: Register, m: Register) Instruction {
9465 const ftype = d.format.scalar;
9466 assert(n.format.scalar == ftype and m.format.scalar == ftype);
9467 return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
9468 .fnmul = .{
9469 .Rd = d.alias.encode(.{ .V = true }),
9470 .Rn = n.alias.encode(.{ .V = true }),
9471 .Rm = m.alias.encode(.{ .V = true }),
9472 .ftype = switch (ftype) {
9473 else => unreachable,
9474 .single => .single,
9475 .double => .double,
9476 .half => .half,
9477 },
9478 },
9479 } } };
9480 }
9481 /// C7.2.156 FRINTA (scalar)
9482 pub fn frinta(d: Register, n: Register) Instruction {
9483 const ftype = d.format.scalar;
9484 assert(n.format.scalar == ftype);
9485 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9486 .frinta = .{
9487 .Rd = d.alias.encode(.{ .V = true }),
9488 .Rn = n.alias.encode(.{ .V = true }),
9489 .ftype = switch (ftype) {
9490 else => unreachable,
9491 .single => .single,
9492 .double => .double,
9493 .half => .half,
9494 },
9495 },
9496 } } };
9497 }
9498 /// C7.2.158 FRINTI (scalar)
9499 pub fn frinti(d: Register, n: Register) Instruction {
9500 const ftype = d.format.scalar;
9501 assert(n.format.scalar == ftype);
9502 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9503 .frinti = .{
9504 .Rd = d.alias.encode(.{ .V = true }),
9505 .Rn = n.alias.encode(.{ .V = true }),
9506 .ftype = switch (ftype) {
9507 else => unreachable,
9508 .single => .single,
9509 .double => .double,
9510 .half => .half,
9511 },
9512 },
9513 } } };
9514 }
9515 /// C7.2.160 FRINTM (scalar)
9516 pub fn frintm(d: Register, n: Register) Instruction {
9517 const ftype = d.format.scalar;
9518 assert(n.format.scalar == ftype);
9519 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9520 .frintm = .{
9521 .Rd = d.alias.encode(.{ .V = true }),
9522 .Rn = n.alias.encode(.{ .V = true }),
9523 .ftype = switch (ftype) {
9524 else => unreachable,
9525 .single => .single,
9526 .double => .double,
9527 .half => .half,
9528 },
9529 },
9530 } } };
9531 }
9532 /// C7.2.162 FRINTN (scalar)
9533 pub fn frintn(d: Register, n: Register) Instruction {
9534 const ftype = d.format.scalar;
9535 assert(n.format.scalar == ftype);
9536 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9537 .frintn = .{
9538 .Rd = d.alias.encode(.{ .V = true }),
9539 .Rn = n.alias.encode(.{ .V = true }),
9540 .ftype = switch (ftype) {
9541 else => unreachable,
9542 .single => .single,
9543 .double => .double,
9544 .half => .half,
9545 },
9546 },
9547 } } };
9548 }
9549 /// C7.2.164 FRINTP (scalar)
9550 pub fn frintp(d: Register, n: Register) Instruction {
9551 const ftype = d.format.scalar;
9552 assert(n.format.scalar == ftype);
9553 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9554 .frintp = .{
9555 .Rd = d.alias.encode(.{ .V = true }),
9556 .Rn = n.alias.encode(.{ .V = true }),
9557 .ftype = switch (ftype) {
9558 else => unreachable,
9559 .single => .single,
9560 .double => .double,
9561 .half => .half,
9562 },
9563 },
9564 } } };
9565 }
9566 /// C7.2.166 FRINTX (scalar)
9567 pub fn frintx(d: Register, n: Register) Instruction {
9568 const ftype = d.format.scalar;
9569 assert(n.format.scalar == ftype);
9570 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9571 .frintx = .{
9572 .Rd = d.alias.encode(.{ .V = true }),
9573 .Rn = n.alias.encode(.{ .V = true }),
9574 .ftype = switch (ftype) {
9575 else => unreachable,
9576 .single => .single,
9577 .double => .double,
9578 .half => .half,
9579 },
9580 },
9581 } } };
9582 }
9583 /// C7.2.168 FRINTZ (scalar)
9584 pub fn frintz(d: Register, n: Register) Instruction {
9585 const ftype = d.format.scalar;
9586 assert(n.format.scalar == ftype);
9587 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9588 .frintz = .{
9589 .Rd = d.alias.encode(.{ .V = true }),
9590 .Rn = n.alias.encode(.{ .V = true }),
9591 .ftype = switch (ftype) {
9592 else => unreachable,
9593 .single => .single,
9594 .double => .double,
9595 .half => .half,
9596 },
9597 },
9598 } } };
9599 }
9600 /// C7.2.172 FSQRT (scalar)
9601 pub fn fsqrt(d: Register, n: Register) Instruction {
9602 const ftype = d.format.scalar;
9603 assert(n.format.scalar == ftype);
9604 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9605 .fsqrt = .{
9606 .Rd = d.alias.encode(.{ .V = true }),
9607 .Rn = n.alias.encode(.{ .V = true }),
9608 .ftype = switch (ftype) {
9609 else => unreachable,
9610 .single => .single,
9611 .double => .double,
9612 .half => .half,
9613 },
9614 },
9615 } } };
9616 }
9617 /// C7.2.174 FSUB (scalar)
9618 pub fn fsub(d: Register, n: Register, m: Register) Instruction {
9619 const ftype = d.format.scalar;
9620 assert(n.format.scalar == ftype and m.format.scalar == ftype);
9621 return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
9622 .fsub = .{
9623 .Rd = d.alias.encode(.{ .V = true }),
9624 .Rn = n.alias.encode(.{ .V = true }),
9625 .Rm = m.alias.encode(.{ .V = true }),
9626 .ftype = switch (ftype) {
9627 else => unreachable,
9628 .single => .single,
9629 .double => .double,
9630 .half => .half,
9631 },
9632 },
9633 } } };
9634 }
9635 /// C6.2.126 HINT
9636 pub fn hint(imm: u7) Instruction {
9637 return .{ .branch_exception_generating_system = .{ .hints = .{
9638 .group = .{
9639 .op2 = @truncate(imm >> 0),
9640 .CRm = @intCast(imm >> 3),
9641 },
9642 } } };
9643 }
9644 /// C6.2.127 HLT
9645 pub fn hlt(imm: u16) Instruction {
9646 return .{ .branch_exception_generating_system = .{ .exception_generating = .{
9647 .hlt = .{ .imm16 = imm },
9648 } } };
9649 }
9650 /// C6.2.128 HVC
9651 pub fn hvc(imm: u16) Instruction {
9652 return .{ .branch_exception_generating_system = .{ .exception_generating = .{
9653 .hvc = .{ .imm16 = imm },
9654 } } };
9655 }
9656 /// C6.2.131 ISB
9657 pub fn isb(option: BranchExceptionGeneratingSystem.Barriers.Option) Instruction {
9658 return .{ .branch_exception_generating_system = .{ .barriers = .{
9659 .isb = .{
9660 .CRm = option,
9661 },
9662 } } };
9663 }
9664 /// C6.2.164 LDP
9665 /// C7.2.190 LDP (SIMD&FP)
9666 pub fn ldp(t1: Register, t2: Register, form: union(enum) {
9667 post_index: struct { base: Register, index: i10 },
9668 pre_index: struct { base: Register, index: i10 },
9669 signed_offset: struct { base: Register, offset: i10 = 0 },
9670 base: Register,
9671 }) Instruction {
9672 switch (t1.format) {
9673 else => unreachable,
9674 .integer => |sf| {
9675 assert(t2.format.integer == sf);
9676 form: switch (form) {
9677 .post_index => |post_index| {
9678 assert(post_index.base.format.integer == .doubleword);
9679 return .{ .load_store = .{ .register_pair_post_indexed = .{ .integer = .{
9680 .ldp = .{
9681 .Rt = t1.alias.encode(.{}),
9682 .Rn = post_index.base.alias.encode(.{ .sp = true }),
9683 .Rt2 = t2.alias.encode(.{}),
9684 .imm7 = @intCast(@shrExact(post_index.index, @as(u2, 2) + @intFromEnum(sf))),
9685 .sf = sf,
9686 },
9687 } } } };
9688 },
9689 .signed_offset => |signed_offset| {
9690 assert(signed_offset.base.format.integer == .doubleword);
9691 return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{
9692 .ldp = .{
9693 .Rt = t1.alias.encode(.{}),
9694 .Rn = signed_offset.base.alias.encode(.{ .sp = true }),
9695 .Rt2 = t2.alias.encode(.{}),
9696 .imm7 = @intCast(@shrExact(signed_offset.offset, @as(u2, 2) + @intFromEnum(sf))),
9697 .sf = sf,
9698 },
9699 } } } };
9700 },
9701 .pre_index => |pre_index| {
9702 assert(pre_index.base.format.integer == .doubleword);
9703 return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{
9704 .ldp = .{
9705 .Rt = t1.alias.encode(.{}),
9706 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
9707 .Rt2 = t2.alias.encode(.{}),
9708 .imm7 = @intCast(@shrExact(pre_index.index, @as(u2, 2) + @intFromEnum(sf))),
9709 .sf = sf,
9710 },
9711 } } } };
9712 },
9713 .base => |base| continue :form .{ .signed_offset = .{ .base = base } },
9714 }
9715 },
9716 .scalar => |vs| {
9717 assert(t2.format.scalar == vs);
9718 form: switch (form) {
9719 .post_index => |post_index| {
9720 assert(post_index.base.format.integer == .doubleword);
9721 return .{ .load_store = .{ .register_pair_post_indexed = .{ .vector = .{
9722 .ldp = .{
9723 .Rt = t1.alias.encode(.{ .V = true }),
9724 .Rn = post_index.base.alias.encode(.{ .sp = true }),
9725 .Rt2 = t2.alias.encode(.{ .V = true }),
9726 .imm7 = @intCast(@shrExact(post_index.index, @intFromEnum(vs))),
9727 .opc = .encode(vs),
9728 },
9729 } } } };
9730 },
9731 .signed_offset => |signed_offset| {
9732 assert(signed_offset.base.format.integer == .doubleword);
9733 return .{ .load_store = .{ .register_pair_offset = .{ .vector = .{
9734 .ldp = .{
9735 .Rt = t1.alias.encode(.{ .V = true }),
9736 .Rn = signed_offset.base.alias.encode(.{ .sp = true }),
9737 .Rt2 = t2.alias.encode(.{ .V = true }),
9738 .imm7 = @intCast(@shrExact(signed_offset.offset, @intFromEnum(vs))),
9739 .opc = .encode(vs),
9740 },
9741 } } } };
9742 },
9743 .pre_index => |pre_index| {
9744 assert(pre_index.base.format.integer == .doubleword);
9745 return .{ .load_store = .{ .register_pair_pre_indexed = .{ .vector = .{
9746 .ldp = .{
9747 .Rt = t1.alias.encode(.{ .V = true }),
9748 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
9749 .Rt2 = t2.alias.encode(.{ .V = true }),
9750 .imm7 = @intCast(@shrExact(pre_index.index, @intFromEnum(vs))),
9751 .opc = .encode(vs),
9752 },
9753 } } } };
9754 },
9755 .base => |base| continue :form .{ .signed_offset = .{ .base = base } },
9756 }
9757 },
9758 }
9759 }
9760 /// C6.2.166 LDR (immediate)
9761 /// C6.2.167 LDR (literal)
9762 /// C6.2.168 LDR (register)
9763 /// C7.2.191 LDR (immediate, SIMD&FP)
9764 /// C7.2.192 LDR (literal, SIMD&FP)
9765 /// C7.2.193 LDR (register, SIMD&FP)
9766 pub fn ldr(t: Register, form: union(enum) {
9767 post_index: struct { base: Register, index: i9 },
9768 pre_index: struct { base: Register, index: i9 },
9769 unsigned_offset: struct { base: Register, offset: u16 = 0 },
9770 base: Register,
9771 literal: i21,
9772 extended_register_explicit: struct {
9773 base: Register,
9774 index: Register,
9775 option: LoadStore.RegisterRegisterOffset.Option,
9776 amount: LoadStore.RegisterRegisterOffset.Extend.Amount,
9777 },
9778 extended_register: struct {
9779 base: Register,
9780 index: Register,
9781 extend: LoadStore.RegisterRegisterOffset.Extend,
9782 },
9783 }) Instruction {
9784 switch (t.format) {
9785 else => unreachable,
9786 .integer => |sf| form: switch (form) {
9787 .post_index => |post_index| {
9788 assert(post_index.base.format.integer == .doubleword);
9789 return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{
9790 .ldr = .{
9791 .Rt = t.alias.encode(.{}),
9792 .Rn = post_index.base.alias.encode(.{ .sp = true }),
9793 .imm9 = post_index.index,
9794 .sf = sf,
9795 },
9796 } } } };
9797 },
9798 .pre_index => |pre_index| {
9799 assert(pre_index.base.format.integer == .doubleword);
9800 return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
9801 .ldr = .{
9802 .Rt = t.alias.encode(.{}),
9803 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
9804 .imm9 = pre_index.index,
9805 .sf = sf,
9806 },
9807 } } } };
9808 },
9809 .unsigned_offset => |unsigned_offset| {
9810 assert(unsigned_offset.base.format.integer == .doubleword);
9811 return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
9812 .ldr = .{
9813 .Rt = t.alias.encode(.{}),
9814 .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
9815 .imm12 = @intCast(@shrExact(unsigned_offset.offset, @as(u2, 2) + @intFromEnum(sf))),
9816 .sf = sf,
9817 },
9818 } } } };
9819 },
9820 .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
9821 .literal => |offset| return .{ .load_store = .{ .register_literal = .{ .integer = .{
9822 .ldr = .{
9823 .Rt = t.alias.encode(.{}),
9824 .imm19 = @intCast(@shrExact(offset, 2)),
9825 .sf = sf,
9826 },
9827 } } } },
9828 .extended_register_explicit => |extended_register_explicit| {
9829 assert(extended_register_explicit.base.format.integer == .doubleword and
9830 extended_register_explicit.index.format.integer == extended_register_explicit.option.sf());
9831 return .{ .load_store = .{ .register_register_offset = .{ .integer = .{
9832 .ldr = .{
9833 .Rt = t.alias.encode(.{}),
9834 .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }),
9835 .S = switch (sf) {
9836 .word => switch (extended_register_explicit.amount) {
9837 0 => false,
9838 2 => true,
9839 else => unreachable,
9840 },
9841 .doubleword => switch (extended_register_explicit.amount) {
9842 0 => false,
9843 3 => true,
9844 else => unreachable,
9845 },
9846 },
9847 .option = extended_register_explicit.option,
9848 .Rm = extended_register_explicit.index.alias.encode(.{}),
9849 .sf = sf,
9850 },
9851 } } } };
9852 },
9853 .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
9854 .base = extended_register.base,
9855 .index = extended_register.index,
9856 .option = extended_register.extend,
9857 .amount = switch (extended_register.extend) {
9858 .uxtw, .lsl, .sxtw, .sxtx => |amount| amount,
9859 },
9860 } },
9861 },
9862 .scalar => |vs| form: switch (form) {
9863 .post_index => |post_index| {
9864 assert(post_index.base.format.integer == .doubleword);
9865 return .{ .load_store = .{ .register_immediate_post_indexed = .{ .vector = .{
9866 .ldr = .{
9867 .Rt = t.alias.encode(.{ .V = true }),
9868 .Rn = post_index.base.alias.encode(.{ .sp = true }),
9869 .imm9 = post_index.index,
9870 .opc1 = .encode(vs),
9871 .size = .encode(vs),
9872 },
9873 } } } };
9874 },
9875 .pre_index => |pre_index| {
9876 assert(pre_index.base.format.integer == .doubleword);
9877 return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .vector = .{
9878 .ldr = .{
9879 .Rt = t.alias.encode(.{ .V = true }),
9880 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
9881 .imm9 = pre_index.index,
9882 .opc1 = .encode(vs),
9883 .size = .encode(vs),
9884 },
9885 } } } };
9886 },
9887 .unsigned_offset => |unsigned_offset| {
9888 assert(unsigned_offset.base.format.integer == .doubleword);
9889 return .{ .load_store = .{ .register_unsigned_immediate = .{ .vector = .{
9890 .ldr = .{
9891 .Rt = t.alias.encode(.{ .V = true }),
9892 .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
9893 .imm12 = @intCast(@shrExact(unsigned_offset.offset, @intFromEnum(vs))),
9894 .opc1 = .encode(vs),
9895 .size = .encode(vs),
9896 },
9897 } } } };
9898 },
9899 .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
9900 .literal => |offset| return .{ .load_store = .{ .register_literal = .{ .vector = .{
9901 .ldr = .{
9902 .Rt = t.alias.encode(.{ .V = true }),
9903 .imm19 = @intCast(@shrExact(offset, 2)),
9904 .opc = .encode(vs),
9905 },
9906 } } } },
9907 .extended_register_explicit => |extended_register_explicit| {
9908 assert(extended_register_explicit.base.format.integer == .doubleword and
9909 extended_register_explicit.index.format.integer == extended_register_explicit.option.sf());
9910 return .{ .load_store = .{ .register_register_offset = .{ .vector = .{
9911 .ldr = .{
9912 .Rt = t.alias.encode(.{ .V = true }),
9913 .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }),
9914 .S = switch (vs) {
9915 else => unreachable,
9916 .byte => switch (extended_register_explicit.amount) {
9917 0 => false,
9918 else => unreachable,
9919 },
9920 .half => switch (extended_register_explicit.amount) {
9921 0 => false,
9922 1 => true,
9923 else => unreachable,
9924 },
9925 .single => switch (extended_register_explicit.amount) {
9926 0 => false,
9927 2 => true,
9928 else => unreachable,
9929 },
9930 .double => switch (extended_register_explicit.amount) {
9931 0 => false,
9932 3 => true,
9933 else => unreachable,
9934 },
9935 .quad => switch (extended_register_explicit.amount) {
9936 0 => false,
9937 4 => true,
9938 else => unreachable,
9939 },
9940 },
9941 .option = extended_register_explicit.option,
9942 .Rm = extended_register_explicit.index.alias.encode(.{}),
9943 .opc1 = .encode(vs),
9944 .size = .encode(vs),
9945 },
9946 } } } };
9947 },
9948 .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
9949 .base = extended_register.base,
9950 .index = extended_register.index,
9951 .option = extended_register.extend,
9952 .amount = switch (extended_register.extend) {
9953 .uxtw, .lsl, .sxtw, .sxtx => |amount| amount,
9954 },
9955 } },
9956 },
9957 }
9958 }
9959 /// C6.2.170 LDRB (immediate)
9960 /// C6.2.171 LDRB (register)
9961 pub fn ldrb(t: Register, form: union(enum) {
9962 post_index: struct { base: Register, index: i9 },
9963 pre_index: struct { base: Register, index: i9 },
9964 unsigned_offset: struct { base: Register, offset: u12 = 0 },
9965 base: Register,
9966 extended_register_explicit: struct {
9967 base: Register,
9968 index: Register,
9969 option: LoadStore.RegisterRegisterOffset.Option,
9970 amount: LoadStore.RegisterRegisterOffset.Extend.Amount,
9971 },
9972 extended_register: struct {
9973 base: Register,
9974 index: Register,
9975 extend: LoadStore.RegisterRegisterOffset.Extend,
9976 },
9977 }) Instruction {
9978 assert(t.format.integer == .word);
9979 form: switch (form) {
9980 .post_index => |post_index| {
9981 assert(post_index.base.format.integer == .doubleword);
9982 return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{
9983 .ldrb = .{
9984 .Rt = t.alias.encode(.{}),
9985 .Rn = post_index.base.alias.encode(.{ .sp = true }),
9986 .imm9 = post_index.index,
9987 },
9988 } } } };
9989 },
9990 .pre_index => |pre_index| {
9991 assert(pre_index.base.format.integer == .doubleword);
9992 return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
9993 .ldrb = .{
9994 .Rt = t.alias.encode(.{}),
9995 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
9996 .imm9 = pre_index.index,
9997 },
9998 } } } };
9999 },
10000 .unsigned_offset => |unsigned_offset| {
10001 assert(unsigned_offset.base.format.integer == .doubleword);
10002 return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
10003 .ldrb = .{
10004 .Rt = t.alias.encode(.{}),
10005 .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
10006 .imm12 = unsigned_offset.offset,
10007 },
10008 } } } };
10009 },
10010 .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
10011 .extended_register_explicit => |extended_register_explicit| {
10012 assert(extended_register_explicit.base.format.integer == .doubleword and
10013 extended_register_explicit.index.format.integer == extended_register_explicit.option.sf());
10014 return .{ .load_store = .{ .register_register_offset = .{ .integer = .{
10015 .ldrb = .{
10016 .Rt = t.alias.encode(.{}),
10017 .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }),
10018 .S = switch (extended_register_explicit.amount) {
10019 0 => false,
10020 else => unreachable,
10021 },
10022 .option = extended_register_explicit.option,
10023 .Rm = extended_register_explicit.index.alias.encode(.{}),
10024 },
10025 } } } };
10026 },
10027 .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
10028 .base = extended_register.base,
10029 .index = extended_register.index,
10030 .option = extended_register.extend,
10031 .amount = switch (extended_register.extend) {
10032 .uxtw, .lsl, .sxtw, .sxtx => |amount| amount,
10033 },
10034 } },
10035 }
10036 }
10037 /// C6.2.172 LDRH (immediate)
10038 /// C6.2.173 LDRH (register)
10039 pub fn ldrh(t: Register, form: union(enum) {
10040 post_index: struct { base: Register, index: i9 },
10041 pre_index: struct { base: Register, index: i9 },
10042 unsigned_offset: struct { base: Register, offset: u13 = 0 },
10043 base: Register,
10044 extended_register_explicit: struct {
10045 base: Register,
10046 index: Register,
10047 option: LoadStore.RegisterRegisterOffset.Option,
10048 amount: LoadStore.RegisterRegisterOffset.Extend.Amount,
10049 },
10050 extended_register: struct {
10051 base: Register,
10052 index: Register,
10053 extend: LoadStore.RegisterRegisterOffset.Extend,
10054 },
10055 }) Instruction {
10056 assert(t.format.integer == .word);
10057 form: switch (form) {
10058 .post_index => |post_index| {
10059 assert(post_index.base.format.integer == .doubleword);
10060 return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{
10061 .ldrh = .{
10062 .Rt = t.alias.encode(.{}),
10063 .Rn = post_index.base.alias.encode(.{ .sp = true }),
10064 .imm9 = post_index.index,
10065 },
10066 } } } };
10067 },
10068 .pre_index => |pre_index| {
10069 assert(pre_index.base.format.integer == .doubleword);
10070 return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
10071 .ldrh = .{
10072 .Rt = t.alias.encode(.{}),
10073 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
10074 .imm9 = pre_index.index,
10075 },
10076 } } } };
10077 },
10078 .unsigned_offset => |unsigned_offset| {
10079 assert(unsigned_offset.base.format.integer == .doubleword);
10080 return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
10081 .ldrh = .{
10082 .Rt = t.alias.encode(.{}),
10083 .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
10084 .imm12 = @intCast(@shrExact(unsigned_offset.offset, 1)),
10085 },
10086 } } } };
10087 },
10088 .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
10089 .extended_register_explicit => |extended_register_explicit| {
10090 assert(extended_register_explicit.base.format.integer == .doubleword and
10091 extended_register_explicit.index.format.integer == extended_register_explicit.option.sf());
10092 return .{ .load_store = .{ .register_register_offset = .{ .integer = .{
10093 .ldrh = .{
10094 .Rt = t.alias.encode(.{}),
10095 .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }),
10096 .S = switch (extended_register_explicit.amount) {
10097 0 => false,
10098 1 => true,
10099 else => unreachable,
10100 },
10101 .option = extended_register_explicit.option,
10102 .Rm = extended_register_explicit.index.alias.encode(.{}),
10103 },
10104 } } } };
10105 },
10106 .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
10107 .base = extended_register.base,
10108 .index = extended_register.index,
10109 .option = extended_register.extend,
10110 .amount = switch (extended_register.extend) {
10111 .uxtw, .lsl, .sxtw, .sxtx => |amount| amount,
10112 },
10113 } },
10114 }
10115 }
10116 /// C6.2.174 LDRSB (immediate)
10117 /// C6.2.175 LDRSB (register)
10118 pub fn ldrsb(t: Register, form: union(enum) {
10119 post_index: struct { base: Register, index: i9 },
10120 pre_index: struct { base: Register, index: i9 },
10121 unsigned_offset: struct { base: Register, offset: u12 = 0 },
10122 base: Register,
10123 extended_register_explicit: struct {
10124 base: Register,
10125 index: Register,
10126 option: LoadStore.RegisterRegisterOffset.Option,
10127 amount: LoadStore.RegisterRegisterOffset.Extend.Amount,
10128 },
10129 extended_register: struct {
10130 base: Register,
10131 index: Register,
10132 extend: LoadStore.RegisterRegisterOffset.Extend,
10133 },
10134 }) Instruction {
10135 const sf = t.format.integer;
10136 form: switch (form) {
10137 .post_index => |post_index| {
10138 assert(post_index.base.format.integer == .doubleword);
10139 return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{
10140 .ldrsb = .{
10141 .Rt = t.alias.encode(.{}),
10142 .Rn = post_index.base.alias.encode(.{ .sp = true }),
10143 .imm9 = post_index.index,
10144 .opc0 = ~@intFromEnum(sf),
10145 },
10146 } } } };
10147 },
10148 .pre_index => |pre_index| {
10149 assert(pre_index.base.format.integer == .doubleword);
10150 return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
10151 .ldrsb = .{
10152 .Rt = t.alias.encode(.{}),
10153 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
10154 .imm9 = pre_index.index,
10155 .opc0 = ~@intFromEnum(sf),
10156 },
10157 } } } };
10158 },
10159 .unsigned_offset => |unsigned_offset| {
10160 assert(unsigned_offset.base.format.integer == .doubleword);
10161 return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
10162 .ldrsb = .{
10163 .Rt = t.alias.encode(.{}),
10164 .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
10165 .imm12 = unsigned_offset.offset,
10166 .opc0 = ~@intFromEnum(sf),
10167 },
10168 } } } };
10169 },
10170 .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
10171 .extended_register_explicit => |extended_register_explicit| {
10172 assert(extended_register_explicit.base.format.integer == .doubleword and
10173 extended_register_explicit.index.format.integer == extended_register_explicit.option.sf());
10174 return .{ .load_store = .{ .register_register_offset = .{ .integer = .{
10175 .ldrsb = .{
10176 .Rt = t.alias.encode(.{}),
10177 .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }),
10178 .S = switch (extended_register_explicit.amount) {
10179 0 => false,
10180 else => unreachable,
10181 },
10182 .option = extended_register_explicit.option,
10183 .Rm = extended_register_explicit.index.alias.encode(.{}),
10184 .opc0 = ~@intFromEnum(sf),
10185 },
10186 } } } };
10187 },
10188 .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
10189 .base = extended_register.base,
10190 .index = extended_register.index,
10191 .option = extended_register.extend,
10192 .amount = switch (extended_register.extend) {
10193 .uxtw, .lsl, .sxtw, .sxtx => |amount| amount,
10194 },
10195 } },
10196 }
10197 }
10198 /// C6.2.176 LDRSH (immediate)
10199 /// C6.2.177 LDRSH (register)
10200 pub fn ldrsh(t: Register, form: union(enum) {
10201 post_index: struct { base: Register, index: i9 },
10202 pre_index: struct { base: Register, index: i9 },
10203 unsigned_offset: struct { base: Register, offset: u13 = 0 },
10204 base: Register,
10205 extended_register_explicit: struct {
10206 base: Register,
10207 index: Register,
10208 option: LoadStore.RegisterRegisterOffset.Option,
10209 amount: LoadStore.RegisterRegisterOffset.Extend.Amount,
10210 },
10211 extended_register: struct {
10212 base: Register,
10213 index: Register,
10214 extend: LoadStore.RegisterRegisterOffset.Extend,
10215 },
10216 }) Instruction {
10217 const sf = t.format.integer;
10218 form: switch (form) {
10219 .post_index => |post_index| {
10220 assert(post_index.base.format.integer == .doubleword);
10221 return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{
10222 .ldrsh = .{
10223 .Rt = t.alias.encode(.{}),
10224 .Rn = post_index.base.alias.encode(.{ .sp = true }),
10225 .imm9 = post_index.index,
10226 .opc0 = ~@intFromEnum(sf),
10227 },
10228 } } } };
10229 },
10230 .pre_index => |pre_index| {
10231 assert(pre_index.base.format.integer == .doubleword);
10232 return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
10233 .ldrsh = .{
10234 .Rt = t.alias.encode(.{}),
10235 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
10236 .imm9 = pre_index.index,
10237 .opc0 = ~@intFromEnum(sf),
10238 },
10239 } } } };
10240 },
10241 .unsigned_offset => |unsigned_offset| {
10242 assert(unsigned_offset.base.format.integer == .doubleword);
10243 return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
10244 .ldrsh = .{
10245 .Rt = t.alias.encode(.{}),
10246 .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
10247 .imm12 = @intCast(@shrExact(unsigned_offset.offset, 1)),
10248 .opc0 = ~@intFromEnum(sf),
10249 },
10250 } } } };
10251 },
10252 .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
10253 .extended_register_explicit => |extended_register_explicit| {
10254 assert(extended_register_explicit.base.format.integer == .doubleword and
10255 extended_register_explicit.index.format.integer == extended_register_explicit.option.sf());
10256 return .{ .load_store = .{ .register_register_offset = .{ .integer = .{
10257 .ldrsh = .{
10258 .Rt = t.alias.encode(.{}),
10259 .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }),
10260 .S = switch (extended_register_explicit.amount) {
10261 0 => false,
10262 1 => true,
10263 else => unreachable,
10264 },
10265 .option = extended_register_explicit.option,
10266 .Rm = extended_register_explicit.index.alias.encode(.{}),
10267 .opc0 = ~@intFromEnum(sf),
10268 },
10269 } } } };
10270 },
10271 .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
10272 .base = extended_register.base,
10273 .index = extended_register.index,
10274 .option = extended_register.extend,
10275 .amount = switch (extended_register.extend) {
10276 .uxtw, .lsl, .sxtw, .sxtx => |amount| amount,
10277 },
10278 } },
10279 }
10280 }
10281 /// C6.2.178 LDRSW (immediate)
10282 /// C6.2.179 LDRSW (literal)
10283 /// C6.2.180 LDRSW (register)
10284 pub fn ldrsw(t: Register, form: union(enum) {
10285 post_index: struct { base: Register, index: i9 },
10286 pre_index: struct { base: Register, index: i9 },
10287 unsigned_offset: struct { base: Register, offset: u14 = 0 },
10288 base: Register,
10289 literal: i21,
10290 extended_register_explicit: struct {
10291 base: Register,
10292 index: Register,
10293 option: LoadStore.RegisterRegisterOffset.Integer.Option,
10294 amount: LoadStore.RegisterRegisterOffset.Integer.Extend.Amount,
10295 },
10296 extended_register: struct {
10297 base: Register,
10298 index: Register,
10299 extend: LoadStore.RegisterRegisterOffset.Integer.Extend,
10300 },
10301 }) Instruction {
10302 assert(t.format.integer == .doubleword);
10303 form: switch (form) {
10304 .post_index => |post_index| {
10305 assert(post_index.base.format.integer == .doubleword);
10306 return .{ .load_store = .{ .register_immediate_post_indexed = .{
10307 .ldrsw = .{
10308 .Rt = t.alias.encode(.{}),
10309 .Rn = post_index.base.alias.encode(.{ .sp = true }),
10310 .imm9 = post_index.index,
10311 },
10312 } } };
10313 },
10314 .pre_index => |pre_index| {
10315 assert(pre_index.base.format.integer == .doubleword);
10316 return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
10317 .ldrsw = .{
10318 .Rt = t.alias.encode(.{}),
10319 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
10320 .imm9 = pre_index.index,
10321 },
10322 } } } };
10323 },
10324 .unsigned_offset => |unsigned_offset| {
10325 assert(unsigned_offset.base.format.integer == .doubleword);
10326 return .{ .load_store = .{ .register_unsigned_immediate = .{
10327 .ldrsw = .{
10328 .Rt = t.alias.encode(.{}),
10329 .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
10330 .imm12 = @intCast(@shrExact(unsigned_offset.offset, 2)),
10331 },
10332 } } };
10333 },
10334 .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
10335 .literal => |offset| return .{ .load_store = .{ .register_literal = .{
10336 .ldrsw = .{
10337 .Rt = t.alias.encode(.{}),
10338 .imm19 = @intCast(@shrExact(offset, 2)),
10339 },
10340 } } },
10341 .extended_register_explicit => |extended_register_explicit| {
10342 assert(extended_register_explicit.base.format.integer == .doubleword and
10343 extended_register_explicit.index.format.integer == extended_register_explicit.option.sf());
10344 return .{ .load_store = .{ .register_register_offset = .{ .integer = .{
10345 .ldrsw = .{
10346 .Rt = t.alias.encode(.{}),
10347 .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }),
10348 .S = switch (extended_register_explicit.amount) {
10349 0 => 0b0,
10350 2 => 0b1,
10351 else => unreachable,
10352 },
10353 .option = extended_register_explicit.option,
10354 .Rm = extended_register_explicit.index.alias.encode(.{}),
10355 },
10356 } } } };
10357 },
10358 .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
10359 .base = extended_register.base,
10360 .index = extended_register.index,
10361 .option = extended_register.extend,
10362 .amount = switch (extended_register.extend) {
10363 .uxtw, .lsl, .sxtw, .sxtx => |amount| amount,
10364 },
10365 } },
10366 }
10367 }
10368 /// C6.2.202 LDUR
10369 /// C7.2.194 LDUR (SIMD&FP)
10370 pub fn ldur(t: Register, n: Register, simm: i9) Instruction {
10371 assert(n.format.integer == .doubleword);
10372 switch (t.format) {
10373 else => unreachable,
10374 .integer => |sf| return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
10375 .ldur = .{
10376 .Rt = t.alias.encode(.{}),
10377 .Rn = n.alias.encode(.{ .sp = true }),
10378 .imm9 = simm,
10379 .sf = sf,
10380 },
10381 } } } },
10382 .scalar => |vs| return .{ .load_store = .{ .register_unscaled_immediate = .{ .vector = .{
10383 .ldur = .{
10384 .Rt = t.alias.encode(.{ .V = true }),
10385 .Rn = n.alias.encode(.{ .sp = true }),
10386 .imm9 = simm,
10387 .opc1 = .encode(vs),
10388 .size = .encode(vs),
10389 },
10390 } } } },
10391 }
10392 }
10393 /// C6.2.203 LDURB
10394 pub fn ldurb(t: Register, n: Register, simm: i9) Instruction {
10395 assert(t.format.integer == .word and n.format.integer == .doubleword);
10396 return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
10397 .ldurb = .{
10398 .Rt = t.alias.encode(.{}),
10399 .Rn = n.alias.encode(.{ .sp = true }),
10400 .imm9 = simm,
10401 },
10402 } } } };
10403 }
10404 /// C6.2.204 LDURH
10405 pub fn ldurh(t: Register, n: Register, simm: i9) Instruction {
10406 assert(t.format.integer == .word and n.format.integer == .doubleword);
10407 return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
10408 .ldurh = .{
10409 .Rt = t.alias.encode(.{}),
10410 .Rn = n.alias.encode(.{ .sp = true }),
10411 .imm9 = simm,
10412 },
10413 } } } };
10414 }
10415 /// C6.2.205 LDURSB
10416 pub fn ldursb(t: Register, n: Register, simm: i9) Instruction {
10417 assert(n.format.integer == .doubleword);
10418 return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
10419 .ldursb = .{
10420 .Rt = t.alias.encode(.{}),
10421 .Rn = n.alias.encode(.{ .sp = true }),
10422 .imm9 = simm,
10423 .opc0 = ~@intFromEnum(t.format.integer),
10424 },
10425 } } } };
10426 }
10427 /// C6.2.206 LDURSH
10428 pub fn ldursh(t: Register, n: Register, simm: i9) Instruction {
10429 assert(n.format.integer == .doubleword);
10430 return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
10431 .ldursh = .{
10432 .Rt = t.alias.encode(.{}),
10433 .Rn = n.alias.encode(.{ .sp = true }),
10434 .imm9 = simm,
10435 .opc0 = ~@intFromEnum(t.format.integer),
10436 },
10437 } } } };
10438 }
10439 /// C6.2.207 LDURSW
10440 pub fn ldursw(t: Register, n: Register, simm: i9) Instruction {
10441 assert(t.format.integer == .doubleword and n.format.integer == .doubleword);
10442 return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
10443 .ldursw = .{
10444 .Rt = t.alias.encode(.{}),
10445 .Rn = n.alias.encode(.{ .sp = true }),
10446 .imm9 = simm,
10447 },
10448 } } } };
10449 }
10450 /// C6.2.214 LSLV
10451 pub fn lslv(d: Register, n: Register, m: Register) Instruction {
10452 const sf = d.format.integer;
10453 assert(n.format.integer == sf and m.format.integer == sf);
10454 return .{ .data_processing_register = .{ .data_processing_two_source = .{
10455 .lslv = .{
10456 .Rd = d.alias.encode(.{}),
10457 .Rn = n.alias.encode(.{}),
10458 .Rm = m.alias.encode(.{}),
10459 .sf = sf,
10460 },
10461 } } };
10462 }
10463 /// C6.2.217 LSRV
10464 pub fn lsrv(d: Register, n: Register, m: Register) Instruction {
10465 const sf = d.format.integer;
10466 assert(n.format.integer == sf and m.format.integer == sf);
10467 return .{ .data_processing_register = .{ .data_processing_two_source = .{
10468 .lsrv = .{
10469 .Rd = d.alias.encode(.{}),
10470 .Rn = n.alias.encode(.{}),
10471 .Rm = m.alias.encode(.{}),
10472 .sf = sf,
10473 },
10474 } } };
10475 }
10476 /// C6.2.218 MADD
10477 pub fn madd(d: Register, n: Register, m: Register, a: Register) Instruction {
10478 const sf = d.format.integer;
10479 assert(n.format.integer == sf and m.format.integer == sf and a.format.integer == sf);
10480 return .{ .data_processing_register = .{ .data_processing_three_source = .{
10481 .madd = .{
10482 .Rd = d.alias.encode(.{}),
10483 .Rn = n.alias.encode(.{}),
10484 .Ra = a.alias.encode(.{}),
10485 .Rm = m.alias.encode(.{}),
10486 .sf = sf,
10487 },
10488 } } };
10489 }
10490 /// C7.2.204 MOVI
10491 pub fn movi(d: Register, imm8: u8, shift: union(enum) { lsl: u5, msl: u5, replicate }) Instruction {
10492 const arrangement = switch (d.format) {
10493 else => unreachable,
10494 .scalar => |vs| switch (vs) {
10495 else => unreachable,
10496 .double => .@"1d",
10497 },
10498 .vector => |arrangement| switch (arrangement) {
10499 .@"1d" => unreachable,
10500 else => arrangement,
10501 },
10502 };
10503 return .{ .data_processing_vector = .{ .simd_modified_immediate = .{
10504 .movi = .{
10505 .Rd = d.alias.encode(.{ .V = true }),
10506 .imm5 = @truncate(imm8 >> 0),
10507 .cmode = switch (shift) {
10508 .lsl => |amount| switch (arrangement) {
10509 else => unreachable,
10510 .@"8b", .@"16b" => @as(u4, 0b1110) |
10511 @as(u4, @as(u0, @intCast(@shrExact(amount, 3)))) << 1,
10512 .@"4h", .@"8h" => @as(u4, 0b1000) |
10513 @as(u4, @as(u1, @intCast(@shrExact(amount, 3)))) << 1,
10514 .@"2s", .@"4s" => @as(u4, 0b0000) |
10515 @as(u4, @as(u2, @intCast(@shrExact(amount, 3)))) << 1,
10516 },
10517 .msl => |amount| switch (arrangement) {
10518 else => unreachable,
10519 .@"2s", .@"4s" => @as(u4, 0b1100) |
10520 @as(u4, @as(u1, @intCast(@shrExact(amount, 3) - 1))) << 0,
10521 },
10522 .replicate => switch (arrangement) {
10523 else => unreachable,
10524 .@"1d", .@"2d" => 0b1110,
10525 },
10526 },
10527 .imm3 = @intCast(imm8 >> 5),
10528 .op = switch (shift) {
10529 .lsl, .msl => 0b0,
10530 .replicate => 0b1,
10531 },
10532 .Q = arrangement.size(),
10533 },
10534 } } };
10535 }
10536 /// C6.2.225 MOVK
10537 pub fn movk(
10538 d: Register,
10539 imm: u16,
10540 shift: struct { lsl: DataProcessingImmediate.MoveWideImmediate.Hw = .@"0" },
10541 ) Instruction {
10542 const sf = d.format.integer;
10543 assert(sf == .doubleword or shift.lsl.sf() == .word);
10544 return .{ .data_processing_immediate = .{ .move_wide_immediate = .{
10545 .movk = .{
10546 .Rd = d.alias.encode(.{}),
10547 .imm16 = imm,
10548 .hw = shift.lsl,
10549 .sf = sf,
10550 },
10551 } } };
10552 }
10553 /// C6.2.226 MOVN
10554 pub fn movn(
10555 d: Register,
10556 imm: u16,
10557 shift: struct { lsl: DataProcessingImmediate.MoveWideImmediate.Hw = .@"0" },
10558 ) Instruction {
10559 const sf = d.format.integer;
10560 assert(sf == .doubleword or shift.lsl.sf() == .word);
10561 return .{ .data_processing_immediate = .{ .move_wide_immediate = .{
10562 .movn = .{
10563 .Rd = d.alias.encode(.{}),
10564 .imm16 = imm,
10565 .hw = shift.lsl,
10566 .sf = sf,
10567 },
10568 } } };
10569 }
10570 /// C6.2.227 MOVZ
10571 pub fn movz(
10572 d: Register,
10573 imm: u16,
10574 shift: struct { lsl: DataProcessingImmediate.MoveWideImmediate.Hw = .@"0" },
10575 ) Instruction {
10576 const sf = d.format.integer;
10577 assert(sf == .doubleword or shift.lsl.sf() == .word);
10578 return .{ .data_processing_immediate = .{ .move_wide_immediate = .{
10579 .movz = .{
10580 .Rd = d.alias.encode(.{}),
10581 .imm16 = imm,
10582 .hw = shift.lsl,
10583 .sf = sf,
10584 },
10585 } } };
10586 }
10587 /// C6.2.228 MRS
10588 pub fn mrs(t: Register, op0: u2, op1: u3, n: u4, m: u4, op2: u3) Instruction {
10589 assert(t.format.integer == .doubleword);
10590 return .{ .branch_exception_generating_system = .{ .system_register_move = .{
10591 .mrs = .{
10592 .Rt = t.alias.encode(.{}),
10593 .op2 = op2,
10594 .CRm = m,
10595 .CRn = n,
10596 .op1 = op1,
10597 .o0 = @intCast(op0 - 0b10),
10598 },
10599 } } };
10600 }
10601 /// C6.2.230 MSR (register)
10602 pub fn msr(op0: u2, op1: u3, n: u4, m: u4, op2: u3, t: Register) Instruction {
10603 assert(t.format.integer == .doubleword);
10604 return .{ .branch_exception_generating_system = .{ .system_register_move = .{
10605 .msr = .{
10606 .Rt = t.alias.encode(.{}),
10607 .op2 = op2,
10608 .CRm = m,
10609 .CRn = n,
10610 .op1 = op1,
10611 .o0 = @intCast(op0 - 0b10),
10612 },
10613 } } };
10614 }
10615 /// C6.2.231 MSUB
10616 pub fn msub(d: Register, n: Register, m: Register, a: Register) Instruction {
10617 const sf = d.format.integer;
10618 assert(n.format.integer == sf and m.format.integer == sf and a.format.integer == sf);
10619 return .{ .data_processing_register = .{ .data_processing_three_source = .{
10620 .msub = .{
10621 .Rd = d.alias.encode(.{}),
10622 .Rn = n.alias.encode(.{}),
10623 .Ra = a.alias.encode(.{}),
10624 .Rm = m.alias.encode(.{}),
10625 .sf = sf,
10626 },
10627 } } };
10628 }
10629 /// C6.2.238 NOP
10630 pub fn nop() Instruction {
10631 return .{ .branch_exception_generating_system = .{ .hints = .{
10632 .nop = .{},
10633 } } };
10634 }
10635 /// C6.2.239 ORN (shifted register)
10636 /// C7.2.211 ORN (vector)
10637 pub fn orn(d: Register, n: Register, form: union(enum) {
10638 register: Register,
10639 shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
10640 shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
10641 }) Instruction {
10642 switch (d.format) {
10643 else => unreachable,
10644 .integer => |sf| {
10645 assert(n.format.integer == sf);
10646 form: switch (form) {
10647 .register => |register| continue :form .{ .shifted_register = .{ .register = register } },
10648 .shifted_register_explicit => |shifted_register_explicit| {
10649 assert(shifted_register_explicit.register.format.integer == sf);
10650 return .{ .data_processing_register = .{ .logical_shifted_register = .{
10651 .orn = .{
10652 .Rd = d.alias.encode(.{}),
10653 .Rn = n.alias.encode(.{}),
10654 .imm6 = switch (sf) {
10655 .word => @as(u5, @intCast(shifted_register_explicit.amount)),
10656 .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
10657 },
10658 .Rm = shifted_register_explicit.register.alias.encode(.{}),
10659 .shift = shifted_register_explicit.shift,
10660 .sf = sf,
10661 },
10662 } } };
10663 },
10664 .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
10665 .register = shifted_register.register,
10666 .shift = shifted_register.shift,
10667 .amount = switch (shifted_register.shift) {
10668 .lsl, .lsr, .asr, .ror => |amount| amount,
10669 },
10670 } },
10671 }
10672 },
10673 .vector => |arrangement| {
10674 const m = form.register;
10675 assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement);
10676 return .{ .data_processing_vector = .{ .simd_three_same = .{
10677 .orn = .{
10678 .Rd = d.alias.encode(.{ .V = true }),
10679 .Rn = n.alias.encode(.{ .V = true }),
10680 .Rm = m.alias.encode(.{ .V = true }),
10681 .Q = arrangement.size(),
10682 },
10683 } } };
10684 },
10685 }
10686 }
10687 /// C6.2.240 ORR (immediate)
10688 /// C6.2.241 ORR (shifted register)
10689 /// C7.2.212 ORR (vector, immediate)
10690 /// C7.2.213 ORR (vector, register)
10691 pub fn orr(d: Register, n: Register, form: union(enum) {
10692 immediate: DataProcessingImmediate.Bitmask,
10693 shifted_immediate: struct { immediate: u8, lsl: u5 = 0 },
10694 register: Register,
10695 shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
10696 shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
10697 }) Instruction {
10698 switch (d.format) {
10699 else => unreachable,
10700 .integer => |sf| {
10701 assert(n.format.integer == sf);
10702 form: switch (form) {
10703 .immediate => |bitmask| {
10704 assert(bitmask.validImmediate(sf));
10705 return .{ .data_processing_immediate = .{ .logical_immediate = .{
10706 .orr = .{
10707 .Rd = d.alias.encode(.{ .sp = true }),
10708 .Rn = n.alias.encode(.{}),
10709 .imm = bitmask,
10710 .sf = sf,
10711 },
10712 } } };
10713 },
10714 .shifted_immediate => unreachable,
10715 .register => |register| continue :form .{ .shifted_register = .{ .register = register } },
10716 .shifted_register_explicit => |shifted_register_explicit| {
10717 assert(shifted_register_explicit.register.format.integer == sf);
10718 return .{ .data_processing_register = .{ .logical_shifted_register = .{
10719 .orr = .{
10720 .Rd = d.alias.encode(.{}),
10721 .Rn = n.alias.encode(.{}),
10722 .imm6 = switch (sf) {
10723 .word => @as(u5, @intCast(shifted_register_explicit.amount)),
10724 .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
10725 },
10726 .Rm = shifted_register_explicit.register.alias.encode(.{}),
10727 .shift = shifted_register_explicit.shift,
10728 .sf = sf,
10729 },
10730 } } };
10731 },
10732 .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
10733 .register = shifted_register.register,
10734 .shift = shifted_register.shift,
10735 .amount = switch (shifted_register.shift) {
10736 .lsl, .lsr, .asr, .ror => |amount| amount,
10737 },
10738 } },
10739 }
10740 },
10741 .vector => |arrangement| switch (form) {
10742 else => unreachable,
10743 .shifted_immediate => |shifted_immediate| {
10744 assert(n.alias == d.alias and n.format.vector == arrangement);
10745 return .{ .data_processing_vector = .{ .simd_modified_immediate = .{
10746 .orr = .{
10747 .Rd = d.alias.encode(.{ .V = true }),
10748 .imm5 = @truncate(shifted_immediate.immediate >> 0),
10749 .cmode = switch (arrangement) {
10750 else => unreachable,
10751 .@"4h", .@"8h" => @as(u3, 0b100) |
10752 @as(u3, @as(u1, @intCast(@shrExact(shifted_immediate.lsl, 3)))) << 0,
10753 .@"2s", .@"4s" => @as(u3, 0b000) |
10754 @as(u3, @as(u2, @intCast(@shrExact(shifted_immediate.lsl, 3)))) << 0,
10755 },
10756 .imm3 = @intCast(shifted_immediate.immediate >> 5),
10757 .Q = arrangement.size(),
10758 },
10759 } } };
10760 },
10761 .register => |m| {
10762 assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement);
10763 return .{ .data_processing_vector = .{ .simd_three_same = .{
10764 .orr = .{
10765 .Rd = d.alias.encode(.{ .V = true }),
10766 .Rn = n.alias.encode(.{ .V = true }),
10767 .Rm = m.alias.encode(.{ .V = true }),
10768 .Q = arrangement.size(),
10769 },
10770 } } };
10771 },
10772 },
10773 }
10774 }
10775 /// C6.2.247 PRFM (immediate)
10776 /// C6.2.248 PRFM (literal)
10777 /// C6.2.249 PRFM (register)
10778 pub fn prfm(prfop: LoadStore.PrfOp, form: union(enum) {
10779 unsigned_offset: struct { base: Register, offset: u15 = 0 },
10780 base: Register,
10781 literal: i21,
10782 extended_register_explicit: struct {
10783 base: Register,
10784 index: Register,
10785 option: LoadStore.RegisterRegisterOffset.Option,
10786 amount: LoadStore.RegisterRegisterOffset.Extend.Amount,
10787 },
10788 extended_register: struct {
10789 base: Register,
10790 index: Register,
10791 extend: LoadStore.RegisterRegisterOffset.Extend,
10792 },
10793 }) Instruction {
10794 form: switch (form) {
10795 .unsigned_offset => |unsigned_offset| {
10796 assert(unsigned_offset.base.format.integer == .doubleword);
10797 return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
10798 .prfm = .{
10799 .prfop = prfop,
10800 .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
10801 .imm12 = @intCast(@shrExact(unsigned_offset.offset, 3)),
10802 },
10803 } } } };
10804 },
10805 .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
10806 .literal => |offset| return .{ .load_store = .{ .register_literal = .{ .integer = .{
10807 .prfm = .{
10808 .prfop = prfop,
10809 .imm19 = @intCast(@shrExact(offset, 2)),
10810 },
10811 } } } },
10812 .extended_register_explicit => |extended_register_explicit| {
10813 assert(extended_register_explicit.base.format.integer == .doubleword and
10814 extended_register_explicit.index.format.integer == extended_register_explicit.option.sf());
10815 return .{ .load_store = .{ .register_register_offset = .{ .integer = .{
10816 .prfm = .{
10817 .prfop = prfop,
10818 .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }),
10819 .S = switch (extended_register_explicit.amount) {
10820 0 => false,
10821 3 => true,
10822 else => unreachable,
10823 },
10824 .option = extended_register_explicit.option,
10825 .Rm = extended_register_explicit.index.alias.encode(.{}),
10826 },
10827 } } } };
10828 },
10829 .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
10830 .base = extended_register.base,
10831 .index = extended_register.index,
10832 .option = extended_register.extend,
10833 .amount = switch (extended_register.extend) {
10834 .uxtw, .lsl, .sxtw, .sxtx => |amount| amount,
10835 },
10836 } },
10837 }
10838 }
10839 /// C6.2.253 RBIT
10840 pub fn rbit(d: Register, n: Register) Instruction {
10841 const sf = d.format.integer;
10842 assert(n.format.integer == sf);
10843 return .{ .data_processing_register = .{ .data_processing_one_source = .{
10844 .rbit = .{
10845 .Rd = d.alias.encode(.{}),
10846 .Rn = n.alias.encode(.{}),
10847 .sf = sf,
10848 },
10849 } } };
10850 }
10851 /// C6.2.254 RET
10852 pub fn ret(n: Register) Instruction {
10853 assert(n.format.integer == .doubleword);
10854 return .{ .branch_exception_generating_system = .{ .unconditional_branch_register = .{
10855 .ret = .{ .Rn = n.alias.encode(.{}) },
10856 } } };
10857 }
10858 /// C6.2.256 REV
10859 pub fn rev(d: Register, n: Register) Instruction {
10860 const sf = d.format.integer;
10861 assert(n.format.integer == sf);
10862 return .{ .data_processing_register = .{ .data_processing_one_source = .{
10863 .rev = .{
10864 .Rd = d.alias.encode(.{}),
10865 .Rn = n.alias.encode(.{}),
10866 .opc0 = sf,
10867 .sf = sf,
10868 },
10869 } } };
10870 }
10871 /// C6.2.257 REV16
10872 pub fn rev16(d: Register, n: Register) Instruction {
10873 const sf = d.format.integer;
10874 assert(n.format.integer == sf);
10875 return .{ .data_processing_register = .{ .data_processing_one_source = .{
10876 .rev16 = .{
10877 .Rd = d.alias.encode(.{}),
10878 .Rn = n.alias.encode(.{}),
10879 .sf = sf,
10880 },
10881 } } };
10882 }
10883 /// C6.2.258 REV32
10884 pub fn rev32(d: Register, n: Register) Instruction {
10885 assert(d.format.integer == .doubleword and n.format.integer == .doubleword);
10886 return .{ .data_processing_register = .{ .data_processing_one_source = .{
10887 .rev32 = .{
10888 .Rd = d.alias.encode(.{}),
10889 .Rn = n.alias.encode(.{}),
10890 },
10891 } } };
10892 }
10893 /// C6.2.263 RORV
10894 pub fn rorv(d: Register, n: Register, m: Register) Instruction {
10895 const sf = d.format.integer;
10896 assert(n.format.integer == sf and m.format.integer == sf);
10897 return .{ .data_processing_register = .{ .data_processing_two_source = .{
10898 .rorv = .{
10899 .Rd = d.alias.encode(.{}),
10900 .Rn = n.alias.encode(.{}),
10901 .Rm = m.alias.encode(.{}),
10902 .sf = sf,
10903 },
10904 } } };
10905 }
10906 /// C6.2.264 SB
10907 pub fn sb() Instruction {
10908 return .{ .branch_exception_generating_system = .{ .barriers = .{
10909 .sb = .{},
10910 } } };
10911 }
10912 /// C6.2.265 SBC
10913 pub fn sbc(d: Register, n: Register, m: Register) Instruction {
10914 const sf = d.format.integer;
10915 assert(n.format.integer == sf and m.format.integer == sf);
10916 return .{ .data_processing_register = .{ .add_subtract_with_carry = .{
10917 .sbc = .{
10918 .Rd = d.alias.encode(.{}),
10919 .Rn = n.alias.encode(.{}),
10920 .Rm = m.alias.encode(.{}),
10921 .sf = sf,
10922 },
10923 } } };
10924 }
10925 /// C6.2.266 SBCS
10926 pub fn sbcs(d: Register, n: Register, m: Register) Instruction {
10927 const sf = d.format.integer;
10928 assert(n.format.integer == sf and m.format.integer == sf);
10929 return .{ .data_processing_register = .{ .add_subtract_with_carry = .{
10930 .sbcs = .{
10931 .Rd = d.alias.encode(.{}),
10932 .Rn = n.alias.encode(.{}),
10933 .Rm = m.alias.encode(.{}),
10934 .sf = sf,
10935 },
10936 } } };
10937 }
10938 /// C6.2.268 SBFM
10939 pub fn sbfm(d: Register, n: Register, bitmask: DataProcessingImmediate.Bitmask) Instruction {
10940 const sf = d.format.integer;
10941 assert(n.format.integer == sf and bitmask.validBitfield(sf));
10942 return .{ .data_processing_immediate = .{ .bitfield = .{
10943 .sbfm = .{
10944 .Rd = d.alias.encode(.{}),
10945 .Rn = n.alias.encode(.{}),
10946 .imm = bitmask,
10947 .sf = sf,
10948 },
10949 } } };
10950 }
10951 /// C7.2.236 SCVTF (scalar, integer)
10952 pub fn scvtf(d: Register, n: Register) Instruction {
10953 return .{ .data_processing_vector = .{ .convert_float_integer = .{
10954 .scvtf = .{
10955 .Rd = d.alias.encode(.{ .V = true }),
10956 .Rn = n.alias.encode(.{}),
10957 .ftype = switch (d.format.scalar) {
10958 else => unreachable,
10959 .single => .single,
10960 .double => .double,
10961 .half => .half,
10962 },
10963 .sf = n.format.integer,
10964 },
10965 } } };
10966 }
10967 /// C6.2.270 SDIV
10968 pub fn sdiv(d: Register, n: Register, m: Register) Instruction {
10969 const sf = d.format.integer;
10970 assert(n.format.integer == sf and m.format.integer == sf);
10971 return .{ .data_processing_register = .{ .data_processing_two_source = .{
10972 .sdiv = .{
10973 .Rd = d.alias.encode(.{}),
10974 .Rn = n.alias.encode(.{}),
10975 .Rm = m.alias.encode(.{}),
10976 .sf = sf,
10977 },
10978 } } };
10979 }
10980 /// C6.2.280 SEV
10981 pub fn sev() Instruction {
10982 return .{ .branch_exception_generating_system = .{ .hints = .{
10983 .sev = .{},
10984 } } };
10985 }
10986 /// C6.2.281 SEVL
10987 pub fn sevl() Instruction {
10988 return .{ .branch_exception_generating_system = .{ .hints = .{
10989 .sevl = .{},
10990 } } };
10991 }
10992 /// C6.2.282 SMADDL
10993 pub fn smaddl(d: Register, n: Register, m: Register, a: Register) Instruction {
10994 assert(d.format.integer == .doubleword and n.format.integer == .word and m.format.integer == .word and a.format.integer == .doubleword);
10995 return .{ .data_processing_register = .{ .data_processing_three_source = .{
10996 .smaddl = .{
10997 .Rd = d.alias.encode(.{}),
10998 .Rn = n.alias.encode(.{}),
10999 .Ra = a.alias.encode(.{}),
11000 .Rm = m.alias.encode(.{}),
11001 },
11002 } } };
11003 }
11004 /// C6.2.283 SMC
11005 pub fn smc(imm: u16) Instruction {
11006 return .{ .branch_exception_generating_system = .{ .exception_generating = .{
11007 .smc = .{ .imm16 = imm },
11008 } } };
11009 }
11010 /// C7.2.279 SMOV
11011 pub fn smov(d: Register, n: Register) Instruction {
11012 const sf = d.format.integer;
11013 const vs = n.format.element.size;
11014 switch (vs) {
11015 else => unreachable,
11016 .byte, .half => {},
11017 .single => assert(sf == .doubleword),
11018 }
11019 return .{ .data_processing_vector = .{ .simd_copy = .{
11020 .smov = .{
11021 .Rd = d.alias.encode(.{}),
11022 .Rn = n.alias.encode(.{ .V = true }),
11023 .imm5 = switch (vs) {
11024 else => unreachable,
11025 .byte => @as(u5, @as(u4, @intCast(n.format.element.index))) << 1 | @as(u5, 0b1) << 0,
11026 .half => @as(u5, @as(u3, @intCast(n.format.element.index))) << 2 | @as(u5, 0b10) << 0,
11027 .single => @as(u5, @as(u2, @intCast(n.format.element.index))) << 3 | @as(u5, 0b100) << 0,
11028 },
11029 .Q = sf,
11030 },
11031 } } };
11032 }
11033 /// C6.2.287 SMSUBL
11034 pub fn smsubl(d: Register, n: Register, m: Register, a: Register) Instruction {
11035 assert(d.format.integer == .doubleword and n.format.integer == .word and m.format.integer == .word and a.format.integer == .doubleword);
11036 return .{ .data_processing_register = .{ .data_processing_three_source = .{
11037 .smsubl = .{
11038 .Rd = d.alias.encode(.{}),
11039 .Rn = n.alias.encode(.{}),
11040 .Ra = a.alias.encode(.{}),
11041 .Rm = m.alias.encode(.{}),
11042 },
11043 } } };
11044 }
11045 /// C6.2.288 SMULH
11046 pub fn smulh(d: Register, n: Register, m: Register) Instruction {
11047 assert(d.format.integer == .doubleword and n.format.integer == .doubleword and m.format.integer == .doubleword);
11048 return .{ .data_processing_register = .{ .data_processing_three_source = .{
11049 .smulh = .{
11050 .Rd = d.alias.encode(.{}),
11051 .Rn = n.alias.encode(.{}),
11052 .Rm = m.alias.encode(.{}),
11053 },
11054 } } };
11055 }
11056 /// C6.2.321 STP
11057 /// C7.2.330 STP (SIMD&FP)
11058 pub fn stp(t1: Register, t2: Register, form: union(enum) {
11059 post_index: struct { base: Register, index: i10 },
11060 pre_index: struct { base: Register, index: i10 },
11061 signed_offset: struct { base: Register, offset: i10 = 0 },
11062 base: Register,
11063 }) Instruction {
11064 switch (t1.format) {
11065 else => unreachable,
11066 .integer => |sf| {
11067 assert(t2.format.integer == sf);
11068 form: switch (form) {
11069 .post_index => |post_index| {
11070 assert(post_index.base.format.integer == .doubleword);
11071 return .{ .load_store = .{ .register_pair_post_indexed = .{ .integer = .{
11072 .stp = .{
11073 .Rt = t1.alias.encode(.{}),
11074 .Rn = post_index.base.alias.encode(.{ .sp = true }),
11075 .Rt2 = t2.alias.encode(.{}),
11076 .imm7 = @intCast(@shrExact(post_index.index, @as(u2, 2) + @intFromEnum(sf))),
11077 .sf = sf,
11078 },
11079 } } } };
11080 },
11081 .signed_offset => |signed_offset| {
11082 assert(signed_offset.base.format.integer == .doubleword);
11083 return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{
11084 .stp = .{
11085 .Rt = t1.alias.encode(.{}),
11086 .Rn = signed_offset.base.alias.encode(.{ .sp = true }),
11087 .Rt2 = t2.alias.encode(.{}),
11088 .imm7 = @intCast(@shrExact(signed_offset.offset, @as(u2, 2) + @intFromEnum(sf))),
11089 .sf = sf,
11090 },
11091 } } } };
11092 },
11093 .pre_index => |pre_index| {
11094 assert(pre_index.base.format.integer == .doubleword);
11095 return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{
11096 .stp = .{
11097 .Rt = t1.alias.encode(.{}),
11098 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
11099 .Rt2 = t2.alias.encode(.{}),
11100 .imm7 = @intCast(@shrExact(pre_index.index, @as(u2, 2) + @intFromEnum(sf))),
11101 .sf = sf,
11102 },
11103 } } } };
11104 },
11105 .base => |base| continue :form .{ .signed_offset = .{ .base = base } },
11106 }
11107 },
11108 .scalar => |vs| {
11109 assert(t2.format.scalar == vs);
11110 form: switch (form) {
11111 .post_index => |post_index| {
11112 assert(post_index.base.format.integer == .doubleword);
11113 return .{ .load_store = .{ .register_pair_post_indexed = .{ .vector = .{
11114 .stp = .{
11115 .Rt = t1.alias.encode(.{ .V = true }),
11116 .Rn = post_index.base.alias.encode(.{ .sp = true }),
11117 .Rt2 = t2.alias.encode(.{ .V = true }),
11118 .imm7 = @intCast(@shrExact(post_index.index, @intFromEnum(vs))),
11119 .opc = .encode(vs),
11120 },
11121 } } } };
11122 },
11123 .signed_offset => |signed_offset| {
11124 assert(signed_offset.base.format.integer == .doubleword);
11125 return .{ .load_store = .{ .register_pair_offset = .{ .vector = .{
11126 .stp = .{
11127 .Rt = t1.alias.encode(.{ .V = true }),
11128 .Rn = signed_offset.base.alias.encode(.{ .sp = true }),
11129 .Rt2 = t2.alias.encode(.{ .V = true }),
11130 .imm7 = @intCast(@shrExact(signed_offset.offset, @intFromEnum(vs))),
11131 .opc = .encode(vs),
11132 },
11133 } } } };
11134 },
11135 .pre_index => |pre_index| {
11136 assert(pre_index.base.format.integer == .doubleword);
11137 return .{ .load_store = .{ .register_pair_pre_indexed = .{ .vector = .{
11138 .stp = .{
11139 .Rt = t1.alias.encode(.{ .V = true }),
11140 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
11141 .Rt2 = t2.alias.encode(.{ .V = true }),
11142 .imm7 = @intCast(@shrExact(pre_index.index, @intFromEnum(vs))),
11143 .opc = .encode(vs),
11144 },
11145 } } } };
11146 },
11147 .base => |base| continue :form .{ .signed_offset = .{ .base = base } },
11148 }
11149 },
11150 }
11151 }
11152 /// C6.2.322 STR (immediate)
11153 /// C7.2.331 STR (immediate, SIMD&FP)
11154 pub fn str(t: Register, form: union(enum) {
11155 post_index: struct { base: Register, index: i9 },
11156 pre_index: struct { base: Register, index: i9 },
11157 unsigned_offset: struct { base: Register, offset: u16 = 0 },
11158 base: Register,
11159 }) Instruction {
11160 switch (t.format) {
11161 else => unreachable,
11162 .integer => |sf| form: switch (form) {
11163 .post_index => |post_index| {
11164 assert(post_index.base.format.integer == .doubleword);
11165 return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{
11166 .str = .{
11167 .Rt = t.alias.encode(.{}),
11168 .Rn = post_index.base.alias.encode(.{ .sp = true }),
11169 .imm9 = post_index.index,
11170 .sf = sf,
11171 },
11172 } } } };
11173 },
11174 .pre_index => |pre_index| {
11175 assert(pre_index.base.format.integer == .doubleword);
11176 return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
11177 .str = .{
11178 .Rt = t.alias.encode(.{}),
11179 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
11180 .imm9 = pre_index.index,
11181 .sf = sf,
11182 },
11183 } } } };
11184 },
11185 .unsigned_offset => |unsigned_offset| {
11186 assert(unsigned_offset.base.format.integer == .doubleword);
11187 return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
11188 .str = .{
11189 .Rt = t.alias.encode(.{}),
11190 .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
11191 .imm12 = @intCast(@shrExact(unsigned_offset.offset, @as(u2, 2) + @intFromEnum(sf))),
11192 .sf = sf,
11193 },
11194 } } } };
11195 },
11196 .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
11197 },
11198 .scalar => |vs| form: switch (form) {
11199 .post_index => |post_index| {
11200 assert(post_index.base.format.integer == .doubleword);
11201 return .{ .load_store = .{ .register_immediate_post_indexed = .{ .vector = .{
11202 .str = .{
11203 .Rt = t.alias.encode(.{ .V = true }),
11204 .Rn = post_index.base.alias.encode(.{ .sp = true }),
11205 .imm9 = post_index.index,
11206 .opc1 = .encode(vs),
11207 .size = .encode(vs),
11208 },
11209 } } } };
11210 },
11211 .pre_index => |pre_index| {
11212 assert(pre_index.base.format.integer == .doubleword);
11213 return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .vector = .{
11214 .str = .{
11215 .Rt = t.alias.encode(.{ .V = true }),
11216 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
11217 .imm9 = pre_index.index,
11218 .opc1 = .encode(vs),
11219 .size = .encode(vs),
11220 },
11221 } } } };
11222 },
11223 .unsigned_offset => |unsigned_offset| {
11224 assert(unsigned_offset.base.format.integer == .doubleword);
11225 return .{ .load_store = .{ .register_unsigned_immediate = .{ .vector = .{
11226 .str = .{
11227 .Rt = t.alias.encode(.{ .V = true }),
11228 .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
11229 .imm12 = @intCast(@shrExact(unsigned_offset.offset, @intFromEnum(vs))),
11230 .opc1 = .encode(vs),
11231 .size = .encode(vs),
11232 },
11233 } } } };
11234 },
11235 .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
11236 },
11237 }
11238 }
11239 /// C6.2.324 STRB (immediate)
11240 pub fn strb(t: Register, form: union(enum) {
11241 post_index: struct { base: Register, index: i9 },
11242 pre_index: struct { base: Register, index: i9 },
11243 unsigned_offset: struct { base: Register, offset: u12 = 0 },
11244 base: Register,
11245 }) Instruction {
11246 assert(t.format.integer == .word);
11247 form: switch (form) {
11248 .post_index => |post_index| {
11249 assert(post_index.base.format.integer == .doubleword);
11250 return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{
11251 .strb = .{
11252 .Rt = t.alias.encode(.{}),
11253 .Rn = post_index.base.alias.encode(.{ .sp = true }),
11254 .imm9 = post_index.index,
11255 },
11256 } } } };
11257 },
11258 .pre_index => |pre_index| {
11259 assert(pre_index.base.format.integer == .doubleword);
11260 return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
11261 .strb = .{
11262 .Rt = t.alias.encode(.{}),
11263 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
11264 .imm9 = pre_index.index,
11265 },
11266 } } } };
11267 },
11268 .unsigned_offset => |unsigned_offset| {
11269 assert(unsigned_offset.base.format.integer == .doubleword);
11270 return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
11271 .strb = .{
11272 .Rt = t.alias.encode(.{}),
11273 .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
11274 .imm12 = unsigned_offset.offset,
11275 },
11276 } } } };
11277 },
11278 .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
11279 }
11280 }
11281 /// C6.2.326 STRH (immediate)
11282 pub fn strh(t: Register, form: union(enum) {
11283 post_index: struct { base: Register, index: i9 },
11284 pre_index: struct { base: Register, index: i9 },
11285 unsigned_offset: struct { base: Register, offset: u13 = 0 },
11286 base: Register,
11287 }) Instruction {
11288 assert(t.format.integer == .word);
11289 form: switch (form) {
11290 .post_index => |post_index| {
11291 assert(post_index.base.format.integer == .doubleword);
11292 return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{
11293 .strh = .{
11294 .Rt = t.alias.encode(.{}),
11295 .Rn = post_index.base.alias.encode(.{ .sp = true }),
11296 .imm9 = post_index.index,
11297 },
11298 } } } };
11299 },
11300 .pre_index => |pre_index| {
11301 assert(pre_index.base.format.integer == .doubleword);
11302 return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
11303 .strh = .{
11304 .Rt = t.alias.encode(.{}),
11305 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
11306 .imm9 = pre_index.index,
11307 },
11308 } } } };
11309 },
11310 .unsigned_offset => |unsigned_offset| {
11311 assert(unsigned_offset.base.format.integer == .doubleword);
11312 return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
11313 .strh = .{
11314 .Rt = t.alias.encode(.{}),
11315 .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
11316 .imm12 = @intCast(@shrExact(unsigned_offset.offset, 1)),
11317 },
11318 } } } };
11319 },
11320 .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
11321 }
11322 }
11323 /// C6.2.346 STUR
11324 /// C7.2.333 STUR (SIMD&FP)
11325 pub fn stur(t: Register, n: Register, simm: i9) Instruction {
11326 assert(n.format.integer == .doubleword);
11327 switch (t.format) {
11328 else => unreachable,
11329 .integer => |sf| return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
11330 .stur = .{
11331 .Rt = t.alias.encode(.{}),
11332 .Rn = n.alias.encode(.{ .sp = true }),
11333 .imm9 = simm,
11334 .sf = sf,
11335 },
11336 } } } },
11337 .scalar => |vs| return .{ .load_store = .{ .register_unscaled_immediate = .{ .vector = .{
11338 .stur = .{
11339 .Rt = t.alias.encode(.{ .V = true }),
11340 .Rn = n.alias.encode(.{ .sp = true }),
11341 .imm9 = simm,
11342 .opc1 = .encode(vs),
11343 .size = .encode(vs),
11344 },
11345 } } } },
11346 }
11347 }
11348 /// C6.2.347 STURB
11349 pub fn sturb(t: Register, n: Register, simm: i9) Instruction {
11350 assert(t.format.integer == .word and n.format.integer == .doubleword);
11351 return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
11352 .sturb = .{
11353 .Rt = t.alias.encode(.{}),
11354 .Rn = n.alias.encode(.{ .sp = true }),
11355 .imm9 = simm,
11356 },
11357 } } } };
11358 }
11359 /// C6.2.348 STURH
11360 pub fn sturh(t: Register, n: Register, simm: i9) Instruction {
11361 assert(t.format.integer == .word and n.format.integer == .doubleword);
11362 return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
11363 .sturh = .{
11364 .Rt = t.alias.encode(.{}),
11365 .Rn = n.alias.encode(.{ .sp = true }),
11366 .imm9 = simm,
11367 },
11368 } } } };
11369 }
11370 /// C6.2.356 SUB (extended register)
11371 /// C6.2.357 SUB (immediate)
11372 /// C6.2.358 SUB (shifted register)
11373 pub fn sub(d: Register, n: Register, form: union(enum) {
11374 extended_register_explicit: struct {
11375 register: Register,
11376 option: DataProcessingRegister.AddSubtractExtendedRegister.Option,
11377 amount: DataProcessingRegister.AddSubtractExtendedRegister.Extend.Amount,
11378 },
11379 extended_register: struct { register: Register, extend: DataProcessingRegister.AddSubtractExtendedRegister.Extend },
11380 immediate: u12,
11381 shifted_immediate: struct { immediate: u12, lsl: DataProcessingImmediate.AddSubtractImmediate.Shift = .@"0" },
11382 register: Register,
11383 shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
11384 shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
11385 }) Instruction {
11386 const sf = d.format.integer;
11387 assert(n.format.integer == sf);
11388 form: switch (form) {
11389 .extended_register_explicit => |extended_register_explicit| {
11390 assert(extended_register_explicit.register.format.integer == extended_register_explicit.option.sf());
11391 return .{ .data_processing_register = .{ .add_subtract_extended_register = .{
11392 .sub = .{
11393 .Rd = d.alias.encode(.{ .sp = true }),
11394 .Rn = n.alias.encode(.{ .sp = true }),
11395 .imm3 = switch (extended_register_explicit.amount) {
11396 0...4 => |amount| amount,
11397 else => unreachable,
11398 },
11399 .option = extended_register_explicit.option,
11400 .Rm = extended_register_explicit.register.alias.encode(.{}),
11401 .sf = sf,
11402 },
11403 } } };
11404 },
11405 .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
11406 .register = extended_register.register,
11407 .option = extended_register.extend,
11408 .amount = switch (extended_register.extend) {
11409 .uxtb, .uxth, .uxtw, .uxtx, .sxtb, .sxth, .sxtw, .sxtx => |amount| amount,
11410 },
11411 } },
11412 .immediate => |immediate| continue :form .{ .shifted_immediate = .{ .immediate = immediate } },
11413 .shifted_immediate => |shifted_immediate| {
11414 return .{ .data_processing_immediate = .{ .add_subtract_immediate = .{
11415 .sub = .{
11416 .Rd = d.alias.encode(.{ .sp = true }),
11417 .Rn = n.alias.encode(.{ .sp = true }),
11418 .imm12 = shifted_immediate.immediate,
11419 .sh = shifted_immediate.lsl,
11420 .sf = sf,
11421 },
11422 } } };
11423 },
11424 .register => |register| continue :form if (d.alias == .sp or n.alias == .sp or register.alias == .sp)
11425 .{ .extended_register = .{ .register = register, .extend = switch (sf) {
11426 .word => .{ .uxtw = 0 },
11427 .doubleword => .{ .uxtx = 0 },
11428 } } }
11429 else
11430 .{ .shifted_register = .{ .register = register } },
11431 .shifted_register_explicit => |shifted_register_explicit| {
11432 assert(shifted_register_explicit.register.format.integer == sf);
11433 return .{ .data_processing_register = .{ .add_subtract_shifted_register = .{
11434 .sub = .{
11435 .Rd = d.alias.encode(.{}),
11436 .Rn = n.alias.encode(.{}),
11437 .imm6 = switch (sf) {
11438 .word => @as(u5, @intCast(shifted_register_explicit.amount)),
11439 .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
11440 },
11441 .Rm = shifted_register_explicit.register.alias.encode(.{}),
11442 .shift = switch (shifted_register_explicit.shift) {
11443 .lsl, .lsr, .asr => |shift| shift,
11444 .ror => unreachable,
11445 },
11446 .sf = sf,
11447 },
11448 } } };
11449 },
11450 .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
11451 .register = shifted_register.register,
11452 .shift = shifted_register.shift,
11453 .amount = switch (shifted_register.shift) {
11454 .lsl, .lsr, .asr => |amount| amount,
11455 .ror => unreachable,
11456 },
11457 } },
11458 }
11459 }
11460 /// C6.2.362 SUBS (extended register)
11461 /// C6.2.363 SUBS (immediate)
11462 /// C6.2.364 SUBS (shifted register)
11463 pub fn subs(d: Register, n: Register, form: union(enum) {
11464 extended_register_explicit: struct {
11465 register: Register,
11466 option: DataProcessingRegister.AddSubtractExtendedRegister.Option,
11467 amount: DataProcessingRegister.AddSubtractExtendedRegister.Extend.Amount,
11468 },
11469 extended_register: struct { register: Register, extend: DataProcessingRegister.AddSubtractExtendedRegister.Extend },
11470 immediate: u12,
11471 shifted_immediate: struct { immediate: u12, lsl: DataProcessingImmediate.AddSubtractImmediate.Shift = .@"0" },
11472 register: Register,
11473 shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
11474 shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
11475 }) Instruction {
11476 const sf = d.format.integer;
11477 assert(n.format.integer == sf);
11478 form: switch (form) {
11479 .extended_register_explicit => |extended_register_explicit| {
11480 assert(extended_register_explicit.register.format.integer == extended_register_explicit.option.sf());
11481 return .{ .data_processing_register = .{ .add_subtract_extended_register = .{
11482 .subs = .{
11483 .Rd = d.alias.encode(.{}),
11484 .Rn = n.alias.encode(.{ .sp = true }),
11485 .imm3 = switch (extended_register_explicit.amount) {
11486 0...4 => |amount| amount,
11487 else => unreachable,
11488 },
11489 .option = extended_register_explicit.option,
11490 .Rm = extended_register_explicit.register.alias.encode(.{}),
11491 .sf = sf,
11492 },
11493 } } };
11494 },
11495 .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
11496 .register = extended_register.register,
11497 .option = extended_register.extend,
11498 .amount = switch (extended_register.extend) {
11499 .uxtb, .uxth, .uxtw, .uxtx, .sxtb, .sxth, .sxtw, .sxtx => |amount| amount,
11500 },
11501 } },
11502 .immediate => |immediate| continue :form .{ .shifted_immediate = .{ .immediate = immediate } },
11503 .shifted_immediate => |shifted_immediate| {
11504 return .{ .data_processing_immediate = .{ .add_subtract_immediate = .{
11505 .subs = .{
11506 .Rd = d.alias.encode(.{}),
11507 .Rn = n.alias.encode(.{ .sp = true }),
11508 .imm12 = shifted_immediate.immediate,
11509 .sh = shifted_immediate.lsl,
11510 .sf = sf,
11511 },
11512 } } };
11513 },
11514 .register => |register| continue :form if (d.alias == .sp or n.alias == .sp or register.alias == .sp)
11515 .{ .extended_register = .{ .register = register, .extend = switch (sf) {
11516 .word => .{ .uxtw = 0 },
11517 .doubleword => .{ .uxtx = 0 },
11518 } } }
11519 else
11520 .{ .shifted_register = .{ .register = register } },
11521 .shifted_register_explicit => |shifted_register_explicit| {
11522 assert(shifted_register_explicit.register.format.integer == sf);
11523 return .{ .data_processing_register = .{ .add_subtract_shifted_register = .{
11524 .subs = .{
11525 .Rd = d.alias.encode(.{}),
11526 .Rn = n.alias.encode(.{}),
11527 .imm6 = switch (sf) {
11528 .word => @as(u5, @intCast(shifted_register_explicit.amount)),
11529 .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
11530 },
11531 .Rm = shifted_register_explicit.register.alias.encode(.{}),
11532 .shift = switch (shifted_register_explicit.shift) {
11533 .lsl, .lsr, .asr => |shift| shift,
11534 .ror => unreachable,
11535 },
11536 .sf = sf,
11537 },
11538 } } };
11539 },
11540 .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
11541 .register = shifted_register.register,
11542 .shift = shifted_register.shift,
11543 .amount = switch (shifted_register.shift) {
11544 .lsl, .lsr, .asr => |amount| amount,
11545 .ror => unreachable,
11546 },
11547 } },
11548 }
11549 }
11550 /// C6.2.365 SVC
11551 pub fn svc(imm: u16) Instruction {
11552 return .{ .branch_exception_generating_system = .{ .exception_generating = .{
11553 .svc = .{ .imm16 = imm },
11554 } } };
11555 }
11556 /// C6.2.372 SYS
11557 pub fn sys(op1: u3, n: u4, m: u4, op2: u3, t: Register) Instruction {
11558 assert(t.format.integer == .doubleword);
11559 return .{ .branch_exception_generating_system = .{ .system = .{
11560 .sys = .{
11561 .Rt = t.alias.encode(.{}),
11562 .op2 = op2,
11563 .CRm = m,
11564 .CRn = n,
11565 .op1 = op1,
11566 },
11567 } } };
11568 }
11569 /// C6.2.373 SYSL
11570 pub fn sysl(t: Register, op1: u3, n: u4, m: u4, op2: u3) Instruction {
11571 assert(t.format.integer == .doubleword);
11572 return .{ .branch_exception_generating_system = .{ .system = .{
11573 .sysl = .{
11574 .Rt = t.alias.encode(.{}),
11575 .op2 = op2,
11576 .CRm = m,
11577 .CRn = n,
11578 .op1 = op1,
11579 },
11580 } } };
11581 }
11582 /// C6.2.374 TBNZ
11583 pub fn tbnz(t: Register, imm: u6, label: i16) Instruction {
11584 return .{ .branch_exception_generating_system = .{ .test_branch_immediate = .{
11585 .tbnz = .{
11586 .Rt = t.alias.encode(.{}),
11587 .imm14 = @intCast(@shrExact(label, 2)),
11588 .b40 = @truncate(switch (t.format.integer) {
11589 .word => @as(u5, @intCast(imm)),
11590 .doubleword => imm,
11591 }),
11592 .b5 = @intCast(imm >> 5),
11593 },
11594 } } };
11595 }
11596 /// C6.2.375 TBZ
11597 pub fn tbz(t: Register, imm: u6, label: i16) Instruction {
11598 return .{ .branch_exception_generating_system = .{ .test_branch_immediate = .{
11599 .tbz = .{
11600 .Rt = t.alias.encode(.{}),
11601 .imm14 = @intCast(@shrExact(label, 2)),
11602 .b40 = @truncate(switch (t.format.integer) {
11603 .word => @as(u5, @intCast(imm)),
11604 .doubleword => imm,
11605 }),
11606 .b5 = @intCast(imm >> 5),
11607 },
11608 } } };
11609 }
11610 /// C6.2.376 TCANCEL
11611 pub fn tcancel(imm: u16) Instruction {
11612 return .{ .branch_exception_generating_system = .{ .exception_generating = .{
11613 .tcancel = .{ .imm16 = imm },
11614 } } };
11615 }
11616 /// C6.2.385 UBFM
11617 pub fn ubfm(d: Register, n: Register, bitmask: DataProcessingImmediate.Bitmask) Instruction {
11618 const sf = d.format.integer;
11619 assert(n.format.integer == sf and bitmask.validBitfield(sf));
11620 return .{ .data_processing_immediate = .{ .bitfield = .{
11621 .ubfm = .{
11622 .Rd = d.alias.encode(.{}),
11623 .Rn = n.alias.encode(.{}),
11624 .imm = bitmask,
11625 .sf = sf,
11626 },
11627 } } };
11628 }
11629 /// C7.2.355 UCVTF (scalar, integer)
11630 pub fn ucvtf(d: Register, n: Register) Instruction {
11631 return .{ .data_processing_vector = .{ .convert_float_integer = .{
11632 .ucvtf = .{
11633 .Rd = d.alias.encode(.{ .V = true }),
11634 .Rn = n.alias.encode(.{}),
11635 .ftype = switch (d.format.scalar) {
11636 else => unreachable,
11637 .single => .single,
11638 .double => .double,
11639 .half => .half,
11640 },
11641 .sf = n.format.integer,
11642 },
11643 } } };
11644 }
11645 /// C6.2.387 UDF
11646 pub fn udf(imm: u16) Instruction {
11647 return .{ .reserved = .{
11648 .udf = .{ .imm16 = imm },
11649 } };
11650 }
11651 /// C6.2.388 UDIV
11652 pub fn udiv(d: Register, n: Register, m: Register) Instruction {
11653 const sf = d.format.integer;
11654 assert(n.format.integer == sf and m.format.integer == sf);
11655 return .{ .data_processing_register = .{ .data_processing_two_source = .{
11656 .udiv = .{
11657 .Rd = d.alias.encode(.{}),
11658 .Rn = n.alias.encode(.{}),
11659 .Rm = m.alias.encode(.{}),
11660 .sf = sf,
11661 },
11662 } } };
11663 }
11664 /// C6.2.389 UMADDL
11665 pub fn umaddl(d: Register, n: Register, m: Register, a: Register) Instruction {
11666 assert(d.format.integer == .doubleword and n.format.integer == .word and m.format.integer == .word and a.format.integer == .doubleword);
11667 return .{ .data_processing_register = .{ .data_processing_three_source = .{
11668 .umaddl = .{
11669 .Rd = d.alias.encode(.{}),
11670 .Rn = n.alias.encode(.{}),
11671 .Ra = a.alias.encode(.{}),
11672 .Rm = m.alias.encode(.{}),
11673 },
11674 } } };
11675 }
11676 /// C6.2.391 UMSUBL
11677 pub fn umsubl(d: Register, n: Register, m: Register, a: Register) Instruction {
11678 assert(d.format.integer == .doubleword and n.format.integer == .word and m.format.integer == .word and a.format.integer == .doubleword);
11679 return .{ .data_processing_register = .{ .data_processing_three_source = .{
11680 .umsubl = .{
11681 .Rd = d.alias.encode(.{}),
11682 .Rn = n.alias.encode(.{}),
11683 .Ra = a.alias.encode(.{}),
11684 .Rm = m.alias.encode(.{}),
11685 },
11686 } } };
11687 }
11688 /// C7.2.371 UMOV
11689 pub fn umov(d: Register, n: Register) Instruction {
11690 const sf = d.format.integer;
11691 const vs = n.format.element.size;
11692 switch (vs) {
11693 else => unreachable,
11694 .byte, .half, .single => assert(sf == .word),
11695 .double => assert(sf == .doubleword),
11696 }
11697 return .{ .data_processing_vector = .{ .simd_copy = .{
11698 .umov = .{
11699 .Rd = d.alias.encode(.{}),
11700 .Rn = n.alias.encode(.{ .V = true }),
11701 .imm5 = switch (vs) {
11702 else => unreachable,
11703 .byte => @as(u5, @as(u4, @intCast(n.format.element.index))) << 1 | @as(u5, 0b1) << 0,
11704 .half => @as(u5, @as(u3, @intCast(n.format.element.index))) << 2 | @as(u5, 0b10) << 0,
11705 .single => @as(u5, @as(u2, @intCast(n.format.element.index))) << 3 | @as(u5, 0b100) << 0,
11706 .double => @as(u5, @as(u1, @intCast(n.format.element.index))) << 4 | @as(u5, 0b1000) << 0,
11707 },
11708 .Q = sf,
11709 },
11710 } } };
11711 }
11712 /// C6.2.392 UMULH
11713 pub fn umulh(d: Register, n: Register, m: Register) Instruction {
11714 assert(d.format.integer == .doubleword and n.format.integer == .doubleword and m.format.integer == .doubleword);
11715 return .{ .data_processing_register = .{ .data_processing_three_source = .{
11716 .umulh = .{
11717 .Rd = d.alias.encode(.{}),
11718 .Rn = n.alias.encode(.{}),
11719 .Rm = m.alias.encode(.{}),
11720 },
11721 } } };
11722 }
11723 /// C6.2.396 WFE
11724 pub fn wfe() Instruction {
11725 return .{ .branch_exception_generating_system = .{ .hints = .{
11726 .wfe = .{},
11727 } } };
11728 }
11729 /// C6.2.398 WFI
11730 pub fn wfi() Instruction {
11731 return .{ .branch_exception_generating_system = .{ .hints = .{
11732 .wfi = .{},
11733 } } };
11734 }
11735 /// C6.2.402 YIELD
11736 pub fn yield() Instruction {
11737 return .{ .branch_exception_generating_system = .{ .hints = .{
11738 .yield = .{},
11739 } } };
11740 }
11741
11742 pub const size = @divExact(@bitSizeOf(Backing), 8);
11743 pub const Backing = u32;
11744 pub fn read(mem: *const [size]u8) Instruction {
11745 return @bitCast(std.mem.readInt(Backing, mem, .little));
11746 }
11747 pub fn write(inst: Instruction, mem: *[size]u8) void {
11748 std.mem.writeInt(Backing, mem, @bitCast(inst), .little);
11749 }
11750
11751 pub fn format(inst: Instruction, writer: *std.Io.Writer) std.Io.Writer.Error!void {
11752 const dis: aarch64.Disassemble = .{};
11753 try dis.printInstruction(inst, writer);
11754 }
11755
11756 comptime {
11757 @setEvalBranchQuota(68_000);
11758 verify(@typeName(Instruction), Instruction);
11759 }
11760 fn verify(name: []const u8, Type: type) void {
11761 switch (@typeInfo(Type)) {
11762 .@"union" => |info| {
11763 if (info.layout != .@"packed" or @bitSizeOf(Type) != @bitSizeOf(Backing)) {
11764 @compileLog(name ++ " should have u32 abi");
11765 }
11766 for (info.fields) |field| verify(name ++ "." ++ field.name, field.type);
11767 },
11768 .@"struct" => |info| {
11769 if (info.layout != .@"packed" or info.backing_integer != Backing) {
11770 @compileLog(name ++ " should have u32 abi");
11771 }
11772 var bit_offset = 0;
11773 for (info.fields) |field| {
11774 if (std.mem.startsWith(u8, field.name, "encoded")) {
11775 if (if (std.fmt.parseInt(u5, field.name["encoded".len..], 10)) |encoded_bit_offset| encoded_bit_offset != bit_offset else |_| true) {
11776 @compileError(std.fmt.comptimePrint("{s}.{s} should be named encoded{d}", .{ name, field.name, bit_offset }));
11777 }
11778 if (field.default_value_ptr != null) {
11779 @compileError(std.fmt.comptimePrint("{s}.{s} should be named decoded{d}", .{ name, field.name, bit_offset }));
11780 }
11781 } else if (std.mem.startsWith(u8, field.name, "decoded")) {
11782 if (if (std.fmt.parseInt(u5, field.name["decoded".len..], 10)) |decoded_bit_offset| decoded_bit_offset != bit_offset else |_| true) {
11783 @compileError(std.fmt.comptimePrint("{s}.{s} should be named decoded{d}", .{ name, field.name, bit_offset }));
11784 }
11785 if (field.default_value_ptr == null) {
11786 @compileError(std.fmt.comptimePrint("{s}.{s} should be named encoded{d}", .{ name, field.name, bit_offset }));
11787 }
11788 }
11789 bit_offset += @bitSizeOf(field.type);
11790 }
11791 },
11792 else => @compileError(name ++ " has an unexpected field type"),
11793 }
11794 }
11795};
11796
11797const aarch64 = @import("../aarch64.zig");
11798const assert = std.debug.assert;
11799const std = @import("std");
src/codegen/aarch64/instructions.zon created+1343
......@@ -0,0 +1,1343 @@
1.{
2 // C6.2.3 ADD (extended register)
3 .{
4 .pattern = "ADD <Wd|WSP>, <Wn|WSP>, <Wm>",
5 .symbols = .{
6 .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
7 .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
8 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
9 },
10 .encode = .{ .add, .Wd, .Wn, .{ .register = .Wm } },
11 },
12 .{
13 .pattern = "ADD <Wd|WSP>, <Wn|WSP>, <Wm>, <extend> #<amount>",
14 .symbols = .{
15 .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
16 .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
17 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
18 .extend = .{ .extend = .{ .size = .word } },
19 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } },
20 },
21 .encode = .{ .add, .Wd, .Wn, .{ .extended_register_explicit = .{ .register = .Wm, .option = .extend, .amount = .amount } } },
22 },
23 .{
24 .pattern = "ADD <Xd|SP>, <Xn|SP>, <Xm>",
25 .symbols = .{
26 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
27 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
28 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
29 },
30 .encode = .{ .add, .Xd, .Xn, .{ .register = .Xm } },
31 },
32 .{
33 .pattern = "ADD <Xd|SP>, <Xn|SP>, <Wm>, <extend> #<amount>",
34 .symbols = .{
35 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
36 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
37 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
38 .extend = .{ .extend = .{ .size = .word } },
39 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } },
40 },
41 .encode = .{ .add, .Xd, .Xn, .{ .extended_register_explicit = .{ .register = .Wm, .option = .extend, .amount = .amount } } },
42 },
43 .{
44 .pattern = "ADD <Xd|SP>, <Xn|SP>, <Xm>, <extend> #<amount>",
45 .symbols = .{
46 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
47 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
48 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
49 .extend = .{ .extend = .{ .size = .doubleword } },
50 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } },
51 },
52 .encode = .{ .add, .Xd, .Xn, .{ .extended_register_explicit = .{ .register = .Xm, .option = .extend, .amount = .amount } } },
53 },
54 // C6.2.4 ADD (immediate)
55 .{
56 .pattern = "ADD <Wd|WSP>, <Wn|WSP>, #<imm>",
57 .symbols = .{
58 .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
59 .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
60 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } },
61 },
62 .encode = .{ .add, .Wd, .Wn, .{ .immediate = .imm } },
63 },
64 .{
65 .pattern = "ADD <Wd|WSP>, <Wn|WSP>, #<imm>, LSL #<shift>",
66 .symbols = .{
67 .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
68 .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
69 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } },
70 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 }, .multiple_of = 12 } },
71 },
72 .encode = .{ .add, .Wd, .Wn, .{ .shifted_immediate = .{ .immediate = .imm, .lsl = .shift } } },
73 },
74 .{
75 .pattern = "ADD <Xd|SP>, <Xn|SP>, #<imm>",
76 .symbols = .{
77 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
78 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
79 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } },
80 },
81 .encode = .{ .add, .Xd, .Xn, .{ .immediate = .imm } },
82 },
83 .{
84 .pattern = "ADD <Xd|SP>, <Xn|SP>, #<imm>, LSL #<shift>",
85 .symbols = .{
86 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
87 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
88 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } },
89 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 }, .multiple_of = 12 } },
90 },
91 .encode = .{ .add, .Xd, .Xn, .{ .shifted_immediate = .{ .immediate = .imm, .lsl = .shift } } },
92 },
93 // C6.2.5 ADD (shifted register)
94 .{
95 .pattern = "ADD <Wd>, <Wn>, <Wm>",
96 .symbols = .{
97 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
98 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
99 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
100 },
101 .encode = .{ .add, .Wd, .Wn, .{ .register = .Wm } },
102 },
103 .{
104 .pattern = "ADD <Wd>, <Wn>, <Wm>, <shift> #<amount>",
105 .symbols = .{
106 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
107 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
108 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
109 .shift = .{ .shift = .{ .allow_ror = false } },
110 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
111 },
112 .encode = .{ .add, .Wd, .Wn, .{ .shifted_register_explicit = .{ .register = .Wm, .shift = .shift, .amount = .amount } } },
113 },
114 .{
115 .pattern = "ADD <Xd>, <Xn>, <Xm>",
116 .symbols = .{
117 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
118 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
119 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
120 },
121 .encode = .{ .add, .Xd, .Xn, .{ .register = .Xm } },
122 },
123 .{
124 .pattern = "ADD <Xd>, <Xn>, <Xm>, <shift> #<amount>",
125 .symbols = .{
126 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
127 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
128 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
129 .shift = .{ .shift = .{ .allow_ror = false } },
130 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
131 },
132 .encode = .{ .add, .Xd, .Xn, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } },
133 },
134 // C6.2.13 AND (shifted register)
135 .{
136 .pattern = "AND <Wd>, <Wn>, <Wm>",
137 .symbols = .{
138 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
139 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
140 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
141 },
142 .encode = .{ .@"and", .Wd, .Wn, .{ .register = .Wm } },
143 },
144 .{
145 .pattern = "AND <Wd>, <Wn>, <Wm>, <shift> #<amount>",
146 .symbols = .{
147 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
148 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
149 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
150 .shift = .{ .shift = .{} },
151 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
152 },
153 .encode = .{ .@"and", .Wd, .Wn, .{ .shifted_register_explicit = .{ .register = .Wm, .shift = .shift, .amount = .amount } } },
154 },
155 .{
156 .pattern = "AND <Xd>, <Xn>, <Xm>",
157 .symbols = .{
158 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
159 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
160 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
161 },
162 .encode = .{ .@"and", .Xd, .Xn, .{ .register = .Xm } },
163 },
164 .{
165 .pattern = "AND <Xd>, <Xn>, <Xm>, <shift> #<amount>",
166 .symbols = .{
167 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
168 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
169 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
170 .shift = .{ .shift = .{} },
171 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
172 },
173 .encode = .{ .@"and", .Xd, .Xn, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } },
174 },
175 // C6.2.15 ANDS (shifted register)
176 .{
177 .pattern = "ANDS <Wd>, <Wn>, <Wm>",
178 .symbols = .{
179 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
180 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
181 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
182 },
183 .encode = .{ .ands, .Wd, .Wn, .{ .register = .Wm } },
184 },
185 .{
186 .pattern = "ANDS <Wd>, <Wn>, <Wm>, <shift> #<amount>",
187 .symbols = .{
188 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
189 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
190 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
191 .shift = .{ .shift = .{} },
192 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
193 },
194 .encode = .{ .ands, .Wd, .Wn, .{ .shifted_register_explicit = .{ .register = .Wm, .shift = .shift, .amount = .amount } } },
195 },
196 .{
197 .pattern = "ANDS <Xd>, <Xn>, <Xm>",
198 .symbols = .{
199 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
200 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
201 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
202 },
203 .encode = .{ .ands, .Xd, .Xn, .{ .register = .Xm } },
204 },
205 .{
206 .pattern = "ANDS <Xd>, <Xn>, <Xm>, <shift> #<amount>",
207 .symbols = .{
208 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
209 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
210 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
211 .shift = .{ .shift = .{} },
212 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
213 },
214 .encode = .{ .ands, .Xd, .Xn, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } },
215 },
216 // C6.2.35 BLR
217 .{
218 .pattern = "BLR <Xn>",
219 .symbols = .{
220 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
221 },
222 .encode = .{ .blr, .Xn },
223 },
224 // C6.2.30 BFM
225 .{
226 .pattern = "BFM <Wd>, <Wn>, #<immr>, #<imms>",
227 .symbols = .{
228 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
229 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
230 .immr = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
231 .imms = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
232 },
233 .encode = .{ .bfm, .Wd, .Wn, .{ .N = .word, .immr = .immr, .imms = .imms } },
234 },
235 .{
236 .pattern = "BFM <Xd>, <Xn>, #<immr>, #<imms>",
237 .symbols = .{
238 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
239 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
240 .immr = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
241 .imms = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
242 },
243 .encode = .{ .bfm, .Xd, .Xn, .{ .N = .doubleword, .immr = .immr, .imms = .imms } },
244 },
245 // C6.2.37 BR
246 .{
247 .pattern = "BR <Xn>",
248 .symbols = .{
249 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
250 },
251 .encode = .{ .br, .Xn },
252 },
253 // C6.2.40 BRK
254 .{
255 .pattern = "BRK #<imm>",
256 .symbols = .{
257 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
258 },
259 .encode = .{ .brk, .imm },
260 },
261 // C6.2.56 CLREX
262 .{
263 .pattern = "CLREX",
264 .symbols = .{},
265 .encode = .{ .clrex, 0b1111 },
266 },
267 .{
268 .pattern = "CLREX #<imm>",
269 .symbols = .{
270 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 } } },
271 },
272 .encode = .{ .clrex, .imm },
273 },
274 // C6.2.109 DC
275 .{
276 .pattern = "DC IVAC, <Xt>",
277 .symbols = .{
278 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
279 },
280 .encode = .{ .sys, 0b000, 0b0111, 0b0110, 0b001, .Xt },
281 },
282 .{
283 .pattern = "DC ISW, <Xt>",
284 .symbols = .{
285 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
286 },
287 .encode = .{ .sys, 0b000, 0b0111, 0b0110, 0b010, .Xt },
288 },
289 .{
290 .pattern = "DC CSW, <Xt>",
291 .symbols = .{
292 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
293 },
294 .encode = .{ .sys, 0b000, 0b0111, 0b1010, 0b010, .Xt },
295 },
296 .{
297 .pattern = "DC CISW, <Xt>",
298 .symbols = .{
299 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
300 },
301 .encode = .{ .sys, 0b000, 0b0111, 0b1110, 0b010, .Xt },
302 },
303 .{
304 .pattern = "DC ZVA, <Xt>",
305 .symbols = .{
306 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
307 },
308 .encode = .{ .sys, 0b011, 0b0111, 0b0100, 0b001, .Xt },
309 },
310 .{
311 .pattern = "DC CVAC, <Xt>",
312 .symbols = .{
313 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
314 },
315 .encode = .{ .sys, 0b011, 0b0111, 0b1010, 0b001, .Xt },
316 },
317 .{
318 .pattern = "DC CVAU, <Xt>",
319 .symbols = .{
320 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
321 },
322 .encode = .{ .sys, 0b011, 0b0111, 0b1011, 0b001, .Xt },
323 },
324 .{
325 .pattern = "DC CIVAC, <Xt>",
326 .symbols = .{
327 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
328 },
329 .encode = .{ .sys, 0b011, 0b0111, 0b1110, 0b001, .Xt },
330 },
331 // C6.2.110 DCPS1
332 .{
333 .pattern = "DCPS1",
334 .symbols = .{},
335 .encode = .{ .dcps1, 0 },
336 },
337 .{
338 .pattern = "DCPS1 #<imm>",
339 .symbols = .{
340 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
341 },
342 .encode = .{ .dcps1, .imm },
343 },
344 // C6.2.111 DCPS2
345 .{
346 .pattern = "DCPS2",
347 .symbols = .{},
348 .encode = .{ .dcps2, 0 },
349 },
350 .{
351 .pattern = "DCPS2 #<imm>",
352 .symbols = .{
353 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
354 },
355 .encode = .{ .dcps2, .imm },
356 },
357 // C6.2.112 DCPS3
358 .{
359 .pattern = "DCPS3",
360 .symbols = .{},
361 .encode = .{ .dcps3, 0 },
362 },
363 .{
364 .pattern = "DCPS3 #<imm>",
365 .symbols = .{
366 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
367 },
368 .encode = .{ .dcps3, .imm },
369 },
370 // C6.2.116 DSB
371 .{
372 .pattern = "DSB <option>",
373 .symbols = .{
374 .option = .{ .barrier = .{} },
375 },
376 .encode = .{ .dsb, .option },
377 },
378 .{
379 .pattern = "DSB #<imm>",
380 .symbols = .{
381 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 } } },
382 },
383 .encode = .{ .dsb, .imm },
384 },
385 // C6.2.120 EOR (shifted register)
386 .{
387 .pattern = "EOR <Wd>, <Wn>, <Wm>",
388 .symbols = .{
389 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
390 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
391 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
392 },
393 .encode = .{ .eor, .Wd, .Wn, .{ .register = .Wm } },
394 },
395 .{
396 .pattern = "EOR <Wd>, <Wn>, <Wm>, <shift> #<amount>",
397 .symbols = .{
398 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
399 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
400 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
401 .shift = .{ .shift = .{} },
402 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
403 },
404 .encode = .{ .eor, .Wd, .Wn, .{ .shifted_register_explicit = .{ .register = .Wm, .shift = .shift, .amount = .amount } } },
405 },
406 .{
407 .pattern = "EOR <Xd>, <Xn>, <Xm>",
408 .symbols = .{
409 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
410 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
411 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
412 },
413 .encode = .{ .eor, .Xd, .Xn, .{ .register = .Xm } },
414 },
415 .{
416 .pattern = "EOR <Xd>, <Xn>, <Xm>, <shift> #<amount>",
417 .symbols = .{
418 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
419 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
420 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
421 .shift = .{ .shift = .{} },
422 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
423 },
424 .encode = .{ .eor, .Xd, .Xn, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } },
425 },
426 // C6.2.124 EXTR
427 .{
428 .pattern = "EXTR <Wd>, <Wn>, <Wm>, #<lsb>",
429 .symbols = .{
430 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
431 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
432 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
433 .lsb = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
434 },
435 .encode = .{ .extr, .Wd, .Wn, .Wm, .lsb },
436 },
437 .{
438 .pattern = "EXTR <Xd>, <Xn>, <Xm>, #<lsb>",
439 .symbols = .{
440 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
441 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
442 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
443 .lsb = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
444 },
445 .encode = .{ .extr, .Xd, .Xn, .Xm, .lsb },
446 },
447 // C6.2.126 HINT
448 .{
449 .pattern = "HINT #<imm>",
450 .symbols = .{
451 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 7 } } },
452 },
453 .encode = .{ .hint, .imm },
454 },
455 // C6.2.127 HLT
456 .{
457 .pattern = "HLT #<imm>",
458 .symbols = .{
459 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
460 },
461 .encode = .{ .hlt, .imm },
462 },
463 // C6.2.128 HVC
464 .{
465 .pattern = "HVC #<imm>",
466 .symbols = .{
467 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
468 },
469 .encode = .{ .hvc, .imm },
470 },
471 // C6.2.129 IC
472 .{
473 .pattern = "IC IALLUIS",
474 .symbols = .{
475 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
476 },
477 .encode = .{ .sys, 0b000, 0b0111, 0b0001, 0b000, .xzr },
478 },
479 .{
480 .pattern = "IC IALLUIS, <Xt>",
481 .symbols = .{
482 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
483 },
484 .encode = .{ .sys, 0b000, 0b0111, 0b0001, 0b000, .Xt },
485 },
486 .{
487 .pattern = "IC IALLU",
488 .symbols = .{
489 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
490 },
491 .encode = .{ .sys, 0b000, 0b0111, 0b0101, 0b000, .xzr },
492 },
493 .{
494 .pattern = "IC IALLU, <Xt>",
495 .symbols = .{
496 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
497 },
498 .encode = .{ .sys, 0b000, 0b0111, 0b0101, 0b000, .Xt },
499 },
500 .{
501 .pattern = "IC IVAU",
502 .symbols = .{
503 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
504 },
505 .encode = .{ .sys, 0b011, 0b0111, 0b0101, 0b001, .xzr },
506 },
507 .{
508 .pattern = "IC IVAU, <Xt>",
509 .symbols = .{
510 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
511 },
512 .encode = .{ .sys, 0b011, 0b0111, 0b0101, 0b001, .Xt },
513 },
514 // C6.2.131 ISB
515 .{
516 .pattern = "ISB",
517 .symbols = .{},
518 .encode = .{ .isb, .sy },
519 },
520 .{
521 .pattern = "ISB <option>",
522 .symbols = .{
523 .option = .{ .barrier = .{ .only_sy = true } },
524 },
525 .encode = .{ .isb, .option },
526 },
527 .{
528 .pattern = "ISB #<imm>",
529 .symbols = .{
530 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 } } },
531 },
532 .encode = .{ .isb, .imm },
533 },
534 // C6.2.164 LDP
535 .{
536 .pattern = "LDP <Wt1>, <Wt2>, [<Xn|SP>], #<imm>",
537 .symbols = .{
538 .Wt1 = .{ .reg = .{ .format = .{ .integer = .word } } },
539 .Wt2 = .{ .reg = .{ .format = .{ .integer = .word } } },
540 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
541 .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 }, .multiple_of = 4 } },
542 },
543 .encode = .{ .ldp, .Wt1, .Wt2, .{ .post_index = .{ .base = .Xn, .index = .imm } } },
544 },
545 .{
546 .pattern = "LDP <Xt1>, <Xt2>, [<Xn|SP>], #<imm>",
547 .symbols = .{
548 .Xt1 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
549 .Xt2 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
550 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
551 .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 10 }, .multiple_of = 8 } },
552 },
553 .encode = .{ .ldp, .Xt1, .Xt2, .{ .post_index = .{ .base = .Xn, .index = .imm } } },
554 },
555 .{
556 .pattern = "LDP <Wt1>, <Wt2>, [<Xn|SP>, #<imm>]!",
557 .symbols = .{
558 .Wt1 = .{ .reg = .{ .format = .{ .integer = .word } } },
559 .Wt2 = .{ .reg = .{ .format = .{ .integer = .word } } },
560 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
561 .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 }, .multiple_of = 4 } },
562 },
563 .encode = .{ .ldp, .Wt1, .Wt2, .{ .pre_index = .{ .base = .Xn, .index = .imm } } },
564 },
565 .{
566 .pattern = "LDP <Xt1>, <Xt2>, [<Xn|SP>, #<imm>]!",
567 .symbols = .{
568 .Xt1 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
569 .Xt2 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
570 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
571 .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 10 }, .multiple_of = 8 } },
572 },
573 .encode = .{ .ldp, .Xt1, .Xt2, .{ .pre_index = .{ .base = .Xn, .index = .imm } } },
574 },
575 .{
576 .pattern = "LDP <Wt1>, <Wt2>, [<Xn|SP>]",
577 .symbols = .{
578 .Wt1 = .{ .reg = .{ .format = .{ .integer = .word } } },
579 .Wt2 = .{ .reg = .{ .format = .{ .integer = .word } } },
580 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
581 },
582 .encode = .{ .ldp, .Wt1, .Wt2, .{ .base = .Xn } },
583 },
584 .{
585 .pattern = "LDP <Wt1>, <Wt2>, [<Xn|SP>, #<imm>]",
586 .symbols = .{
587 .Wt1 = .{ .reg = .{ .format = .{ .integer = .word } } },
588 .Wt2 = .{ .reg = .{ .format = .{ .integer = .word } } },
589 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
590 .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 }, .multiple_of = 4 } },
591 },
592 .encode = .{ .ldp, .Wt1, .Wt2, .{ .signed_offset = .{ .base = .Xn, .offset = .imm } } },
593 },
594 .{
595 .pattern = "LDP <Xt1>, <Xt2>, [<Xn|SP>]",
596 .symbols = .{
597 .Xt1 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
598 .Xt2 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
599 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
600 },
601 .encode = .{ .ldp, .Xt1, .Xt2, .{ .base = .Xn } },
602 },
603 .{
604 .pattern = "LDP <Xt1>, <Xt2>, [<Xn|SP>, #<imm>]",
605 .symbols = .{
606 .Xt1 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
607 .Xt2 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
608 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
609 .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 10 }, .multiple_of = 8 } },
610 },
611 .encode = .{ .ldp, .Xt1, .Xt2, .{ .signed_offset = .{ .base = .Xn, .offset = .imm } } },
612 },
613 // C6.2.166 LDR (immediate)
614 .{
615 .pattern = "LDR <Wt>, [<Xn|SP>], #<simm>",
616 .symbols = .{
617 .Wt = .{ .reg = .{ .format = .{ .integer = .word } } },
618 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
619 .simm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 } } },
620 },
621 .encode = .{ .ldr, .Wt, .{ .post_index = .{ .base = .Xn, .index = .simm } } },
622 },
623 .{
624 .pattern = "LDR <Xt>, [<Xn|SP>], #<simm>",
625 .symbols = .{
626 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
627 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
628 .simm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 } } },
629 },
630 .encode = .{ .ldr, .Xt, .{ .post_index = .{ .base = .Xn, .index = .simm } } },
631 },
632 .{
633 .pattern = "LDR <Wt>, [<Xn|SP>, #<simm>]!",
634 .symbols = .{
635 .Wt = .{ .reg = .{ .format = .{ .integer = .word } } },
636 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
637 .simm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 } } },
638 },
639 .encode = .{ .ldr, .Wt, .{ .pre_index = .{ .base = .Xn, .index = .simm } } },
640 },
641 .{
642 .pattern = "LDR <Xt>, [<Xn|SP>, #<simm>]!",
643 .symbols = .{
644 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
645 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
646 .simm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 } } },
647 },
648 .encode = .{ .ldr, .Xt, .{ .pre_index = .{ .base = .Xn, .index = .simm } } },
649 },
650 .{
651 .pattern = "LDR <Wt>, [<Xn|SP>]",
652 .symbols = .{
653 .Wt = .{ .reg = .{ .format = .{ .integer = .word } } },
654 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
655 },
656 .encode = .{ .ldr, .Wt, .{ .base = .Xn } },
657 },
658 .{
659 .pattern = "LDR <Wt>, [<Xn|SP>, #<pimm>]",
660 .symbols = .{
661 .Wt = .{ .reg = .{ .format = .{ .integer = .word } } },
662 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
663 .pimm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 14 }, .multiple_of = 4 } },
664 },
665 .encode = .{ .ldr, .Wt, .{ .unsigned_offset = .{ .base = .Xn, .offset = .pimm } } },
666 },
667 .{
668 .pattern = "LDR <Xt>, [<Xn|SP>]",
669 .symbols = .{
670 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
671 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
672 },
673 .encode = .{ .ldr, .Xt, .{ .base = .Xn } },
674 },
675 .{
676 .pattern = "LDR <Xt>, [<Xn|SP>, #<pimm>]",
677 .symbols = .{
678 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
679 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
680 .pimm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 15 }, .multiple_of = 8 } },
681 },
682 .encode = .{ .ldr, .Xt, .{ .unsigned_offset = .{ .base = .Xn, .offset = .pimm } } },
683 },
684 // C6.2.220 MOV (to/from SP)
685 .{
686 .pattern = "MOV WSP, <Wn|WSP>",
687 .symbols = .{
688 .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
689 },
690 .encode = .{ .add, .wsp, .Wn, .{ .immediate = 0 } },
691 },
692 .{
693 .pattern = "MOV <Wd|WSP>, WSP",
694 .symbols = .{
695 .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
696 },
697 .encode = .{ .add, .Wd, .wsp, .{ .immediate = 0 } },
698 },
699 .{
700 .pattern = "MOV SP, <Xn|SP>",
701 .symbols = .{
702 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
703 },
704 .encode = .{ .add, .sp, .Xn, .{ .immediate = 0 } },
705 },
706 .{
707 .pattern = "MOV <Xd|SP>, SP",
708 .symbols = .{
709 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
710 },
711 .encode = .{ .add, .Xd, .sp, .{ .immediate = 0 } },
712 },
713 // C6.2.222 MOV (wide immediate)
714 .{
715 .pattern = "MOV <Wd>, #<imm>",
716 .symbols = .{
717 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
718 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
719 },
720 .encode = .{ .movz, .Wd, .imm, .{ .lsl = .@"0" } },
721 },
722 .{
723 .pattern = "MOV <Xd>, #<imm>",
724 .symbols = .{
725 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
726 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
727 },
728 .encode = .{ .movz, .Xd, .imm, .{ .lsl = .@"0" } },
729 },
730 // C6.2.224 MOV (register)
731 .{
732 .pattern = "MOV <Wd>, <Wm>",
733 .symbols = .{
734 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
735 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
736 },
737 .encode = .{ .orr, .Wd, .wzr, .{ .register = .Wm } },
738 },
739 .{
740 .pattern = "MOV <Xd>, <Xm>",
741 .symbols = .{
742 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
743 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
744 },
745 .encode = .{ .orr, .Xd, .xzr, .{ .register = .Xm } },
746 },
747 // C6.2.225 MOVK
748 .{
749 .pattern = "MOVK <Wd>, #<imm>",
750 .symbols = .{
751 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
752 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
753 },
754 .encode = .{ .movk, .Wd, .imm, .{} },
755 },
756 .{
757 .pattern = "MOVK <Wd>, #<imm>, LSL #<shift>",
758 .symbols = .{
759 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
760 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
761 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 }, .multiple_of = 16 } },
762 },
763 .encode = .{ .movk, .Wd, .imm, .{ .lsl = .shift } },
764 },
765 .{
766 .pattern = "MOVK <Xd>, #<imm>",
767 .symbols = .{
768 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
769 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
770 },
771 .encode = .{ .movk, .Xd, .imm, .{} },
772 },
773 .{
774 .pattern = "MOVK <Xd>, #<imm>, LSL #<shift>",
775 .symbols = .{
776 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
777 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
778 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 }, .multiple_of = 16 } },
779 },
780 .encode = .{ .movk, .Xd, .imm, .{ .lsl = .shift } },
781 },
782 // C6.2.226 MOVN
783 .{
784 .pattern = "MOVN <Wd>, #<imm>",
785 .symbols = .{
786 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
787 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
788 },
789 .encode = .{ .movn, .Wd, .imm, .{} },
790 },
791 .{
792 .pattern = "MOVN <Wd>, #<imm>, LSL #<shift>",
793 .symbols = .{
794 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
795 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
796 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 }, .multiple_of = 16 } },
797 },
798 .encode = .{ .movn, .Wd, .imm, .{ .lsl = .shift } },
799 },
800 .{
801 .pattern = "MOVN <Xd>, #<imm>",
802 .symbols = .{
803 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
804 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
805 },
806 .encode = .{ .movn, .Xd, .imm, .{} },
807 },
808 .{
809 .pattern = "MOVN <Xd>, #<imm>, LSL #<shift>",
810 .symbols = .{
811 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
812 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
813 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 }, .multiple_of = 16 } },
814 },
815 .encode = .{ .movn, .Xd, .imm, .{ .lsl = .shift } },
816 },
817 // C6.2.227 MOVZ
818 .{
819 .pattern = "MOVZ <Wd>, #<imm>",
820 .symbols = .{
821 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
822 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
823 },
824 .encode = .{ .movz, .Wd, .imm, .{} },
825 },
826 .{
827 .pattern = "MOVZ <Wd>, #<imm>, LSL #<shift>",
828 .symbols = .{
829 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
830 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
831 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 }, .multiple_of = 16 } },
832 },
833 .encode = .{ .movz, .Wd, .imm, .{ .lsl = .shift } },
834 },
835 .{
836 .pattern = "MOVZ <Xd>, #<imm>",
837 .symbols = .{
838 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
839 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
840 },
841 .encode = .{ .movz, .Xd, .imm, .{} },
842 },
843 .{
844 .pattern = "MOVZ <Xd>, #<imm>, LSL #<shift>",
845 .symbols = .{
846 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
847 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
848 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 }, .multiple_of = 16 } },
849 },
850 .encode = .{ .movz, .Xd, .imm, .{ .lsl = .shift } },
851 },
852 // C6.2.228 MRS
853 .{
854 .pattern = "MRS <Xt>, CTR_EL0",
855 .symbols = .{
856 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
857 },
858 .encode = .{ .mrs, .Xt, 0b11, 0b011, 0b0000, 0b0000, 0b001 },
859 },
860 // C6.2.234 NEG
861 .{
862 .pattern = "NEG <Wd>, <Wm>",
863 .symbols = .{
864 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
865 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
866 },
867 .encode = .{ .sub, .Wd, .wzr, .{ .register = .Wm } },
868 },
869 .{
870 .pattern = "NEG <Wd>, <Wm>, <shift> #<amount>",
871 .symbols = .{
872 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
873 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
874 .shift = .{ .shift = .{ .allow_ror = false } },
875 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
876 },
877 .encode = .{ .sub, .Wd, .wzr, .{ .shifted_register_explicit = .{ .register = .Wm, .shift = .shift, .amount = .amount } } },
878 },
879 .{
880 .pattern = "NEG <Xd>, <Xm>",
881 .symbols = .{
882 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
883 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
884 },
885 .encode = .{ .sub, .Xd, .xzr, .{ .register = .Xm } },
886 },
887 .{
888 .pattern = "NEG <Xd>, <Xm>, <shift> #<amount>",
889 .symbols = .{
890 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
891 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
892 .shift = .{ .shift = .{ .allow_ror = false } },
893 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
894 },
895 .encode = .{ .sub, .Xd, .xzr, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } },
896 },
897 // C6.2.238 NOP
898 .{
899 .pattern = "NOP",
900 .symbols = .{},
901 .encode = .{.nop},
902 },
903 // C6.2.241 ORR (shifted register)
904 .{
905 .pattern = "ORR <Wd>, <Wn>, <Wm>",
906 .symbols = .{
907 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
908 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
909 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
910 },
911 .encode = .{ .orr, .Wd, .Wn, .{ .register = .Wm } },
912 },
913 .{
914 .pattern = "ORR <Wd>, <Wn>, <Wm>, <shift> #<amount>",
915 .symbols = .{
916 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
917 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
918 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
919 .shift = .{ .shift = .{} },
920 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
921 },
922 .encode = .{ .orr, .Wd, .Wn, .{ .shifted_register_explicit = .{ .register = .Wm, .shift = .shift, .amount = .amount } } },
923 },
924 .{
925 .pattern = "ORR <Xd>, <Xn>, <Xm>",
926 .symbols = .{
927 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
928 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
929 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
930 },
931 .encode = .{ .orr, .Xd, .Xn, .{ .register = .Xm } },
932 },
933 .{
934 .pattern = "ORR <Xd>, <Xn>, <Xm>, <shift> #<amount>",
935 .symbols = .{
936 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
937 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
938 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
939 .shift = .{ .shift = .{} },
940 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
941 },
942 .encode = .{ .orr, .Xd, .Xn, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } },
943 },
944 // C6.2.254 RET
945 .{
946 .pattern = "RET",
947 .symbols = .{},
948 .encode = .{ .ret, .x30 },
949 },
950 .{
951 .pattern = "RET <Xn>",
952 .symbols = .{
953 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
954 },
955 .encode = .{ .ret, .Xn },
956 },
957 // C6.2.268 SBFM
958 .{
959 .pattern = "SBFM <Wd>, <Wn>, #<immr>, #<imms>",
960 .symbols = .{
961 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
962 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
963 .immr = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
964 .imms = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
965 },
966 .encode = .{ .sbfm, .Wd, .Wn, .{ .N = .word, .immr = .immr, .imms = .imms } },
967 },
968 .{
969 .pattern = "SBFM <Xd>, <Xn>, #<immr>, #<imms>",
970 .symbols = .{
971 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
972 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
973 .immr = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
974 .imms = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
975 },
976 .encode = .{ .sbfm, .Xd, .Xn, .{ .N = .doubleword, .immr = .immr, .imms = .imms } },
977 },
978 // C6.2.280 SEV
979 .{
980 .pattern = "SEV",
981 .symbols = .{},
982 .encode = .{.sev},
983 },
984 // C6.2.281 SEVL
985 .{
986 .pattern = "SEVL",
987 .symbols = .{},
988 .encode = .{.sevl},
989 },
990 // C6.2.283 SMC
991 .{
992 .pattern = "SMC #<imm>",
993 .symbols = .{
994 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
995 },
996 .encode = .{ .smc, .imm },
997 },
998 // C6.2.321 STP
999 .{
1000 .pattern = "STP <Wt1>, <Wt2>, [<Xn|SP>], #<imm>",
1001 .symbols = .{
1002 .Wt1 = .{ .reg = .{ .format = .{ .integer = .word } } },
1003 .Wt2 = .{ .reg = .{ .format = .{ .integer = .word } } },
1004 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1005 .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 }, .multiple_of = 4 } },
1006 },
1007 .encode = .{ .stp, .Wt1, .Wt2, .{ .post_index = .{ .base = .Xn, .index = .imm } } },
1008 },
1009 .{
1010 .pattern = "STP <Xt1>, <Xt2>, [<Xn|SP>], #<imm>",
1011 .symbols = .{
1012 .Xt1 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1013 .Xt2 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1014 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1015 .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 10 }, .multiple_of = 8 } },
1016 },
1017 .encode = .{ .stp, .Xt1, .Xt2, .{ .post_index = .{ .base = .Xn, .index = .imm } } },
1018 },
1019 .{
1020 .pattern = "STP <Wt1>, <Wt2>, [<Xn|SP>, #<imm>]!",
1021 .symbols = .{
1022 .Wt1 = .{ .reg = .{ .format = .{ .integer = .word } } },
1023 .Wt2 = .{ .reg = .{ .format = .{ .integer = .word } } },
1024 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1025 .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 }, .multiple_of = 4 } },
1026 },
1027 .encode = .{ .stp, .Wt1, .Wt2, .{ .pre_index = .{ .base = .Xn, .index = .imm } } },
1028 },
1029 .{
1030 .pattern = "STP <Xt1>, <Xt2>, [<Xn|SP>, #<imm>]!",
1031 .symbols = .{
1032 .Xt1 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1033 .Xt2 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1034 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1035 .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 10 }, .multiple_of = 8 } },
1036 },
1037 .encode = .{ .stp, .Xt1, .Xt2, .{ .pre_index = .{ .base = .Xn, .index = .imm } } },
1038 },
1039 .{
1040 .pattern = "STP <Wt1>, <Wt2>, [<Xn|SP>]",
1041 .symbols = .{
1042 .Wt1 = .{ .reg = .{ .format = .{ .integer = .word } } },
1043 .Wt2 = .{ .reg = .{ .format = .{ .integer = .word } } },
1044 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1045 },
1046 .encode = .{ .stp, .Wt1, .Wt2, .{ .base = .Xn } },
1047 },
1048 .{
1049 .pattern = "STP <Wt1>, <Wt2>, [<Xn|SP>, #<imm>]",
1050 .symbols = .{
1051 .Wt1 = .{ .reg = .{ .format = .{ .integer = .word } } },
1052 .Wt2 = .{ .reg = .{ .format = .{ .integer = .word } } },
1053 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1054 .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 }, .multiple_of = 4 } },
1055 },
1056 .encode = .{ .stp, .Wt1, .Wt2, .{ .signed_offset = .{ .base = .Xn, .offset = .imm } } },
1057 },
1058 .{
1059 .pattern = "STP <Xt1>, <Xt2>, [<Xn|SP>]",
1060 .symbols = .{
1061 .Xt1 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1062 .Xt2 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1063 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1064 },
1065 .encode = .{ .stp, .Xt1, .Xt2, .{ .base = .Xn } },
1066 },
1067 .{
1068 .pattern = "STP <Xt1>, <Xt2>, [<Xn|SP>, #<imm>]",
1069 .symbols = .{
1070 .Xt1 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1071 .Xt2 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1072 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1073 .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 10 }, .multiple_of = 8 } },
1074 },
1075 .encode = .{ .stp, .Xt1, .Xt2, .{ .signed_offset = .{ .base = .Xn, .offset = .imm } } },
1076 },
1077 // C6.2.322 STR (immediate)
1078 .{
1079 .pattern = "STR <Wt>, [<Xn|SP>], #<simm>",
1080 .symbols = .{
1081 .Wt = .{ .reg = .{ .format = .{ .integer = .word } } },
1082 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1083 .simm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 } } },
1084 },
1085 .encode = .{ .str, .Wt, .{ .post_index = .{ .base = .Xn, .index = .simm } } },
1086 },
1087 .{
1088 .pattern = "STR <Xt>, [<Xn|SP>], #<simm>",
1089 .symbols = .{
1090 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1091 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1092 .simm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 } } },
1093 },
1094 .encode = .{ .str, .Xt, .{ .post_index = .{ .base = .Xn, .index = .simm } } },
1095 },
1096 .{
1097 .pattern = "STR <Wt>, [<Xn|SP>, #<simm>]!",
1098 .symbols = .{
1099 .Wt = .{ .reg = .{ .format = .{ .integer = .word } } },
1100 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1101 .simm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 } } },
1102 },
1103 .encode = .{ .str, .Wt, .{ .pre_index = .{ .base = .Xn, .index = .simm } } },
1104 },
1105 .{
1106 .pattern = "STR <Xt>, [<Xn|SP>, #<simm>]!",
1107 .symbols = .{
1108 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1109 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1110 .simm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 } } },
1111 },
1112 .encode = .{ .str, .Xt, .{ .pre_index = .{ .base = .Xn, .index = .simm } } },
1113 },
1114 .{
1115 .pattern = "STR <Wt>, [<Xn|SP>]",
1116 .symbols = .{
1117 .Wt = .{ .reg = .{ .format = .{ .integer = .word } } },
1118 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1119 },
1120 .encode = .{ .str, .Wt, .{ .base = .Xn } },
1121 },
1122 .{
1123 .pattern = "STR <Wt>, [<Xn|SP>, #<pimm>]",
1124 .symbols = .{
1125 .Wt = .{ .reg = .{ .format = .{ .integer = .word } } },
1126 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1127 .pimm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 14 }, .multiple_of = 4 } },
1128 },
1129 .encode = .{ .str, .Wt, .{ .unsigned_offset = .{ .base = .Xn, .offset = .pimm } } },
1130 },
1131 .{
1132 .pattern = "STR <Xt>, [<Xn|SP>]",
1133 .symbols = .{
1134 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1135 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1136 },
1137 .encode = .{ .str, .Xt, .{ .base = .Xn } },
1138 },
1139 .{
1140 .pattern = "STR <Xt>, [<Xn|SP>, #<pimm>]",
1141 .symbols = .{
1142 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1143 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1144 .pimm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 15 }, .multiple_of = 8 } },
1145 },
1146 .encode = .{ .str, .Xt, .{ .unsigned_offset = .{ .base = .Xn, .offset = .pimm } } },
1147 },
1148 // C6.2.356 SUB (extended register)
1149 .{
1150 .pattern = "SUB <Wd|WSP>, <Wn|WSP>, <Wm>",
1151 .symbols = .{
1152 .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
1153 .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
1154 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
1155 },
1156 .encode = .{ .sub, .Wd, .Wn, .{ .register = .Wm } },
1157 },
1158 .{
1159 .pattern = "SUB <Wd|WSP>, <Wn|WSP>, <Wm>, <extend> #<amount>",
1160 .symbols = .{
1161 .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
1162 .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
1163 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
1164 .extend = .{ .extend = .{ .size = .word } },
1165 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } },
1166 },
1167 .encode = .{ .sub, .Wd, .Wn, .{ .extended_register_explicit = .{ .register = .Wm, .option = .extend, .amount = .amount } } },
1168 },
1169 .{
1170 .pattern = "SUB <Xd|SP>, <Xn|SP>, <Xm>",
1171 .symbols = .{
1172 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1173 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1174 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1175 },
1176 .encode = .{ .sub, .Xd, .Xn, .{ .register = .Xm } },
1177 },
1178 .{
1179 .pattern = "SUB <Xd|SP>, <Xn|SP>, <Wm>, <extend> #<amount>",
1180 .symbols = .{
1181 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1182 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1183 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
1184 .extend = .{ .extend = .{ .size = .word } },
1185 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } },
1186 },
1187 .encode = .{ .sub, .Xd, .Xn, .{ .extended_register_explicit = .{ .register = .Wm, .option = .extend, .amount = .amount } } },
1188 },
1189 .{
1190 .pattern = "SUB <Xd|SP>, <Xn|SP>, <Xm>, <extend> #<amount>",
1191 .symbols = .{
1192 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1193 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1194 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1195 .extend = .{ .extend = .{ .size = .doubleword } },
1196 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } },
1197 },
1198 .encode = .{ .sub, .Xd, .Xn, .{ .extended_register_explicit = .{ .register = .Xm, .option = .extend, .amount = .amount } } },
1199 },
1200 // C6.2.357 SUB (immediate)
1201 .{
1202 .pattern = "SUB <Wd|WSP>, <Wn|WSP>, #<imm>",
1203 .symbols = .{
1204 .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
1205 .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
1206 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } },
1207 },
1208 .encode = .{ .sub, .Wd, .Wn, .{ .immediate = .imm } },
1209 },
1210 .{
1211 .pattern = "SUB <Wd|WSP>, <Wn|WSP>, #<imm>, LSL #<shift>",
1212 .symbols = .{
1213 .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
1214 .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
1215 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } },
1216 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 }, .multiple_of = 12 } },
1217 },
1218 .encode = .{ .sub, .Wd, .Wn, .{ .shifted_immediate = .{ .immediate = .imm, .lsl = .shift } } },
1219 },
1220 .{
1221 .pattern = "SUB <Xd|SP>, <Xn|SP>, #<imm>",
1222 .symbols = .{
1223 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1224 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1225 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } },
1226 },
1227 .encode = .{ .sub, .Xd, .Xn, .{ .immediate = .imm } },
1228 },
1229 .{
1230 .pattern = "SUB <Xd|SP>, <Xn|SP>, #<imm>, LSL #<shift>",
1231 .symbols = .{
1232 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1233 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1234 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } },
1235 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 }, .multiple_of = 12 } },
1236 },
1237 .encode = .{ .sub, .Xd, .Xn, .{ .shifted_immediate = .{ .immediate = .imm, .lsl = .shift } } },
1238 },
1239 // C6.2.358 SUB (shifted register)
1240 .{
1241 .pattern = "SUB <Wd>, <Wn>, <Wm>",
1242 .symbols = .{
1243 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
1244 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
1245 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
1246 },
1247 .encode = .{ .sub, .Wd, .Wn, .{ .register = .Wm } },
1248 },
1249 .{
1250 .pattern = "SUB <Wd>, <Wn>, <Wm>, <shift> #<amount>",
1251 .symbols = .{
1252 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
1253 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
1254 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
1255 .shift = .{ .shift = .{ .allow_ror = false } },
1256 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
1257 },
1258 .encode = .{ .sub, .Wd, .Wn, .{ .shifted_register_explicit = .{ .register = .Wm, .shift = .shift, .amount = .amount } } },
1259 },
1260 .{
1261 .pattern = "SUB <Xd>, <Xn>, <Xm>",
1262 .symbols = .{
1263 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1264 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1265 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1266 },
1267 .encode = .{ .sub, .Xd, .Xn, .{ .register = .Xm } },
1268 },
1269 .{
1270 .pattern = "SUB <Xd>, <Xn>, <Xm>, <shift> #<amount>",
1271 .symbols = .{
1272 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1273 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1274 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1275 .shift = .{ .shift = .{ .allow_ror = false } },
1276 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
1277 },
1278 .encode = .{ .sub, .Xd, .Xn, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } },
1279 },
1280 // C6.2.365 SVC
1281 .{
1282 .pattern = "SVC #<imm>",
1283 .symbols = .{
1284 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
1285 },
1286 .encode = .{ .svc, .imm },
1287 },
1288 // C6.2.376 TCANCEL
1289 .{
1290 .pattern = "TCANCEL #<imm>",
1291 .symbols = .{
1292 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
1293 },
1294 .encode = .{ .tcancel, .imm },
1295 },
1296 // C6.2.385 UBFM
1297 .{
1298 .pattern = "UBFM <Wd>, <Wn>, #<immr>, #<imms>",
1299 .symbols = .{
1300 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
1301 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
1302 .immr = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
1303 .imms = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
1304 },
1305 .encode = .{ .ubfm, .Wd, .Wn, .{ .N = .word, .immr = .immr, .imms = .imms } },
1306 },
1307 .{
1308 .pattern = "UBFM <Xd>, <Xn>, #<immr>, #<imms>",
1309 .symbols = .{
1310 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1311 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1312 .immr = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
1313 .imms = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
1314 },
1315 .encode = .{ .ubfm, .Xd, .Xn, .{ .N = .doubleword, .immr = .immr, .imms = .imms } },
1316 },
1317 // C6.2.387 UDF
1318 .{
1319 .pattern = "UDF #<imm>",
1320 .symbols = .{
1321 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
1322 },
1323 .encode = .{ .udf, .imm },
1324 },
1325 // C6.2.396 WFE
1326 .{
1327 .pattern = "WFE",
1328 .symbols = .{},
1329 .encode = .{.wfe},
1330 },
1331 // C6.2.398 WFI
1332 .{
1333 .pattern = "WFI",
1334 .symbols = .{},
1335 .encode = .{.wfi},
1336 },
1337 // C6.2.402 YIELD
1338 .{
1339 .pattern = "YIELD",
1340 .symbols = .{},
1341 .encode = .{.yield},
1342 },
1343}
src/codegen/c.zig+16-17
......@@ -449,14 +449,15 @@ pub const Function = struct {
449449 if (gop.found_existing) return gop.value_ptr.*;
450450
451451 const pt = f.object.dg.pt;
452 const zcu = pt.zcu;
452453 const val = (try f.air.value(ref, pt)).?;
453454 const ty = f.typeOf(ref);
454455
455 const result: CValue = if (lowersToArray(ty, pt)) result: {
456 const result: CValue = if (lowersToArray(ty, zcu)) result: {
456457 const ch = &f.object.code_header.writer;
457458 const decl_c_value = try f.allocLocalValue(.{
458459 .ctype = try f.ctypeFromType(ty, .complete),
459 .alignas = CType.AlignAs.fromAbiAlignment(ty.abiAlignment(pt.zcu)),
460 .alignas = CType.AlignAs.fromAbiAlignment(ty.abiAlignment(zcu)),
460461 });
461462 const gpa = f.object.dg.gpa;
462463 try f.allocs.put(gpa, decl_c_value.new_local, false);
......@@ -916,7 +917,7 @@ pub const DeclGen = struct {
916917 // Ensure complete type definition is available before accessing fields.
917918 _ = try dg.ctypeFromType(parent_ptr_ty.childType(zcu), .complete);
918919
919 switch (fieldLocation(parent_ptr_ty, field.result_ptr_ty, field.field_idx, pt)) {
920 switch (fieldLocation(parent_ptr_ty, field.result_ptr_ty, field.field_idx, zcu)) {
920921 .begin => {
921922 const ptr_ctype = try dg.ctypeFromType(field.result_ptr_ty, .complete);
922923 try w.writeByte('(');
......@@ -3008,7 +3009,7 @@ pub fn generate(
30083009 src_loc: Zcu.LazySrcLoc,
30093010 func_index: InternPool.Index,
30103011 air: *const Air,
3011 liveness: *const Air.Liveness,
3012 liveness: *const ?Air.Liveness,
30123013) @import("../codegen.zig").CodeGenError!Mir {
30133014 const zcu = pt.zcu;
30143015 const gpa = zcu.gpa;
......@@ -3021,7 +3022,7 @@ pub fn generate(
30213022 var function: Function = .{
30223023 .value_map = .init(gpa),
30233024 .air = air.*,
3024 .liveness = liveness.*,
3025 .liveness = liveness.*.?,
30253026 .func_index = func_index,
30263027 .object = .{
30273028 .dg = .{
......@@ -3961,7 +3962,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
39613962 ptr_info.flags.alignment.order(src_ty.abiAlignment(zcu)).compare(.gte)
39623963 else
39633964 true;
3964 const is_array = lowersToArray(src_ty, pt);
3965 const is_array = lowersToArray(src_ty, zcu);
39653966 const need_memcpy = !is_aligned or is_array;
39663967
39673968 const w = &f.object.code.writer;
......@@ -4044,7 +4045,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !void {
40444045 const operand = try f.resolveInst(un_op);
40454046 try reap(f, inst, &.{un_op});
40464047 var deref = is_ptr;
4047 const is_array = lowersToArray(ret_ty, pt);
4048 const is_array = lowersToArray(ret_ty, zcu);
40484049 const ret_val = if (is_array) ret_val: {
40494050 const array_local = try f.allocAlignedLocal(inst, .{
40504051 .ctype = ret_ctype,
......@@ -4228,7 +4229,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
42284229 ptr_info.flags.alignment.order(src_ty.abiAlignment(zcu)).compare(.gte)
42294230 else
42304231 true;
4231 const is_array = lowersToArray(.fromInterned(ptr_info.child), pt);
4232 const is_array = lowersToArray(.fromInterned(ptr_info.child), zcu);
42324233 const need_memcpy = !is_aligned or is_array;
42334234
42344235 const src_val = try f.resolveInst(bin_op.rhs);
......@@ -4873,7 +4874,7 @@ fn airCall(
48734874 }
48744875
48754876 const result = result: {
4876 if (result_local == .none or !lowersToArray(ret_ty, pt))
4877 if (result_local == .none or !lowersToArray(ret_ty, zcu))
48774878 break :result result_local;
48784879
48794880 const array_local = try f.allocLocal(inst, ret_ty);
......@@ -5971,13 +5972,12 @@ fn fieldLocation(
59715972 container_ptr_ty: Type,
59725973 field_ptr_ty: Type,
59735974 field_index: u32,
5974 pt: Zcu.PerThread,
5975 zcu: *Zcu,
59755976) union(enum) {
59765977 begin: void,
59775978 field: CValue,
59785979 byte_offset: u64,
59795980} {
5980 const zcu = pt.zcu;
59815981 const ip = &zcu.intern_pool;
59825982 const container_ty: Type = .fromInterned(ip.indexToKey(container_ptr_ty.toIntern()).ptr_type.child);
59835983 switch (ip.indexToKey(container_ty.toIntern())) {
......@@ -5994,7 +5994,7 @@ fn fieldLocation(
59945994 else
59955995 .{ .field = field_index } },
59965996 .@"packed" => if (field_ptr_ty.ptrInfo(zcu).packed_offset.host_size == 0)
5997 .{ .byte_offset = @divExact(pt.structPackedFieldBitOffset(loaded_struct, field_index) +
5997 .{ .byte_offset = @divExact(zcu.structPackedFieldBitOffset(loaded_struct, field_index) +
59985998 container_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset, 8) }
59995999 else
60006000 .begin,
......@@ -6076,7 +6076,7 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
60766076 try f.renderType(w, container_ptr_ty);
60776077 try w.writeByte(')');
60786078
6079 switch (fieldLocation(container_ptr_ty, field_ptr_ty, extra.field_index, pt)) {
6079 switch (fieldLocation(container_ptr_ty, field_ptr_ty, extra.field_index, zcu)) {
60806080 .begin => try f.writeCValue(w, field_ptr_val, .Other),
60816081 .field => |field| {
60826082 const u8_ptr_ty = try pt.adjustPtrTypeChild(field_ptr_ty, .u8);
......@@ -6131,7 +6131,7 @@ fn fieldPtr(
61316131 try f.renderType(w, field_ptr_ty);
61326132 try w.writeByte(')');
61336133
6134 switch (fieldLocation(container_ptr_ty, field_ptr_ty, field_index, pt)) {
6134 switch (fieldLocation(container_ptr_ty, field_ptr_ty, field_index, zcu)) {
61356135 .begin => try f.writeCValue(w, container_ptr_val, .Other),
61366136 .field => |field| {
61376137 try w.writeByte('&');
......@@ -6189,7 +6189,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
61896189
61906190 const bit_offset_ty = try pt.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1));
61916191
6192 const bit_offset = pt.structPackedFieldBitOffset(loaded_struct, extra.field_index);
6192 const bit_offset = zcu.structPackedFieldBitOffset(loaded_struct, extra.field_index);
61936193
61946194 const field_int_signedness = if (inst_ty.isAbiInt(zcu))
61956195 inst_ty.intInfo(zcu).signedness
......@@ -8573,8 +8573,7 @@ const Vectorize = struct {
85738573 }
85748574};
85758575
8576fn lowersToArray(ty: Type, pt: Zcu.PerThread) bool {
8577 const zcu = pt.zcu;
8576fn lowersToArray(ty: Type, zcu: *Zcu) bool {
85788577 return switch (ty.zigTypeTag(zcu)) {
85798578 .array, .vector => return true,
85808579 else => return ty.isAbiInt(zcu) and toCIntBits(@as(u32, @intCast(ty.bitSize(zcu)))) == null,
src/codegen/llvm.zig+6-5
......@@ -20,6 +20,7 @@ const Package = @import("../Package.zig");
2020const Air = @import("../Air.zig");
2121const Value = @import("../Value.zig");
2222const Type = @import("../Type.zig");
23const codegen = @import("../codegen.zig");
2324const x86_64_abi = @import("../arch/x86_64/abi.zig");
2425const wasm_c_abi = @import("wasm/abi.zig");
2526const aarch64_c_abi = @import("aarch64/abi.zig");
......@@ -1131,7 +1132,7 @@ pub const Object = struct {
11311132 pt: Zcu.PerThread,
11321133 func_index: InternPool.Index,
11331134 air: *const Air,
1134 liveness: *const Air.Liveness,
1135 liveness: *const ?Air.Liveness,
11351136 ) !void {
11361137 const zcu = pt.zcu;
11371138 const comp = zcu.comp;
......@@ -1489,7 +1490,7 @@ pub const Object = struct {
14891490 var fg: FuncGen = .{
14901491 .gpa = gpa,
14911492 .air = air.*,
1492 .liveness = liveness.*,
1493 .liveness = liveness.*.?,
14931494 .ng = &ng,
14941495 .wip = wip,
14951496 .is_naked = fn_info.cc == .naked,
......@@ -4210,7 +4211,7 @@ pub const Object = struct {
42104211 .eu_payload => |eu_ptr| try o.lowerPtr(
42114212 pt,
42124213 eu_ptr,
4213 offset + @import("../codegen.zig").errUnionPayloadOffset(
4214 offset + codegen.errUnionPayloadOffset(
42144215 Value.fromInterned(eu_ptr).typeOf(zcu).childType(zcu),
42154216 zcu,
42164217 ),
......@@ -6969,7 +6970,7 @@ pub const FuncGen = struct {
69696970 .@"struct" => switch (struct_ty.containerLayout(zcu)) {
69706971 .@"packed" => {
69716972 const struct_type = zcu.typeToStruct(struct_ty).?;
6972 const bit_offset = pt.structPackedFieldBitOffset(struct_type, field_index);
6973 const bit_offset = zcu.structPackedFieldBitOffset(struct_type, field_index);
69736974 const containing_int = struct_llvm_val;
69746975 const shift_amt =
69756976 try o.builder.intValue(containing_int.typeOfWip(&self.wip), bit_offset);
......@@ -11364,7 +11365,7 @@ pub const FuncGen = struct {
1136411365
1136511366 // We have a pointer to a packed struct field that happens to be byte-aligned.
1136611367 // Offset our operand pointer by the correct number of bytes.
11367 const byte_offset = @divExact(pt.structPackedFieldBitOffset(struct_type, field_index) + struct_ptr_ty_info.packed_offset.bit_offset, 8);
11368 const byte_offset = @divExact(zcu.structPackedFieldBitOffset(struct_type, field_index) + struct_ptr_ty_info.packed_offset.bit_offset, 8);
1136811369 if (byte_offset == 0) return struct_ptr;
1136911370 const usize_ty = try o.lowerType(pt, Type.usize);
1137011371 const llvm_index = try o.builder.intValue(usize_ty, byte_offset);
src/codegen/spirv.zig+3-3
......@@ -251,11 +251,11 @@ pub const Object = struct {
251251 pt: Zcu.PerThread,
252252 func_index: InternPool.Index,
253253 air: *const Air,
254 liveness: *const Air.Liveness,
254 liveness: *const ?Air.Liveness,
255255 ) !void {
256256 const nav = pt.zcu.funcInfo(func_index).owner_nav;
257257 // TODO: Separate types for generating decls and functions?
258 try self.genNav(pt, nav, air.*, liveness.*, true);
258 try self.genNav(pt, nav, air.*, liveness.*.?, true);
259259 }
260260
261261 pub fn updateNav(
......@@ -5134,7 +5134,7 @@ const NavGen = struct {
51345134 .@"struct" => switch (object_ty.containerLayout(zcu)) {
51355135 .@"packed" => {
51365136 const struct_ty = zcu.typeToPackedStruct(object_ty).?;
5137 const bit_offset = pt.structPackedFieldBitOffset(struct_ty, field_index);
5137 const bit_offset = zcu.structPackedFieldBitOffset(struct_ty, field_index);
51385138 const bit_offset_id = try self.constInt(.u16, bit_offset);
51395139 const signedness = if (field_ty.isInt(zcu)) field_ty.intInfo(zcu).signedness else .unsigned;
51405140 const field_bit_size: u16 = @intCast(field_ty.bitSize(zcu));
src/dev.zig+27-14
......@@ -25,13 +25,13 @@ pub const Env = enum {
2525 /// - `zig build-* -fno-emit-bin`
2626 sema,
2727
28 /// - sema
29 /// - `zig build-* -fincremental -fno-llvm -fno-lld -target aarch64-linux --listen=-`
30 @"aarch64-linux",
31
2832 /// - `zig build-* -ofmt=c`
2933 cbe,
3034
31 /// - sema
32 /// - `zig build-* -fincremental -fno-llvm -fno-lld -target x86_64-linux --listen=-`
33 @"x86_64-linux",
34
3535 /// - sema
3636 /// - `zig build-* -fincremental -fno-llvm -fno-lld -target powerpc(64)(le)-linux --listen=-`
3737 @"powerpc-linux",
......@@ -48,6 +48,10 @@ pub const Env = enum {
4848 /// - `zig build-* -fno-llvm -fno-lld -target wasm32-* --listen=-`
4949 wasm,
5050
51 /// - sema
52 /// - `zig build-* -fincremental -fno-llvm -fno-lld -target x86_64-linux --listen=-`
53 @"x86_64-linux",
54
5155 pub inline fn supports(comptime dev_env: Env, comptime feature: Feature) bool {
5256 return switch (dev_env) {
5357 .full => true,
......@@ -153,23 +157,22 @@ pub const Env = enum {
153157 => true,
154158 else => Env.ast_gen.supports(feature),
155159 },
156 .cbe => switch (feature) {
157 .legalize,
158 .c_backend,
159 .c_linker,
160 => true,
161 else => Env.sema.supports(feature),
162 },
163 .@"x86_64-linux" => switch (feature) {
160 .@"aarch64-linux" => switch (feature) {
164161 .build_command,
165162 .stdio_listen,
166163 .incremental,
167 .legalize,
168 .x86_64_backend,
164 .aarch64_backend,
169165 .elf_linker,
170166 => true,
171167 else => Env.sema.supports(feature),
172168 },
169 .cbe => switch (feature) {
170 .legalize,
171 .c_backend,
172 .c_linker,
173 => true,
174 else => Env.sema.supports(feature),
175 },
173176 .@"powerpc-linux" => switch (feature) {
174177 .build_command,
175178 .stdio_listen,
......@@ -199,6 +202,16 @@ pub const Env = enum {
199202 => true,
200203 else => Env.sema.supports(feature),
201204 },
205 .@"x86_64-linux" => switch (feature) {
206 .build_command,
207 .stdio_listen,
208 .incremental,
209 .legalize,
210 .x86_64_backend,
211 .elf_linker,
212 => true,
213 else => Env.sema.supports(feature),
214 },
202215 };
203216 }
204217
src/link.zig+1
......@@ -23,6 +23,7 @@ const dev = @import("dev.zig");
2323const target_util = @import("target.zig");
2424const codegen = @import("codegen.zig");
2525
26pub const aarch64 = @import("link/aarch64.zig");
2627pub const LdScript = @import("link/LdScript.zig");
2728pub const Queue = @import("link/Queue.zig");
2829
src/link/Coff.zig+25-51
......@@ -1335,9 +1335,13 @@ fn updateNavCode(
13351335
13361336 log.debug("updateNavCode {f} 0x{x}", .{ nav.fqn.fmt(ip), nav_index });
13371337
1338 const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;
1339 const required_alignment = switch (pt.navAlignment(nav_index)) {
1340 .none => target_util.defaultFunctionAlignment(target),
1338 const mod = zcu.navFileScope(nav_index).mod.?;
1339 const target = &mod.resolved_target.result;
1340 const required_alignment = switch (nav.status.fully_resolved.alignment) {
1341 .none => switch (mod.optimize_mode) {
1342 .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target),
1343 .ReleaseSmall => target_util.minFunctionAlignment(target),
1344 },
13411345 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
13421346 };
13431347
......@@ -2832,58 +2836,33 @@ pub const Relocation = struct {
28322836 };
28332837
28342838 fn resolveAarch64(reloc: Relocation, ctx: Context) void {
2839 const Instruction = aarch64_util.encoding.Instruction;
28352840 var buffer = ctx.code[reloc.offset..];
28362841 switch (reloc.type) {
28372842 .got_page, .import_page, .page => {
28382843 const source_page = @as(i32, @intCast(ctx.source_vaddr >> 12));
28392844 const target_page = @as(i32, @intCast(ctx.target_vaddr >> 12));
2840 const pages = @as(u21, @bitCast(@as(i21, @intCast(target_page - source_page))));
2841 var inst = aarch64_util.Instruction{
2842 .pc_relative_address = mem.bytesToValue(@FieldType(
2843 aarch64_util.Instruction,
2844 @tagName(aarch64_util.Instruction.pc_relative_address),
2845 ), buffer[0..4]),
2846 };
2847 inst.pc_relative_address.immhi = @as(u19, @truncate(pages >> 2));
2848 inst.pc_relative_address.immlo = @as(u2, @truncate(pages));
2849 mem.writeInt(u32, buffer[0..4], inst.toU32(), .little);
2845 const pages: i21 = @intCast(target_page - source_page);
2846 var inst: Instruction = .read(buffer[0..Instruction.size]);
2847 inst.data_processing_immediate.pc_relative_addressing.group.immhi = @intCast(pages >> 2);
2848 inst.data_processing_immediate.pc_relative_addressing.group.immlo = @truncate(@as(u21, @bitCast(pages)));
2849 inst.write(buffer[0..Instruction.size]);
28502850 },
28512851 .got_pageoff, .import_pageoff, .pageoff => {
28522852 assert(!reloc.pcrel);
28532853
2854 const narrowed = @as(u12, @truncate(@as(u64, @intCast(ctx.target_vaddr))));
2855 if (isArithmeticOp(buffer[0..4])) {
2856 var inst = aarch64_util.Instruction{
2857 .add_subtract_immediate = mem.bytesToValue(@FieldType(
2858 aarch64_util.Instruction,
2859 @tagName(aarch64_util.Instruction.add_subtract_immediate),
2860 ), buffer[0..4]),
2861 };
2862 inst.add_subtract_immediate.imm12 = narrowed;
2863 mem.writeInt(u32, buffer[0..4], inst.toU32(), .little);
2864 } else {
2865 var inst = aarch64_util.Instruction{
2866 .load_store_register = mem.bytesToValue(@FieldType(
2867 aarch64_util.Instruction,
2868 @tagName(aarch64_util.Instruction.load_store_register),
2869 ), buffer[0..4]),
2870 };
2871 const offset: u12 = blk: {
2872 if (inst.load_store_register.size == 0) {
2873 if (inst.load_store_register.v == 1) {
2874 // 128-bit SIMD is scaled by 16.
2875 break :blk @divExact(narrowed, 16);
2876 }
2877 // Otherwise, 8-bit SIMD or ldrb.
2878 break :blk narrowed;
2879 } else {
2880 const denom: u4 = math.powi(u4, 2, inst.load_store_register.size) catch unreachable;
2881 break :blk @divExact(narrowed, denom);
2882 }
2883 };
2884 inst.load_store_register.offset = offset;
2885 mem.writeInt(u32, buffer[0..4], inst.toU32(), .little);
2854 const narrowed: u12 = @truncate(@as(u64, @intCast(ctx.target_vaddr)));
2855 var inst: Instruction = .read(buffer[0..Instruction.size]);
2856 switch (inst.decode()) {
2857 else => unreachable,
2858 .data_processing_immediate => inst.data_processing_immediate.add_subtract_immediate.group.imm12 = narrowed,
2859 .load_store => |load_store| inst.load_store.register_unsigned_immediate.group.imm12 =
2860 switch (load_store.register_unsigned_immediate.decode()) {
2861 .integer => |integer| @shrExact(narrowed, @intFromEnum(integer.group.size)),
2862 .vector => |vector| @shrExact(narrowed, @intFromEnum(vector.group.opc1.decode(vector.group.size))),
2863 },
28862864 }
2865 inst.write(buffer[0..Instruction.size]);
28872866 },
28882867 .direct => {
28892868 assert(!reloc.pcrel);
......@@ -2934,11 +2913,6 @@ pub const Relocation = struct {
29342913 },
29352914 }
29362915 }
2937
2938 fn isArithmeticOp(inst: *const [4]u8) bool {
2939 const group_decode = @as(u5, @truncate(inst[3]));
2940 return ((group_decode >> 2) == 4);
2941 }
29422916};
29432917
29442918pub fn addRelocation(coff: *Coff, atom_index: Atom.Index, reloc: Relocation) !void {
......@@ -3112,7 +3086,7 @@ const Path = std.Build.Cache.Path;
31123086const Directory = std.Build.Cache.Directory;
31133087const Cache = std.Build.Cache;
31143088
3115const aarch64_util = @import("../arch/aarch64/bits.zig");
3089const aarch64_util = link.aarch64;
31163090const allocPrint = std.fmt.allocPrint;
31173091const codegen = @import("../codegen.zig");
31183092const link = @import("../link.zig");
src/link/Dwarf.zig+7-1
......@@ -2487,7 +2487,13 @@ fn initWipNavInner(
24872487 try wip_nav.strp(nav.fqn.toSlice(ip));
24882488 const ty: Type = nav_val.typeOf(zcu);
24892489 const addr: Loc = .{ .addr_reloc = sym_index };
2490 const loc: Loc = if (decl.is_threadlocal) .{ .form_tls_address = &addr } else addr;
2490 const loc: Loc = if (decl.is_threadlocal) loc: {
2491 const target = zcu.comp.root_mod.resolved_target.result;
2492 break :loc switch (target.cpu.arch) {
2493 .x86_64 => .{ .form_tls_address = &addr },
2494 else => .empty,
2495 };
2496 } else addr;
24912497 switch (decl.kind) {
24922498 .unnamed_test, .@"test", .decltest, .@"comptime" => unreachable,
24932499 .@"const" => {
src/link/Elf/Atom.zig+27-43
......@@ -1627,7 +1627,7 @@ const aarch64 = struct {
16271627 const S_ = th.targetAddress(target_index, elf_file);
16281628 break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow;
16291629 };
1630 aarch64_util.writeBranchImm(disp, code);
1630 util.writeBranchImm(disp, code);
16311631 },
16321632
16331633 .PREL32 => {
......@@ -1640,15 +1640,18 @@ const aarch64 = struct {
16401640 mem.writeInt(u64, code_buffer[r_offset..][0..8], @bitCast(value), .little);
16411641 },
16421642
1643 .ADR_PREL_LO21 => {
1644 const value = math.cast(i21, S + A - P) orelse return error.Overflow;
1645 util.writeAdrInst(value, code);
1646 },
1647
16431648 .ADR_PREL_PG_HI21 => {
16441649 // TODO: check for relaxation of ADRP+ADD
1645 const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(P, S + A)));
1646 aarch64_util.writeAdrpInst(pages, code);
1650 util.writeAdrInst(try util.calcNumberOfPages(P, S + A), code);
16471651 },
16481652
16491653 .ADR_GOT_PAGE => if (target.flags.has_got) {
1650 const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(P, G + GOT + A)));
1651 aarch64_util.writeAdrpInst(pages, code);
1654 util.writeAdrInst(try util.calcNumberOfPages(P, G + GOT + A), code);
16521655 } else {
16531656 // TODO: relax
16541657 var err = try diags.addErrorWithNotes(1);
......@@ -1663,12 +1666,12 @@ const aarch64 = struct {
16631666 .LD64_GOT_LO12_NC => {
16641667 assert(target.flags.has_got);
16651668 const taddr = @as(u64, @intCast(G + GOT + A));
1666 aarch64_util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code);
1669 util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code);
16671670 },
16681671
16691672 .ADD_ABS_LO12_NC => {
16701673 const taddr = @as(u64, @intCast(S + A));
1671 aarch64_util.writeAddImmInst(@truncate(taddr), code);
1674 util.writeAddImmInst(@truncate(taddr), code);
16721675 },
16731676
16741677 .LDST8_ABS_LO12_NC,
......@@ -1687,57 +1690,54 @@ const aarch64 = struct {
16871690 .LDST128_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 16),
16881691 else => unreachable,
16891692 };
1690 aarch64_util.writeLoadStoreRegInst(off, code);
1693 util.writeLoadStoreRegInst(off, code);
16911694 },
16921695
16931696 .TLSLE_ADD_TPREL_HI12 => {
16941697 const value = math.cast(i12, (S + A - TP) >> 12) orelse
16951698 return error.Overflow;
1696 aarch64_util.writeAddImmInst(@bitCast(value), code);
1699 util.writeAddImmInst(@bitCast(value), code);
16971700 },
16981701
16991702 .TLSLE_ADD_TPREL_LO12_NC => {
17001703 const value: i12 = @truncate(S + A - TP);
1701 aarch64_util.writeAddImmInst(@bitCast(value), code);
1704 util.writeAddImmInst(@bitCast(value), code);
17021705 },
17031706
17041707 .TLSIE_ADR_GOTTPREL_PAGE21 => {
17051708 const S_ = target.gotTpAddress(elf_file);
17061709 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1707 const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A));
1708 aarch64_util.writeAdrpInst(pages, code);
1710 util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code);
17091711 },
17101712
17111713 .TLSIE_LD64_GOTTPREL_LO12_NC => {
17121714 const S_ = target.gotTpAddress(elf_file);
17131715 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
17141716 const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);
1715 aarch64_util.writeLoadStoreRegInst(off, code);
1717 util.writeLoadStoreRegInst(off, code);
17161718 },
17171719
17181720 .TLSGD_ADR_PAGE21 => {
17191721 const S_ = target.tlsGdAddress(elf_file);
17201722 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1721 const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A));
1722 aarch64_util.writeAdrpInst(pages, code);
1723 util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code);
17231724 },
17241725
17251726 .TLSGD_ADD_LO12_NC => {
17261727 const S_ = target.tlsGdAddress(elf_file);
17271728 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
17281729 const off: u12 = @truncate(@as(u64, @bitCast(S_ + A)));
1729 aarch64_util.writeAddImmInst(off, code);
1730 util.writeAddImmInst(off, code);
17301731 },
17311732
17321733 .TLSDESC_ADR_PAGE21 => {
17331734 if (target.flags.has_tlsdesc) {
17341735 const S_ = target.tlsDescAddress(elf_file);
17351736 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1736 const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A));
1737 aarch64_util.writeAdrpInst(pages, code);
1737 util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code);
17381738 } else {
17391739 relocs_log.debug(" relaxing adrp => nop", .{});
1740 mem.writeInt(u32, code, Instruction.nop().toU32(), .little);
1740 util.encoding.Instruction.nop().write(code);
17411741 }
17421742 },
17431743
......@@ -1746,10 +1746,10 @@ const aarch64 = struct {
17461746 const S_ = target.tlsDescAddress(elf_file);
17471747 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
17481748 const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);
1749 aarch64_util.writeLoadStoreRegInst(off, code);
1749 util.writeLoadStoreRegInst(off, code);
17501750 } else {
17511751 relocs_log.debug(" relaxing ldr => nop", .{});
1752 mem.writeInt(u32, code, Instruction.nop().toU32(), .little);
1752 util.encoding.Instruction.nop().write(code);
17531753 }
17541754 },
17551755
......@@ -1758,32 +1758,18 @@ const aarch64 = struct {
17581758 const S_ = target.tlsDescAddress(elf_file);
17591759 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
17601760 const off: u12 = @truncate(@as(u64, @bitCast(S_ + A)));
1761 aarch64_util.writeAddImmInst(off, code);
1761 util.writeAddImmInst(off, code);
17621762 } else {
1763 const old_inst: Instruction = .{
1764 .add_subtract_immediate = mem.bytesToValue(@FieldType(
1765 Instruction,
1766 @tagName(Instruction.add_subtract_immediate),
1767 ), code),
1768 };
1769 const rd: Register = @enumFromInt(old_inst.add_subtract_immediate.rd);
1770 relocs_log.debug(" relaxing add({s}) => movz(x0, {x})", .{ @tagName(rd), S + A - TP });
1763 relocs_log.debug(" relaxing add => movz(x0, {x})", .{S + A - TP});
17711764 const value: u16 = @bitCast(math.cast(i16, (S + A - TP) >> 16) orelse return error.Overflow);
1772 mem.writeInt(u32, code, Instruction.movz(.x0, value, 16).toU32(), .little);
1765 util.encoding.Instruction.movz(.x0, value, .{ .lsl = .@"16" }).write(code);
17731766 }
17741767 },
17751768
17761769 .TLSDESC_CALL => if (!target.flags.has_tlsdesc) {
1777 const old_inst: Instruction = .{
1778 .unconditional_branch_register = mem.bytesToValue(@FieldType(
1779 Instruction,
1780 @tagName(Instruction.unconditional_branch_register),
1781 ), code),
1782 };
1783 const rn: Register = @enumFromInt(old_inst.unconditional_branch_register.rn);
1784 relocs_log.debug(" relaxing br({s}) => movk(x0, {x})", .{ @tagName(rn), S + A - TP });
1770 relocs_log.debug(" relaxing br => movk(x0, {x})", .{S + A - TP});
17851771 const value: u16 = @bitCast(@as(i16, @truncate(S + A - TP)));
1786 mem.writeInt(u32, code, Instruction.movk(.x0, value, 0).toU32(), .little);
1772 util.encoding.Instruction.movk(.x0, value, .{}).write(code);
17871773 },
17881774
17891775 else => try atom.reportUnhandledRelocError(rel, elf_file),
......@@ -1819,9 +1805,7 @@ const aarch64 = struct {
18191805 }
18201806 }
18211807
1822 const aarch64_util = @import("../aarch64.zig");
1823 const Instruction = aarch64_util.Instruction;
1824 const Register = aarch64_util.Register;
1808 const util = @import("../aarch64.zig");
18251809};
18261810
18271811const riscv = struct {
src/link/Elf/Thunk.zig+9-6
......@@ -95,18 +95,21 @@ const aarch64 = struct {
9595 const sym = elf_file.symbol(ref).?;
9696 const saddr = thunk.address(elf_file) + @as(i64, @intCast(i * trampoline_size));
9797 const taddr = sym.address(.{}, elf_file);
98 const pages = try util.calcNumberOfPages(saddr, taddr);
99 try writer.writeInt(u32, Instruction.adrp(.x16, pages).toU32(), .little);
100 const off: u12 = @truncate(@as(u64, @bitCast(taddr)));
101 try writer.writeInt(u32, Instruction.add(.x16, .x16, off, false).toU32(), .little);
102 try writer.writeInt(u32, Instruction.br(.x16).toU32(), .little);
98 try writer.writeInt(u32, @bitCast(
99 util.encoding.Instruction.adrp(.x16, try util.calcNumberOfPages(saddr, taddr) << 12),
100 ), .little);
101 try writer.writeInt(u32, @bitCast(util.encoding.Instruction.add(
102 .x16,
103 .x16,
104 .{ .immediate = @truncate(@as(u64, @bitCast(taddr))) },
105 )), .little);
106 try writer.writeInt(u32, @bitCast(util.encoding.Instruction.br(.x16)), .little);
103107 }
104108 }
105109
106110 const trampoline_size = 3 * @sizeOf(u32);
107111
108112 const util = @import("../aarch64.zig");
109 const Instruction = util.Instruction;
110113};
111114
112115const assert = std.debug.assert;
src/link/Elf/ZigObject.zig+7-3
......@@ -1270,9 +1270,13 @@ fn updateNavCode(
12701270
12711271 log.debug("updateNavCode {f}({d})", .{ nav.fqn.fmt(ip), nav_index });
12721272
1273 const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;
1274 const required_alignment = switch (pt.navAlignment(nav_index)) {
1275 .none => target_util.defaultFunctionAlignment(target),
1273 const mod = zcu.navFileScope(nav_index).mod.?;
1274 const target = &mod.resolved_target.result;
1275 const required_alignment = switch (nav.status.fully_resolved.alignment) {
1276 .none => switch (mod.optimize_mode) {
1277 .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target),
1278 .ReleaseSmall => target_util.minFunctionAlignment(target),
1279 },
12761280 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
12771281 };
12781282
src/link/Elf/relocation.zig+18-6
......@@ -94,14 +94,18 @@ pub fn encode(comptime kind: Kind, cpu_arch: std.Target.Cpu.Arch) u32 {
9494pub const dwarf = struct {
9595 pub fn crossSectionRelocType(format: DW.Format, cpu_arch: std.Target.Cpu.Arch) u32 {
9696 return switch (cpu_arch) {
97 .x86_64 => @intFromEnum(switch (format) {
98 .@"32" => elf.R_X86_64.@"32",
97 .x86_64 => @intFromEnum(@as(elf.R_X86_64, switch (format) {
98 .@"32" => .@"32",
9999 .@"64" => .@"64",
100 }),
101 .riscv64 => @intFromEnum(switch (format) {
102 .@"32" => elf.R_RISCV.@"32",
100 })),
101 .aarch64 => @intFromEnum(@as(elf.R_AARCH64, switch (format) {
102 .@"32" => .ABS32,
103 .@"64" => .ABS64,
104 })),
105 .riscv64 => @intFromEnum(@as(elf.R_RISCV, switch (format) {
106 .@"32" => .@"32",
103107 .@"64" => .@"64",
104 }),
108 })),
105109 else => @panic("TODO unhandled cpu arch"),
106110 };
107111 }
......@@ -121,6 +125,14 @@ pub const dwarf = struct {
121125 },
122126 .debug_frame => .PC32,
123127 })),
128 .aarch64 => @intFromEnum(@as(elf.R_AARCH64, switch (source_section) {
129 else => switch (address_size) {
130 .@"32" => .ABS32,
131 .@"64" => .ABS64,
132 else => unreachable,
133 },
134 .debug_frame => .PREL32,
135 })),
124136 .riscv64 => @intFromEnum(@as(elf.R_RISCV, switch (source_section) {
125137 else => switch (address_size) {
126138 .@"32" => .@"32",
src/link/Elf/synthetic_sections.zig+30-45
......@@ -810,54 +810,43 @@ pub const PltSection = struct {
810810 const got_plt_addr: i64 = @intCast(shdrs[elf_file.section_indexes.got_plt.?].sh_addr);
811811 // TODO: relax if possible
812812 // .got.plt[2]
813 const pages = try aarch64_util.calcNumberOfPages(plt_addr + 4, got_plt_addr + 16);
814 const ldr_off = try math.divExact(u12, @truncate(@as(u64, @bitCast(got_plt_addr + 16))), 8);
813 const pages = try util.calcNumberOfPages(plt_addr + 4, got_plt_addr + 16);
814 const ldr_off: u12 = @truncate(@as(u64, @bitCast(got_plt_addr + 16)));
815815 const add_off: u12 = @truncate(@as(u64, @bitCast(got_plt_addr + 16)));
816816
817 const preamble = &[_]Instruction{
818 Instruction.stp(
819 .x16,
820 .x30,
821 Register.sp,
822 Instruction.LoadStorePairOffset.pre_index(-16),
823 ),
824 Instruction.adrp(.x16, pages),
825 Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(ldr_off)),
826 Instruction.add(.x16, .x16, add_off, false),
827 Instruction.br(.x17),
828 Instruction.nop(),
829 Instruction.nop(),
830 Instruction.nop(),
817 const preamble = [_]util.encoding.Instruction{
818 .stp(.x16, .x30, .{ .pre_index = .{ .base = .sp, .index = -16 } }),
819 .adrp(.x16, pages << 12),
820 .ldr(.x17, .{ .unsigned_offset = .{ .base = .x16, .offset = ldr_off } }),
821 .add(.x16, .x16, .{ .immediate = add_off }),
822 .br(.x17),
823 .nop(),
824 .nop(),
825 .nop(),
831826 };
832827 comptime assert(preamble.len == 8);
833 for (preamble) |inst| {
834 try writer.writeInt(u32, inst.toU32(), .little);
835 }
828 for (preamble) |inst| try writer.writeInt(util.encoding.Instruction.Backing, @bitCast(inst), .little);
836829 }
837830
838831 for (plt.symbols.items) |ref| {
839832 const sym = elf_file.symbol(ref).?;
840833 const target_addr = sym.gotPltAddress(elf_file);
841834 const source_addr = sym.pltAddress(elf_file);
842 const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr);
843 const ldr_off = try math.divExact(u12, @truncate(@as(u64, @bitCast(target_addr))), 8);
835 const pages = try util.calcNumberOfPages(source_addr, target_addr);
836 const ldr_off: u12 = @truncate(@as(u64, @bitCast(target_addr)));
844837 const add_off: u12 = @truncate(@as(u64, @bitCast(target_addr)));
845 const insts = &[_]Instruction{
846 Instruction.adrp(.x16, pages),
847 Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(ldr_off)),
848 Instruction.add(.x16, .x16, add_off, false),
849 Instruction.br(.x17),
838 const insts = [_]util.encoding.Instruction{
839 .adrp(.x16, pages << 12),
840 .ldr(.x17, .{ .unsigned_offset = .{ .base = .x16, .offset = ldr_off } }),
841 .add(.x16, .x16, .{ .immediate = add_off }),
842 .br(.x17),
850843 };
851844 comptime assert(insts.len == 4);
852 for (insts) |inst| {
853 try writer.writeInt(u32, inst.toU32(), .little);
854 }
845 for (insts) |inst| try writer.writeInt(util.encoding.Instruction.Backing, @bitCast(inst), .little);
855846 }
856847 }
857848
858 const aarch64_util = @import("../aarch64.zig");
859 const Instruction = aarch64_util.Instruction;
860 const Register = aarch64_util.Register;
849 const util = @import("../aarch64.zig");
861850 };
862851};
863852
......@@ -979,24 +968,20 @@ pub const PltGotSection = struct {
979968 const sym = elf_file.symbol(ref).?;
980969 const target_addr = sym.gotAddress(elf_file);
981970 const source_addr = sym.pltGotAddress(elf_file);
982 const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr);
983 const off = try math.divExact(u12, @truncate(@as(u64, @bitCast(target_addr))), 8);
984 const insts = &[_]Instruction{
985 Instruction.adrp(.x16, pages),
986 Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(off)),
987 Instruction.br(.x17),
988 Instruction.nop(),
971 const pages = try util.calcNumberOfPages(source_addr, target_addr);
972 const off: u12 = @truncate(@as(u64, @bitCast(target_addr)));
973 const insts = [_]util.encoding.Instruction{
974 .adrp(.x16, pages << 12),
975 .ldr(.x17, .{ .unsigned_offset = .{ .base = .x16, .offset = off } }),
976 .br(.x17),
977 .nop(),
989978 };
990979 comptime assert(insts.len == 4);
991 for (insts) |inst| {
992 try writer.writeInt(u32, inst.toU32(), .little);
993 }
980 for (insts) |inst| try writer.writeInt(util.encoding.Instruction.Backing, @bitCast(inst), .little);
994981 }
995982 }
996983
997 const aarch64_util = @import("../aarch64.zig");
998 const Instruction = aarch64_util.Instruction;
999 const Register = aarch64_util.Register;
984 const util = @import("../aarch64.zig");
1000985 };
1001986};
1002987
src/link/MachO.zig+2-1
......@@ -328,6 +328,7 @@ pub fn deinit(self: *MachO) void {
328328 self.unwind_info.deinit(gpa);
329329 self.data_in_code.deinit(gpa);
330330
331 for (self.thunks.items) |*thunk| thunk.deinit(gpa);
331332 self.thunks.deinit(gpa);
332333}
333334
......@@ -5373,7 +5374,7 @@ const mem = std.mem;
53735374const meta = std.meta;
53745375const Writer = std.io.Writer;
53755376
5376const aarch64 = @import("../arch/aarch64/bits.zig");
5377const aarch64 = codegen.aarch64.encoding;
53775378const bind = @import("MachO/dyld_info/bind.zig");
53785379const calcUuid = @import("MachO/uuid.zig").calcUuid;
53795380const codegen = @import("../codegen.zig");
src/link/MachO/Atom.zig+29-71
......@@ -780,8 +780,7 @@ fn resolveRelocInner(
780780 };
781781 break :target math.cast(u64, target) orelse return error.Overflow;
782782 };
783 const pages = @as(u21, @bitCast(try aarch64.calcNumberOfPages(@intCast(source), @intCast(target))));
784 aarch64.writeAdrpInst(pages, code[rel_offset..][0..4]);
783 aarch64.writeAdrInst(try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)), code[rel_offset..][0..aarch64.encoding.Instruction.size]);
785784 },
786785
787786 .pageoff => {
......@@ -789,26 +788,18 @@ fn resolveRelocInner(
789788 assert(rel.meta.length == 2);
790789 assert(!rel.meta.pcrel);
791790 const target = math.cast(u64, S + A) orelse return error.Overflow;
792 const inst_code = code[rel_offset..][0..4];
793 if (aarch64.isArithmeticOp(inst_code)) {
794 aarch64.writeAddImmInst(@truncate(target), inst_code);
795 } else {
796 var inst = aarch64.Instruction{
797 .load_store_register = mem.bytesToValue(@FieldType(
798 aarch64.Instruction,
799 @tagName(aarch64.Instruction.load_store_register),
800 ), inst_code),
801 };
802 inst.load_store_register.offset = switch (inst.load_store_register.size) {
803 0 => if (inst.load_store_register.v == 1)
804 try divExact(self, rel, @truncate(target), 16, macho_file)
805 else
806 @truncate(target),
807 1 => try divExact(self, rel, @truncate(target), 2, macho_file),
808 2 => try divExact(self, rel, @truncate(target), 4, macho_file),
809 3 => try divExact(self, rel, @truncate(target), 8, macho_file),
810 };
811 try writer.writeInt(u32, inst.toU32(), .little);
791 const inst_code = code[rel_offset..][0..aarch64.encoding.Instruction.size];
792 var inst: aarch64.encoding.Instruction = .read(inst_code);
793 switch (inst.decode()) {
794 else => unreachable,
795 .data_processing_immediate => aarch64.writeAddImmInst(@truncate(target), inst_code),
796 .load_store => |load_store| {
797 inst.load_store.register_unsigned_immediate.group.imm12 = switch (load_store.register_unsigned_immediate.decode()) {
798 .integer => |integer| try divExact(self, rel, @truncate(target), @as(u4, 1) << @intFromEnum(integer.group.size), macho_file),
799 .vector => |vector| try divExact(self, rel, @truncate(target), @as(u5, 1) << @intFromEnum(vector.group.opc1.decode(vector.group.size)), macho_file),
800 };
801 try writer.writeInt(u32, @bitCast(inst), .little);
802 },
812803 }
813804 },
814805
......@@ -834,59 +825,26 @@ fn resolveRelocInner(
834825 break :target math.cast(u64, target) orelse return error.Overflow;
835826 };
836827
837 const RegInfo = struct {
838 rd: u5,
839 rn: u5,
840 size: u2,
841 };
842
843828 const inst_code = code[rel_offset..][0..4];
844 const reg_info: RegInfo = blk: {
845 if (aarch64.isArithmeticOp(inst_code)) {
846 const inst = mem.bytesToValue(@FieldType(
847 aarch64.Instruction,
848 @tagName(aarch64.Instruction.add_subtract_immediate),
849 ), inst_code);
850 break :blk .{
851 .rd = inst.rd,
852 .rn = inst.rn,
853 .size = inst.sf,
854 };
855 } else {
856 const inst = mem.bytesToValue(@FieldType(
857 aarch64.Instruction,
858 @tagName(aarch64.Instruction.load_store_register),
859 ), inst_code);
860 break :blk .{
861 .rd = inst.rt,
862 .rn = inst.rn,
863 .size = inst.size,
864 };
865 }
866 };
867
868 var inst = if (sym.getSectionFlags().tlv_ptr) aarch64.Instruction{
869 .load_store_register = .{
870 .rt = reg_info.rd,
871 .rn = reg_info.rn,
872 .offset = try divExact(self, rel, @truncate(target), 8, macho_file),
873 .opc = 0b01,
874 .op1 = 0b01,
875 .v = 0,
876 .size = reg_info.size,
829 const rd, const rn = switch (aarch64.encoding.Instruction.read(inst_code).decode()) {
830 else => unreachable,
831 .data_processing_immediate => |decoded| .{
832 decoded.add_subtract_immediate.group.Rd.decodeInteger(.doubleword, .{ .sp = true }),
833 decoded.add_subtract_immediate.group.Rn.decodeInteger(.doubleword, .{ .sp = true }),
877834 },
878 } else aarch64.Instruction{
879 .add_subtract_immediate = .{
880 .rd = reg_info.rd,
881 .rn = reg_info.rn,
882 .imm12 = @truncate(target),
883 .sh = 0,
884 .s = 0,
885 .op = 0,
886 .sf = @as(u1, @truncate(reg_info.size)),
835 .load_store => |decoded| .{
836 decoded.register_unsigned_immediate.integer.group.Rt.decodeInteger(.doubleword, .{}),
837 decoded.register_unsigned_immediate.group.Rn.decodeInteger(.doubleword, .{ .sp = true }),
887838 },
888839 };
889 try writer.writeInt(u32, inst.toU32(), .little);
840
841 try writer.writeInt(u32, @bitCast(@as(
842 aarch64.encoding.Instruction,
843 if (sym.getSectionFlags().tlv_ptr) .ldr(rd, .{ .unsigned_offset = .{
844 .base = rn,
845 .offset = try divExact(self, rel, @truncate(target), 8, macho_file) * 8,
846 } }) else .add(rd, rn, .{ .immediate = @truncate(target) }),
847 )), .little);
890848 },
891849 }
892850}
src/link/MachO/Thunk.zig+6-4
......@@ -21,15 +21,17 @@ pub fn getTargetAddress(thunk: Thunk, ref: MachO.Ref, macho_file: *MachO) u64 {
2121}
2222
2323pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void {
24 const Instruction = aarch64.encoding.Instruction;
2425 for (thunk.symbols.keys(), 0..) |ref, i| {
2526 const sym = ref.getSymbol(macho_file).?;
2627 const saddr = thunk.getAddress(macho_file) + i * trampoline_size;
2728 const taddr = sym.getAddress(.{}, macho_file);
2829 const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr));
29 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
30 const off: u12 = @truncate(taddr);
31 try writer.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little);
32 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
30 try writer.writeInt(u32, @bitCast(Instruction.adrp(.x16, pages << 12)), .little);
31 try writer.writeInt(u32, @bitCast(
32 Instruction.add(.x16, .x16, .{ .immediate = @truncate(taddr) }),
33 ), .little);
34 try writer.writeInt(u32, @bitCast(Instruction.br(.x16)), .little);
3335 }
3436}
3537
src/link/MachO/ZigObject.zig+7-3
......@@ -945,9 +945,13 @@ fn updateNavCode(
945945
946946 log.debug("updateNavCode {f} 0x{x}", .{ nav.fqn.fmt(ip), nav_index });
947947
948 const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;
949 const required_alignment = switch (pt.navAlignment(nav_index)) {
950 .none => target_util.defaultFunctionAlignment(target),
948 const mod = zcu.navFileScope(nav_index).mod.?;
949 const target = &mod.resolved_target.result;
950 const required_alignment = switch (nav.status.fully_resolved.alignment) {
951 .none => switch (mod.optimize_mode) {
952 .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target),
953 .ReleaseSmall => target_util.minFunctionAlignment(target),
954 },
951955 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
952956 };
953957
src/link/MachO/synthetic.zig+43-52
......@@ -105,16 +105,15 @@ pub const StubsSection = struct {
105105 try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little);
106106 },
107107 .aarch64 => {
108 const Instruction = aarch64.encoding.Instruction;
108109 // TODO relax if possible
109110 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
110 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
111 const off = try math.divExact(u12, @truncate(target), 8);
112 try writer.writeInt(
113 u32,
114 aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
115 .little,
116 );
117 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
111 try writer.writeInt(u32, @bitCast(Instruction.adrp(.x16, pages << 12)), .little);
112 try writer.writeInt(u32, @bitCast(Instruction.ldr(
113 .x16,
114 .{ .unsigned_offset = .{ .base = .x16, .offset = @as(u12, @truncate(target)) } },
115 )), .little);
116 try writer.writeInt(u32, @bitCast(Instruction.br(.x16)), .little);
118117 },
119118 else => unreachable,
120119 }
......@@ -201,18 +200,16 @@ pub const StubsHelperSection = struct {
201200 try writer.writeInt(i32, @intCast(target - source - 6 - 4), .little);
202201 },
203202 .aarch64 => {
204 const literal = blk: {
205 const div_res = try std.math.divExact(u64, entry_size - @sizeOf(u32), 4);
206 break :blk std.math.cast(u18, div_res) orelse return error.Overflow;
207 };
208 try writer.writeInt(u32, aarch64.Instruction.ldrLiteral(
209 .w16,
210 literal,
211 ).toU32(), .little);
203 const Instruction = aarch64.encoding.Instruction;
204 if (entry_size % Instruction.size != 0) return error.UnexpectedRemainder;
205 try writer.writeInt(u32, @bitCast(
206 Instruction.ldr(.w16, .{ .literal = std.math.cast(i21, entry_size - Instruction.size) orelse
207 return error.Overflow }),
208 ), .little);
212209 const disp = math.cast(i28, @as(i64, @intCast(target)) - @as(i64, @intCast(source + 4))) orelse
213210 return error.Overflow;
214 try writer.writeInt(u32, aarch64.Instruction.b(disp).toU32(), .little);
215 try writer.writeAll(&.{ 0x0, 0x0, 0x0, 0x0 });
211 try writer.writeInt(u32, @bitCast(Instruction.b(disp)), .little);
212 try writer.writeInt(u32, @bitCast(Instruction.udf(0x0)), .little);
216213 },
217214 else => unreachable,
218215 }
......@@ -242,31 +239,28 @@ pub const StubsHelperSection = struct {
242239 try writer.writeByte(0x90);
243240 },
244241 .aarch64 => {
242 const Instruction = aarch64.encoding.Instruction;
245243 {
246244 // TODO relax if possible
247245 const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr), @intCast(dyld_private_addr));
248 try writer.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little);
249 const off: u12 = @truncate(dyld_private_addr);
250 try writer.writeInt(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32(), .little);
246 try writer.writeInt(Instruction.Backing, @bitCast(Instruction.adrp(.x17, pages << 12)), .little);
247 try writer.writeInt(Instruction.Backing, @bitCast(
248 Instruction.add(.x17, .x17, .{ .immediate = @as(u12, @truncate(dyld_private_addr)) }),
249 ), .little);
251250 }
252 try writer.writeInt(u32, aarch64.Instruction.stp(
253 .x16,
254 .x17,
255 aarch64.Register.sp,
256 aarch64.Instruction.LoadStorePairOffset.pre_index(-16),
257 ).toU32(), .little);
251 try writer.writeInt(Instruction.Backing, @bitCast(
252 Instruction.stp(.x16, .x17, .{ .pre_index = .{ .base = .sp, .index = -16 } }),
253 ), .little);
258254 {
259255 // TODO relax if possible
260256 const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr + 12), @intCast(dyld_stub_binder_addr));
261 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
262 const off = try math.divExact(u12, @truncate(dyld_stub_binder_addr), 8);
263 try writer.writeInt(u32, aarch64.Instruction.ldr(
264 .x16,
257 try writer.writeInt(Instruction.Backing, @bitCast(Instruction.adrp(.x16, pages << 12)), .little);
258 try writer.writeInt(Instruction.Backing, @bitCast(Instruction.ldr(
265259 .x16,
266 aarch64.Instruction.LoadStoreOffset.imm(off),
267 ).toU32(), .little);
260 .{ .unsigned_offset = .{ .base = .x16, .offset = @as(u12, @truncate(dyld_stub_binder_addr)) } },
261 )), .little);
268262 }
269 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
263 try writer.writeInt(Instruction.Backing, @bitCast(Instruction.br(.x16)), .little);
270264 },
271265 else => unreachable,
272266 }
......@@ -426,35 +420,32 @@ pub const ObjcStubsSection = struct {
426420 }
427421 },
428422 .aarch64 => {
423 const Instruction = aarch64.encoding.Instruction;
429424 {
430425 const target = sym.getObjcSelrefsAddress(macho_file);
431426 const source = addr;
432427 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
433 try writer.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little);
434 const off = try math.divExact(u12, @truncate(target), 8);
435 try writer.writeInt(
436 u32,
437 aarch64.Instruction.ldr(.x1, .x1, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
438 .little,
439 );
428 try writer.writeInt(u32, @bitCast(Instruction.adrp(.x1, pages << 12)), .little);
429 try writer.writeInt(u32, @bitCast(Instruction.ldr(
430 .x1,
431 .{ .unsigned_offset = .{ .base = .x1, .offset = @as(u12, @truncate(target)) } },
432 )), .little);
440433 }
441434 {
442435 const target_sym = obj.getObjcMsgSendRef(macho_file).?.getSymbol(macho_file).?;
443436 const target = target_sym.getGotAddress(macho_file);
444437 const source = addr + 2 * @sizeOf(u32);
445438 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
446 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
447 const off = try math.divExact(u12, @truncate(target), 8);
448 try writer.writeInt(
449 u32,
450 aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
451 .little,
452 );
439 try writer.writeInt(u32, @bitCast(Instruction.adrp(.x16, pages << 12)), .little);
440 try writer.writeInt(u32, @bitCast(Instruction.ldr(
441 .x16,
442 .{ .unsigned_offset = .{ .base = .x16, .offset = @as(u12, @truncate(target)) } },
443 )), .little);
453444 }
454 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
455 try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
456 try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
457 try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);
445 try writer.writeInt(u32, @bitCast(Instruction.br(.x16)), .little);
446 try writer.writeInt(u32, @bitCast(Instruction.brk(0x1)), .little);
447 try writer.writeInt(u32, @bitCast(Instruction.brk(0x1)), .little);
448 try writer.writeInt(u32, @bitCast(Instruction.brk(0x1)), .little);
458449 },
459450 else => unreachable,
460451 }
src/link/aarch64.zig+17-47
......@@ -1,66 +1,36 @@
1pub inline fn isArithmeticOp(inst: *const [4]u8) bool {
2 const group_decode = @as(u5, @truncate(inst[3]));
3 return ((group_decode >> 2) == 4);
4}
1pub const encoding = @import("../codegen.zig").aarch64.encoding;
52
63pub fn writeAddImmInst(value: u12, code: *[4]u8) void {
7 var inst = Instruction{
8 .add_subtract_immediate = mem.bytesToValue(@FieldType(
9 Instruction,
10 @tagName(Instruction.add_subtract_immediate),
11 ), code),
12 };
13 inst.add_subtract_immediate.imm12 = value;
14 mem.writeInt(u32, code, inst.toU32(), .little);
4 var inst: encoding.Instruction = .read(code);
5 inst.data_processing_immediate.add_subtract_immediate.group.imm12 = value;
6 inst.write(code);
157}
168
179pub fn writeLoadStoreRegInst(value: u12, code: *[4]u8) void {
18 var inst: Instruction = .{
19 .load_store_register = mem.bytesToValue(@FieldType(
20 Instruction,
21 @tagName(Instruction.load_store_register),
22 ), code),
23 };
24 inst.load_store_register.offset = value;
25 mem.writeInt(u32, code, inst.toU32(), .little);
10 var inst: encoding.Instruction = .read(code);
11 inst.load_store.register_unsigned_immediate.group.imm12 = value;
12 inst.write(code);
2613}
2714
28pub fn calcNumberOfPages(saddr: i64, taddr: i64) error{Overflow}!i21 {
29 const spage = math.cast(i32, saddr >> 12) orelse return error.Overflow;
30 const tpage = math.cast(i32, taddr >> 12) orelse return error.Overflow;
31 const pages = math.cast(i21, tpage - spage) orelse return error.Overflow;
32 return pages;
15pub fn calcNumberOfPages(saddr: i64, taddr: i64) error{Overflow}!i33 {
16 return math.cast(i21, (taddr >> 12) - (saddr >> 12)) orelse error.Overflow;
3317}
3418
35pub fn writeAdrpInst(pages: u21, code: *[4]u8) void {
36 var inst = Instruction{
37 .pc_relative_address = mem.bytesToValue(@FieldType(
38 Instruction,
39 @tagName(Instruction.pc_relative_address),
40 ), code),
41 };
42 inst.pc_relative_address.immhi = @as(u19, @truncate(pages >> 2));
43 inst.pc_relative_address.immlo = @as(u2, @truncate(pages));
44 mem.writeInt(u32, code, inst.toU32(), .little);
19pub fn writeAdrInst(imm: i33, code: *[4]u8) void {
20 var inst: encoding.Instruction = .read(code);
21 inst.data_processing_immediate.pc_relative_addressing.group.immhi = @intCast(imm >> 2);
22 inst.data_processing_immediate.pc_relative_addressing.group.immlo = @bitCast(@as(i2, @truncate(imm)));
23 inst.write(code);
4524}
4625
4726pub fn writeBranchImm(disp: i28, code: *[4]u8) void {
48 var inst = Instruction{
49 .unconditional_branch_immediate = mem.bytesToValue(@FieldType(
50 Instruction,
51 @tagName(Instruction.unconditional_branch_immediate),
52 ), code),
53 };
54 inst.unconditional_branch_immediate.imm26 = @as(u26, @truncate(@as(u28, @bitCast(disp >> 2))));
55 mem.writeInt(u32, code, inst.toU32(), .little);
27 var inst: encoding.Instruction = .read(code);
28 inst.branch_exception_generating_system.unconditional_branch_immediate.group.imm26 = @intCast(@shrExact(disp, 2));
29 inst.write(code);
5630}
5731
5832const assert = std.debug.assert;
59const bits = @import("../arch/aarch64/bits.zig");
6033const builtin = @import("builtin");
6134const math = std.math;
6235const mem = std.mem;
6336const std = @import("std");
64
65pub const Instruction = bits.Instruction;
66pub const Register = bits.Register;
src/main.zig+1
......@@ -37,6 +37,7 @@ const dev = @import("dev.zig");
3737
3838test {
3939 _ = Package;
40 _ = @import("codegen.zig");
4041}
4142
4243const thread_stack_size = 60 << 20;
src/target.zig+14-4
......@@ -347,7 +347,7 @@ pub fn defaultCompilerRtOptimizeMode(target: *const std.Target) std.builtin.Opti
347347 }
348348}
349349
350pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, have_llvm: bool) bool {
350pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, comptime have_llvm: bool) bool {
351351 switch (target.os.tag) {
352352 .plan9 => return false,
353353 else => {},
......@@ -359,6 +359,7 @@ pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, have_llv
359359 else => {},
360360 }
361361 return switch (zigBackend(target, use_llvm)) {
362 .stage2_aarch64 => true,
362363 .stage2_llvm => true,
363364 .stage2_x86_64 => switch (target.ofmt) {
364365 .elf, .macho => true,
......@@ -368,13 +369,21 @@ pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, have_llv
368369 };
369370}
370371
371pub fn canBuildLibUbsanRt(target: *const std.Target) bool {
372pub fn canBuildLibUbsanRt(target: *const std.Target, use_llvm: bool, comptime have_llvm: bool) bool {
372373 switch (target.cpu.arch) {
373374 .spirv32, .spirv64 => return false,
374375 // Remove this once https://github.com/ziglang/zig/issues/23715 is fixed
375376 .nvptx, .nvptx64 => return false,
376 else => return true,
377 else => {},
377378 }
379 return switch (zigBackend(target, use_llvm)) {
380 .stage2_llvm => true,
381 .stage2_x86_64 => switch (target.ofmt) {
382 .elf, .macho => true,
383 else => have_llvm,
384 },
385 else => have_llvm,
386 };
378387}
379388
380389pub fn hasRedZone(target: *const std.Target) bool {
......@@ -767,6 +776,7 @@ pub fn supportsTailCall(target: *const std.Target, backend: std.builtin.Compiler
767776
768777pub fn supportsThreads(target: *const std.Target, backend: std.builtin.CompilerBackend) bool {
769778 return switch (backend) {
779 .stage2_aarch64 => false,
770780 .stage2_powerpc => true,
771781 .stage2_x86_64 => target.ofmt == .macho or target.ofmt == .elf,
772782 else => true,
......@@ -864,7 +874,7 @@ pub inline fn backendSupportsFeature(backend: std.builtin.CompilerBackend, compt
864874 else => false,
865875 },
866876 .field_reordering => switch (backend) {
867 .stage2_c, .stage2_llvm, .stage2_x86_64 => true,
877 .stage2_aarch64, .stage2_c, .stage2_llvm, .stage2_x86_64 => true,
868878 else => false,
869879 },
870880 .separate_thread => switch (backend) {
test/behavior.zig+2-2
......@@ -123,7 +123,6 @@ test {
123123 }
124124
125125 if (builtin.zig_backend != .stage2_arm and
126 builtin.zig_backend != .stage2_aarch64 and
127126 builtin.zig_backend != .stage2_spirv)
128127 {
129128 _ = @import("behavior/export_keyword.zig");
......@@ -141,7 +140,8 @@ test {
141140}
142141
143142// This bug only repros in the root file
144test "deference @embedFile() of a file full of zero bytes" {
143test "dereference @embedFile() of a file full of zero bytes" {
144 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
145145 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
146146
147147 const contents = @embedFile("behavior/zero.bin").*;
test/behavior/abs.zig+3-7
......@@ -3,7 +3,6 @@ const std = @import("std");
33const expect = std.testing.expect;
44
55test "@abs integers" {
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
76 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -50,7 +49,6 @@ fn testAbsIntegers() !void {
5049}
5150
5251test "@abs unsigned integers" {
53 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5452 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5553 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5654
......@@ -90,7 +88,6 @@ fn testAbsUnsignedIntegers() !void {
9088}
9189
9290test "@abs big int <= 128 bits" {
93 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9491 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9592 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9693 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
......@@ -153,7 +150,6 @@ fn testAbsUnsignedBigInt() !void {
153150}
154151
155152test "@abs floats" {
156 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
157153 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
158154 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
159155
......@@ -207,9 +203,9 @@ fn testAbsFloats(comptime T: type) !void {
207203}
208204
209205test "@abs int vectors" {
206 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
210207 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
211208 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
212 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
213209 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
214210 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
215211 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -275,8 +271,8 @@ fn testAbsIntVectors(comptime len: comptime_int) !void {
275271}
276272
277273test "@abs unsigned int vectors" {
274 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
278275 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
279 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
280276 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
281277 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
282278 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -334,8 +330,8 @@ fn testAbsUnsignedIntVectors(comptime len: comptime_int) !void {
334330}
335331
336332test "@abs float vectors" {
333 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
337334 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
338 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
339335 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
340336 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
341337 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/align.zig+1-19
......@@ -16,7 +16,6 @@ test "global variable alignment" {
1616}
1717
1818test "large alignment of local constant" {
19 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2019 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2120 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky
2221
......@@ -25,7 +24,6 @@ test "large alignment of local constant" {
2524}
2625
2726test "slicing array of length 1 can not assume runtime index is always zero" {
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2927 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3028 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky
3129
......@@ -74,7 +72,6 @@ test "alignment of struct with pointer has same alignment as usize" {
7472
7573test "alignment and size of structs with 128-bit fields" {
7674 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7875 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7976
8077 const A = struct {
......@@ -160,7 +157,6 @@ test "alignment and size of structs with 128-bit fields" {
160157}
161158
162159test "implicitly decreasing slice alignment" {
163 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
164160 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
165161 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
166162
......@@ -173,7 +169,6 @@ fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 {
173169}
174170
175171test "specifying alignment allows pointer cast" {
176 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
177172 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
178173 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
179174
......@@ -186,7 +181,6 @@ fn testBytesAlign(b: u8) !void {
186181}
187182
188183test "@alignCast slices" {
189 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
190184 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
191185 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
192186 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -205,7 +199,6 @@ fn sliceExpects4(slice: []align(4) u32) void {
205199
206200test "return error union with 128-bit integer" {
207201 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
208 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
209202 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
210203 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
211204 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -218,7 +211,6 @@ fn give() anyerror!u128 {
218211
219212test "page aligned array on stack" {
220213 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
221 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
222214 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
223215 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
224216 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -238,7 +230,6 @@ test "page aligned array on stack" {
238230}
239231
240232test "function alignment" {
241 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
242233 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
243234 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
244235 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -268,7 +259,6 @@ test "function alignment" {
268259}
269260
270261test "implicitly decreasing fn alignment" {
271 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
272262 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
273263 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
274264 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -292,7 +282,6 @@ fn alignedBig() align(16) i32 {
292282}
293283
294284test "@alignCast functions" {
295 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
296285 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
297286 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
298287 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -376,7 +365,6 @@ const DefaultAligned = struct {
376365
377366test "read 128-bit field from default aligned struct in stack memory" {
378367 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
379 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
380368 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
381369 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
382370 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -396,7 +384,6 @@ var default_aligned_global = DefaultAligned{
396384
397385test "read 128-bit field from default aligned struct in global memory" {
398386 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
399 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
400387 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
401388 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
402389 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -405,8 +392,8 @@ test "read 128-bit field from default aligned struct in global memory" {
405392}
406393
407394test "struct field explicit alignment" {
408 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
409395 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
396 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
410397 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
411398 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky
412399 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
......@@ -426,7 +413,6 @@ test "struct field explicit alignment" {
426413}
427414
428415test "align(N) on functions" {
429 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
430416 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
431417 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
432418 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -455,7 +441,6 @@ test "comptime alloc alignment" {
455441 // TODO: it's impossible to test this in Zig today, since comptime vars do not have runtime addresses.
456442 if (true) return error.SkipZigTest;
457443 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
458 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
459444 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
460445 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky
461446
......@@ -468,7 +453,6 @@ test "comptime alloc alignment" {
468453}
469454
470455test "@alignCast null" {
471 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
472456 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
473457 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
474458
......@@ -484,7 +468,6 @@ test "alignment of slice element" {
484468}
485469
486470test "sub-aligned pointer field access" {
487 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
488471 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
489472 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
490473 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -538,7 +521,6 @@ test "alignment of zero-bit types is respected" {
538521
539522test "zero-bit fields in extern struct pad fields appropriately" {
540523 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
541 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
542524 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
543525 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
544526 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/array.zig+5-37
......@@ -19,7 +19,6 @@ test "array to slice" {
1919}
2020
2121test "arrays" {
22 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2322 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2423 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2524
......@@ -47,7 +46,6 @@ fn getArrayLen(a: []const u32) usize {
4746}
4847
4948test "array concat with undefined" {
50 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5149 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5250 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
5351
......@@ -73,7 +71,6 @@ test "array concat with undefined" {
7371test "array concat with tuple" {
7472 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
7573 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7774 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7875
7976 const array: [2]u8 = .{ 1, 2 };
......@@ -89,7 +86,6 @@ test "array concat with tuple" {
8986
9087test "array init with concat" {
9188 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
92 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9389
9490 const a = 'a';
9591 var i: [4]u8 = [2]u8{ a, 'b' } ++ [2]u8{ 'c', 'd' };
......@@ -98,7 +94,6 @@ test "array init with concat" {
9894
9995test "array init with mult" {
10096 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
101 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10297 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10398
10499 const a = 'a';
......@@ -110,7 +105,6 @@ test "array init with mult" {
110105}
111106
112107test "array literal with explicit type" {
113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
114108 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
115109
116110 const hex_mult: [4]u16 = .{ 4096, 256, 16, 1 };
......@@ -138,7 +132,6 @@ const ArrayDotLenConstExpr = struct {
138132const some_array = [_]u8{ 0, 1, 2, 3 };
139133
140134test "array literal with specified size" {
141 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
142135 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
143136 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
144137
......@@ -162,7 +155,6 @@ test "array len field" {
162155
163156test "array with sentinels" {
164157 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
165 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
166158 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
167159
168160 const S = struct {
......@@ -200,7 +192,6 @@ test "void arrays" {
200192
201193test "nested arrays of strings" {
202194 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
203 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
204195 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
205196 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
206197
......@@ -215,7 +206,6 @@ test "nested arrays of strings" {
215206}
216207
217208test "nested arrays of integers" {
218 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
219209 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
220210
221211 const array_of_numbers = [_][2]u8{
......@@ -230,7 +220,6 @@ test "nested arrays of integers" {
230220}
231221
232222test "implicit comptime in array type size" {
233 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
234223 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
235224
236225 var arr: [plusOne(10)]bool = undefined;
......@@ -243,7 +232,6 @@ fn plusOne(x: u32) u32 {
243232}
244233
245234test "single-item pointer to array indexing and slicing" {
246 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
247235 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
248236 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
249237
......@@ -285,7 +273,6 @@ test "implicit cast zero sized array ptr to slice" {
285273}
286274
287275test "anonymous list literal syntax" {
288 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
289276 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
290277 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
291278
......@@ -308,7 +295,6 @@ const Sub = struct { b: u8 };
308295const Str = struct { a: []Sub };
309296test "set global var array via slice embedded in struct" {
310297 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
311 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
312298 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
313299
314300 var s = Str{ .a = s_array[0..] };
......@@ -323,7 +309,6 @@ test "set global var array via slice embedded in struct" {
323309}
324310
325311test "read/write through global variable array of struct fields initialized via array mult" {
326 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
327312 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
328313 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
329314
......@@ -345,7 +330,6 @@ test "read/write through global variable array of struct fields initialized via
345330
346331test "implicit cast single-item pointer" {
347332 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
348 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
349333 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
350334
351335 try testImplicitCastSingleItemPtr();
......@@ -364,7 +348,6 @@ fn testArrayByValAtComptime(b: [2]u8) u8 {
364348}
365349
366350test "comptime evaluating function that takes array by value" {
367 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
368351 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
369352
370353 const arr = [_]u8{ 1, 2 };
......@@ -376,7 +359,6 @@ test "comptime evaluating function that takes array by value" {
376359
377360test "runtime initialize array elem and then implicit cast to slice" {
378361 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
379 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
380362 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
381363
382364 var two: i32 = 2;
......@@ -387,7 +369,6 @@ test "runtime initialize array elem and then implicit cast to slice" {
387369
388370test "array literal as argument to function" {
389371 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
390 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
391372 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
392373
393374 const S = struct {
......@@ -414,8 +395,8 @@ test "array literal as argument to function" {
414395}
415396
416397test "double nested array to const slice cast in array literal" {
417 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
418398 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
399 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
419400 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
420401 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
421402
......@@ -476,7 +457,6 @@ test "double nested array to const slice cast in array literal" {
476457}
477458
478459test "anonymous literal in array" {
479 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
480460 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
481461 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
482462
......@@ -502,7 +482,6 @@ test "anonymous literal in array" {
502482}
503483
504484test "access the null element of a null terminated array" {
505 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
506485 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
507486
508487 const S = struct {
......@@ -520,7 +499,6 @@ test "access the null element of a null terminated array" {
520499}
521500
522501test "type deduction for array subscript expression" {
523 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
524502 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
525503 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
526504
......@@ -540,7 +518,6 @@ test "type deduction for array subscript expression" {
540518
541519test "sentinel element count towards the ABI size calculation" {
542520 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
543 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
544521 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
545522 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
546523
......@@ -564,7 +541,7 @@ test "sentinel element count towards the ABI size calculation" {
564541}
565542
566543test "zero-sized array with recursive type definition" {
567 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
544 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
568545 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
569546 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
570547
......@@ -587,8 +564,8 @@ test "zero-sized array with recursive type definition" {
587564}
588565
589566test "type coercion of anon struct literal to array" {
567 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
590568 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
591 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
592569 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
593570 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
594571
......@@ -628,7 +605,6 @@ test "array with comptime-only element type" {
628605}
629606
630607test "tuple to array handles sentinel" {
631 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
632608 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
633609 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
634610
......@@ -641,7 +617,6 @@ test "tuple to array handles sentinel" {
641617
642618test "array init of container level array variable" {
643619 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
644 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
645620 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
646621 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
647622
......@@ -675,8 +650,8 @@ test "runtime initialized sentinel-terminated array literal" {
675650}
676651
677652test "array of array agregate init" {
653 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
678654 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
679 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
680655 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
681656
682657 var a = [1]u32{11} ** 10;
......@@ -725,7 +700,6 @@ test "array init with no result location has result type" {
725700}
726701
727702test "slicing array of zero-sized values" {
728 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
729703 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
730704 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
731705 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -890,7 +864,6 @@ test "tuple initialized through reference to anonymous array init provides resul
890864
891865test "copied array element doesn't alias source" {
892866 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
893 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
894867 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
895868
896869 var x: [10][10]u32 = undefined;
......@@ -945,7 +918,6 @@ test "array initialized with array with sentinel" {
945918}
946919
947920test "store array of array of structs at comptime" {
948 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
949921 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
950922 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
951923
......@@ -970,7 +942,6 @@ test "store array of array of structs at comptime" {
970942}
971943
972944test "accessing multidimensional global array at comptime" {
973 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
974945 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
975946 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
976947
......@@ -986,8 +957,8 @@ test "accessing multidimensional global array at comptime" {
986957}
987958
988959test "union that needs padding bytes inside an array" {
989 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
990960 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
961 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
991962 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
992963 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
993964
......@@ -1023,7 +994,6 @@ test "runtime index of array of zero-bit values" {
1023994}
1024995
1025996test "@splat array" {
1026 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1027997 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1028998 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1029999
......@@ -1046,7 +1016,6 @@ test "@splat array" {
10461016
10471017test "@splat array with sentinel" {
10481018 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1049 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10501019 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10511020 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10521021
......@@ -1070,7 +1039,6 @@ test "@splat array with sentinel" {
10701039
10711040test "@splat zero-length array" {
10721041 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1073 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10741042 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10751043 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10761044
test/behavior/asm.zig+2-7
......@@ -7,7 +7,6 @@ const is_x86_64_linux = builtin.cpu.arch == .x86_64 and builtin.os.tag == .linux
77
88comptime {
99 if (builtin.zig_backend != .stage2_arm and
10 builtin.zig_backend != .stage2_aarch64 and
1110 !(builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) and // MSVC doesn't support inline assembly
1211 is_x86_64_linux)
1312 {
......@@ -30,7 +29,6 @@ test "module level assembly" {
3029 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
3130 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
3231 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
33 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3432 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3533
3634 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly
......@@ -41,9 +39,9 @@ test "module level assembly" {
4139}
4240
4341test "output constraint modifiers" {
42 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4443 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
4544 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
46 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4745 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4846 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4947 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -63,9 +61,9 @@ test "output constraint modifiers" {
6361}
6462
6563test "alternative constraints" {
64 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6665 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
6766 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
68 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6967 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7068 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
7169 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -83,7 +81,6 @@ test "alternative constraints" {
8381test "sized integer/float in asm input" {
8482 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
8583 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
86 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8784 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8885 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
8986 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -127,7 +124,6 @@ test "sized integer/float in asm input" {
127124test "struct/array/union types as input values" {
128125 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
129126 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
130 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
131127 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
132128 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
133129
......@@ -167,7 +163,6 @@ test "rw constraint (x86_64)" {
167163
168164test "asm modifiers (AArch64)" {
169165 if (!builtin.target.cpu.arch.isAARCH64()) return error.SkipZigTest;
170 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
171166
172167 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly
173168
test/behavior/atomics.zig+12-13
......@@ -12,7 +12,7 @@ const supports_128_bit_atomics = switch (builtin.cpu.arch) {
1212};
1313
1414test "cmpxchg" {
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1616 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1717 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1818 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -39,7 +39,7 @@ fn testCmpxchg() !void {
3939}
4040
4141test "atomicrmw and atomicload" {
42 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
42 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4343 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4444 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4545 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -68,7 +68,7 @@ fn testAtomicLoad(ptr: *u8) !void {
6868}
6969
7070test "cmpxchg with ptr" {
71 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
71 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7272 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7373 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7474 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -94,7 +94,7 @@ test "cmpxchg with ptr" {
9494}
9595
9696test "cmpxchg with ignored result" {
97 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
97 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9898 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9999 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
100100 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -110,8 +110,8 @@ test "128-bit cmpxchg" {
110110 // TODO: this must appear first
111111 if (!supports_128_bit_atomics) return error.SkipZigTest;
112112
113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
113114 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
114 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
115115 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
116116 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
117117
......@@ -139,7 +139,7 @@ fn test_u128_cmpxchg() !void {
139139var a_global_variable = @as(u32, 1234);
140140
141141test "cmpxchg on a global variable" {
142 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
142 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
143143 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
144144 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
145145 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -149,7 +149,7 @@ test "cmpxchg on a global variable" {
149149}
150150
151151test "atomic load and rmw with enum" {
152 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
152 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
153153 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
154154 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
155155 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -167,7 +167,7 @@ test "atomic load and rmw with enum" {
167167}
168168
169169test "atomic store" {
170 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
170 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
171171 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
172172 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
173173 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -185,7 +185,7 @@ fn testAtomicStore() !void {
185185}
186186
187187test "atomicrmw with floats" {
188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
189189 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
190190 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
191191 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -211,7 +211,7 @@ fn testAtomicRmwFloat() !void {
211211}
212212
213213test "atomicrmw with ints" {
214 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
214 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
215215 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
216216 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
217217 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -290,7 +290,7 @@ test "atomicrmw with 128-bit ints" {
290290 // TODO: this must appear first
291291 if (!supports_128_bit_atomics) return error.SkipZigTest;
292292
293 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
293 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
294294
295295 try testAtomicRmwInt128(.signed);
296296 try testAtomicRmwInt128(.unsigned);
......@@ -359,7 +359,7 @@ fn testAtomicRmwInt128(comptime signedness: std.builtin.Signedness) !void {
359359}
360360
361361test "atomics with different types" {
362 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
362 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
363363 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
364364 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
365365 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -409,7 +409,6 @@ fn testAtomicsWithPackedStruct(comptime T: type, a: T, b: T) !void {
409409}
410410
411411test "return @atomicStore, using it as a void value" {
412 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
413412 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
414413 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
415414 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/basic.zig+1-18
......@@ -39,7 +39,6 @@ test "truncate to non-power-of-two integers" {
3939}
4040
4141test "truncate to non-power-of-two integers from 128-bit" {
42 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4342 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4443 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4544 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -422,7 +421,6 @@ fn copy(src: *const u64, dst: *u64) void {
422421}
423422
424423test "call result of if else expression" {
425 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
426424 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
427425 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
428426 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -448,7 +446,6 @@ fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA {
448446}
449447
450448test "take address of parameter" {
451 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
452449 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
453450 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
454451
......@@ -536,7 +533,6 @@ fn nine() u8 {
536533}
537534
538535test "struct inside function" {
539 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
540536 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
541537
542538 try testStructInFn();
......@@ -588,7 +584,6 @@ test "global variable assignment with optional unwrapping with var initialized t
588584var global_foo: *i32 = undefined;
589585
590586test "peer result location with typed parent, runtime condition, comptime prongs" {
591 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
592587 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
593588
594589 const S = struct {
......@@ -719,7 +714,6 @@ test "global constant is loaded with a runtime-known index" {
719714}
720715
721716test "multiline string literal is null terminated" {
722 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
723717 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
724718
725719 const s1 =
......@@ -732,7 +726,6 @@ test "multiline string literal is null terminated" {
732726}
733727
734728test "string escapes" {
735 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
736729 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
737730 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
738731 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -764,7 +757,6 @@ fn ptrEql(a: *const []const u8, b: *const []const u8) bool {
764757}
765758
766759test "string concatenation" {
767 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
768760 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
769761 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
770762
......@@ -787,7 +779,6 @@ test "string concatenation" {
787779}
788780
789781test "result location is optional inside error union" {
790 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
791782 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
792783 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
793784
......@@ -803,7 +794,6 @@ fn maybe(x: bool) anyerror!?u32 {
803794}
804795
805796test "auto created variables have correct alignment" {
806 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
807797 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
808798 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
809799
......@@ -821,7 +811,6 @@ test "auto created variables have correct alignment" {
821811
822812test "extern variable with non-pointer opaque type" {
823813 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
824 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
825814 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
826815 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
827816 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
......@@ -866,7 +855,6 @@ test "if expression type coercion" {
866855}
867856
868857test "discarding the result of various expressions" {
869 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
870858 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
871859 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
872860
......@@ -908,7 +896,6 @@ test "labeled block implicitly ends in a break" {
908896}
909897
910898test "catch in block has correct result location" {
911 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
912899 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
913900
914901 const S = struct {
......@@ -964,7 +951,6 @@ test "vector initialized with array init syntax has proper type" {
964951}
965952
966953test "weird array and tuple initializations" {
967 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
968954 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
969955 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
970956
......@@ -1010,7 +996,6 @@ test "generic function uses return type of other generic function" {
1010996 // https://github.com/ziglang/zig/issues/12208
1011997 return error.SkipZigTest;
1012998 }
1013 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1014999
10151000 const S = struct {
10161001 fn call(
......@@ -1128,7 +1113,6 @@ test "returning an opaque type from a function" {
11281113}
11291114
11301115test "orelse coercion as function argument" {
1131 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11321116 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11331117
11341118 const Loc = struct { start: i32 = -1 };
......@@ -1378,7 +1362,6 @@ test "copy array of self-referential struct" {
13781362
13791363test "break out of block based on comptime known values" {
13801364 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1381 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13821365 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13831366
13841367 const S = struct {
......@@ -1412,8 +1395,8 @@ test "break out of block based on comptime known values" {
14121395}
14131396
14141397test "allocation and looping over 3-byte integer" {
1398 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14151399 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1416 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14171400 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14181401 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14191402 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/bit_shifting.zig+2-1
......@@ -112,7 +112,7 @@ test "comptime shift safety check" {
112112}
113113
114114test "Saturating Shift Left where lhs is of a computed type" {
115 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
115 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
116116 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
117117 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
118118 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -161,6 +161,7 @@ comptime {
161161}
162162
163163test "Saturating Shift Left" {
164 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
164165 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
165166 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
166167 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/bitcast.zig+9-12
......@@ -20,7 +20,6 @@ test "@bitCast iX -> uX (32, 64)" {
2020}
2121
2222test "@bitCast iX -> uX (8, 16, 128)" {
23 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2423 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2524 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2625 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -35,8 +34,8 @@ test "@bitCast iX -> uX (8, 16, 128)" {
3534}
3635
3736test "@bitCast iX -> uX exotic integers" {
38 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
3937 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
38 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
4039 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
4140 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4241 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -80,8 +79,8 @@ fn conv_uN(comptime N: usize, x: std.meta.Int(.unsigned, N)) std.meta.Int(.signe
8079}
8180
8281test "bitcast uX to bytes" {
83 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
8482 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
83 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
8584 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
8685 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8786 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -296,9 +295,9 @@ test "triple level result location with bitcast sandwich passed as tuple element
296295}
297296
298297test "@bitCast packed struct of floats" {
298 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
299299 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
300300 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
301 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
302301 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
303302 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
304303 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -334,9 +333,9 @@ test "@bitCast packed struct of floats" {
334333}
335334
336335test "comptime @bitCast packed struct to int and back" {
336 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
337337 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
338338 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
339 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
340339 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
341340 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
342341 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -379,7 +378,6 @@ test "comptime bitcast with fields following f80" {
379378 }
380379
381380 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
382 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
383381 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
384382 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
385383
......@@ -393,7 +391,7 @@ test "comptime bitcast with fields following f80" {
393391}
394392
395393test "bitcast vector to integer and back" {
396 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
394 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
397395 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
398396 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
399397 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
......@@ -420,7 +418,6 @@ fn bitCastWrapper128(x: f128) u128 {
420418 return @as(u128, @bitCast(x));
421419}
422420test "bitcast nan float does not modify signaling bit" {
423 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
424421 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
425422 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
426423 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -473,7 +470,7 @@ test "bitcast nan float does not modify signaling bit" {
473470}
474471
475472test "@bitCast of packed struct of bools all true" {
476 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
473 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
477474 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
478475 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
479476 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -494,7 +491,7 @@ test "@bitCast of packed struct of bools all true" {
494491}
495492
496493test "@bitCast of packed struct of bools all false" {
497 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
494 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
498495 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
499496 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
500497 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -514,7 +511,7 @@ test "@bitCast of packed struct of bools all false" {
514511}
515512
516513test "@bitCast of packed struct containing pointer" {
517 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
514 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
518515 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
519516 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
520517 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
......@@ -544,7 +541,7 @@ test "@bitCast of packed struct containing pointer" {
544541}
545542
546543test "@bitCast of extern struct containing pointer" {
547 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
544 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
548545 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
549546 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
550547 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
test/behavior/bitreverse.zig+4-4
......@@ -8,8 +8,8 @@ test "@bitReverse large exotic integer" {
88}
99
1010test "@bitReverse" {
11 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1211 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1313 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1414 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1515 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -121,9 +121,9 @@ fn vector8() !void {
121121}
122122
123123test "bitReverse vectors u8" {
124 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
124125 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
125126 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
126 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
127127 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
128128 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
129129 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -141,9 +141,9 @@ fn vector16() !void {
141141}
142142
143143test "bitReverse vectors u16" {
144 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
144145 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
145146 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
146 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
147147 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
148148 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
149149 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -161,9 +161,9 @@ fn vector24() !void {
161161}
162162
163163test "bitReverse vectors u24" {
164 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
164165 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
165166 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
166 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
167167 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
168168 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
169169 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/builtin_functions_returning_void_or_noreturn.zig-1
......@@ -7,7 +7,6 @@ var x: u8 = 1;
77// This excludes builtin functions that return void or noreturn that cannot be tested.
88test {
99 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1211 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1312 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/byteswap.zig+32-43
......@@ -3,40 +3,8 @@ const builtin = @import("builtin");
33const expect = std.testing.expect;
44
55test "@byteSwap integers" {
6 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
7
8 if (builtin.zig_backend == .stage2_wasm) {
9 // TODO: Remove when self-hosted wasm supports more types for byteswap
10 const ByteSwapIntTest = struct {
11 fn run() !void {
12 try t(u8, 0x12, 0x12);
13 try t(u16, 0x1234, 0x3412);
14 try t(u24, 0x123456, 0x563412);
15 try t(i24, @as(i24, @bitCast(@as(u24, 0xf23456))), 0x5634f2);
16 try t(i24, 0x1234f6, @as(i24, @bitCast(@as(u24, 0xf63412))));
17 try t(u32, 0x12345678, 0x78563412);
18 try t(i32, @as(i32, @bitCast(@as(u32, 0xf2345678))), 0x785634f2);
19 try t(i32, 0x123456f8, @as(i32, @bitCast(@as(u32, 0xf8563412))));
20 try t(u64, 0x123456789abcdef1, 0xf1debc9a78563412);
21
22 try t(u0, @as(u0, 0), 0);
23 try t(i8, @as(i8, -50), -50);
24 try t(i16, @as(i16, @bitCast(@as(u16, 0x1234))), @as(i16, @bitCast(@as(u16, 0x3412))));
25 try t(i24, @as(i24, @bitCast(@as(u24, 0x123456))), @as(i24, @bitCast(@as(u24, 0x563412))));
26 try t(i32, @as(i32, @bitCast(@as(u32, 0x12345678))), @as(i32, @bitCast(@as(u32, 0x78563412))));
27 try t(i64, @as(i64, @bitCast(@as(u64, 0x123456789abcdef1))), @as(i64, @bitCast(@as(u64, 0xf1debc9a78563412))));
28 }
29 fn t(comptime I: type, input: I, expected_output: I) !void {
30 try std.testing.expect(expected_output == @byteSwap(input));
31 }
32 };
33 try comptime ByteSwapIntTest.run();
34 try ByteSwapIntTest.run();
35 return;
36 }
37
386 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
39 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
408 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
419 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4210
......@@ -51,23 +19,44 @@ test "@byteSwap integers" {
5119 try t(u32, 0x12345678, 0x78563412);
5220 try t(i32, @as(i32, @bitCast(@as(u32, 0xf2345678))), 0x785634f2);
5321 try t(i32, 0x123456f8, @as(i32, @bitCast(@as(u32, 0xf8563412))));
54 try t(u40, 0x123456789a, 0x9a78563412);
55 try t(i48, 0x123456789abc, @as(i48, @bitCast(@as(u48, 0xbc9a78563412))));
56 try t(u56, 0x123456789abcde, 0xdebc9a78563412);
5722 try t(u64, 0x123456789abcdef1, 0xf1debc9a78563412);
58 try t(u88, 0x123456789abcdef1112131, 0x312111f1debc9a78563412);
59 try t(u96, 0x123456789abcdef111213141, 0x41312111f1debc9a78563412);
60 try t(u128, 0x123456789abcdef11121314151617181, 0x8171615141312111f1debc9a78563412);
6123
6224 try t(u0, @as(u0, 0), 0);
6325 try t(i8, @as(i8, -50), -50);
6426 try t(i16, @as(i16, @bitCast(@as(u16, 0x1234))), @as(i16, @bitCast(@as(u16, 0x3412))));
6527 try t(i24, @as(i24, @bitCast(@as(u24, 0x123456))), @as(i24, @bitCast(@as(u24, 0x563412))));
6628 try t(i32, @as(i32, @bitCast(@as(u32, 0x12345678))), @as(i32, @bitCast(@as(u32, 0x78563412))));
29 try t(i64, @as(i64, @bitCast(@as(u64, 0x123456789abcdef1))), @as(i64, @bitCast(@as(u64, 0xf1debc9a78563412))));
30 }
31 fn t(comptime I: type, input: I, expected_output: I) !void {
32 try std.testing.expect(expected_output == @byteSwap(input));
33 }
34 };
35 try comptime ByteSwapIntTest.run();
36 try ByteSwapIntTest.run();
37}
38
39test "@byteSwap exotic integers" {
40 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
41 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
42 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
43 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
44 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
45 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
46
47 const ByteSwapIntTest = struct {
48 fn run() !void {
49 try t(u0, 0, 0);
50 try t(u40, 0x123456789a, 0x9a78563412);
51 try t(i48, 0x123456789abc, @as(i48, @bitCast(@as(u48, 0xbc9a78563412))));
52 try t(u56, 0x123456789abcde, 0xdebc9a78563412);
53 try t(u88, 0x123456789abcdef1112131, 0x312111f1debc9a78563412);
54 try t(u96, 0x123456789abcdef111213141, 0x41312111f1debc9a78563412);
55 try t(u128, 0x123456789abcdef11121314151617181, 0x8171615141312111f1debc9a78563412);
56
6757 try t(u40, @as(i40, @bitCast(@as(u40, 0x123456789a))), @as(u40, 0x9a78563412));
6858 try t(i48, @as(i48, @bitCast(@as(u48, 0x123456789abc))), @as(i48, @bitCast(@as(u48, 0xbc9a78563412))));
6959 try t(i56, @as(i56, @bitCast(@as(u56, 0x123456789abcde))), @as(i56, @bitCast(@as(u56, 0xdebc9a78563412))));
70 try t(i64, @as(i64, @bitCast(@as(u64, 0x123456789abcdef1))), @as(i64, @bitCast(@as(u64, 0xf1debc9a78563412))));
7160 try t(i88, @as(i88, @bitCast(@as(u88, 0x123456789abcdef1112131))), @as(i88, @bitCast(@as(u88, 0x312111f1debc9a78563412))));
7261 try t(i96, @as(i96, @bitCast(@as(u96, 0x123456789abcdef111213141))), @as(i96, @bitCast(@as(u96, 0x41312111f1debc9a78563412))));
7362 try t(
......@@ -93,9 +82,9 @@ fn vector8() !void {
9382}
9483
9584test "@byteSwap vectors u8" {
85 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9686 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
9787 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
98 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9988 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10089 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10190 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -113,9 +102,9 @@ fn vector16() !void {
113102}
114103
115104test "@byteSwap vectors u16" {
105 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
116106 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
117107 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
118 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
119108 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
120109 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
121110 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -133,9 +122,9 @@ fn vector24() !void {
133122}
134123
135124test "@byteSwap vectors u24" {
125 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
136126 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
137127 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
138 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
139128 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
140129 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
141130 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/call.zig+6-13
......@@ -20,8 +20,8 @@ test "super basic invocations" {
2020}
2121
2222test "basic invocations" {
23 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2324 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
24 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2525 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2626 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2727 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -60,7 +60,6 @@ test "basic invocations" {
6060}
6161
6262test "tuple parameters" {
63 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6463 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
6564 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6665 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -95,7 +94,6 @@ test "tuple parameters" {
9594
9695test "result location of function call argument through runtime condition and struct init" {
9796 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9997 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10098
10199 const E = enum { a, b };
......@@ -115,6 +113,7 @@ test "result location of function call argument through runtime condition and st
115113}
116114
117115test "function call with 40 arguments" {
116 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
118117 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
119118 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
120119
......@@ -270,7 +269,7 @@ test "arguments to comptime parameters generated in comptime blocks" {
270269}
271270
272271test "forced tail call" {
273 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
272 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
274273 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
275274 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
276275 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -305,7 +304,7 @@ test "forced tail call" {
305304}
306305
307306test "inline call preserves tail call" {
308 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
307 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
309308 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
310309 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
311310 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -342,7 +341,6 @@ test "inline call preserves tail call" {
342341}
343342
344343test "inline call doesn't re-evaluate non generic struct" {
345 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
346344 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
347345 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
348346
......@@ -409,7 +407,6 @@ test "recursive inline call with comptime known argument" {
409407}
410408
411409test "inline while with @call" {
412 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
413410 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
414411
415412 const S = struct {
......@@ -439,7 +436,6 @@ test "method call as parameter type" {
439436}
440437
441438test "non-anytype generic parameters provide result type" {
442 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
443439 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
444440 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
445441
......@@ -468,7 +464,6 @@ test "non-anytype generic parameters provide result type" {
468464}
469465
470466test "argument to generic function has correct result type" {
471 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
472467 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
473468 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
474469
......@@ -521,7 +516,6 @@ test "call function in comptime field" {
521516
522517test "call function pointer in comptime field" {
523518 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
524 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
525519 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
526520 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
527521
......@@ -573,7 +567,6 @@ test "value returned from comptime function is comptime known" {
573567}
574568
575569test "registers get overwritten when ignoring return" {
576 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
577570 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
578571 if (builtin.cpu.arch != .x86_64 or builtin.os.tag != .linux) return error.SkipZigTest;
579572
......@@ -619,7 +612,6 @@ test "call with union with zero sized field is not memorized incorrectly" {
619612}
620613
621614test "function call with cast to anyopaque pointer" {
622 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
623615 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
624616 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
625617 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -637,6 +629,7 @@ test "function call with cast to anyopaque pointer" {
637629}
638630
639631test "arguments pointed to on stack into tailcall" {
632 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
640633 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
641634 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
642635 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -708,7 +701,7 @@ test "arguments pointed to on stack into tailcall" {
708701}
709702
710703test "tail call function pointer" {
711 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
704 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
712705 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
713706 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
714707 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
test/behavior/cast.zig+19-100
......@@ -21,7 +21,6 @@ test "integer literal to pointer cast" {
2121}
2222
2323test "peer type resolution: ?T and T" {
24 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2524 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2625 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2726
......@@ -100,7 +99,6 @@ test "comptime_int @floatFromInt" {
10099}
101100
102101test "@floatFromInt" {
103 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
104102 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
105103 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
106104 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -121,7 +119,6 @@ test "@floatFromInt" {
121119}
122120
123121test "@floatFromInt(f80)" {
124 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
125122 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
126123 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
127124 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -157,7 +154,6 @@ test "@floatFromInt(f80)" {
157154}
158155
159156test "@intFromFloat" {
160 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
161157 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
162158 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
163159 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -181,7 +177,6 @@ fn expectIntFromFloat(comptime F: type, f: F, comptime I: type, i: I) !void {
181177}
182178
183179test "implicitly cast indirect pointer to maybe-indirect pointer" {
184 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
185180 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
186181 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
187182
......@@ -241,7 +236,6 @@ test "@floatCast comptime_int and comptime_float" {
241236}
242237
243238test "coerce undefined to optional" {
244 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
245239 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
246240 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
247241
......@@ -262,7 +256,6 @@ fn MakeType(comptime T: type) type {
262256}
263257
264258test "implicit cast from *[N]T to [*c]T" {
265 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
266259 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
267260 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
268261
......@@ -299,7 +292,6 @@ test "@intCast to u0 and use the result" {
299292}
300293
301294test "peer result null and comptime_int" {
302 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
303295 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
304296 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
305297
......@@ -324,7 +316,6 @@ test "peer result null and comptime_int" {
324316}
325317
326318test "*const ?[*]const T to [*c]const [*c]const T" {
327 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
328319 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
329320 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
330321 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -338,7 +329,6 @@ test "*const ?[*]const T to [*c]const [*c]const T" {
338329}
339330
340331test "array coercion to undefined at runtime" {
341 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
342332 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
343333 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
344334
......@@ -368,7 +358,6 @@ fn implicitIntLitToOptional() void {
368358}
369359
370360test "return u8 coercing into ?u32 return type" {
371 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
372361 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
373362 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
374363
......@@ -390,7 +379,6 @@ test "cast from ?[*]T to ??[*]T" {
390379}
391380
392381test "peer type unsigned int to signed" {
393 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
394382 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
395383
396384 var w: u31 = 5;
......@@ -403,7 +391,6 @@ test "peer type unsigned int to signed" {
403391}
404392
405393test "expected [*c]const u8, found [*:0]const u8" {
406 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
407394 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
408395 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
409396
......@@ -415,7 +402,6 @@ test "expected [*c]const u8, found [*:0]const u8" {
415402}
416403
417404test "explicit cast from integer to error type" {
418 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
419405 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
420406 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
421407 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -431,7 +417,6 @@ fn testCastIntToErr(err: anyerror) !void {
431417}
432418
433419test "peer resolve array and const slice" {
434 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
435420 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
436421 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
437422 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -447,7 +432,6 @@ fn testPeerResolveArrayConstSlice(b: bool) !void {
447432}
448433
449434test "implicitly cast from T to anyerror!?T" {
450 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
451435 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
452436 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
453437
......@@ -473,7 +457,6 @@ fn castToOptionalTypeError(z: i32) !void {
473457}
474458
475459test "implicitly cast from [0]T to anyerror![]T" {
476 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
477460 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
478461
479462 try testCastZeroArrayToErrSliceMut();
......@@ -489,7 +472,6 @@ fn gimmeErrOrSlice() anyerror![]u8 {
489472}
490473
491474test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" {
492 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
493475 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
494476 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
495477 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -522,7 +504,6 @@ fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 {
522504}
523505
524506test "implicit cast from *const [N]T to []const T" {
525 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
526507 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
527508 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
528509
......@@ -548,7 +529,6 @@ fn testCastConstArrayRefToConstSlice() !void {
548529}
549530
550531test "peer type resolution: error and [N]T" {
551 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
552532 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
553533 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
554534
......@@ -573,7 +553,6 @@ fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 {
573553}
574554
575555test "single-item pointer of array to slice to unknown length pointer" {
576 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
577556 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
578557 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
579558
......@@ -603,7 +582,6 @@ fn testCastPtrOfArrayToSliceAndPtr() !void {
603582}
604583
605584test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
606 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
607585 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
608586 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
609587
......@@ -613,8 +591,8 @@ test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
613591}
614592
615593test "@intCast on vector" {
594 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
616595 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
617 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
618596 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
619597 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
620598 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -651,7 +629,6 @@ test "@intCast on vector" {
651629}
652630
653631test "@floatCast cast down" {
654 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
655632 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
656633 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
657634 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -670,7 +647,6 @@ test "@floatCast cast down" {
670647}
671648
672649test "peer type resolution: unreachable, error set, unreachable" {
673 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
674650 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
675651
676652 const Error = error{
......@@ -704,7 +680,6 @@ test "peer cast: error set any anyerror" {
704680}
705681
706682test "peer type resolution: error set supersets" {
707 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
708683 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
709684 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
710685 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -735,7 +710,6 @@ test "peer type resolution: error set supersets" {
735710
736711test "peer type resolution: disjoint error sets" {
737712 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
738 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
739713 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
740714 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
741715
......@@ -765,7 +739,6 @@ test "peer type resolution: disjoint error sets" {
765739
766740test "peer type resolution: error union and error set" {
767741 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
768 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
769742 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
770743 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
771744
......@@ -799,7 +772,6 @@ test "peer type resolution: error union and error set" {
799772
800773test "peer type resolution: error union after non-error" {
801774 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
802 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
803775 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
804776 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
805777
......@@ -833,7 +805,6 @@ test "peer type resolution: error union after non-error" {
833805
834806test "peer cast *[0]T to E![]const T" {
835807 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
836 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
837808 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
838809 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
839810
......@@ -849,7 +820,6 @@ test "peer cast *[0]T to E![]const T" {
849820
850821test "peer cast *[0]T to []const T" {
851822 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
852 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
853823 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
854824 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
855825
......@@ -872,7 +842,6 @@ test "peer cast *[N]T to [*]T" {
872842}
873843
874844test "peer resolution of string literals" {
875 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
876845 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
877846 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
878847 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -895,7 +864,6 @@ test "peer resolution of string literals" {
895864}
896865
897866test "peer cast [:x]T to []T" {
898 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
899867 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
900868 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
901869
......@@ -912,7 +880,6 @@ test "peer cast [:x]T to []T" {
912880}
913881
914882test "peer cast [N:x]T to [N]T" {
915 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
916883 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
917884 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
918885
......@@ -929,7 +896,6 @@ test "peer cast [N:x]T to [N]T" {
929896}
930897
931898test "peer cast *[N:x]T to *[N]T" {
932 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
933899 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
934900 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
935901
......@@ -945,7 +911,6 @@ test "peer cast *[N:x]T to *[N]T" {
945911}
946912
947913test "peer cast [*:x]T to [*]T" {
948 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
949914 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
950915 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
951916 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -966,7 +931,6 @@ test "peer cast [*:x]T to [*]T" {
966931}
967932
968933test "peer cast [:x]T to [*:x]T" {
969 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
970934 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
971935 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
972936 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -988,7 +952,6 @@ test "peer cast [:x]T to [*:x]T" {
988952}
989953
990954test "peer type resolution implicit cast to return type" {
991 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
992955 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
993956 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
994957
......@@ -1009,7 +972,6 @@ test "peer type resolution implicit cast to return type" {
1009972}
1010973
1011974test "peer type resolution implicit cast to variable type" {
1012 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1013975 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1014976 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1015977
......@@ -1035,7 +997,6 @@ test "variable initialization uses result locations properly with regards to the
1035997}
1036998
1037999test "cast between C pointer with different but compatible types" {
1038 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10391000 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10401001 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10411002
......@@ -1053,7 +1014,6 @@ test "cast between C pointer with different but compatible types" {
10531014}
10541015
10551016test "peer type resolve string lit with sentinel-terminated mutable slice" {
1056 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10571017 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10581018 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10591019
......@@ -1104,7 +1064,6 @@ test "comptime float casts" {
11041064}
11051065
11061066test "pointer reinterpret const float to int" {
1107 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11081067 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11091068
11101069 // The hex representation is 0x3fe3333333333303.
......@@ -1119,7 +1078,6 @@ test "pointer reinterpret const float to int" {
11191078}
11201079
11211080test "implicit cast from [*]T to ?*anyopaque" {
1122 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11231081 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11241082 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11251083 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1184,7 +1142,6 @@ test "cast function with an opaque parameter" {
11841142}
11851143
11861144test "implicit ptr to *anyopaque" {
1187 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11881145 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11891146 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11901147 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1199,7 +1156,6 @@ test "implicit ptr to *anyopaque" {
11991156}
12001157
12011158test "return null from fn () anyerror!?&T" {
1202 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12031159 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12041160 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
12051161
......@@ -1216,7 +1172,6 @@ fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A {
12161172}
12171173
12181174test "peer type resolution: [0]u8 and []const u8" {
1219 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12201175 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12211176 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12221177 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1237,7 +1192,6 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {
12371192}
12381193
12391194test "implicitly cast from [N]T to ?[]const T" {
1240 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12411195 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12421196 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12431197 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1251,7 +1205,6 @@ fn castToOptionalSlice() ?[]const u8 {
12511205}
12521206
12531207test "cast u128 to f128 and back" {
1254 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12551208 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12561209 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12571210 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1274,7 +1227,6 @@ fn cast128Float(x: u128) f128 {
12741227}
12751228
12761229test "implicit cast from *[N]T to ?[*]T" {
1277 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12781230 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12791231 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12801232 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1291,7 +1243,6 @@ test "implicit cast from *[N]T to ?[*]T" {
12911243}
12921244
12931245test "implicit cast from *T to ?*anyopaque" {
1294 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12951246 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12961247 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12971248 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1306,7 +1257,6 @@ fn incrementVoidPtrValue(value: ?*anyopaque) void {
13061257}
13071258
13081259test "implicit cast *[0]T to E![]const u8" {
1309 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13101260 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13111261
13121262 var x = @as(anyerror![]const u8, &[0]u8{});
......@@ -1330,7 +1280,6 @@ test "cast from array reference to fn: runtime fn ptr" {
13301280}
13311281
13321282test "*const [N]null u8 to ?[]const u8" {
1333 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13341283 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13351284 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13361285 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1367,7 +1316,6 @@ test "cast between [*c]T and ?[*:0]T on fn parameter" {
13671316
13681317var global_struct: struct { f0: usize } = undefined;
13691318test "assignment to optional pointer result loc" {
1370 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13711319 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13721320 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13731321 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1386,7 +1334,6 @@ test "cast between *[N]void and []void" {
13861334}
13871335
13881336test "peer resolve arrays of different size to const slice" {
1389 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13901337 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13911338 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
13921339
......@@ -1400,7 +1347,6 @@ fn boolToStr(b: bool) []const u8 {
14001347}
14011348
14021349test "cast f16 to wider types" {
1403 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14041350 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14051351 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14061352 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1421,7 +1367,6 @@ test "cast f16 to wider types" {
14211367}
14221368
14231369test "cast f128 to narrower types" {
1424 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14251370 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14261371 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14271372 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1441,7 +1386,6 @@ test "cast f128 to narrower types" {
14411386}
14421387
14431388test "peer type resolution: unreachable, null, slice" {
1444 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14451389 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14461390 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14471391 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1460,7 +1404,6 @@ test "peer type resolution: unreachable, null, slice" {
14601404}
14611405
14621406test "cast i8 fn call peers to i32 result" {
1463 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14641407 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14651408
14661409 const S = struct {
......@@ -1482,7 +1425,6 @@ test "cast i8 fn call peers to i32 result" {
14821425}
14831426
14841427test "cast compatible optional types" {
1485 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14861428 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14871429 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14881430 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1494,7 +1436,6 @@ test "cast compatible optional types" {
14941436}
14951437
14961438test "coerce undefined single-item pointer of array to error union of slice" {
1497 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14981439 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14991440
15001441 const a = @as([*]u8, undefined)[0..0];
......@@ -1513,7 +1454,6 @@ test "pointer to empty struct literal to mutable slice" {
15131454}
15141455
15151456test "coerce between pointers of compatible differently-named floats" {
1516 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15171457 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15181458 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows and !builtin.link_libc) return error.SkipZigTest;
15191459 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1548,7 +1488,6 @@ test "peer type resolution of const and non-const pointer to array" {
15481488}
15491489
15501490test "intFromFloat to zero-bit int" {
1551 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15521491 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15531492 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15541493
......@@ -1573,8 +1512,6 @@ test "cast typed undefined to int" {
15731512}
15741513
15751514// test "implicit cast from [:0]T to [*c]T" {
1576// if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1577
15781515// var a: [:0]const u8 = "foo";
15791516// _ = &a;
15801517// const b: [*c]const u8 = a;
......@@ -1584,7 +1521,6 @@ test "cast typed undefined to int" {
15841521// }
15851522
15861523test "bitcast packed struct with u0" {
1587 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15881524 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
15891525
15901526 const S = packed struct(u2) { a: u0, b: u2 };
......@@ -1691,7 +1627,6 @@ test "coercion from single-item pointer to @as to slice" {
16911627}
16921628
16931629test "peer type resolution: const sentinel slice and mutable non-sentinel slice" {
1694 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16951630 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
16961631 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16971632 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1721,7 +1656,6 @@ test "peer type resolution: const sentinel slice and mutable non-sentinel slice"
17211656}
17221657
17231658test "peer type resolution: float and comptime-known fixed-width integer" {
1724 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17251659 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17261660 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17271661
......@@ -1743,7 +1677,7 @@ test "peer type resolution: float and comptime-known fixed-width integer" {
17431677}
17441678
17451679test "peer type resolution: same array type with sentinel" {
1746 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1680 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
17471681 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17481682 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17491683 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1766,7 +1700,6 @@ test "peer type resolution: same array type with sentinel" {
17661700}
17671701
17681702test "peer type resolution: array with sentinel and array without sentinel" {
1769 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17701703 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17711704 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17721705 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1789,7 +1722,7 @@ test "peer type resolution: array with sentinel and array without sentinel" {
17891722}
17901723
17911724test "peer type resolution: array and vector with same child type" {
1792 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1725 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
17931726 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17941727 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17951728 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1813,7 +1746,7 @@ test "peer type resolution: array and vector with same child type" {
18131746}
18141747
18151748test "peer type resolution: array with smaller child type and vector with larger child type" {
1816 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1749 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
18171750 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18181751 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
18191752 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1837,7 +1770,7 @@ test "peer type resolution: array with smaller child type and vector with larger
18371770}
18381771
18391772test "peer type resolution: error union and optional of same type" {
1840 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1773 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
18411774 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18421775 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
18431776 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1861,7 +1794,6 @@ test "peer type resolution: error union and optional of same type" {
18611794}
18621795
18631796test "peer type resolution: C pointer and @TypeOf(null)" {
1864 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
18651797 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18661798 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
18671799 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1884,7 +1816,7 @@ test "peer type resolution: C pointer and @TypeOf(null)" {
18841816}
18851817
18861818test "peer type resolution: three-way resolution combines error set and optional" {
1887 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1819 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
18881820 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18891821 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
18901822 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1927,7 +1859,7 @@ test "peer type resolution: three-way resolution combines error set and optional
19271859}
19281860
19291861test "peer type resolution: vector and optional vector" {
1930 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1862 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
19311863 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19321864 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
19331865 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1952,7 +1884,6 @@ test "peer type resolution: vector and optional vector" {
19521884}
19531885
19541886test "peer type resolution: optional fixed-width int and comptime_int" {
1955 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
19561887 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19571888 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
19581889
......@@ -1974,7 +1905,7 @@ test "peer type resolution: optional fixed-width int and comptime_int" {
19741905}
19751906
19761907test "peer type resolution: array and tuple" {
1977 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1908 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
19781909 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19791910 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
19801911 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1998,7 +1929,7 @@ test "peer type resolution: array and tuple" {
19981929}
19991930
20001931test "peer type resolution: vector and tuple" {
2001 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1932 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
20021933 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
20031934 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
20041935 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -2022,7 +1953,7 @@ test "peer type resolution: vector and tuple" {
20221953}
20231954
20241955test "peer type resolution: vector and array and tuple" {
2025 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1956 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
20261957 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
20271958 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
20281959 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -2066,7 +1997,6 @@ test "peer type resolution: vector and array and tuple" {
20661997}
20671998
20681999test "peer type resolution: empty tuple pointer and slice" {
2069 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
20702000 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
20712001 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
20722002 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -2088,7 +2018,6 @@ test "peer type resolution: empty tuple pointer and slice" {
20882018}
20892019
20902020test "peer type resolution: tuple pointer and slice" {
2091 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
20922021 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
20932022 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
20942023 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -2110,7 +2039,6 @@ test "peer type resolution: tuple pointer and slice" {
21102039}
21112040
21122041test "peer type resolution: tuple pointer and optional slice" {
2113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
21142042 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
21152043 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
21162044 // Miscompilation on Intel's OpenCL CPU runtime.
......@@ -2133,7 +2061,6 @@ test "peer type resolution: tuple pointer and optional slice" {
21332061}
21342062
21352063test "peer type resolution: many compatible pointers" {
2136 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
21372064 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
21382065 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
21392066 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -2200,7 +2127,6 @@ test "peer type resolution: many compatible pointers" {
22002127}
22012128
22022129test "peer type resolution: tuples with comptime fields" {
2203 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
22042130 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
22052131 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
22062132 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -2232,7 +2158,6 @@ test "peer type resolution: tuples with comptime fields" {
22322158}
22332159
22342160test "peer type resolution: C pointer and many pointer" {
2235 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
22362161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
22372162 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
22382163 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -2256,7 +2181,6 @@ test "peer type resolution: C pointer and many pointer" {
22562181}
22572182
22582183test "peer type resolution: pointer attributes are combined correctly" {
2259 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
22602184 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
22612185 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
22622186 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -2338,7 +2262,7 @@ test "peer type resolution: pointer attributes are combined correctly" {
23382262}
23392263
23402264test "peer type resolution: arrays of compatible types" {
2341 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2265 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
23422266 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
23432267 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
23442268 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -2356,7 +2280,6 @@ test "peer type resolution: arrays of compatible types" {
23562280}
23572281
23582282test "cast builtins can wrap result in optional" {
2359 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
23602283 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
23612284 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
23622285 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -2394,7 +2317,6 @@ test "cast builtins can wrap result in optional" {
23942317}
23952318
23962319test "cast builtins can wrap result in error union" {
2397 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
23982320 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
23992321 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
24002322
......@@ -2432,7 +2354,6 @@ test "cast builtins can wrap result in error union" {
24322354}
24332355
24342356test "cast builtins can wrap result in error union and optional" {
2435 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
24362357 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
24372358 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
24382359 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -2471,8 +2392,8 @@ test "cast builtins can wrap result in error union and optional" {
24712392}
24722393
24732394test "@floatCast on vector" {
2395 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
24742396 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2475 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
24762397 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
24772398 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
24782399 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -2512,8 +2433,8 @@ test "@floatCast on vector" {
25122433}
25132434
25142435test "@ptrFromInt on vector" {
2436 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
25152437 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2516 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
25172438 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
25182439 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
25192440 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -2537,8 +2458,8 @@ test "@ptrFromInt on vector" {
25372458}
25382459
25392460test "@intFromPtr on vector" {
2461 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
25402462 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2541 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
25422463 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
25432464 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
25442465 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -2562,8 +2483,8 @@ test "@intFromPtr on vector" {
25622483}
25632484
25642485test "@floatFromInt on vector" {
2486 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
25652487 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2566 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
25672488 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
25682489 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
25692490 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -2582,8 +2503,8 @@ test "@floatFromInt on vector" {
25822503}
25832504
25842505test "@intFromFloat on vector" {
2506 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
25852507 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2586 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
25872508 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
25882509 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
25892510 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -2602,8 +2523,8 @@ test "@intFromFloat on vector" {
26022523}
26032524
26042525test "@intFromBool on vector" {
2526 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
26052527 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2606 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
26072528 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
26082529 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
26092530 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -2639,7 +2560,6 @@ test "15-bit int to float" {
26392560}
26402561
26412562test "@as does not corrupt values with incompatible representations" {
2642 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
26432563 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
26442564 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
26452565
......@@ -2654,7 +2574,6 @@ test "@as does not corrupt values with incompatible representations" {
26542574}
26552575
26562576test "result information is preserved through many nested structures" {
2657 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
26582577 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
26592578 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
26602579 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -2679,7 +2598,7 @@ test "result information is preserved through many nested structures" {
26792598}
26802599
26812600test "@intCast vector of signed integer" {
2682 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2601 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
26832602 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
26842603 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
26852604 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -2703,7 +2622,6 @@ test "result type is preserved into comptime block" {
27032622}
27042623
27052624test "bitcast vector" {
2706 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
27072625 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
27082626
27092627 const u8x32 = @Vector(32, u8);
......@@ -2766,6 +2684,7 @@ test "@intFromFloat boundary cases" {
27662684}
27672685
27682686test "@intFromFloat vector boundary cases" {
2687 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
27692688 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
27702689 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
27712690 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
test/behavior/cast_int.zig+4-3
......@@ -5,7 +5,6 @@ const expectEqual = std.testing.expectEqual;
55const maxInt = std.math.maxInt;
66
77test "@intCast i32 to u7" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -19,7 +18,6 @@ test "@intCast i32 to u7" {
1918}
2019
2120test "coerce i8 to i32 and @intCast back" {
22 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2321 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2422 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2523
......@@ -36,6 +34,7 @@ test "coerce i8 to i32 and @intCast back" {
3634
3735test "coerce non byte-sized integers accross 32bits boundary" {
3836 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
37
3938 {
4039 var v: u21 = 6417;
4140 _ = &v;
......@@ -164,8 +163,9 @@ const Piece = packed struct {
164163 }
165164};
166165
166// Originally reported at https://github.com/ziglang/zig/issues/14200
167167test "load non byte-sized optional value" {
168 // Originally reported at https://github.com/ziglang/zig/issues/14200
168 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
169169 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
170170 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
171171
......@@ -181,6 +181,7 @@ test "load non byte-sized optional value" {
181181}
182182
183183test "load non byte-sized value in struct" {
184 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
184185 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
185186 if (builtin.cpu.arch.endian() != .little) return error.SkipZigTest; // packed struct TODO
186187 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
test/behavior/comptime_memory.zig-2
......@@ -66,7 +66,6 @@ fn bigToNativeEndian(comptime T: type, v: T) T {
6666 return if (endian == .big) v else @byteSwap(v);
6767}
6868test "type pun endianness" {
69 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7069 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7170
7271 comptime {
......@@ -360,7 +359,6 @@ test "offset field ptr by enclosing array element size" {
360359}
361360
362361test "accessing reinterpreted memory of parent object" {
363 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
364362 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
365363
366364 const S = extern struct {
test/behavior/const_slice_child.zig-1
......@@ -7,7 +7,6 @@ const expect = testing.expect;
77var argv: [*]const [*]const u8 = undefined;
88
99test "const slice child" {
10 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1211 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1312 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/decl_literals.zig+2-1
......@@ -33,9 +33,9 @@ test "decl literal with pointer" {
3333}
3434
3535test "call decl literal with optional" {
36 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3637 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
3738 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
38 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3939 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4040
4141 const S = struct {
......@@ -74,6 +74,7 @@ test "call decl literal" {
7474}
7575
7676test "call decl literal with error union" {
77 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7778 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
7879
7980 const S = struct {
test/behavior/defer.zig+2-6
......@@ -32,7 +32,6 @@ test "defer and labeled break" {
3232}
3333
3434test "errdefer does not apply to fn inside fn" {
35 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3635 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3736
3837 if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| try expect(e == error.Bad);
......@@ -51,7 +50,6 @@ fn testNestedFnErrDefer() anyerror!void {
5150
5251test "return variable while defer expression in scope to modify it" {
5352 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
54 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5553 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5654
5755 const S = struct {
......@@ -91,7 +89,6 @@ fn runSomeErrorDefers(x: bool) !bool {
9189}
9290
9391test "mixing normal and error defers" {
94 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9592 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9693 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9794
......@@ -110,7 +107,7 @@ test "mixing normal and error defers" {
110107}
111108
112109test "errdefer with payload" {
113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
110 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
114111 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
115112 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
116113 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -132,8 +129,8 @@ test "errdefer with payload" {
132129}
133130
134131test "reference to errdefer payload" {
132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
135133 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
136 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
137134 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
138135 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
139136 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -157,7 +154,6 @@ test "reference to errdefer payload" {
157154}
158155
159156test "simple else prong doesn't emit an error for unreachable else prong" {
160 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
161157 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
162158 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
163159
test/behavior/enum.zig+10-18
......@@ -25,7 +25,6 @@ fn testEnumFromIntEval(x: i32) !void {
2525const EnumFromIntNumber = enum { Zero, One, Two, Three, Four };
2626
2727test "int to enum" {
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2928 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3029
3130 try testEnumFromIntEval(3);
......@@ -608,7 +607,6 @@ fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void {
608607}
609608
610609test "enum with specified tag values" {
611 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
612610 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
613611
614612 try testEnumWithSpecifiedTagValues(MultipleChoice.C);
......@@ -616,7 +614,6 @@ test "enum with specified tag values" {
616614}
617615
618616test "non-exhaustive enum" {
619 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
620617 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
621618
622619 const S = struct {
......@@ -680,7 +677,6 @@ test "empty non-exhaustive enum" {
680677}
681678
682679test "single field non-exhaustive enum" {
683 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
684680 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
685681
686682 const S = struct {
......@@ -744,7 +740,6 @@ test "cast integer literal to enum" {
744740}
745741
746742test "enum with specified and unspecified tag values" {
747 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
748743 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
749744
750745 try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
......@@ -904,8 +899,8 @@ test "enum value allocation" {
904899}
905900
906901test "enum literal casting to tagged union" {
907 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
908902 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
903 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
909904 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
910905
911906 const Arch = union(enum) {
......@@ -941,8 +936,8 @@ test "enum literal casting to error union with payload enum" {
941936}
942937
943938test "constant enum initialization with differing sizes" {
944 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
945939 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
940 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
946941 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
947942 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
948943 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -985,8 +980,8 @@ fn test3_2(f: Test3Foo) !void {
985980}
986981
987982test "@tagName" {
988 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
989983 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
984 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
990985 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
991986 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
992987 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1002,8 +997,8 @@ fn testEnumTagNameBare(n: anytype) []const u8 {
1002997const BareNumber = enum { One, Two, Three };
1003998
1004999test "@tagName non-exhaustive enum" {
1005 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10061000 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1001 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10071002 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10081003 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10091004 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1014,8 +1009,8 @@ test "@tagName non-exhaustive enum" {
10141009const NonExhaustive = enum(u8) { A, B, _ };
10151010
10161011test "@tagName is null-terminated" {
1017 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10181012 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1013 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10191014 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10201015 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10211016 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1030,8 +1025,8 @@ test "@tagName is null-terminated" {
10301025}
10311026
10321027test "tag name with assigned enum values" {
1033 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10341028 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1029 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10351030 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10361031 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10371032 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1046,7 +1041,6 @@ test "tag name with assigned enum values" {
10461041}
10471042
10481043test "@tagName on enum literals" {
1049 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10501044 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10511045 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10521046
......@@ -1055,8 +1049,8 @@ test "@tagName on enum literals" {
10551049}
10561050
10571051test "tag name with signed enum values" {
1058 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10591052 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1053 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10601054 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10611055 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10621056 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1073,8 +1067,8 @@ test "tag name with signed enum values" {
10731067}
10741068
10751069test "@tagName in callconv(.c) function" {
1076 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10771070 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1071 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10781072 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
10791073 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10801074 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1091,7 +1085,6 @@ fn testEnumTagNameCallconvC() callconv(.c) [*:0]const u8 {
10911085
10921086test "enum literal casting to optional" {
10931087 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1094 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10951088 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10961089
10971090 var bar: ?Bar = undefined;
......@@ -1117,8 +1110,8 @@ const bit_field_1 = BitFieldOfEnums{
11171110};
11181111
11191112test "bit field access with enum fields" {
1120 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
11211113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1114 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
11221115 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11231116 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
11241117 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
......@@ -1158,8 +1151,8 @@ test "enum literal in array literal" {
11581151}
11591152
11601153test "tag name functions are unique" {
1161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
11621154 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1155 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
11631156 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11641157 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
11651158 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1179,7 +1172,6 @@ test "tag name functions are unique" {
11791172}
11801173
11811174test "size of enum with only one tag which has explicit integer tag type" {
1182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11831175 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11841176
11851177 const E = enum(u8) { nope = 10 };
test/behavior/error.zig+19-22
......@@ -145,11 +145,14 @@ test "implicit cast to optional to error union to return result loc" {
145145}
146146
147147test "fn returning empty error set can be passed as fn returning any error" {
148 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
149
148150 entry();
149151 comptime entry();
150152}
151153
152154test "fn returning empty error set can be passed as fn returning any error - pointer" {
155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
153156 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
154157
155158 entryPtr();
......@@ -401,8 +404,8 @@ fn intLiteral(str: []const u8) !?i64 {
401404}
402405
403406test "nested error union function call in optional unwrap" {
407 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
404408 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
405 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
406409 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
407410
408411 const S = struct {
......@@ -448,7 +451,6 @@ test "nested error union function call in optional unwrap" {
448451}
449452
450453test "return function call to error set from error union function" {
451 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
452454 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
453455
454456 const S = struct {
......@@ -465,7 +467,6 @@ test "return function call to error set from error union function" {
465467}
466468
467469test "optional error set is the same size as error set" {
468 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
469470 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
470471 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
471472
......@@ -481,7 +482,7 @@ test "optional error set is the same size as error set" {
481482}
482483
483484test "nested catch" {
484 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
485 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
485486 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
486487
487488 const S = struct {
......@@ -530,7 +531,7 @@ test "function pointer with return type that is error union with payload which i
530531}
531532
532533test "return result loc as peer result loc in inferred error set function" {
533 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
534 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
534535 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
535536 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
536537
......@@ -562,7 +563,6 @@ test "return result loc as peer result loc in inferred error set function" {
562563
563564test "error payload type is correctly resolved" {
564565 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
565 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
566566 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
567567
568568 const MyIntWrapper = struct {
......@@ -590,8 +590,8 @@ test "error union comptime caching" {
590590}
591591
592592test "@errorName" {
593 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
594593 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
594 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
595595 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
596596 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
597597 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -605,8 +605,8 @@ fn gimmeItBroke() anyerror {
605605}
606606
607607test "@errorName sentinel length matches slice length" {
608 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
609608 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
609 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
610610 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
611611 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
612612 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -700,8 +700,8 @@ test "coerce error set to the current inferred error set" {
700700}
701701
702702test "error union payload is properly aligned" {
703 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
703704 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
704 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
705705 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
706706 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
707707 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -719,7 +719,6 @@ test "error union payload is properly aligned" {
719719}
720720
721721test "ret_ptr doesn't cause own inferred error set to be resolved" {
722 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
723722 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
724723
725724 const S = struct {
......@@ -760,7 +759,7 @@ test "simple else prong allowed even when all errors handled" {
760759}
761760
762761test "pointer to error union payload" {
763 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
762 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
764763 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
765764 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
766765 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -794,7 +793,6 @@ const NoReturn = struct {
794793};
795794
796795test "error union of noreturn used with if" {
797 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
798796 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
799797 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
800798 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -809,7 +807,6 @@ test "error union of noreturn used with if" {
809807}
810808
811809test "error union of noreturn used with try" {
812 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
813810 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
814811 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
815812 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -821,7 +818,6 @@ test "error union of noreturn used with try" {
821818}
822819
823820test "error union of noreturn used with catch" {
824 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
825821 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
826822 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
827823 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -833,7 +829,6 @@ test "error union of noreturn used with catch" {
833829}
834830
835831test "alignment of wrapping an error union payload" {
836 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
837832 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
838833 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
839834 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -852,6 +847,7 @@ test "alignment of wrapping an error union payload" {
852847}
853848
854849test "compare error union and error set" {
850 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
855851 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
856852
857853 var a: anyerror = error.Foo;
......@@ -887,7 +883,7 @@ test "catch within a function that calls no errorable functions" {
887883}
888884
889885test "error from comptime string" {
890 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
886 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
891887 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
892888 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
893889 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -913,7 +909,6 @@ test "field access of anyerror results in smaller error set" {
913909}
914910
915911test "optional error union return type" {
916 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
917912 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
918913
919914 const S = struct {
......@@ -928,7 +923,6 @@ test "optional error union return type" {
928923
929924test "optional error set return type" {
930925 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
931 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
932926
933927 const E = error{ A, B };
934928 const S = struct {
......@@ -952,8 +946,8 @@ test "optional error set function parameter" {
952946}
953947
954948test "returning an error union containing a type with no runtime bits" {
949 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
955950 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
956 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
957951 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
958952
959953 const ZeroByteType = struct {
......@@ -969,7 +963,7 @@ test "returning an error union containing a type with no runtime bits" {
969963}
970964
971965test "try used in recursive function with inferred error set" {
972 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
966 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
973967 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
974968 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
975969
......@@ -1010,7 +1004,6 @@ test "generic inline function returns inferred error set" {
10101004}
10111005
10121006test "function called at runtime is properly analyzed for inferred error set" {
1013 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10141007 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10151008 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10161009
......@@ -1045,6 +1038,8 @@ test "errorCast to adhoc inferred error set" {
10451038}
10461039
10471040test "@errorCast from error set to error union" {
1041 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1042
10481043 const S = struct {
10491044 fn doTheTest(set: error{ A, B }) error{A}!i32 {
10501045 return @errorCast(set);
......@@ -1055,6 +1050,8 @@ test "@errorCast from error set to error union" {
10551050}
10561051
10571052test "@errorCast from error union to error union" {
1053 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1054
10581055 const S = struct {
10591056 fn doTheTest(set: error{ A, B }!i32) error{A}!i32 {
10601057 return @errorCast(set);
......@@ -1065,8 +1062,8 @@ test "@errorCast from error union to error union" {
10651062}
10661063
10671064test "result location initialization of error union with OPV payload" {
1065 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10681066 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1069 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10701067 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10711068 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10721069 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
test/behavior/eval.zig+2-34
......@@ -18,7 +18,6 @@ fn unwrapAndAddOne(blah: ?i32) i32 {
1818}
1919const should_be_1235 = unwrapAndAddOne(1234);
2020test "static add one" {
21 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2221 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2322 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2423
......@@ -71,7 +70,6 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 {
7170}
7271
7372test "constant expressions" {
74 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7573 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7674
7775 var array: [array_size]u8 = undefined;
......@@ -93,7 +91,6 @@ fn letsTryToCompareBools(a: bool, b: bool) bool {
9391 return max(bool, a, b);
9492}
9593test "inlined block and runtime block phi" {
96 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9794 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9895
9996 try expect(letsTryToCompareBools(true, true));
......@@ -140,7 +137,6 @@ test "pointer to type" {
140137}
141138
142139test "a type constructed in a global expression" {
143 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
144140 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
145141 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
146142 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -236,7 +232,6 @@ const vertices = [_]Vertex{
236232};
237233
238234test "statically initialized list" {
239 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
240235 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
241236
242237 try expect(static_point_list[0].x == 1);
......@@ -342,7 +337,6 @@ fn doesAlotT(comptime T: type, value: usize) T {
342337}
343338
344339test "@setEvalBranchQuota at same scope as generic function call" {
345 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
346340 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
347341
348342 try expect(doesAlotT(u32, 2) == 2);
......@@ -394,7 +388,6 @@ test "return 0 from function that has u0 return type" {
394388}
395389
396390test "statically initialized struct" {
397 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
398391 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
399392
400393 st_init_str_foo.x += 1;
......@@ -444,7 +437,6 @@ fn copyWithPartialInline(s: []u32, b: []u8) void {
444437
445438test "binary math operator in partially inlined function" {
446439 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
447 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
448440 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
449441 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
450442
......@@ -462,7 +454,6 @@ test "binary math operator in partially inlined function" {
462454}
463455
464456test "comptime shl" {
465 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
466457 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
467458 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
468459 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -491,6 +482,7 @@ test "comptime bitwise operators" {
491482}
492483
493484test "comptime shlWithOverflow" {
485 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
494486 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
495487 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
496488
......@@ -503,7 +495,6 @@ test "comptime shlWithOverflow" {
503495}
504496
505497test "const ptr to variable data changes at runtime" {
506 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
507498 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
508499 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
509500
......@@ -521,7 +512,6 @@ const foo_ref = &foo_contents;
521512
522513test "runtime 128 bit integer division" {
523514 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
524 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
525515 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
526516 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
527517 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -536,7 +526,6 @@ test "runtime 128 bit integer division" {
536526}
537527
538528test "@tagName of @typeInfo" {
539 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
540529 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
541530 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
542531
......@@ -545,7 +534,6 @@ test "@tagName of @typeInfo" {
545534}
546535
547536test "static eval list init" {
548 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
549537 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
550538 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
551539
......@@ -578,7 +566,6 @@ test "inlined loop has array literal with elided runtime scope on first iteratio
578566}
579567
580568test "ptr to local array argument at comptime" {
581 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
582569 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
583570
584571 comptime {
......@@ -741,7 +728,6 @@ test "*align(1) u16 is the same as *align(1:0:2) u16" {
741728
742729test "array concatenation of function calls" {
743730 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
744 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
745731 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
746732 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
747733
......@@ -751,7 +737,6 @@ test "array concatenation of function calls" {
751737
752738test "array multiplication of function calls" {
753739 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
754 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
755740 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
756741 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
757742
......@@ -769,7 +754,6 @@ fn scalar(x: u32) u32 {
769754
770755test "array concatenation peer resolves element types - value" {
771756 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
772 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
773757 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
774758
775759 var a = [2]u3{ 1, 7 };
......@@ -786,7 +770,6 @@ test "array concatenation peer resolves element types - value" {
786770
787771test "array concatenation peer resolves element types - pointer" {
788772 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
789 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
790773 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
791774 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
792775
......@@ -803,7 +786,6 @@ test "array concatenation peer resolves element types - pointer" {
803786
804787test "array concatenation sets the sentinel - value" {
805788 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
806 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
807789 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
808790 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
809791 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -823,7 +805,6 @@ test "array concatenation sets the sentinel - value" {
823805}
824806
825807test "array concatenation sets the sentinel - pointer" {
826 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
827808 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
828809 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
829810 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -843,7 +824,6 @@ test "array concatenation sets the sentinel - pointer" {
843824
844825test "array multiplication sets the sentinel - value" {
845826 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
846 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
847827 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
848828 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
849829 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -862,7 +842,6 @@ test "array multiplication sets the sentinel - value" {
862842
863843test "array multiplication sets the sentinel - pointer" {
864844 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
865 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
866845 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
867846 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
868847 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -889,7 +868,6 @@ test "comptime assign int to optional int" {
889868
890869test "two comptime calls with array default initialized to undefined" {
891870 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
892 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
893871 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
894872
895873 const S = struct {
......@@ -976,7 +954,6 @@ test "const local with comptime init through array init" {
976954}
977955
978956test "closure capture type of runtime-known parameter" {
979 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
980957 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
981958
982959 const S = struct {
......@@ -992,7 +969,6 @@ test "closure capture type of runtime-known parameter" {
992969}
993970
994971test "closure capture type of runtime-known var" {
995 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
996972 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
997973
998974 var x: u32 = 1234;
......@@ -1035,7 +1011,6 @@ test "comptime break passing through runtime condition converted to runtime brea
10351011}
10361012
10371013test "comptime break to outer loop passing through runtime condition converted to runtime break" {
1038 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10391014 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10401015 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10411016
......@@ -1088,7 +1063,6 @@ test "comptime break operand passing through runtime condition converted to runt
10881063}
10891064
10901065test "comptime break operand passing through runtime switch converted to runtime break" {
1091 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10921066 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10931067
10941068 const S = struct {
......@@ -1108,7 +1082,6 @@ test "comptime break operand passing through runtime switch converted to runtime
11081082}
11091083
11101084test "no dependency loop for alignment of self struct" {
1111 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11121085 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11131086 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11141087 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1147,7 +1120,6 @@ test "no dependency loop for alignment of self struct" {
11471120}
11481121
11491122test "no dependency loop for alignment of self bare union" {
1150 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11511123 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11521124 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11531125 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1186,7 +1158,6 @@ test "no dependency loop for alignment of self bare union" {
11861158}
11871159
11881160test "no dependency loop for alignment of self tagged union" {
1189 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11901161 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11911162 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11921163 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1230,7 +1201,6 @@ test "equality of pointers to comptime const" {
12301201}
12311202
12321203test "storing an array of type in a field" {
1233 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12341204 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12351205 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12361206 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1260,7 +1230,6 @@ test "storing an array of type in a field" {
12601230}
12611231
12621232test "pass pointer to field of comptime-only type as a runtime parameter" {
1263 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12641233 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12651234 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
12661235
......@@ -1387,7 +1356,6 @@ test "lazy sizeof union tag size in compare" {
13871356}
13881357
13891358test "lazy value is resolved as slice operand" {
1390 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13911359 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13921360 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13931361 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1568,7 +1536,7 @@ test "x or true is comptime-known true" {
15681536}
15691537
15701538test "non-optional and optional array elements concatenated" {
1571 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1539 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
15721540 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15731541 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15741542
test/behavior/export_builtin.zig-4
......@@ -4,7 +4,6 @@ const expect = std.testing.expect;
44
55test "exporting enum value" {
66 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
87
98 if (builtin.cpu.arch.isWasm()) {
109 // https://github.com/ziglang/zig/issues/4866
......@@ -23,7 +22,6 @@ test "exporting enum value" {
2322
2423test "exporting with internal linkage" {
2524 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
26 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2725
2826 const S = struct {
2927 fn foo() callconv(.c) void {}
......@@ -36,7 +34,6 @@ test "exporting with internal linkage" {
3634
3735test "exporting using namespace access" {
3836 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
39 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4037
4138 if (builtin.cpu.arch.isWasm()) {
4239 // https://github.com/ziglang/zig/issues/4866
......@@ -57,7 +54,6 @@ test "exporting using namespace access" {
5754
5855test "exporting comptime-known value" {
5956 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
60 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6157 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
6258 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
6359
test/behavior/field_parent_ptr.zig+5
......@@ -2,6 +2,7 @@ const expect = @import("std").testing.expect;
22const builtin = @import("builtin");
33
44test "@fieldParentPtr struct" {
5 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
56 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
67 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
78
......@@ -586,6 +587,7 @@ test "@fieldParentPtr extern struct last zero-bit field" {
586587}
587588
588589test "@fieldParentPtr unaligned packed struct" {
590 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
589591 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
590592 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
591593 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -724,6 +726,7 @@ test "@fieldParentPtr unaligned packed struct" {
724726}
725727
726728test "@fieldParentPtr aligned packed struct" {
729 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
727730 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
728731 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
729732 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1339,6 +1342,7 @@ test "@fieldParentPtr packed struct last zero-bit field" {
13391342}
13401343
13411344test "@fieldParentPtr tagged union" {
1345 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13421346 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13431347 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
13441348
......@@ -1475,6 +1479,7 @@ test "@fieldParentPtr tagged union" {
14751479}
14761480
14771481test "@fieldParentPtr untagged union" {
1482 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14781483 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14791484 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14801485
test/behavior/floatop.zig+18-68
......@@ -143,7 +143,6 @@ test "cmp f64" {
143143}
144144
145145test "cmp f128" {
146 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
147146 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
148147 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
149148 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -154,7 +153,6 @@ test "cmp f128" {
154153}
155154
156155test "cmp f80/c_longdouble" {
157 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
158156 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
159157 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
160158 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
......@@ -223,6 +221,7 @@ fn testCmp(comptime T: type) !void {
223221}
224222
225223test "vector cmp f16" {
224 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
226225 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
227226 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
228227 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
......@@ -236,6 +235,7 @@ test "vector cmp f16" {
236235}
237236
238237test "vector cmp f32" {
238 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
239239 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
240240 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
241241 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -249,6 +249,7 @@ test "vector cmp f32" {
249249}
250250
251251test "vector cmp f64" {
252 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
252253 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
253254 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
254255 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -261,8 +262,8 @@ test "vector cmp f64" {
261262}
262263
263264test "vector cmp f128" {
265 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
264266 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
265 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
266267 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
267268 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
268269 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -276,6 +277,7 @@ test "vector cmp f128" {
276277}
277278
278279test "vector cmp f80/c_longdouble" {
280 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
279281 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest;
280282 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .powerpc64le) return error.SkipZigTest;
281283 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -324,7 +326,6 @@ fn testCmpVector(comptime T: type) !void {
324326
325327test "different sized float comparisons" {
326328 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
327 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
328329 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
329330 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
330331
......@@ -371,7 +372,6 @@ test "negative f128 intFromFloat at compile-time" {
371372
372373test "@sqrt f16" {
373374 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
374 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
375375 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
376376 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
377377 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -382,7 +382,6 @@ test "@sqrt f16" {
382382
383383test "@sqrt f32/f64" {
384384 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
385 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
386385 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
387386 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
388387
......@@ -394,7 +393,6 @@ test "@sqrt f32/f64" {
394393
395394test "@sqrt f80/f128/c_longdouble" {
396395 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
397 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
398396 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
399397 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
400398 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -481,9 +479,9 @@ fn testSqrt(comptime T: type) !void {
481479}
482480
483481test "@sqrt with vectors" {
482 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
484483 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
485484 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
486 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
487485 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
488486 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
489487
......@@ -503,7 +501,6 @@ fn testSqrtWithVectors() !void {
503501
504502test "@sin f16" {
505503 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
506 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
507504 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
508505 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
509506 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -514,7 +511,6 @@ test "@sin f16" {
514511
515512test "@sin f32/f64" {
516513 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
517 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
518514 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
519515 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
520516 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -527,7 +523,6 @@ test "@sin f32/f64" {
527523
528524test "@sin f80/f128/c_longdouble" {
529525 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
530 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
531526 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
532527 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
533528 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -554,9 +549,9 @@ fn testSin(comptime T: type) !void {
554549}
555550
556551test "@sin with vectors" {
552 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
557553 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
558554 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
559 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
560555 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
561556 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
562557
......@@ -576,7 +571,6 @@ fn testSinWithVectors() !void {
576571
577572test "@cos f16" {
578573 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
579 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
580574 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
581575 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
582576 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -587,7 +581,6 @@ test "@cos f16" {
587581
588582test "@cos f32/f64" {
589583 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
590 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
591584 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
592585 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
593586 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -600,7 +593,6 @@ test "@cos f32/f64" {
600593
601594test "@cos f80/f128/c_longdouble" {
602595 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
603 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
604596 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
605597 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
606598 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -627,9 +619,9 @@ fn testCos(comptime T: type) !void {
627619}
628620
629621test "@cos with vectors" {
622 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
630623 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
631624 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
632 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
633625 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
634626 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
635627
......@@ -649,7 +641,6 @@ fn testCosWithVectors() !void {
649641
650642test "@tan f16" {
651643 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
652 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
653644 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
654645 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
655646 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -660,7 +651,6 @@ test "@tan f16" {
660651
661652test "@tan f32/f64" {
662653 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
663 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
664654 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
665655 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
666656 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -673,7 +663,6 @@ test "@tan f32/f64" {
673663
674664test "@tan f80/f128/c_longdouble" {
675665 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
676 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
677666 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
678667 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
679668 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -700,9 +689,9 @@ fn testTan(comptime T: type) !void {
700689}
701690
702691test "@tan with vectors" {
692 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
703693 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
704694 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
705 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
706695 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
707696 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
708697
......@@ -722,7 +711,6 @@ fn testTanWithVectors() !void {
722711
723712test "@exp f16" {
724713 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
725 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
726714 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
727715 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
728716 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -733,7 +721,6 @@ test "@exp f16" {
733721
734722test "@exp f32/f64" {
735723 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
736 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
737724 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
738725 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
739726 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -746,7 +733,6 @@ test "@exp f32/f64" {
746733
747734test "@exp f80/f128/c_longdouble" {
748735 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
749 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
750736 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
751737 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
752738 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -777,9 +763,9 @@ fn testExp(comptime T: type) !void {
777763}
778764
779765test "@exp with vectors" {
766 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
780767 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
781768 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
782 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
783769 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
784770 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
785771
......@@ -799,7 +785,6 @@ fn testExpWithVectors() !void {
799785
800786test "@exp2 f16" {
801787 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
802 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
803788 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
804789 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
805790 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -810,7 +795,6 @@ test "@exp2 f16" {
810795
811796test "@exp2 f32/f64" {
812797 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
813 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
814798 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
815799 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
816800 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -823,7 +807,6 @@ test "@exp2 f32/f64" {
823807
824808test "@exp2 f80/f128/c_longdouble" {
825809 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
826 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
827810 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
828811 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
829812 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -849,9 +832,9 @@ fn testExp2(comptime T: type) !void {
849832}
850833
851834test "@exp2 with @vectors" {
835 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
852836 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
853837 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
854 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
855838 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
856839 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
857840
......@@ -870,7 +853,6 @@ fn testExp2WithVectors() !void {
870853}
871854
872855test "@log f16" {
873 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
874856 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
875857 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
876858 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -881,7 +863,6 @@ test "@log f16" {
881863}
882864
883865test "@log f32/f64" {
884 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
885866 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
886867 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
887868 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -894,7 +875,6 @@ test "@log f32/f64" {
894875}
895876
896877test "@log f80/f128/c_longdouble" {
897 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
898878 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
899879 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
900880 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -921,8 +901,8 @@ fn testLog(comptime T: type) !void {
921901}
922902
923903test "@log with @vectors" {
904 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
924905 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
925 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
926906 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
927907 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
928908 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -940,7 +920,6 @@ test "@log with @vectors" {
940920}
941921
942922test "@log2 f16" {
943 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
944923 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
945924 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
946925 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -951,7 +930,6 @@ test "@log2 f16" {
951930}
952931
953932test "@log2 f32/f64" {
954 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
955933 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
956934 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
957935 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -964,7 +942,6 @@ test "@log2 f32/f64" {
964942}
965943
966944test "@log2 f80/f128/c_longdouble" {
967 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
968945 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
969946 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
970947 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -991,8 +968,8 @@ fn testLog2(comptime T: type) !void {
991968}
992969
993970test "@log2 with vectors" {
971 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
994972 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
995 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
996973 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
997974 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
998975 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1016,7 +993,6 @@ fn testLog2WithVectors() !void {
1016993}
1017994
1018995test "@log10 f16" {
1019 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1020996 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1021997 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1022998 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1027,7 +1003,6 @@ test "@log10 f16" {
10271003}
10281004
10291005test "@log10 f32/f64" {
1030 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10311006 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10321007 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10331008 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1040,7 +1015,6 @@ test "@log10 f32/f64" {
10401015}
10411016
10421017test "@log10 f80/f128/c_longdouble" {
1043 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10441018 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10451019 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10461020 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1067,8 +1041,8 @@ fn testLog10(comptime T: type) !void {
10671041}
10681042
10691043test "@log10 with vectors" {
1044 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10701045 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1071 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10721046 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10731047 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10741048 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1089,7 +1063,6 @@ fn testLog10WithVectors() !void {
10891063
10901064test "@abs f16" {
10911065 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1092 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10931066 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10941067 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10951068
......@@ -1099,7 +1072,6 @@ test "@abs f16" {
10991072
11001073test "@abs f32/f64" {
11011074 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1102 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11031075 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11041076
11051077 try testFabs(f32);
......@@ -1110,7 +1082,6 @@ test "@abs f32/f64" {
11101082
11111083test "@abs f80/f128/c_longdouble" {
11121084 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11141085 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
11151086 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11161087 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1190,7 +1161,7 @@ fn testFabs(comptime T: type) !void {
11901161}
11911162
11921163test "@abs with vectors" {
1193 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1164 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11941165 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11951166 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
11961167 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1210,7 +1181,6 @@ fn testFabsWithVectors() !void {
12101181}
12111182
12121183test "@floor f16" {
1213 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12141184 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12151185 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12161186 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1220,7 +1190,6 @@ test "@floor f16" {
12201190}
12211191
12221192test "@floor f32/f64" {
1223 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12241193 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12251194 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12261195 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1232,7 +1201,6 @@ test "@floor f32/f64" {
12321201}
12331202
12341203test "@floor f80/f128/c_longdouble" {
1235 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12361204 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12371205 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
12381206 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1284,7 +1252,7 @@ fn testFloor(comptime T: type) !void {
12841252}
12851253
12861254test "@floor with vectors" {
1287 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1255 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12881256 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12891257 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
12901258 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1304,7 +1272,6 @@ fn testFloorWithVectors() !void {
13041272}
13051273
13061274test "@ceil f16" {
1307 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13081275 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13091276 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13101277 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1314,7 +1281,6 @@ test "@ceil f16" {
13141281}
13151282
13161283test "@ceil f32/f64" {
1317 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13181284 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13191285 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13201286 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1326,7 +1292,6 @@ test "@ceil f32/f64" {
13261292}
13271293
13281294test "@ceil f80/f128/c_longdouble" {
1329 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13301295 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13311296 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
13321297 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1378,7 +1343,7 @@ fn testCeil(comptime T: type) !void {
13781343}
13791344
13801345test "@ceil with vectors" {
1381 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1346 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13821347 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13831348 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
13841349 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1398,7 +1363,6 @@ fn testCeilWithVectors() !void {
13981363}
13991364
14001365test "@trunc f16" {
1401 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14021366 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14031367 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14041368 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1408,7 +1372,6 @@ test "@trunc f16" {
14081372}
14091373
14101374test "@trunc f32/f64" {
1411 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14121375 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14131376 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14141377 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1420,7 +1383,6 @@ test "@trunc f32/f64" {
14201383}
14211384
14221385test "@trunc f80/f128/c_longdouble" {
1423 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14241386 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14251387 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
14261388 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1472,7 +1434,7 @@ fn testTrunc(comptime T: type) !void {
14721434}
14731435
14741436test "@trunc with vectors" {
1475 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1437 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14761438 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14771439 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
14781440 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1492,7 +1454,6 @@ fn testTruncWithVectors() !void {
14921454}
14931455
14941456test "neg f16" {
1495 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14961457 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14971458 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14981459 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1508,7 +1469,6 @@ test "neg f16" {
15081469}
15091470
15101471test "neg f32/f64" {
1511 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15121472 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15131473 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15141474 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1520,7 +1480,6 @@ test "neg f32/f64" {
15201480}
15211481
15221482test "neg f80/f128/c_longdouble" {
1523 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15241483 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15251484 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15261485 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1606,7 +1565,6 @@ fn testNeg(comptime T: type) !void {
16061565}
16071566
16081567test "eval @setFloatMode at compile-time" {
1609 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16101568 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16111569
16121570 const result = comptime fnWithFloatMode();
......@@ -1629,7 +1587,6 @@ test "f128 at compile time is lossy" {
16291587
16301588test "comptime fixed-width float zero divided by zero produces NaN" {
16311589 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1632 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16331590 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16341591 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16351592 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1641,7 +1598,6 @@ test "comptime fixed-width float zero divided by zero produces NaN" {
16411598
16421599test "comptime fixed-width float non-zero divided by zero produces signed Inf" {
16431600 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1644 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16451601 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16461602 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16471603
......@@ -1686,21 +1642,18 @@ test "comptime inf >= runtime 1" {
16861642 try std.testing.expect(f >= i);
16871643}
16881644test "comptime isNan(nan * 1)" {
1689 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16901645 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
16911646
16921647 const nan_times_one = comptime std.math.nan(f64) * 1;
16931648 try std.testing.expect(std.math.isNan(nan_times_one));
16941649}
16951650test "runtime isNan(nan * 1)" {
1696 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16971651 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
16981652
16991653 const nan_times_one = std.math.nan(f64) * 1;
17001654 try std.testing.expect(std.math.isNan(nan_times_one));
17011655}
17021656test "comptime isNan(nan * 0)" {
1703 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17041657 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17051658
17061659 const nan_times_zero = comptime std.math.nan(f64) * 0;
......@@ -1709,7 +1662,6 @@ test "comptime isNan(nan * 0)" {
17091662 try std.testing.expect(std.math.isNan(zero_times_nan));
17101663}
17111664test "runtime isNan(nan * 0)" {
1712 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17131665 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17141666
17151667 const nan_times_zero = std.math.nan(f64) * 0;
......@@ -1718,7 +1670,6 @@ test "runtime isNan(nan * 0)" {
17181670 try std.testing.expect(std.math.isNan(zero_times_nan));
17191671}
17201672test "comptime isNan(inf * 0)" {
1721 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17221673 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17231674
17241675 const inf_times_zero = comptime std.math.inf(f64) * 0;
......@@ -1727,7 +1678,6 @@ test "comptime isNan(inf * 0)" {
17271678 try std.testing.expect(std.math.isNan(zero_times_inf));
17281679}
17291680test "runtime isNan(inf * 0)" {
1730 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17311681 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17321682
17331683 const inf_times_zero = std.math.inf(f64) * 0;
test/behavior/fn.zig-13
......@@ -78,7 +78,6 @@ test "return inner function which references comptime variable of outer function
7878
7979test "discard the result of a function that returns a struct" {
8080 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
81 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8281 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8382
8483 const S = struct {
......@@ -101,7 +100,6 @@ test "discard the result of a function that returns a struct" {
101100
102101test "inline function call that calls optional function pointer, return pointer at callsite interacts correctly with callsite return type" {
103102 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
104 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
105103 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
106104 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
107105
......@@ -179,7 +177,6 @@ fn fComplexCallconvRet(x: u32) callconv(blk: {
179177
180178test "function with complex callconv and return type expressions" {
181179 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
183180 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
184181
185182 try expect(fComplexCallconvRet(3).x == 9);
......@@ -255,7 +252,6 @@ test "pass by non-copying value as method, at comptime" {
255252
256253test "implicit cast fn call result to optional in field result" {
257254 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
258 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
259255 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
260256 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
261257
......@@ -283,7 +279,6 @@ test "implicit cast fn call result to optional in field result" {
283279
284280test "void parameters" {
285281 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
286 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
287282
288283 try voidFun(1, void{}, 2, {});
289284}
......@@ -306,7 +301,6 @@ fn acceptsString(foo: []u8) void {
306301}
307302
308303test "function pointers" {
309 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
310304 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
311305 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
312306 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -345,7 +339,6 @@ fn numberLiteralArg(a: anytype) !void {
345339
346340test "function call with anon list literal" {
347341 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
348 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
349342 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
350343
351344 const S = struct {
......@@ -365,7 +358,6 @@ test "function call with anon list literal" {
365358
366359test "function call with anon list literal - 2D" {
367360 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
368 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
369361 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
370362
371363 const S = struct {
......@@ -426,7 +418,6 @@ test "import passed byref to function in return type" {
426418
427419test "implicit cast function to function ptr" {
428420 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
429 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
430421 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
431422 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
432423
......@@ -485,7 +476,6 @@ test "method call with optional pointer first param" {
485476
486477test "using @ptrCast on function pointers" {
487478 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
488 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
489479 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
490480 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
491481
......@@ -524,8 +514,6 @@ test "function returns function returning type" {
524514}
525515
526516test "peer type resolution of inferred error set with non-void payload" {
527 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
528
529517 const S = struct {
530518 fn openDataFile(mode: enum { read, write }) !u32 {
531519 return switch (mode) {
......@@ -582,7 +570,6 @@ test "pass and return comptime-only types" {
582570
583571test "pointer to alias behaves same as pointer to function" {
584572 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
585 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
586573 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
587574
588575 const S = struct {
test/behavior/for.zig-20
......@@ -5,7 +5,6 @@ const expectEqual = std.testing.expectEqual;
55const mem = std.mem;
66
77test "continue in for loop" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
98 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
109
1110 const array = [_]i32{ 1, 2, 3, 4, 5 };
......@@ -67,7 +66,6 @@ test "ignore lval with underscore (for loop)" {
6766
6867test "basic for loop" {
6968 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
70 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7169 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7270 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
7371
......@@ -111,7 +109,6 @@ test "basic for loop" {
111109
112110test "for with null and T peer types and inferred result location type" {
113111 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
114 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
115112 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
116113 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
117114
......@@ -132,7 +129,6 @@ test "for with null and T peer types and inferred result location type" {
132129}
133130
134131test "2 break statements and an else" {
135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
136132 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
137133
138134 const S = struct {
......@@ -152,7 +148,6 @@ test "2 break statements and an else" {
152148}
153149
154150test "for loop with pointer elem var" {
155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
156151 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
157152 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
158153 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -180,7 +175,6 @@ fn mangleString(s: []u8) void {
180175}
181176
182177test "for copies its payload" {
183 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
184178 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
185179
186180 const S = struct {
......@@ -198,7 +192,6 @@ test "for copies its payload" {
198192}
199193
200194test "for on slice with allowzero ptr" {
201 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
202195 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
203196 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
204197 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -215,7 +208,6 @@ test "for on slice with allowzero ptr" {
215208}
216209
217210test "else continue outer for" {
218 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
219211 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
220212 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
221213
......@@ -230,8 +222,6 @@ test "else continue outer for" {
230222}
231223
232224test "for loop with else branch" {
233 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
234
235225 {
236226 var x = [_]u32{ 1, 2 };
237227 _ = &x;
......@@ -312,7 +302,6 @@ test "1-based counter and ptr to array" {
312302test "slice and two counters, one is offset and one is runtime" {
313303 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
314304 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
315 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
316305 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
317306
318307 const slice: []const u8 = "blah";
......@@ -342,7 +331,6 @@ test "slice and two counters, one is offset and one is runtime" {
342331test "two slices, one captured by-ref" {
343332 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
344333 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
345 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
346334 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
347335
348336 var buf: [10]u8 = undefined;
......@@ -362,7 +350,6 @@ test "two slices, one captured by-ref" {
362350test "raw pointer and slice" {
363351 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
364352 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
365 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
366353 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
367354
368355 var buf: [10]u8 = undefined;
......@@ -382,7 +369,6 @@ test "raw pointer and slice" {
382369test "raw pointer and counter" {
383370 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
384371 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
385 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
386372 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
387373
388374 var buf: [10]u8 = undefined;
......@@ -401,7 +387,6 @@ test "raw pointer and counter" {
401387test "inline for with slice as the comptime-known" {
402388 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
403389 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
404 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
405390
406391 const comptime_slice = "hello";
407392 var runtime_i: usize = 3;
......@@ -432,7 +417,6 @@ test "inline for with slice as the comptime-known" {
432417test "inline for with counter as the comptime-known" {
433418 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
434419 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
435 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
436420 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
437421
438422 var runtime_slice = "hello";
......@@ -464,7 +448,6 @@ test "inline for with counter as the comptime-known" {
464448test "inline for on tuple pointer" {
465449 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
466450 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
467 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
468451 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
469452
470453 const S = struct { u32, u32, u32 };
......@@ -480,7 +463,6 @@ test "inline for on tuple pointer" {
480463test "ref counter that starts at zero" {
481464 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
482465 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
483 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
484466
485467 for ([_]usize{ 0, 1, 2 }, 0..) |i, j| {
486468 try expectEqual(i, j);
......@@ -495,7 +477,6 @@ test "ref counter that starts at zero" {
495477test "inferred alloc ptr of for loop" {
496478 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
497479 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
498 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
499480
500481 {
501482 var cond = false;
......@@ -516,7 +497,6 @@ test "inferred alloc ptr of for loop" {
516497}
517498
518499test "for loop results in a bool" {
519 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
520500 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
521501
522502 try std.testing.expect(for ([1]u8{0}) |x| {
test/behavior/generics.zig+1-18
......@@ -17,7 +17,6 @@ fn checkSize(comptime T: type) usize {
1717}
1818
1919test "simple generic fn" {
20 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2120 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2221
2322 try expect(max(i32, 3, -1) == 3);
......@@ -53,7 +52,6 @@ fn sameButWithFloats(a: f64, b: f64) f64 {
5352
5453test "fn with comptime args" {
5554 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
56 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5755 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5856
5957 try expect(gimmeTheBigOne(1234, 5678) == 5678);
......@@ -63,7 +61,6 @@ test "fn with comptime args" {
6361
6462test "anytype params" {
6563 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
66 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6764 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6865
6966 try expect(max_i32(12, 34) == 34);
......@@ -87,7 +84,6 @@ fn max_f64(a: f64, b: f64) f64 {
8784}
8885
8986test "type constructed by comptime function call" {
90 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9187 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9288 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
9389 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -113,7 +109,6 @@ fn SimpleList(comptime L: usize) type {
113109
114110test "function with return type type" {
115111 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
116 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
117112 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
118113
119114 var list: List(i32) = undefined;
......@@ -154,7 +149,6 @@ fn aGenericFn(comptime T: type, comptime a: T, b: T) T {
154149
155150test "generic fn with implicit cast" {
156151 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
157 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
158152 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
159153 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
160154
......@@ -173,7 +167,6 @@ fn getFirstByte(comptime T: type, mem: []const T) u8 {
173167
174168test "generic fn keeps non-generic parameter types" {
175169 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
176 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
177170 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
178171 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
179172
......@@ -249,7 +242,6 @@ test "function parameter is generic" {
249242}
250243
251244test "generic function instantiation turns into comptime call" {
252 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
253245 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
254246 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
255247 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -300,7 +292,6 @@ test "generic function with void and comptime parameter" {
300292}
301293
302294test "anonymous struct return type referencing comptime parameter" {
303 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
304295 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
305296
306297 const S = struct {
......@@ -318,7 +309,6 @@ test "anonymous struct return type referencing comptime parameter" {
318309
319310test "generic function instantiation non-duplicates" {
320311 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
321 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
322312 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
323313 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
324314
......@@ -339,7 +329,6 @@ test "generic function instantiation non-duplicates" {
339329
340330test "generic instantiation of tagged union with only one field" {
341331 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
342 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
343332
344333 if (builtin.os.tag == .wasi) return error.SkipZigTest;
345334
......@@ -439,8 +428,6 @@ test "null sentinel pointer passed as generic argument" {
439428}
440429
441430test "generic function passed as comptime argument" {
442 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
443
444431 const S = struct {
445432 fn doMath(comptime f: fn (comptime type, i32, i32) error{Overflow}!i32, a: i32, b: i32) !void {
446433 const result = try f(i32, a, b);
......@@ -451,7 +438,6 @@ test "generic function passed as comptime argument" {
451438}
452439
453440test "return type of generic function is function pointer" {
454 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
455441 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
456442
457443 const S = struct {
......@@ -464,8 +450,6 @@ test "return type of generic function is function pointer" {
464450}
465451
466452test "coerced function body has inequal value with its uncoerced body" {
467 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
468
469453 const S = struct {
470454 const A = B(i32, c);
471455 fn c() !i32 {
......@@ -513,7 +497,6 @@ test "union in struct captures argument" {
513497
514498test "function argument tuple used as struct field" {
515499 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
516 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
517500 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
518501
519502 const S = struct {
......@@ -546,8 +529,8 @@ test "comptime callconv(.c) function ptr uses comptime type argument" {
546529}
547530
548531test "call generic function with from function called by the generic function" {
549 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
550532 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
533 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
551534 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
552535
553536 const GET = struct {
test/behavior/globals.zig+2-4
......@@ -6,7 +6,6 @@ var pos = [2]f32{ 0.0, 0.0 };
66test "store to global array" {
77 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
88 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
109
1110 try expect(pos[1] == 0.0);
1211 pos = [2]f32{ 0.0, 1.0 };
......@@ -15,9 +14,9 @@ test "store to global array" {
1514
1615var vpos = @Vector(2, f32){ 0.0, 0.0 };
1716test "store to global vector" {
17 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1818 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
1919 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
20 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2120
2221 try expect(vpos[1] == 0.0);
2322 vpos = @Vector(2, f32){ 0.0, 1.0 };
......@@ -26,7 +25,6 @@ test "store to global vector" {
2625
2726test "slices pointing at the same address as global array." {
2827 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3028 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3129 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
3230
......@@ -47,7 +45,6 @@ test "slices pointing at the same address as global array." {
4745test "global loads can affect liveness" {
4846 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
4947 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
50 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5148
5249 const S = struct {
5350 const ByRef = struct {
......@@ -188,6 +185,7 @@ test "function pointer field call on global extern struct, conditional on global
188185}
189186
190187test "function pointer field call on global extern struct" {
188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
191189 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
192190
193191 const S = struct {
test/behavior/if.zig+4-2
......@@ -116,7 +116,6 @@ test "if prongs cast to expected type instead of peer type resolution" {
116116
117117test "if peer expressions inferred optional type" {
118118 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
119 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
120119 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
121120 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
122121
......@@ -135,7 +134,6 @@ test "if peer expressions inferred optional type" {
135134
136135test "if-else expression with runtime condition result location is inferred optional" {
137136 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
138 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
139137 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
140138
141139 const A = struct { b: u64, c: u64 };
......@@ -174,6 +172,8 @@ fn returnTrue() bool {
174172}
175173
176174test "if value shouldn't be load-elided if used later (structs)" {
175 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
176
177177 const Foo = struct { x: i32 };
178178
179179 var a = Foo{ .x = 1 };
......@@ -191,6 +191,8 @@ test "if value shouldn't be load-elided if used later (structs)" {
191191}
192192
193193test "if value shouldn't be load-elided if used later (optionals)" {
194 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
195
194196 var a: ?i32 = 1;
195197 var b: ?i32 = 1;
196198
test/behavior/import_c_keywords.zig-1
......@@ -27,7 +27,6 @@ extern fn @"break"() Id;
2727extern fn an_alias_of_some_non_c_keyword_function() Id;
2828
2929test "import c keywords" {
30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3130 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3231 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
3332 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/inline_switch.zig+2-9
......@@ -3,7 +3,6 @@ const expect = std.testing.expect;
33const builtin = @import("builtin");
44
55test "inline scalar prongs" {
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
76 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
87
98 var x: usize = 0;
......@@ -18,7 +17,6 @@ test "inline scalar prongs" {
1817}
1918
2019test "inline prong ranges" {
21 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2220 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2321
2422 var x: usize = 0;
......@@ -33,7 +31,6 @@ test "inline prong ranges" {
3331
3432const E = enum { a, b, c, d };
3533test "inline switch enums" {
36 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3734 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3835
3936 var x: E = .a;
......@@ -46,7 +43,7 @@ test "inline switch enums" {
4643
4744const U = union(E) { a: void, b: u2, c: u3, d: u4 };
4845test "inline switch unions" {
49 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
46 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5047 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5148 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5249
......@@ -73,7 +70,6 @@ test "inline switch unions" {
7370}
7471
7572test "inline else bool" {
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7773 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7874
7975 var a = true;
......@@ -85,7 +81,6 @@ test "inline else bool" {
8581}
8682
8783test "inline else error" {
88 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8984 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9085
9186 const Err = error{ a, b, c };
......@@ -98,7 +93,6 @@ test "inline else error" {
9893}
9994
10095test "inline else enum" {
101 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10296 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10397
10498 const E2 = enum(u8) { a = 2, b = 3, c = 4, d = 5 };
......@@ -111,7 +105,7 @@ test "inline else enum" {
111105}
112106
113107test "inline else int with gaps" {
114 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
108 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
115109 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
116110 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
117111
......@@ -130,7 +124,6 @@ test "inline else int with gaps" {
130124}
131125
132126test "inline else int all values" {
133 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
134127 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
135128
136129 var a: u2 = 0;
test/behavior/int128.zig-5
......@@ -5,7 +5,6 @@ const minInt = std.math.minInt;
55const builtin = @import("builtin");
66
77test "uint128" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -25,7 +24,6 @@ test "uint128" {
2524}
2625
2726test "undefined 128 bit int" {
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2927 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
3028 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3129 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -45,7 +43,6 @@ test "undefined 128 bit int" {
4543}
4644
4745test "int128" {
48 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4946 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5047 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5148 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -68,7 +65,6 @@ test "int128" {
6865}
6966
7067test "truncate int128" {
71 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7268 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7369 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7470 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -92,7 +88,6 @@ test "truncate int128" {
9288}
9389
9490test "shift int128" {
95 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9691 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9792 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9893 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/int_comparison_elision.zig-1
......@@ -15,7 +15,6 @@ test "int comparison elision" {
1515
1616 // TODO: support int types > 128 bits wide in other backends
1717 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
18 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1918 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2019 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2120
test/behavior/ir_block_deps.zig-1
......@@ -18,7 +18,6 @@ fn getErrInt() anyerror!i32 {
1818}
1919
2020test "ir block deps" {
21 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2221 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2322 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2423
test/behavior/lower_strlit_to_vector.zig-1
......@@ -3,7 +3,6 @@ const builtin = @import("builtin");
33
44test "strlit to vector" {
55 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
76 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/math.zig+23-49
......@@ -62,11 +62,11 @@ fn assertFalse(b: bool) !void {
6262}
6363
6464test "@clz" {
65 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6665 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
6766 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6867 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
6968 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
69
7070 try testClz();
7171 try comptime testClz();
7272}
......@@ -80,7 +80,6 @@ fn testClz() !void {
8080}
8181
8282test "@clz big ints" {
83 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8483 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8584 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8685 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -100,8 +99,8 @@ fn testOneClz(comptime T: type, x: T) u32 {
10099}
101100
102101test "@clz vectors" {
102 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
103103 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
104 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
105104 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
106105 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
107106 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -146,7 +145,6 @@ fn expectVectorsEqual(a: anytype, b: anytype) !void {
146145}
147146
148147test "@ctz" {
149 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
150148 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
151149 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
152150 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -170,7 +168,7 @@ fn testOneCtz(comptime T: type, x: T) u32 {
170168}
171169
172170test "@ctz 128-bit integers" {
173 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
171 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
174172 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
175173 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
176174 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -188,8 +186,8 @@ fn testCtz128() !void {
188186}
189187
190188test "@ctz vectors" {
189 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
191190 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
192 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
193191 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
194192 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
195193 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -227,7 +225,6 @@ test "const number literal" {
227225const ten = 10;
228226
229227test "float equality" {
230 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
231228 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
232229 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
233230
......@@ -433,7 +430,6 @@ test "binary not" {
433430}
434431
435432test "binary not big int <= 128 bits" {
436 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
437433 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
438434 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
439435 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -467,7 +463,7 @@ test "binary not big int <= 128 bits" {
467463}
468464
469465test "division" {
470 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
466 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
471467 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
472468 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
473469 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -607,7 +603,6 @@ test "large integer division" {
607603}
608604
609605test "division half-precision floats" {
610 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
611606 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
612607 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
613608 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -694,7 +689,6 @@ fn testUnsignedNegationWrappingEval(x: u16) !void {
694689}
695690
696691test "negation wrapping" {
697 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
698692 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
699693 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
700694
......@@ -747,7 +741,6 @@ fn testShrTrunc(x: u16) !void {
747741}
748742
749743test "f128" {
750 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
751744 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
752745 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
753746 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -776,6 +769,7 @@ fn should_not_be_zero(x: f128) !void {
776769}
777770
778771test "umax wrapped squaring" {
772 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
779773 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
780774 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
781775
......@@ -832,7 +826,6 @@ test "umax wrapped squaring" {
832826}
833827
834828test "128-bit multiplication" {
835 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
836829 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
837830 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
838831 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -867,7 +860,6 @@ fn testAddWithOverflow(comptime T: type, a: T, b: T, add: T, bit: u1) !void {
867860}
868861
869862test "@addWithOverflow" {
870 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
871863 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
872864 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
873865 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
......@@ -886,7 +878,6 @@ test "@addWithOverflow" {
886878}
887879
888880test "@addWithOverflow > 64 bits" {
889 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
890881 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
891882 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
892883 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -958,7 +949,7 @@ fn testMulWithOverflow(comptime T: type, a: T, b: T, mul: T, bit: u1) !void {
958949}
959950
960951test "basic @mulWithOverflow" {
961 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
952 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
962953 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
963954 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
964955
......@@ -970,7 +961,7 @@ test "basic @mulWithOverflow" {
970961}
971962
972963test "extensive @mulWithOverflow" {
973 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
964 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
974965 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
975966 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
976967 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1010,11 +1001,9 @@ test "extensive @mulWithOverflow" {
10101001}
10111002
10121003test "@mulWithOverflow bitsize > 32" {
1013 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1014
1015 // aarch64 fails on a release build of the compiler.
1016 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1004 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10171005 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1006 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10181007 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10191008
10201009 try testMulWithOverflow(u40, 3, 0x55_5555_5555, 0xff_ffff_ffff, 0);
......@@ -1041,9 +1030,9 @@ test "@mulWithOverflow bitsize > 32" {
10411030}
10421031
10431032test "@mulWithOverflow bitsize 128 bits" {
1033 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10441034 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
10451035 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1046 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10471036 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10481037 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10491038 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -1068,6 +1057,7 @@ test "@mulWithOverflow bitsize 128 bits" {
10681057}
10691058
10701059test "@mulWithOverflow bitsize 256 bits" {
1060 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10711061 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
10721062 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
10731063 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1114,7 +1104,6 @@ fn testSubWithOverflow(comptime T: type, a: T, b: T, sub: T, bit: u1) !void {
11141104}
11151105
11161106test "@subWithOverflow" {
1117 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11181107 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11191108 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11201109
......@@ -1131,7 +1120,6 @@ test "@subWithOverflow" {
11311120}
11321121
11331122test "@subWithOverflow > 64 bits" {
1134 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11351123 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11361124 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11371125 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1179,7 +1167,7 @@ fn testShlWithOverflow(comptime T: type, a: T, b: math.Log2Int(T), shl: T, bit:
11791167}
11801168
11811169test "@shlWithOverflow" {
1182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1170 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11831171 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11841172 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
11851173 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1198,7 +1186,7 @@ test "@shlWithOverflow" {
11981186}
11991187
12001188test "@shlWithOverflow > 64 bits" {
1201 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1189 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12021190 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12031191 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
12041192 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1267,7 +1255,6 @@ test "allow signed integer division/remainder when values are comptime-known and
12671255}
12681256
12691257test "quad hex float literal parsing accurate" {
1270 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12711258 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12721259 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12731260 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1425,8 +1412,8 @@ test "comptime float rem int" {
14251412}
14261413
14271414test "remainder division" {
1415 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14281416 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1429 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14301417 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14311418 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14321419 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
......@@ -1465,7 +1452,6 @@ fn remdivOne(comptime T: type, a: T, b: T, c: T) !void {
14651452
14661453test "float remainder division using @rem" {
14671454 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1468 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14691455 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14701456 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14711457 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1506,8 +1492,8 @@ fn fremOne(comptime T: type, a: T, b: T, c: T, epsilon: T) !void {
15061492}
15071493
15081494test "float modulo division using @mod" {
1495 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
15091496 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1510 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15111497 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15121498 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
15131499 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
......@@ -1550,7 +1536,6 @@ fn fmodOne(comptime T: type, a: T, b: T, c: T, epsilon: T) !void {
15501536
15511537test "@round f16" {
15521538 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1553 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15541539 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15551540 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
15561541
......@@ -1560,7 +1545,6 @@ test "@round f16" {
15601545
15611546test "@round f32/f64" {
15621547 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1563 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15641548 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15651549 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
15661550
......@@ -1577,7 +1561,6 @@ test "@round f32/f64" {
15771561
15781562test "@round f80" {
15791563 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1580 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15811564 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15821565 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
15831566 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
......@@ -1589,7 +1572,6 @@ test "@round f80" {
15891572
15901573test "@round f128" {
15911574 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1592 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15931575 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15941576 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
15951577 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
......@@ -1606,9 +1588,9 @@ fn testRound(comptime T: type, x: T) !void {
16061588}
16071589
16081590test "vector integer addition" {
1591 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16091592 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
16101593 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1611 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16121594 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16131595 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16141596 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1630,7 +1612,6 @@ test "vector integer addition" {
16301612
16311613test "NaN comparison" {
16321614 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1633 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16341615 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16351616 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16361617 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1648,7 +1629,6 @@ test "NaN comparison" {
16481629
16491630test "NaN comparison f80" {
16501631 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1651 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16521632 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16531633 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16541634 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1670,9 +1650,9 @@ fn testNanEqNan(comptime F: type) !void {
16701650}
16711651
16721652test "vector comparison" {
1653 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16731654 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
16741655 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1675 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16761656 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16771657 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16781658 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1703,7 +1683,6 @@ test "compare undefined literal with comptime_int" {
17031683
17041684test "signed zeros are represented properly" {
17051685 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1706 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17071686 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17081687 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
17091688 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1735,7 +1714,6 @@ test "signed zeros are represented properly" {
17351714
17361715test "absFloat" {
17371716 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1738 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17391717 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17401718
17411719 try testAbsFloat();
......@@ -1765,8 +1743,8 @@ test "mod lazy values" {
17651743}
17661744
17671745test "@clz works on both vector and scalar inputs" {
1746 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
17681747 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1769 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17701748 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17711749 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17721750 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1784,7 +1762,6 @@ test "@clz works on both vector and scalar inputs" {
17841762
17851763test "runtime comparison to NaN is comptime-known" {
17861764 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1787 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17881765 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17891766 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
17901767 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1814,7 +1791,6 @@ test "runtime comparison to NaN is comptime-known" {
18141791
18151792test "runtime int comparison to inf is comptime-known" {
18161793 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1817 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
18181794 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
18191795 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
18201796 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1843,8 +1819,8 @@ test "runtime int comparison to inf is comptime-known" {
18431819}
18441820
18451821test "float divide by zero" {
1822 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
18461823 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1847 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
18481824 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18491825 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
18501826 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1878,8 +1854,8 @@ test "float divide by zero" {
18781854}
18791855
18801856test "partially-runtime integer vector division would be illegal if vector elements were reordered" {
1857 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
18811858 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1882 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
18831859 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18841860 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
18851861 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1907,8 +1883,8 @@ test "partially-runtime integer vector division would be illegal if vector eleme
19071883}
19081884
19091885test "float vector division of comptime zero by runtime nan is nan" {
1886 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
19101887 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1911 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
19121888 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19131889 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
19141890 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1925,8 +1901,8 @@ test "float vector division of comptime zero by runtime nan is nan" {
19251901}
19261902
19271903test "float vector multiplication of comptime zero by runtime nan is nan" {
1904 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
19281905 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1929 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
19301906 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19311907 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
19321908 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1943,7 +1919,6 @@ test "float vector multiplication of comptime zero by runtime nan is nan" {
19431919
19441920test "comptime float vector division of zero by nan is nan" {
19451921 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1946 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
19471922 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19481923 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
19491924 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1959,7 +1934,6 @@ test "comptime float vector division of zero by nan is nan" {
19591934
19601935test "comptime float vector multiplication of zero by nan is nan" {
19611936 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1962 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
19631937 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19641938 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
19651939 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/maximum_minimum.zig+7-15
......@@ -7,7 +7,6 @@ const expectEqual = std.testing.expectEqual;
77
88test "@max" {
99 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1211 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1312
......@@ -28,9 +27,9 @@ test "@max" {
2827}
2928
3029test "@max on vectors" {
30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3131 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
3232 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
33 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3433 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3534 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3635 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -61,7 +60,6 @@ test "@max on vectors" {
6160}
6261
6362test "@min" {
64 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6563 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
6664 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6765 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -83,8 +81,8 @@ test "@min" {
8381}
8482
8583test "@min for vectors" {
84 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8685 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8886 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8987 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9088 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -116,7 +114,6 @@ test "@min for vectors" {
116114}
117115
118116test "@min/max for floats" {
119 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
120117 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
121118 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
122119 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -167,8 +164,8 @@ test "@min/@max more than two arguments" {
167164}
168165
169166test "@min/@max more than two vector arguments" {
167 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
170168 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
171 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
172169 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
173170 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
174171 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -181,7 +178,6 @@ test "@min/@max more than two vector arguments" {
181178}
182179
183180test "@min/@max notices bounds" {
184 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
185181 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
186182 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
187183
......@@ -198,8 +194,8 @@ test "@min/@max notices bounds" {
198194}
199195
200196test "@min/@max notices vector bounds" {
197 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
201198 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
202 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
203199 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
204200 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
205201 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -217,7 +213,6 @@ test "@min/@max notices vector bounds" {
217213}
218214
219215test "@min/@max on comptime_int" {
220 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
221216 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
222217 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
223218
......@@ -231,7 +226,6 @@ test "@min/@max on comptime_int" {
231226}
232227
233228test "@min/@max notices bounds from types" {
234 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
235229 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
236230 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
237231
......@@ -251,8 +245,8 @@ test "@min/@max notices bounds from types" {
251245}
252246
253247test "@min/@max notices bounds from vector types" {
248 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
254249 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
255 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
256250 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
257251 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
258252 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -273,7 +267,6 @@ test "@min/@max notices bounds from vector types" {
273267}
274268
275269test "@min/@max notices bounds from types when comptime-known value is undef" {
276 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
277270 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
278271 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
279272 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -293,8 +286,8 @@ test "@min/@max notices bounds from types when comptime-known value is undef" {
293286}
294287
295288test "@min/@max notices bounds from vector types when element of comptime-known vector is undef" {
289 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
296290 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
297 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
298291 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
299292 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
300293 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -333,7 +326,6 @@ test "@min/@max of signed and unsigned runtime integers" {
333326}
334327
335328test "@min resulting in u0" {
336 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
337329 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
338330 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
339331
......@@ -364,8 +356,8 @@ test "@min/@max with runtime signed and unsigned integers of same size" {
364356}
365357
366358test "@min/@max with runtime vectors of signed and unsigned integers of same size" {
359 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
367360 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
368 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
369361 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
370362 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
371363 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/member_func.zig-2
......@@ -28,7 +28,6 @@ const HasFuncs = struct {
2828
2929test "standard field calls" {
3030 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
31 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3231 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3332 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
3433
......@@ -72,7 +71,6 @@ test "standard field calls" {
7271
7372test "@field field calls" {
7473 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
75 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7674 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7775 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
7876
test/behavior/memcpy.zig+1-4
......@@ -4,7 +4,6 @@ const expect = std.testing.expect;
44const assert = std.debug.assert;
55
66test "memcpy and memset intrinsics" {
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
87 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
98 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -26,7 +25,6 @@ fn testMemcpyMemset() !void {
2625}
2726
2827test "@memcpy with both operands single-ptr-to-array, one is null-terminated" {
29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3028 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3129 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
3230 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -47,7 +45,6 @@ fn testMemcpyBothSinglePtrArrayOneIsNullTerminated() !void {
4745}
4846
4947test "@memcpy dest many pointer" {
50 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5148 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
5249 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
5350 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -70,7 +67,6 @@ fn testMemcpyDestManyPtr() !void {
7067}
7168
7269test "@memcpy C pointer" {
73 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7470 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7571 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
7672 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -156,6 +152,7 @@ test "@memcpy zero-bit type with aliasing" {
156152}
157153
158154test "@memcpy with sentinel" {
155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
159156 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
160157
161158 const S = struct {
test/behavior/memmove.zig-3
......@@ -3,7 +3,6 @@ const builtin = @import("builtin");
33const expect = std.testing.expect;
44
55test "memmove and memset intrinsics" {
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
76 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
87 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -32,7 +31,6 @@ fn testMemmoveMemset() !void {
3231}
3332
3433test "@memmove with both operands single-ptr-to-array, one is null-terminated" {
35 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3634 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3735 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
3836 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -77,7 +75,6 @@ fn testMemmoveBothSinglePtrArrayOneIsNullTerminated() !void {
7775}
7876
7977test "@memmove dest many pointer" {
80 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8178 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
8279 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
8380 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/memset.zig-7
......@@ -3,7 +3,6 @@ const builtin = @import("builtin");
33const expect = std.testing.expect;
44
55test "@memset on array pointers" {
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
76 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
87 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
98 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -32,7 +31,6 @@ fn testMemsetArray() !void {
3231}
3332
3433test "@memset on slices" {
35 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3634 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3735 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
3836 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -68,7 +66,6 @@ fn testMemsetSlice() !void {
6866}
6967
7068test "memset with bool element" {
71 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7269 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7370 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
7471 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -80,7 +77,6 @@ test "memset with bool element" {
8077}
8178
8279test "memset with 1-byte struct element" {
83 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8480 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
8581 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
8682 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -94,7 +90,6 @@ test "memset with 1-byte struct element" {
9490}
9591
9692test "memset with 1-byte array element" {
97 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9893 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
9994 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
10095 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -145,7 +140,6 @@ test "memset with large array element, comptime known" {
145140}
146141
147142test "@memset provides result type" {
148 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
149143 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
150144 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
151145 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -164,7 +158,6 @@ test "@memset provides result type" {
164158}
165159
166160test "zero keys with @memset" {
167 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
168161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
169162 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
170163 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/muladd.zig+5-9
......@@ -4,7 +4,6 @@ const expect = std.testing.expect;
44
55test "@mulAdd" {
66 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
109 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -32,7 +31,6 @@ fn testMulAdd() !void {
3231
3332test "@mulAdd f16" {
3433 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
35 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3634 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3735 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3836 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -51,7 +49,6 @@ fn testMulAdd16() !void {
5149
5250test "@mulAdd f80" {
5351 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
54 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5552 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5653 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
5754 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
......@@ -71,7 +68,6 @@ fn testMulAdd80() !void {
7168
7269test "@mulAdd f128" {
7370 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
74 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7571 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7672 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
7773 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
......@@ -103,9 +99,9 @@ fn vector16() !void {
10399}
104100
105101test "vector f16" {
102 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
106103 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
107104 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
108 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
109105 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
110106 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
111107 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -128,9 +124,9 @@ fn vector32() !void {
128124}
129125
130126test "vector f32" {
127 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
131128 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
132129 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
133 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
134130 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
135131 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
136132 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -153,9 +149,9 @@ fn vector64() !void {
153149}
154150
155151test "vector f64" {
152 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
156153 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
157154 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
158 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
159155 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
160156 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
161157 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -177,9 +173,9 @@ fn vector80() !void {
177173}
178174
179175test "vector f80" {
176 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
180177 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
181178 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
183179 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
184180 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
185181 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
......@@ -203,9 +199,9 @@ fn vector128() !void {
203199}
204200
205201test "vector f128" {
202 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
206203 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
207204 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
208 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
209205 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
210206 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
211207 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
test/behavior/multiple_externs_with_conflicting_types.zig-1
......@@ -11,7 +11,6 @@ comptime {
1111const builtin = @import("builtin");
1212
1313test "call extern function defined with conflicting type" {
14 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1514 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1615 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1716 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/nan.zig-1
......@@ -23,7 +23,6 @@ const snan_f128: f128 = math.snan(f128);
2323
2424test "nan memory equality" {
2525 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
26 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2726 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
2827 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2928
test/behavior/null.zig+2-4
......@@ -29,8 +29,8 @@ test "optional type" {
2929}
3030
3131test "test maybe object and get a pointer to the inner value" {
32 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3332 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
33 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3434 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3535 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3636
......@@ -51,7 +51,6 @@ test "rhs maybe unwrap return" {
5151
5252test "maybe return" {
5353 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
54 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5554 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5655
5756 try maybeReturnImpl();
......@@ -140,8 +139,8 @@ test "optional pointer to 0 bit type null value at runtime" {
140139}
141140
142141test "if var maybe pointer" {
143 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
144142 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
143 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
145144 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
146145 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
147146
......@@ -185,7 +184,6 @@ const here_is_a_null_literal = SillyStruct{ .context = null };
185184
186185test "unwrap optional which is field of global var" {
187186 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
189187 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
190188
191189 struct_with_optional.field = null;
test/behavior/optional.zig+10-12
......@@ -59,6 +59,7 @@ fn testNullPtrsEql() !void {
5959}
6060
6161test "optional with zero-bit type" {
62 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6263 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
6364
6465 const S = struct {
......@@ -109,7 +110,6 @@ test "optional with zero-bit type" {
109110}
110111
111112test "address of unwrap optional" {
112 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
113113 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
114114 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
115115 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -132,7 +132,6 @@ test "address of unwrap optional" {
132132}
133133
134134test "nested optional field in struct" {
135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
136135 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
137136 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
138137
......@@ -210,6 +209,7 @@ test "equality compare optionals and non-optionals" {
210209}
211210
212211test "compare optionals with modified payloads" {
212 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
213213 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
214214
215215 var lhs: ?bool = false;
......@@ -319,7 +319,7 @@ test "assigning to an unwrapped optional field in an inline loop" {
319319}
320320
321321test "coerce an anon struct literal to optional struct" {
322 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
322 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
323323 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
324324 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
325325 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -339,7 +339,6 @@ test "coerce an anon struct literal to optional struct" {
339339}
340340
341341test "0-bit child type coerced to optional return ptr result location" {
342 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
343342 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
344343 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
345344
......@@ -365,6 +364,7 @@ test "0-bit child type coerced to optional return ptr result location" {
365364}
366365
367366test "0-bit child type coerced to optional" {
367 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
368368 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
369369 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
370370
......@@ -391,7 +391,7 @@ test "0-bit child type coerced to optional" {
391391}
392392
393393test "array of optional unaligned types" {
394 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
394 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
395395 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
396396 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
397397 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -428,8 +428,8 @@ test "array of optional unaligned types" {
428428}
429429
430430test "optional pointer to zero bit optional payload" {
431 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
431432 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
432 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
433433 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
434434 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
435435
......@@ -447,8 +447,8 @@ test "optional pointer to zero bit optional payload" {
447447}
448448
449449test "optional pointer to zero bit error union payload" {
450 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
450451 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
451 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
452452 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
453453 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
454454 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -543,7 +543,6 @@ test "alignment of wrapping an optional payload" {
543543}
544544
545545test "Optional slice size is optimized" {
546 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
547546 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
548547 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
549548 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -556,7 +555,7 @@ test "Optional slice size is optimized" {
556555}
557556
558557test "Optional slice passed to function" {
559 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
558 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
560559 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
561560 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
562561 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -574,7 +573,6 @@ test "Optional slice passed to function" {
574573}
575574
576575test "peer type resolution in nested if expressions" {
577 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
578576 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
579577
580578 const Thing = struct { n: i32 };
......@@ -623,8 +621,8 @@ test "variable of optional of noreturn" {
623621}
624622
625623test "copied optional doesn't alias source" {
624 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
626625 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
627 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
628626 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
629627 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
630628
......@@ -637,8 +635,8 @@ test "copied optional doesn't alias source" {
637635}
638636
639637test "result location initialization of optional with OPV payload" {
638 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
640639 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
641 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
642640 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
643641 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
644642 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
test/behavior/packed-struct.zig+24-22
......@@ -120,7 +120,6 @@ test "consistent size of packed structs" {
120120}
121121
122122test "correct sizeOf and offsets in packed structs" {
123 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
124123 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
125124 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
126125
......@@ -187,7 +186,6 @@ test "correct sizeOf and offsets in packed structs" {
187186}
188187
189188test "nested packed structs" {
190 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
191189 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
192190 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
193191
......@@ -484,7 +482,6 @@ test "load pointer from packed struct" {
484482}
485483
486484test "@intFromPtr on a packed struct field" {
487 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
488485 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
489486 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
490487 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -507,7 +504,6 @@ test "@intFromPtr on a packed struct field" {
507504}
508505
509506test "@intFromPtr on a packed struct field unaligned and nested" {
510 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
511507 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
512508 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
513509 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -617,6 +613,7 @@ test "@intFromPtr on a packed struct field unaligned and nested" {
617613}
618614
619615test "packed struct fields modification" {
616 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
620617 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
621618
622619 // Originally reported at https://github.com/ziglang/zig/issues/16615
......@@ -656,9 +653,9 @@ test "optional pointer in packed struct" {
656653}
657654
658655test "nested packed struct field access test" {
656 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
659657 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
660658 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO packed structs larger than 64 bits
661 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
662659 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
663660 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
664661 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -777,6 +774,7 @@ test "nested packed struct field access test" {
777774}
778775
779776test "nested packed struct at non-zero offset" {
777 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
780778 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
781779 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
782780
......@@ -915,7 +913,6 @@ test "packed struct passed to callconv(.c) function" {
915913}
916914
917915test "overaligned pointer to packed struct" {
918 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
919916 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
920917 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
921918 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -937,7 +934,7 @@ test "overaligned pointer to packed struct" {
937934}
938935
939936test "packed struct initialized in bitcast" {
940 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
937 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
941938 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
942939 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
943940 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -986,8 +983,8 @@ test "store undefined to packed result location" {
986983 try expectEqual(x, s.x);
987984}
988985
986// Originally reported at https://github.com/ziglang/zig/issues/9914
989987test "bitcast back and forth" {
990 // Originally reported at https://github.com/ziglang/zig/issues/9914
991988 const S = packed struct { one: u6, two: u1 };
992989 const s = S{ .one = 0b110101, .two = 0b1 };
993990 const u: u7 = @bitCast(s);
......@@ -996,8 +993,9 @@ test "bitcast back and forth" {
996993 try expect(s.two == s2.two);
997994}
998995
996// Originally reported at https://github.com/ziglang/zig/issues/14200
999997test "field access of packed struct smaller than its abi size inside struct initialized with rls" {
1000 // Originally reported at https://github.com/ziglang/zig/issues/14200
998 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1001999 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10021000 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
10031001
......@@ -1015,8 +1013,8 @@ test "field access of packed struct smaller than its abi size inside struct init
10151013 try expect(@as(i2, 1) == s.ps.y);
10161014}
10171015
1016// Originally reported at https://github.com/ziglang/zig/issues/14632
10181017test "modify nested packed struct aligned field" {
1019 // Originally reported at https://github.com/ziglang/zig/issues/14632
10201018 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10211019 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10221020 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
......@@ -1045,10 +1043,10 @@ test "modify nested packed struct aligned field" {
10451043 try std.testing.expect(!opts.baz);
10461044}
10471045
1046// Originally reported at https://github.com/ziglang/zig/issues/9674
10481047test "assigning packed struct inside another packed struct" {
1048 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10491049 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1050
1051 // Originally reported at https://github.com/ziglang/zig/issues/9674
10521050 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10531051
10541052 const S = struct {
......@@ -1078,7 +1076,6 @@ test "assigning packed struct inside another packed struct" {
10781076}
10791077
10801078test "packed struct used as part of anon decl name" {
1081 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10821079 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10831080 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10841081 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1104,7 +1101,13 @@ test "packed struct acts as a namespace" {
11041101}
11051102
11061103test "pointer loaded correctly from packed struct" {
1104 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1105 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
11071106 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1107 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
1108 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1109
1110 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // crashes MSVC
11081111
11091112 const RAM = struct {
11101113 data: [0xFFFF + 1]u8,
......@@ -1132,12 +1135,6 @@ test "pointer loaded correctly from packed struct" {
11321135 }
11331136 }
11341137 };
1135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1136 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1137 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
1138 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1139
1140 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // crashes MSVC
11411138
11421139 var ram = try RAM.new();
11431140 var cpu = try CPU.new(&ram);
......@@ -1146,7 +1143,7 @@ test "pointer loaded correctly from packed struct" {
11461143}
11471144
11481145test "assignment to non-byte-aligned field in packed struct" {
1149 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1146 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11501147 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11511148 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
11521149 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
......@@ -1167,7 +1164,6 @@ test "assignment to non-byte-aligned field in packed struct" {
11671164}
11681165
11691166test "packed struct field pointer aligned properly" {
1170 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11711167 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11721168 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11731169 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -1186,7 +1182,7 @@ test "packed struct field pointer aligned properly" {
11861182}
11871183
11881184test "load flag from packed struct in union" {
1189 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1185 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11901186 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11911187 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11921188 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1311,6 +1307,7 @@ test "packed struct equality" {
13111307}
13121308
13131309test "packed struct equality ignores padding bits" {
1310 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13141311 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
13151312 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
13161313
......@@ -1322,6 +1319,8 @@ test "packed struct equality ignores padding bits" {
13221319}
13231320
13241321test "packed struct with signed field" {
1322 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1323
13251324 var s: packed struct {
13261325 a: i2,
13271326 b: u6,
......@@ -1332,6 +1331,7 @@ test "packed struct with signed field" {
13321331}
13331332
13341333test "assign packed struct initialized with RLS to packed struct literal field" {
1334 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13351335 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isWasm()) return error.SkipZigTest;
13361336 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
13371337 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1349,6 +1349,7 @@ test "assign packed struct initialized with RLS to packed struct literal field"
13491349}
13501350
13511351test "byte-aligned packed relocation" {
1352 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13521353 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
13531354 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
13541355 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1363,6 +1364,7 @@ test "byte-aligned packed relocation" {
13631364}
13641365
13651366test "packed struct store of comparison result" {
1367 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13661368 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
13671369 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
13681370
test/behavior/packed-union.zig+3-3
......@@ -99,10 +99,10 @@ fn testFlagsInPackedUnionAtOffset() !void {
9999 try expectEqual(false, test_bits.adv_flags.adv.flags.enable_2);
100100}
101101
102// Originally reported at https://github.com/ziglang/zig/issues/16581
102103test "packed union in packed struct" {
104 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
103105 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
104
105 // Originally reported at https://github.com/ziglang/zig/issues/16581
106106 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
107107
108108 try testPackedUnionInPackedStruct();
......@@ -136,7 +136,7 @@ fn testPackedUnionInPackedStruct() !void {
136136}
137137
138138test "packed union initialized with a runtime value" {
139 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
139 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
140140 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
141141 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
142142 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/packed_struct_explicit_backing_int.zig-1
......@@ -5,7 +5,6 @@ const expectEqual = std.testing.expectEqual;
55const native_endian = builtin.cpu.arch.endian();
66
77test "packed struct explicit backing integer" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1110
test/behavior/pointers.zig+1-12
......@@ -18,7 +18,6 @@ fn testDerefPtr() !void {
1818}
1919
2020test "pointer-integer arithmetic" {
21 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2221 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2322 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2423 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -232,7 +231,6 @@ test "peer type resolution with C pointer and const pointer" {
232231
233232test "implicit casting between C pointer and optional non-C pointer" {
234233 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
235 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
236234 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
237235 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
238236 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -248,8 +246,8 @@ test "implicit casting between C pointer and optional non-C pointer" {
248246}
249247
250248test "implicit cast error unions with non-optional to optional pointer" {
249 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
251250 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
252 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
253251 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
254252 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
255253 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -298,7 +296,6 @@ test "allowzero pointer and slice" {
298296
299297test "assign null directly to C pointer and test null equality" {
300298 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
301 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
302299 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
303300 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
304301
......@@ -366,7 +363,6 @@ test "array initialization types" {
366363}
367364
368365test "null terminated pointer" {
369 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
370366 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
371367 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
372368
......@@ -384,7 +380,6 @@ test "null terminated pointer" {
384380}
385381
386382test "allow any sentinel" {
387 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
388383 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
389384 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
390385 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -401,7 +396,6 @@ test "allow any sentinel" {
401396}
402397
403398test "pointer sentinel with enums" {
404 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
405399 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
406400 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
407401 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -515,7 +509,6 @@ test "@intFromPtr on null optional at comptime" {
515509}
516510
517511test "indexing array with sentinel returns correct type" {
518 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
519512 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
520513 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
521514 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -525,7 +518,6 @@ test "indexing array with sentinel returns correct type" {
525518}
526519
527520test "element pointer to slice" {
528 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
529521 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
530522 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
531523
......@@ -548,7 +540,6 @@ test "element pointer to slice" {
548540}
549541
550542test "element pointer arithmetic to slice" {
551 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
552543 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
553544 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
554545
......@@ -604,7 +595,6 @@ test "pointer to constant decl preserves alignment" {
604595
605596test "ptrCast comptime known slice to C pointer" {
606597 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
607 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
608598 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
609599 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
610600
......@@ -625,7 +615,6 @@ test "pointer alignment and element type include call expression" {
625615}
626616
627617test "pointer to array has explicit alignment" {
628 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
629618 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
630619
631620 const S = struct {
test/behavior/popcount.zig+2-3
......@@ -4,7 +4,6 @@ const expect = std.testing.expect;
44const expectEqual = std.testing.expectEqual;
55
66test "@popCount integers" {
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -15,7 +14,7 @@ test "@popCount integers" {
1514}
1615
1716test "@popCount 128bit integer" {
18 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
17 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1918 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2019 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2120 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -77,8 +76,8 @@ fn testPopCountIntegers() !void {
7776}
7877
7978test "@popCount vectors" {
79 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8080 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
81 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8281 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8382 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8483 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/ptrcast.zig-19
......@@ -22,7 +22,6 @@ fn testReinterpretBytesAsInteger() !void {
2222
2323test "reinterpret an array over multiple elements, with no well-defined layout" {
2424 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
25 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2625 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2726 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2827
......@@ -56,7 +55,6 @@ fn testReinterpretStructWrappedBytesAsInteger() !void {
5655}
5756
5857test "reinterpret bytes of an array into an extern struct" {
59 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6058 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6159 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
6260
......@@ -130,7 +128,6 @@ fn testReinterpretOverAlignedExternStructAsExternStruct() !void {
130128
131129test "lower reinterpreted comptime field ptr (with under-aligned fields)" {
132130 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
133 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
134131 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
135132
136133 // Test lowering a field ptr
......@@ -152,7 +149,6 @@ test "lower reinterpreted comptime field ptr (with under-aligned fields)" {
152149
153150test "lower reinterpreted comptime field ptr" {
154151 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
156152 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
157153
158154 // Test lowering a field ptr
......@@ -174,7 +170,6 @@ test "lower reinterpreted comptime field ptr" {
174170
175171test "reinterpret struct field at comptime" {
176172 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
177 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
178173 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
179174
180175 const numNative = comptime Bytes.init(0x12345678);
......@@ -232,7 +227,6 @@ test "ptrcast of const integer has the correct object size" {
232227test "implicit optional pointer to optional anyopaque pointer" {
233228 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
234229 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
235 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
236230 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
237231
238232 var buf: [4]u8 = "aoeu".*;
......@@ -244,7 +238,6 @@ test "implicit optional pointer to optional anyopaque pointer" {
244238
245239test "@ptrCast slice to slice" {
246240 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
247 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
248241 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
249242 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
250243
......@@ -262,7 +255,6 @@ test "@ptrCast slice to slice" {
262255
263256test "comptime @ptrCast a subset of an array, then write through it" {
264257 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
265 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
266258 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
267259
268260 comptime {
......@@ -354,7 +346,6 @@ test "@ptrCast restructures sliced comptime-only array" {
354346
355347test "@ptrCast slice multiplying length" {
356348 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
357 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
358349 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
359350 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
360351
......@@ -372,7 +363,6 @@ test "@ptrCast slice multiplying length" {
372363
373364test "@ptrCast array pointer to slice multiplying length" {
374365 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
375 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
376366 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
377367 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
378368
......@@ -390,7 +380,6 @@ test "@ptrCast array pointer to slice multiplying length" {
390380
391381test "@ptrCast slice dividing length" {
392382 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
393 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
394383 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
395384 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
396385
......@@ -408,7 +397,6 @@ test "@ptrCast slice dividing length" {
408397
409398test "@ptrCast array pointer to slice dividing length" {
410399 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
411 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
412400 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
413401 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
414402
......@@ -426,7 +414,6 @@ test "@ptrCast array pointer to slice dividing length" {
426414
427415test "@ptrCast slice with complex length increase" {
428416 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
429 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
430417 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
431418 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
432419
......@@ -447,7 +434,6 @@ test "@ptrCast slice with complex length increase" {
447434
448435test "@ptrCast array pointer to slice with complex length increase" {
449436 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
450 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
451437 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
452438 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
453439
......@@ -468,7 +454,6 @@ test "@ptrCast array pointer to slice with complex length increase" {
468454
469455test "@ptrCast slice with complex length decrease" {
470456 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
471 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
472457 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
473458 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
474459
......@@ -489,7 +474,6 @@ test "@ptrCast slice with complex length decrease" {
489474
490475test "@ptrCast array pointer to slice with complex length decrease" {
491476 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
492 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
493477 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
494478 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
495479
......@@ -510,7 +494,6 @@ test "@ptrCast array pointer to slice with complex length decrease" {
510494
511495test "@ptrCast slice of zero-bit type to different slice" {
512496 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
513 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
514497 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
515498 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
516499
......@@ -530,7 +513,6 @@ test "@ptrCast slice of zero-bit type to different slice" {
530513
531514test "@ptrCast single-item pointer to slice with length 1" {
532515 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
533 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
534516 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
535517 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
536518 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
......@@ -552,7 +534,6 @@ test "@ptrCast single-item pointer to slice with length 1" {
552534
553535test "@ptrCast single-item pointer to slice of bytes" {
554536 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
555 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
556537 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
557538 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
558539 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
test/behavior/ptrfromint.zig-3
......@@ -17,7 +17,6 @@ fn addressToFunction() void {
1717
1818test "mutate through ptr initialized with constant ptrFromInt value" {
1919 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
20 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2120 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2221 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2322
......@@ -35,7 +34,6 @@ fn forceCompilerAnalyzeBranchHardCodedPtrDereference(x: bool) void {
3534
3635test "@ptrFromInt creates null pointer" {
3736 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
38 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3937 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4038 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4139
......@@ -45,7 +43,6 @@ test "@ptrFromInt creates null pointer" {
4543
4644test "@ptrFromInt creates allowzero zero pointer" {
4745 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
48 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4946 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5047
5148 const ptr = @as(*allowzero u32, @ptrFromInt(0));
test/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig-1
......@@ -6,7 +6,6 @@ const mem = std.mem;
66var ok: bool = false;
77test "reference a variable in an if after an if in the 2nd switch prong" {
88 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
109 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1211
test/behavior/reflection.zig-1
......@@ -26,7 +26,6 @@ fn dummy(a: bool, b: i32, c: f32) i32 {
2626}
2727
2828test "reflection: @field" {
29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3029 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3130
3231 var f = Foo{
test/behavior/return_address.zig+1-1
......@@ -6,7 +6,7 @@ fn retAddr() usize {
66}
77
88test "return address" {
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1010 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1111 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1212 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/saturating_arithmetic.zig+9-8
......@@ -5,7 +5,7 @@ const maxInt = std.math.maxInt;
55const expect = std.testing.expect;
66
77test "saturating add" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
99 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1010 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1111 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -52,8 +52,8 @@ test "saturating add" {
5252}
5353
5454test "saturating add 128bit" {
55 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5556 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
56 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5757 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5858 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5959 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -79,7 +79,7 @@ test "saturating add 128bit" {
7979}
8080
8181test "saturating subtraction" {
82 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
82 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8383 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8484 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8585 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -125,8 +125,8 @@ test "saturating subtraction" {
125125}
126126
127127test "saturating subtraction 128bit" {
128 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
128129 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
129 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
130130 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
131131 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
132132 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -158,7 +158,6 @@ fn testSatMul(comptime T: type, a: T, b: T, expected: T) !void {
158158}
159159
160160test "saturating multiplication <= 32 bits" {
161 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
162161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
163162 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
164163 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -229,6 +228,7 @@ test "saturating multiplication <= 32 bits" {
229228}
230229
231230test "saturating mul i64, i128" {
231 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
232232 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
233233 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
234234
......@@ -256,8 +256,8 @@ test "saturating mul i64, i128" {
256256}
257257
258258test "saturating multiplication" {
259 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
259260 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
260 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
261261 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
262262 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
263263 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -295,7 +295,7 @@ test "saturating multiplication" {
295295}
296296
297297test "saturating shift-left" {
298 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
298 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
299299 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
300300 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
301301 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -340,6 +340,7 @@ test "saturating shift-left" {
340340}
341341
342342test "saturating shift-left large rhs" {
343 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
343344 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
344345 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
345346 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -357,7 +358,7 @@ test "saturating shift-left large rhs" {
357358}
358359
359360test "saturating shl uses the LHS type" {
360 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
361 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
361362 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
362363 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
363364 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/select.zig+3-2
......@@ -4,9 +4,9 @@ const mem = std.mem;
44const expect = std.testing.expect;
55
66test "@select vectors" {
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
78 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
89 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1010 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1111 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1212 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -35,9 +35,9 @@ fn selectVectors() !void {
3535}
3636
3737test "@select arrays" {
38 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3839 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
3940 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
40 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4141 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4242 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
4343 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -66,6 +66,7 @@ fn selectArrays() !void {
6666}
6767
6868test "@select compare result" {
69 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6970 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
7071 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
7172 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest;
test/behavior/shuffle.zig+4-4
......@@ -5,7 +5,7 @@ const expect = std.testing.expect;
55const expectEqual = std.testing.expectEqual;
66
77test "@shuffle int" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
99 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1010 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1111 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -50,8 +50,8 @@ test "@shuffle int" {
5050}
5151
5252test "@shuffle int strange sizes" {
53 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5354 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
54 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5555 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5656 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5757 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -132,8 +132,8 @@ fn testShuffle(
132132}
133133
134134test "@shuffle bool 1" {
135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
135136 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
136 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
137137 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
138138 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
139139 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -155,8 +155,8 @@ test "@shuffle bool 1" {
155155}
156156
157157test "@shuffle bool 2" {
158 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
158159 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
159 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
160160 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
161161 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
162162 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/sizeof_and_typeof.zig-3
......@@ -270,7 +270,6 @@ test "bitSizeOf comptime_int" {
270270}
271271
272272test "runtime instructions inside typeof in comptime only scope" {
273 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
274273 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
275274 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
276275
......@@ -326,7 +325,6 @@ test "lazy abi size used in comparison" {
326325}
327326
328327test "peer type resolution with @TypeOf doesn't trigger dependency loop check" {
329 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
330328 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
331329 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
332330
......@@ -437,7 +435,6 @@ test "Peer resolution of extern function calls in @TypeOf" {
437435}
438436
439437test "Extern function calls, dereferences and field access in @TypeOf" {
440 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
441438 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
442439
443440 const Test = struct {
test/behavior/slice.zig+2-22
......@@ -211,7 +211,6 @@ test "comptime pointer cast array and then slice" {
211211}
212212
213213test "slicing zero length array" {
214 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
215214 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
216215 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
217216
......@@ -273,7 +272,6 @@ test "result location zero sized array inside struct field implicit cast to slic
273272}
274273
275274test "runtime safety lets us slice from len..len" {
276 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
277275 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
278276 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
279277 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -287,7 +285,6 @@ fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 {
287285}
288286
289287test "C pointer" {
290 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
291288 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
292289 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
293290
......@@ -299,7 +296,6 @@ test "C pointer" {
299296}
300297
301298test "C pointer slice access" {
302 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
303299 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
304300 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
305301 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -331,7 +327,6 @@ fn sliceSum(comptime q: []const u8) i32 {
331327}
332328
333329test "slice type with custom alignment" {
334 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
335330 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
336331 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
337332
......@@ -390,7 +385,6 @@ test "empty array to slice" {
390385}
391386
392387test "@ptrCast slice to pointer" {
393 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
394388 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
395389 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
396390
......@@ -445,7 +439,6 @@ test "slice multi-pointer without end" {
445439}
446440
447441test "slice syntax resulting in pointer-to-array" {
448 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
449442 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
450443 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
451444 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -665,7 +658,6 @@ test "slice syntax resulting in pointer-to-array" {
665658}
666659
667660test "slice pointer-to-array null terminated" {
668 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
669661 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
670662 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
671663
......@@ -718,7 +710,7 @@ test "slice pointer-to-array zero length" {
718710}
719711
720712test "type coercion of pointer to anon struct literal to pointer to slice" {
721 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
713 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
722714 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
723715 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
724716 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -812,7 +804,6 @@ test "slice sentinel access at comptime" {
812804}
813805
814806test "slicing array with sentinel as end index" {
815 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
816807 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
817808 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
818809
......@@ -831,7 +822,6 @@ test "slicing array with sentinel as end index" {
831822}
832823
833824test "slicing slice with sentinel as end index" {
834 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
835825 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
836826 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
837827
......@@ -888,7 +878,7 @@ test "slice field ptr var" {
888878}
889879
890880test "global slice field access" {
891 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
881 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
892882 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
893883 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
894884 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -929,7 +919,6 @@ test "slice with dereferenced value" {
929919}
930920
931921test "empty slice ptr is non null" {
932 if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest; // TODO
933922 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // Test assumes `undefined` is non-zero
934923
935924 {
......@@ -947,7 +936,6 @@ test "empty slice ptr is non null" {
947936}
948937
949938test "slice decays to many pointer" {
950 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
951939 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
952940 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
953941
......@@ -957,7 +945,6 @@ test "slice decays to many pointer" {
957945}
958946
959947test "write through pointer to optional slice arg" {
960 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
961948 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
962949 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
963950 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -977,7 +964,6 @@ test "write through pointer to optional slice arg" {
977964}
978965
979966test "modify slice length at comptime" {
980 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
981967 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
982968 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
983969 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -994,7 +980,6 @@ test "modify slice length at comptime" {
994980}
995981
996982test "slicing zero length array field of struct" {
997 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
998983 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
999984 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1000985 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1010,7 +995,6 @@ test "slicing zero length array field of struct" {
1010995}
1011996
1012997test "slicing slices gives correct result" {
1013 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1014998 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1015999 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10161000
......@@ -1024,7 +1008,6 @@ test "slicing slices gives correct result" {
10241008}
10251009
10261010test "get address of element of zero-sized slice" {
1027 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10281011 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10291012 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10301013
......@@ -1037,7 +1020,6 @@ test "get address of element of zero-sized slice" {
10371020}
10381021
10391022test "sentinel-terminated 0-length slices" {
1040 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10411023 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10421024 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10431025
......@@ -1058,8 +1040,6 @@ test "sentinel-terminated 0-length slices" {
10581040}
10591041
10601042test "peer slices keep abi alignment with empty struct" {
1061 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1062
10631043 var cond: bool = undefined;
10641044 cond = false;
10651045 const slice = if (cond) &[1]u32{42} else &.{};
test/behavior/src.zig-1
......@@ -16,7 +16,6 @@ const expect = std.testing.expect;
1616const expectEqualStrings = std.testing.expectEqualStrings;
1717
1818test "@src" {
19 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2019 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2120 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2221 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/string_literals.zig+1-5
......@@ -6,7 +6,6 @@ const tag_name = @tagName(TestEnum.TestEnumValue);
66const ptr_tag_name: [*:0]const u8 = tag_name;
77
88test "@tagName() returns a string literal" {
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1211
......@@ -20,7 +19,6 @@ const error_name = @errorName(TestError.TestErrorCode);
2019const ptr_error_name: [*:0]const u8 = error_name;
2120
2221test "@errorName() returns a string literal" {
23 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2422 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2523 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2624
......@@ -34,7 +32,6 @@ const type_name = @typeName(TestType);
3432const ptr_type_name: [*:0]const u8 = type_name;
3533
3634test "@typeName() returns a string literal" {
37 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3835 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3936 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4037
......@@ -48,7 +45,6 @@ const ptr_actual_contents: [*:0]const u8 = actual_contents;
4845const expected_contents = "hello zig\n";
4946
5047test "@embedFile() returns a string literal" {
51 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5248 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5349 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
5450 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -64,7 +60,7 @@ fn testFnForSrc() std.builtin.SourceLocation {
6460}
6561
6662test "@src() returns a struct containing 0-terminated string slices" {
67 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
63 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6864 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6965 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
7066
test/behavior/struct.zig+17-45
......@@ -10,7 +10,6 @@ const maxInt = std.math.maxInt;
1010top_level_field: i32,
1111
1212test "top level fields" {
13 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1413 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1514
1615 var instance = @This(){
......@@ -87,7 +86,6 @@ const StructFoo = struct {
8786};
8887
8988test "structs" {
90 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9189 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
9290 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9391 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -200,7 +198,6 @@ const MemberFnRand = struct {
200198};
201199
202200test "return struct byval from function" {
203 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
204201 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
205202
206203 const Bar = struct {
......@@ -237,7 +234,6 @@ test "call method with mutable reference to struct with no fields" {
237234}
238235
239236test "struct field init with catch" {
240 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
241237 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
242238
243239 const S = struct {
......@@ -280,7 +276,6 @@ const Val = struct {
280276};
281277
282278test "struct point to self" {
283 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
284279 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
285280 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
286281
......@@ -297,7 +292,6 @@ test "struct point to self" {
297292}
298293
299294test "void struct fields" {
300 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
301295 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
302296
303297 const foo = VoidStructFieldsFoo{
......@@ -335,7 +329,6 @@ fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize {
335329}
336330
337331test "self-referencing struct via array member" {
338 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
339332 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
340333 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
341334 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -492,7 +485,7 @@ const Bitfields = packed struct {
492485};
493486
494487test "packed struct fields are ordered from LSB to MSB" {
495 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
488 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
496489 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
497490 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
498491 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -610,7 +603,6 @@ fn getC(data: *const BitField1) u2 {
610603}
611604
612605test "default struct initialization fields" {
613 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
614606 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
615607
616608 const S = struct {
......@@ -634,8 +626,8 @@ test "default struct initialization fields" {
634626}
635627
636628test "packed array 24bits" {
637 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
638629 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
630 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
639631 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
640632 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
641633
......@@ -701,8 +693,8 @@ const FooArrayOfAligned = packed struct {
701693};
702694
703695test "pointer to packed struct member in a stack variable" {
696 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
704697 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
705 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
706698 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
707699 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
708700 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
......@@ -731,7 +723,6 @@ test "packed struct with u0 field access" {
731723}
732724
733725test "access to global struct fields" {
734 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
735726 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
736727
737728 g_foo.bar.value = 42;
......@@ -753,8 +744,8 @@ const S0 = struct {
753744var g_foo: S0 = S0.init();
754745
755746test "packed struct with fp fields" {
747 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
756748 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
757 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
758749 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
759750 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
760751 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -783,7 +774,6 @@ test "packed struct with fp fields" {
783774
784775test "fn with C calling convention returns struct by value" {
785776 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
786 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
787777 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
788778
789779 const S = struct {
......@@ -807,7 +797,7 @@ test "fn with C calling convention returns struct by value" {
807797}
808798
809799test "non-packed struct with u128 entry in union" {
810 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
800 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
811801 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
812802 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
813803 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -834,8 +824,8 @@ test "non-packed struct with u128 entry in union" {
834824}
835825
836826test "packed struct field passed to generic function" {
827 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
837828 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
838 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
839829 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
840830 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
841831
......@@ -859,7 +849,6 @@ test "packed struct field passed to generic function" {
859849}
860850
861851test "anonymous struct literal syntax" {
862 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
863852 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
864853
865854 const S = struct {
......@@ -951,7 +940,6 @@ test "comptime struct field" {
951940test "tuple element initialized with fn call" {
952941 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
953942 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
954 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
955943 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
956944
957945 const S = struct {
......@@ -968,8 +956,8 @@ test "tuple element initialized with fn call" {
968956}
969957
970958test "struct with union field" {
959 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
971960 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
972 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
973961 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
974962 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
975963
......@@ -990,7 +978,6 @@ test "struct with union field" {
990978}
991979
992980test "struct with 0-length union array field" {
993 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
994981 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
995982 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
996983
......@@ -1039,6 +1026,7 @@ test "packed struct with undefined initializers" {
10391026}
10401027
10411028test "for loop over pointers to struct, getting field from struct pointer" {
1029 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10421030 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10431031 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10441032 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1078,7 +1066,7 @@ test "for loop over pointers to struct, getting field from struct pointer" {
10781066}
10791067
10801068test "anon init through error unions and optionals" {
1081 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1069 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10821070 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10831071 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10841072 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1105,7 +1093,7 @@ test "anon init through error unions and optionals" {
11051093}
11061094
11071095test "anon init through optional" {
1108 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1096 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11091097 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11101098 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11111099 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1125,7 +1113,7 @@ test "anon init through optional" {
11251113}
11261114
11271115test "anon init through error union" {
1128 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1116 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11291117 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11301118 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11311119 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1145,7 +1133,7 @@ test "anon init through error union" {
11451133}
11461134
11471135test "typed init through error unions and optionals" {
1148 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1136 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11491137 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11501138 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11511139
......@@ -1171,7 +1159,6 @@ test "typed init through error unions and optionals" {
11711159}
11721160
11731161test "initialize struct with empty literal" {
1174 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11751162 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11761163
11771164 const S = struct { x: i32 = 1234 };
......@@ -1206,7 +1193,7 @@ test "loading a struct pointer perfoms a copy" {
12061193}
12071194
12081195test "packed struct aggregate init" {
1209 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1196 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12101197 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12111198 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12121199 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1226,7 +1213,7 @@ test "packed struct aggregate init" {
12261213}
12271214
12281215test "packed struct field access via pointer" {
1229 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1216 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12301217 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12311218 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12321219 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1267,7 +1254,6 @@ test "store to comptime field" {
12671254}
12681255
12691256test "struct field init value is size of the struct" {
1270 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12711257 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12721258
12731259 const namespace = struct {
......@@ -1282,7 +1268,6 @@ test "struct field init value is size of the struct" {
12821268}
12831269
12841270test "under-aligned struct field" {
1285 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12861271 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12871272 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12881273 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1306,7 +1291,6 @@ test "under-aligned struct field" {
13061291}
13071292
13081293test "fieldParentPtr of a zero-bit field" {
1309 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13101294 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13111295 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
13121296 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1357,7 +1341,6 @@ test "fieldParentPtr of a zero-bit field" {
13571341
13581342test "struct field has a pointer to an aligned version of itself" {
13591343 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1360 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13611344
13621345 const E = struct {
13631346 next: *align(1) @This(),
......@@ -1437,7 +1420,6 @@ test "discarded struct initialization works as expected" {
14371420}
14381421
14391422test "function pointer in struct returns the struct" {
1440 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14411423 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14421424
14431425 const A = struct {
......@@ -1455,7 +1437,6 @@ test "function pointer in struct returns the struct" {
14551437
14561438test "no dependency loop on optional field wrapped in generic function" {
14571439 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1458 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14591440
14601441 const S = struct {
14611442 fn Atomic(comptime T: type) type {
......@@ -1473,7 +1454,6 @@ test "no dependency loop on optional field wrapped in generic function" {
14731454}
14741455
14751456test "optional field init with tuple" {
1476 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14771457 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14781458
14791459 const S = struct {
......@@ -1488,8 +1468,6 @@ test "optional field init with tuple" {
14881468}
14891469
14901470test "if inside struct init inside if" {
1491 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1492
14931471 const MyStruct = struct { x: u32 };
14941472 const b: u32 = 5;
14951473 var i: u32 = 1;
......@@ -1580,7 +1558,6 @@ test "instantiate struct with comptime field" {
15801558test "struct field pointer has correct alignment" {
15811559 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
15821560 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1583 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15841561 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15851562
15861563 const S = struct {
......@@ -1610,7 +1587,6 @@ test "struct field pointer has correct alignment" {
16101587test "extern struct field pointer has correct alignment" {
16111588 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
16121589 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1613 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16141590 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16151591
16161592 const S = struct {
......@@ -1828,7 +1804,6 @@ test "tuple with comptime-only field" {
18281804}
18291805
18301806test "extern struct fields are aligned to 1" {
1831 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
18321807 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18331808
18341809 const Foo = extern struct {
......@@ -1845,7 +1820,7 @@ test "extern struct fields are aligned to 1" {
18451820}
18461821
18471822test "assign to slice.len of global variable" {
1848 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1823 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
18491824 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18501825 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
18511826 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1897,7 +1872,6 @@ test "array of structs inside struct initialized with undefined" {
18971872}
18981873
18991874test "runtime call in nested initializer" {
1900 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
19011875 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19021876 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
19031877
......@@ -1929,7 +1903,6 @@ test "runtime call in nested initializer" {
19291903}
19301904
19311905test "runtime value in nested initializer passed as pointer to function" {
1932 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
19331906 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19341907
19351908 const Bar = struct {
......@@ -1953,7 +1926,7 @@ test "runtime value in nested initializer passed as pointer to function" {
19531926}
19541927
19551928test "struct field default value is a call" {
1956 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1929 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
19571930 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19581931 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
19591932
......@@ -2001,7 +1974,6 @@ test "aggregate initializers should allow initializing comptime fields, verifyin
20011974
20021975test "assignment of field with padding" {
20031976 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2004 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
20051977 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
20061978
20071979 const Mesh = extern struct {
......@@ -2031,7 +2003,6 @@ test "assignment of field with padding" {
20312003
20322004test "initiate global variable with runtime value" {
20332005 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2034 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
20352006 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
20362007
20372008 const S = struct {
......@@ -2126,6 +2097,7 @@ test "anonymous struct equivalence" {
21262097}
21272098
21282099test "field access through mem ptr arg" {
2100 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
21292101 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
21302102
21312103 const S = struct {
test/behavior/struct_contains_null_ptr_itself.zig-1
......@@ -3,7 +3,6 @@ const expect = std.testing.expect;
33const builtin = @import("builtin");
44
55test "struct contains null pointer which contains original struct" {
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
76 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
98
test/behavior/struct_contains_slice_of_itself.zig+2-1
......@@ -12,6 +12,7 @@ const NodeAligned = struct {
1212};
1313
1414test "struct contains slice of itself" {
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1516 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1617 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1718
......@@ -52,7 +53,7 @@ test "struct contains slice of itself" {
5253}
5354
5455test "struct contains aligned slice of itself" {
55 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
56 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5657 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5758 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
5859
test/behavior/switch.zig+20-13
......@@ -8,6 +8,7 @@ const minInt = std.math.minInt;
88const maxInt = std.math.maxInt;
99
1010test "switch with numbers" {
11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1112 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1213 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1314
......@@ -43,7 +44,7 @@ fn testSwitchWithAllRanges(x: u32, y: u32) u32 {
4344}
4445
4546test "switch arbitrary int size" {
46 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
47 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4748 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4849 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4950 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -274,8 +275,8 @@ const SwitchProngWithVarEnum = union(enum) {
274275};
275276
276277test "switch prong with variable" {
278 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
277279 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
278 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
279280 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
280281 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
281282
......@@ -299,8 +300,8 @@ fn switchProngWithVarFn(a: SwitchProngWithVarEnum) !void {
299300}
300301
301302test "switch on enum using pointer capture" {
303 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
302304 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
303 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
304305 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
305306
306307 try testSwitchEnumPtrCapture();
......@@ -360,8 +361,8 @@ fn testSwitchHandleAllCasesRange(x: u8) u8 {
360361}
361362
362363test "switch on union with some prongs capturing" {
364 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
363365 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
364 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
365366 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
366367
367368 const X = union(enum) {
......@@ -398,7 +399,6 @@ test "switch on const enum with var" {
398399}
399400
400401test "anon enum literal used in switch on union enum" {
401 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
402402 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
403403
404404 const Foo = union(enum) {
......@@ -469,8 +469,8 @@ test "switch on integer with else capturing expr" {
469469}
470470
471471test "else prong of switch on error set excludes other cases" {
472 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
472473 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
473 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
474474 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
475475 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
476476 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -505,8 +505,8 @@ test "else prong of switch on error set excludes other cases" {
505505}
506506
507507test "switch prongs with error set cases make a new error set type for capture value" {
508 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
508509 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
509 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
510510 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
511511 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
512512 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -563,7 +563,6 @@ test "return result loc and then switch with range implicit casted to error unio
563563
564564test "switch with null and T peer types and inferred result location type" {
565565 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
566 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
567566 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
568567
569568 const S = struct {
......@@ -582,7 +581,7 @@ test "switch with null and T peer types and inferred result location type" {
582581}
583582
584583test "switch prongs with cases with identical payload types" {
585 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
584 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
586585 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
587586 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
588587
......@@ -689,7 +688,7 @@ test "switch prong pointer capture alignment" {
689688}
690689
691690test "switch on pointer type" {
692 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
691 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
693692 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
694693 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
695694
......@@ -737,8 +736,8 @@ test "switch on error set with single else" {
737736}
738737
739738test "switch capture copies its payload" {
739 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
740740 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
741 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
742741 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
743742 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
744743
......@@ -831,6 +830,7 @@ test "comptime inline switch" {
831830}
832831
833832test "switch capture peer type resolution" {
833 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
834834 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
835835
836836 const U = union(enum) {
......@@ -848,6 +848,8 @@ test "switch capture peer type resolution" {
848848}
849849
850850test "switch capture peer type resolution for in-memory coercible payloads" {
851 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
852
851853 const T1 = c_int;
852854 const T2 = @Type(@typeInfo(T1));
853855
......@@ -868,6 +870,8 @@ test "switch capture peer type resolution for in-memory coercible payloads" {
868870}
869871
870872test "switch pointer capture peer type resolution" {
873 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
874
871875 const T1 = c_int;
872876 const T2 = @Type(@typeInfo(T1));
873877
......@@ -904,6 +908,7 @@ test "inline switch range that includes the maximum value of the switched type"
904908}
905909
906910test "nested break ignores switch conditions and breaks instead" {
911 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
907912 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
908913 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
909914
......@@ -926,6 +931,7 @@ test "nested break ignores switch conditions and breaks instead" {
926931}
927932
928933test "peer type resolution on switch captures ignores unused payload bits" {
934 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
929935 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
930936 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
931937
......@@ -951,7 +957,6 @@ test "peer type resolution on switch captures ignores unused payload bits" {
951957}
952958
953959test "switch prong captures range" {
954 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
955960 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
956961 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
957962
......@@ -971,6 +976,8 @@ test "switch prong captures range" {
971976}
972977
973978test "prong with inline call to unreachable" {
979 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
980
974981 const U = union(enum) {
975982 void: void,
976983 bool: bool,
......@@ -1042,7 +1049,7 @@ test "labeled switch with break" {
10421049}
10431050
10441051test "unlabeled break ignores switch" {
1045 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1052 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10461053 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10471054 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10481055 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
test/behavior/switch_loop.zig+7-9
......@@ -3,7 +3,7 @@ const std = @import("std");
33const expect = std.testing.expect;
44
55test "simple switch loop" {
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
77 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
88 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
99 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -27,7 +27,7 @@ test "simple switch loop" {
2727}
2828
2929test "switch loop with ranges" {
30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3131 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
3232 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3333 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -48,7 +48,7 @@ test "switch loop with ranges" {
4848}
4949
5050test "switch loop on enum" {
51 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
51 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5252 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5353 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5454 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -72,7 +72,7 @@ test "switch loop on enum" {
7272}
7373
7474test "switch loop with error set" {
75 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
75 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7676 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7777 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7878 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -96,7 +96,7 @@ test "switch loop with error set" {
9696}
9797
9898test "switch loop on tagged union" {
99 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
99 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
100100 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
101101 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
102102 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -129,7 +129,7 @@ test "switch loop on tagged union" {
129129}
130130
131131test "switch loop dispatching instructions" {
132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
133133 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
134134 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
135135 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -179,7 +179,7 @@ test "switch loop dispatching instructions" {
179179}
180180
181181test "switch loop with pointer capture" {
182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
183183 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
184184 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
185185 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
......@@ -218,8 +218,6 @@ test "switch loop with pointer capture" {
218218}
219219
220220test "unanalyzed continue with operand" {
221 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
222
223221 @setRuntimeSafety(false);
224222 label: switch (false) {
225223 false => if (false) continue :label true,
test/behavior/switch_on_captured_error.zig+2
......@@ -6,6 +6,7 @@ const expectEqual = std.testing.expectEqual;
66const builtin = @import("builtin");
77
88test "switch on error union catch capture" {
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
910 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1011 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1112
......@@ -300,6 +301,7 @@ test "switch on error union catch capture" {
300301}
301302
302303test "switch on error union if else capture" {
304 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
303305 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
304306 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
305307
test/behavior/switch_prong_err_enum.zig+1-1
......@@ -21,8 +21,8 @@ fn doThing(form_id: u64) anyerror!FormValue {
2121}
2222
2323test "switch prong returns error enum" {
24 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2524 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
25 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2626 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2727 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2828
test/behavior/switch_prong_implicit_cast.zig+1-1
......@@ -15,8 +15,8 @@ fn foo(id: u64) !FormValue {
1515}
1616
1717test "switch prong implicit cast" {
18 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1918 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
19 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2020 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2121
2222 const result = switch (foo(2) catch unreachable) {
test/behavior/this.zig-2
......@@ -26,7 +26,6 @@ test "this refer to module call private fn" {
2626}
2727
2828test "this refer to container" {
29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3029 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3130
3231 var pt: Point(i32) = undefined;
......@@ -47,7 +46,6 @@ fn prev(p: ?State) void {
4746}
4847
4948test "this used as optional function parameter" {
50 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5149 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
5250 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5351 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/threadlocal.zig-3
......@@ -4,7 +4,6 @@ const expect = std.testing.expect;
44
55test "thread local variable" {
66 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -25,7 +24,6 @@ test "thread local variable" {
2524
2625test "pointer to thread local array" {
2726 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2927 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
3028 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3129 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -40,7 +38,6 @@ threadlocal var buffer: [11]u8 = undefined;
4038
4139test "reference a global threadlocal variable" {
4240 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
43 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4441 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4542 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4643 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/truncate.zig+1-1
......@@ -65,8 +65,8 @@ test "truncate on comptime integer" {
6565}
6666
6767test "truncate on vectors" {
68 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
6968 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
69 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
7070 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7171 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7272 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/try.zig+1-2
......@@ -47,7 +47,7 @@ test "try then not executed with assignment" {
4747}
4848
4949test "`try`ing an if/else expression" {
50 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
50 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5151 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5252 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
5353 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -68,7 +68,6 @@ test "`try`ing an if/else expression" {
6868}
6969
7070test "'return try' of empty error set in function returning non-error" {
71 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7271 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7372 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
7473
test/behavior/tuple.zig+2-20
......@@ -8,7 +8,6 @@ const expectEqual = std.testing.expectEqual;
88
99test "tuple concatenation" {
1010 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1211 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1312
1413 const S = struct {
......@@ -51,7 +50,6 @@ test "tuple multiplication" {
5150}
5251
5352test "more tuple concatenation" {
54 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5553 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5654 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5755 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -129,7 +127,6 @@ test "tuple initializer for var" {
129127}
130128
131129test "array-like initializer for tuple types" {
132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
133130 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
134131 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
135132
......@@ -216,7 +213,6 @@ test "initializing anon struct with explicit type" {
216213}
217214
218215test "fieldParentPtr of tuple" {
219 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
220216 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
221217 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
222218 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -229,7 +225,6 @@ test "fieldParentPtr of tuple" {
229225}
230226
231227test "fieldParentPtr of anon struct" {
232 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
233228 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
234229 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
235230 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -256,7 +251,6 @@ test "offsetOf anon struct" {
256251}
257252
258253test "initializing tuple with mixed comptime-runtime fields" {
259 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
260254 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
261255
262256 var x: u32 = 15;
......@@ -268,7 +262,6 @@ test "initializing tuple with mixed comptime-runtime fields" {
268262}
269263
270264test "initializing anon struct with mixed comptime-runtime fields" {
271 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
272265 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
273266
274267 var x: u32 = 15;
......@@ -280,7 +273,6 @@ test "initializing anon struct with mixed comptime-runtime fields" {
280273}
281274
282275test "tuple in tuple passed to generic function" {
283 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
284276 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
285277 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
286278 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -300,7 +292,6 @@ test "tuple in tuple passed to generic function" {
300292}
301293
302294test "coerce tuple to tuple" {
303 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
304295 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
305296 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
306297 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -315,7 +306,6 @@ test "coerce tuple to tuple" {
315306}
316307
317308test "tuple type with void field" {
318 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
319309 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
320310 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
321311 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -353,7 +343,6 @@ test "zero sized struct in tuple handled correctly" {
353343}
354344
355345test "tuple type with void field and a runtime field" {
356 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
357346 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
358347 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
359348
......@@ -364,7 +353,6 @@ test "tuple type with void field and a runtime field" {
364353}
365354
366355test "branching inside tuple literal" {
367 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
368356 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
369357 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
370358
......@@ -410,7 +398,6 @@ test "tuple of struct concatenation and coercion to array" {
410398}
411399
412400test "nested runtime conditionals in tuple initializer" {
413 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
414401 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
415402 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
416403 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -446,7 +433,6 @@ test "sentinel slice in tuple" {
446433}
447434
448435test "tuple pointer is indexable" {
449 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
450436 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
451437 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
452438 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -470,7 +456,6 @@ test "tuple pointer is indexable" {
470456}
471457
472458test "coerce anon tuple to tuple" {
473 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
474459 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
475460 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
476461
......@@ -496,14 +481,12 @@ test "empty tuple type" {
496481}
497482
498483test "tuple with comptime fields with non empty initializer" {
499 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
500
501484 const a: struct { comptime comptime_int = 0 } = .{0};
502485 _ = a;
503486}
504487
505488test "tuple with runtime value coerced into a slice with a sentinel" {
506 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
489 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
507490 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
508491 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
509492 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -578,7 +561,6 @@ test "comptime fields in tuple can be initialized" {
578561
579562test "empty struct in tuple" {
580563 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
581 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
582564 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
583565 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
584566
......@@ -591,7 +573,6 @@ test "empty struct in tuple" {
591573
592574test "empty union in tuple" {
593575 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
594 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
595576 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
596577 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
597578
......@@ -604,6 +585,7 @@ test "empty union in tuple" {
604585
605586test "field pointer of underaligned tuple" {
606587 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
588
607589 const S = struct {
608590 fn doTheTest() !void {
609591 const T = struct { u8, u32 };
test/behavior/tuple_declarations.zig-2
......@@ -5,7 +5,6 @@ const expect = testing.expect;
55const expectEqualStrings = testing.expectEqualStrings;
66
77test "tuple declaration type info" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
98 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
109 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1110
......@@ -34,7 +33,6 @@ test "tuple declaration type info" {
3433}
3534
3635test "tuple declaration usage" {
37 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
3836 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3937 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4038
test/behavior/type.zig+3-6
......@@ -200,8 +200,8 @@ test "Type.ErrorUnion" {
200200}
201201
202202test "Type.Opaque" {
203 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
203204 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
204 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
205205 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
206206 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
207207
......@@ -258,8 +258,8 @@ test "Type.ErrorSet" {
258258}
259259
260260test "Type.Struct" {
261 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
261262 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
262 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
263263 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
264264 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
265265
......@@ -348,7 +348,6 @@ test "Type.Struct" {
348348
349349test "Type.Enum" {
350350 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
351 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
352351 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
353352
354353 const Foo = @Type(.{
......@@ -409,8 +408,8 @@ test "Type.Enum" {
409408}
410409
411410test "Type.Union" {
411 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
412412 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
413 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
414413 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
415414
416415 const Untagged = @Type(.{
......@@ -547,7 +546,6 @@ test "Type.Union from empty Type.Enum" {
547546
548547test "Type.Fn" {
549548 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
550 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
551549
552550 const some_opaque = opaque {};
553551 const some_ptr = *some_opaque;
......@@ -724,7 +722,6 @@ test "@Type should resolve its children types" {
724722}
725723
726724test "struct field names sliced at comptime from larger string" {
727 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
728725 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
729726
730727 const text =
test/behavior/type_info.zig+2-4
......@@ -158,7 +158,6 @@ fn testArray() !void {
158158}
159159
160160test "type info: error set, error union info, anyerror" {
161 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
162161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
163162 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
164163 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -190,7 +189,6 @@ fn testErrorSet() !void {
190189}
191190
192191test "type info: error set single value" {
193 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
194192 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
195193 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
196194 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -204,7 +202,6 @@ test "type info: error set single value" {
204202}
205203
206204test "type info: error set merged" {
207 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
208205 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
209206 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
210207 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -221,7 +218,6 @@ test "type info: error set merged" {
221218
222219test "type info: enum info" {
223220 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
224 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
225221 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
226222 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
227223
......@@ -362,6 +358,8 @@ test "type info: function type info" {
362358}
363359
364360fn testFunction() !void {
361 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
362
365363 const S = struct {
366364 export fn typeInfoFoo() callconv(.c) usize {
367365 unreachable;
test/behavior/typename.zig-8
......@@ -12,7 +12,6 @@ const expectStringStartsWith = std.testing.expectStringStartsWith;
1212// failures.
1313
1414test "anon fn param" {
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1615 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1716 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1817 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -38,7 +37,6 @@ test "anon fn param" {
3837}
3938
4039test "anon field init" {
41 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4240 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4341 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4442 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -64,7 +62,6 @@ test "anon field init" {
6462}
6563
6664test "basic" {
67 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6865 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
6966 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7067 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -86,7 +83,6 @@ test "basic" {
8683}
8784
8885test "top level decl" {
89 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9086 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9187 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9288 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -136,7 +132,6 @@ const B = struct {
136132};
137133
138134test "fn param" {
139 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
140135 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
141136 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
142137 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -216,7 +211,6 @@ pub fn expectEqualStringsIgnoreDigits(expected: []const u8, actual: []const u8)
216211}
217212
218213test "local variable" {
219 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
220214 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
221215 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
222216 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -235,7 +229,6 @@ test "local variable" {
235229}
236230
237231test "comptime parameters not converted to anytype in function type" {
238 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
239232 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
240233 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
241234 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -245,7 +238,6 @@ test "comptime parameters not converted to anytype in function type" {
245238}
246239
247240test "anon name strategy used in sub expression" {
248 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
249241 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
250242 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
251243 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/undefined.zig-4
......@@ -46,7 +46,6 @@ fn setFooX(foo: *Foo) void {
4646
4747test "assign undefined to struct" {
4848 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
49 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5049 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5150
5251 comptime {
......@@ -63,7 +62,6 @@ test "assign undefined to struct" {
6362
6463test "assign undefined to struct with method" {
6564 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
66 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6765 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6866
6967 comptime {
......@@ -89,7 +87,6 @@ test "type name of undefined" {
8987var buf: []u8 = undefined;
9088
9189test "reslice of undefined global var slice" {
92 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9390 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9491 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
9592
......@@ -100,7 +97,6 @@ test "reslice of undefined global var slice" {
10097}
10198
10299test "returned undef is 0xaa bytes when runtime safety is enabled" {
103 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
104100 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
105101 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
106102 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/union.zig+60-60
......@@ -12,8 +12,8 @@ const FooWithFloats = union {
1212};
1313
1414test "basic unions with floats" {
15 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1615 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1717 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1818 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1919 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -29,8 +29,8 @@ fn setFloat(foo: *FooWithFloats, x: f64) void {
2929}
3030
3131test "init union with runtime value - floats" {
32 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3332 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
33 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
3434 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3535 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3636
......@@ -60,8 +60,8 @@ const Foo = union {
6060};
6161
6262test "init union with runtime value" {
63 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
6463 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
64 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
6565 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6666 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
6767 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -160,8 +160,8 @@ test "unions embedded in aggregate types" {
160160}
161161
162162test "constant tagged union with payload" {
163 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
164163 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
164 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
165165 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
166166
167167 var empty = TaggedUnionWithPayload{ .Empty = {} };
......@@ -210,8 +210,8 @@ const Payload = union(Letter) {
210210};
211211
212212test "union with specified enum tag" {
213 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
214213 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
214 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
215215 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
216216 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
217217 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -221,8 +221,8 @@ test "union with specified enum tag" {
221221}
222222
223223test "packed union generates correctly aligned type" {
224 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
225224 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
225 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
226226 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
227227 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
228228 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -263,8 +263,8 @@ fn testComparison() !void {
263263}
264264
265265test "comparison between union and enum literal" {
266 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
267266 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
267 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
268268 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
269269 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
270270
......@@ -279,8 +279,8 @@ const TheUnion = union(TheTag) {
279279 C: i32,
280280};
281281test "cast union to tag type of union" {
282 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
283282 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
283 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
284284 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
285285
286286 try testCastUnionToTag();
......@@ -300,8 +300,8 @@ test "union field access gives the enum values" {
300300}
301301
302302test "cast tag type of union to union" {
303 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
304303 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
304 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
305305 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
306306
307307 var x: Value2 = Letter2.B;
......@@ -316,8 +316,8 @@ const Value2 = union(Letter2) {
316316};
317317
318318test "implicit cast union to its tag type" {
319 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
320319 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
320 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
321321 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
322322
323323 var x: Value2 = Letter2.B;
......@@ -337,8 +337,8 @@ pub const PackThis = union(enum) {
337337};
338338
339339test "constant packed union" {
340 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
341340 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
341 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
342342 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
343343 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
344344
......@@ -357,7 +357,6 @@ const MultipleChoice = union(enum(u32)) {
357357};
358358test "simple union(enum(u32))" {
359359 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
360 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
361360 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
362361
363362 var x = MultipleChoice.C;
......@@ -403,7 +402,6 @@ test "assigning to union with zero size field" {
403402
404403test "tagged union initialization with runtime void" {
405404 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
406 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
407405 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
408406
409407 try expect(testTaggedUnionInit({}));
......@@ -423,7 +421,6 @@ pub const UnionEnumNoPayloads = union(enum) { A, B };
423421
424422test "tagged union with no payloads" {
425423 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
426 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
427424 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
428425
429426 const a = UnionEnumNoPayloads{ .B = {} };
......@@ -470,7 +467,6 @@ var glbl: Foo1 = undefined;
470467
471468test "global union with single field is correctly initialized" {
472469 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
473 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
474470 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
475471
476472 glbl = Foo1{
......@@ -487,8 +483,8 @@ pub const FooUnion = union(enum) {
487483var glbl_array: [2]FooUnion = undefined;
488484
489485test "initialize global array of union" {
490 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
491486 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
487 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
492488 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
493489 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
494490
......@@ -499,8 +495,8 @@ test "initialize global array of union" {
499495}
500496
501497test "update the tag value for zero-sized unions" {
502 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
503498 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
499 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
504500 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
505501
506502 const S = union(enum) {
......@@ -515,7 +511,6 @@ test "update the tag value for zero-sized unions" {
515511
516512test "union initializer generates padding only if needed" {
517513 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
518 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
519514 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
520515
521516 const U = union(enum) {
......@@ -528,7 +523,6 @@ test "union initializer generates padding only if needed" {
528523}
529524
530525test "runtime tag name with single field" {
531 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
532526 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
533527 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
534528
......@@ -543,7 +537,6 @@ test "runtime tag name with single field" {
543537
544538test "method call on an empty union" {
545539 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
546 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
547540 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
548541
549542 const S = struct {
......@@ -604,8 +597,8 @@ test "tagged union type" {
604597}
605598
606599test "tagged union as return value" {
607 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
608600 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
601 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
609602 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
610603 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
611604 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -621,8 +614,8 @@ fn returnAnInt(x: i32) TaggedFoo {
621614}
622615
623616test "tagged union with all void fields but a meaningful tag" {
624 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
625617 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
618 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
626619 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
627620
628621 const S = struct {
......@@ -649,8 +642,8 @@ test "tagged union with all void fields but a meaningful tag" {
649642}
650643
651644test "union(enum(u32)) with specified and unspecified tag values" {
652 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
653645 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
646 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
654647 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
655648 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
656649
......@@ -687,7 +680,6 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void {
687680}
688681
689682test "switch on union with only 1 field" {
690 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
691683 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
692684 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
693685
......@@ -742,8 +734,8 @@ test "union with only 1 field casted to its enum type which has enum value speci
742734}
743735
744736test "@intFromEnum works on unions" {
737 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
745738 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
746 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
747739 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
748740
749741 const Bar = union(enum) {
......@@ -801,8 +793,8 @@ fn Setter(comptime attr: Attribute) type {
801793}
802794
803795test "return union init with void payload" {
804 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
805796 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
797 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
806798 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
807799
808800 const S = struct {
......@@ -825,7 +817,7 @@ test "return union init with void payload" {
825817}
826818
827819test "@unionInit stored to a const" {
828 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
820 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
829821 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
830822 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
831823 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -856,7 +848,7 @@ test "@unionInit stored to a const" {
856848}
857849
858850test "@unionInit can modify a union type" {
859 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
851 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
860852 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
861853 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
862854
......@@ -879,7 +871,7 @@ test "@unionInit can modify a union type" {
879871}
880872
881873test "@unionInit can modify a pointer value" {
882 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
874 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
883875 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
884876 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
885877
......@@ -899,7 +891,6 @@ test "@unionInit can modify a pointer value" {
899891}
900892
901893test "union no tag with struct member" {
902 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
903894 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
904895 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
905896 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -935,8 +926,8 @@ test "extern union doesn't trigger field check at comptime" {
935926}
936927
937928test "anonymous union literal syntax" {
929 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
938930 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
939 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
940931 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
941932 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
942933 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -964,8 +955,8 @@ test "anonymous union literal syntax" {
964955}
965956
966957test "function call result coerces from tagged union to the tag" {
958 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
967959 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
968 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
969960 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
970961
971962 const S = struct {
......@@ -999,8 +990,8 @@ test "function call result coerces from tagged union to the tag" {
999990}
1000991
1001992test "switching on non exhaustive union" {
993 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1002994 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1003 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1004995 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1005996
1006997 const S = struct {
......@@ -1028,7 +1019,6 @@ test "switching on non exhaustive union" {
10281019
10291020test "containers with single-field enums" {
10301021 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1031 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10321022 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10331023
10341024 const S = struct {
......@@ -1057,8 +1047,8 @@ test "containers with single-field enums" {
10571047}
10581048
10591049test "@unionInit on union with tag but no fields" {
1050 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10601051 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1061 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10621052 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10631053
10641054 const S = struct {
......@@ -1106,7 +1096,7 @@ test "union enum type gets a separate scope" {
11061096}
11071097
11081098test "global variable struct contains union initialized to non-most-aligned field" {
1109 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1099 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11101100 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11111101 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11121102 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1133,8 +1123,8 @@ test "global variable struct contains union initialized to non-most-aligned fiel
11331123}
11341124
11351125test "union with no result loc initiated with a runtime value" {
1126 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11361127 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1137 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11381128 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11391129 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11401130
......@@ -1151,8 +1141,8 @@ test "union with no result loc initiated with a runtime value" {
11511141}
11521142
11531143test "union with a large struct field" {
1144 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11541145 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11561146 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11571147 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11581148
......@@ -1186,8 +1176,8 @@ test "comptime equality of extern unions with same tag" {
11861176}
11871177
11881178test "union tag is set when initiated as a temporary value at runtime" {
1179 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11891180 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1190 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11911181 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11921182 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11931183
......@@ -1206,8 +1196,8 @@ test "union tag is set when initiated as a temporary value at runtime" {
12061196}
12071197
12081198test "extern union most-aligned field is smaller" {
1199 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12091200 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1210 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12111201 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12121202 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
12131203
......@@ -1226,8 +1216,8 @@ test "extern union most-aligned field is smaller" {
12261216}
12271217
12281218test "return an extern union from C calling convention" {
1219 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12291220 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1230 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12311221 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12321222 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12331223
......@@ -1258,7 +1248,7 @@ test "return an extern union from C calling convention" {
12581248}
12591249
12601250test "noreturn field in union" {
1261 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1251 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12621252 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12631253 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12641254
......@@ -1309,7 +1299,7 @@ test "noreturn field in union" {
13091299}
13101300
13111301test "@unionInit uses tag value instead of field index" {
1312 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1302 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13131303 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13141304 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13151305 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1339,7 +1329,6 @@ test "@unionInit uses tag value instead of field index" {
13391329}
13401330
13411331test "union field ptr - zero sized payload" {
1342 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13431332 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13441333 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13451334 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1354,7 +1343,6 @@ test "union field ptr - zero sized payload" {
13541343}
13551344
13561345test "union field ptr - zero sized field" {
1357 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13581346 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13591347 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13601348 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1369,7 +1357,7 @@ test "union field ptr - zero sized field" {
13691357}
13701358
13711359test "packed union in packed struct" {
1372 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1360 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13731361 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13741362 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13751363
......@@ -1420,8 +1408,8 @@ test "union int tag type is properly managed" {
14201408}
14211409
14221410test "no dependency loop when function pointer in union returns the union" {
1411 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14231412 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1424 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14251413 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14261414 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14271415
......@@ -1442,7 +1430,7 @@ test "no dependency loop when function pointer in union returns the union" {
14421430}
14431431
14441432test "union reassignment can use previous value" {
1445 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1433 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14461434 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14471435 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14481436
......@@ -1456,7 +1444,7 @@ test "union reassignment can use previous value" {
14561444}
14571445
14581446test "packed union with zero-bit field" {
1459 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1447 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14601448 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14611449 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14621450
......@@ -1475,7 +1463,7 @@ test "packed union with zero-bit field" {
14751463}
14761464
14771465test "reinterpreting enum value inside packed union" {
1478 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1466 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14791467 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14801468
14811469 const U = packed union {
......@@ -1493,7 +1481,7 @@ test "reinterpreting enum value inside packed union" {
14931481}
14941482
14951483test "access the tag of a global tagged union" {
1496 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1484 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14971485
14981486 const U = union(enum) {
14991487 a,
......@@ -1504,7 +1492,7 @@ test "access the tag of a global tagged union" {
15041492}
15051493
15061494test "coerce enum literal to union in result loc" {
1507 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1495 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
15081496
15091497 const U = union(enum) {
15101498 a,
......@@ -1522,7 +1510,6 @@ test "coerce enum literal to union in result loc" {
15221510test "defined-layout union field pointer has correct alignment" {
15231511 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
15241512 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1525 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15261513 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15271514
15281515 const S = struct {
......@@ -1557,7 +1544,6 @@ test "defined-layout union field pointer has correct alignment" {
15571544test "undefined-layout union field pointer has correct alignment" {
15581545 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
15591546 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1560 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15611547 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15621548
15631549 const S = struct {
......@@ -1590,8 +1576,8 @@ test "undefined-layout union field pointer has correct alignment" {
15901576}
15911577
15921578test "packed union field pointer has correct alignment" {
1579 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
15931580 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1594 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15951581 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15961582 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
15971583
......@@ -1624,6 +1610,7 @@ test "packed union field pointer has correct alignment" {
16241610}
16251611
16261612test "union with 128 bit integer" {
1613 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16271614 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16281615
16291616 const ValueTag = enum { int, other };
......@@ -1647,6 +1634,7 @@ test "union with 128 bit integer" {
16471634}
16481635
16491636test "memset extern union" {
1637 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16501638 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16511639
16521640 const U = extern union {
......@@ -1668,6 +1656,7 @@ test "memset extern union" {
16681656}
16691657
16701658test "memset packed union" {
1659 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16711660 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16721661
16731662 const U = packed union {
......@@ -1768,6 +1757,7 @@ test "reinterpret extern union" {
17681757}
17691758
17701759test "reinterpret packed union" {
1760 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
17711761 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
17721762
17731763 const U = packed union {
......@@ -1840,6 +1830,7 @@ test "reinterpret packed union" {
18401830}
18411831
18421832test "reinterpret packed union inside packed struct" {
1833 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
18431834 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
18441835 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
18451836
......@@ -1945,6 +1936,8 @@ test "extern union initialized via reintepreted struct field initializer" {
19451936}
19461937
19471938test "packed union initialized via reintepreted struct field initializer" {
1939 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1940
19481941 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
19491942
19501943 const U = packed union {
......@@ -1963,6 +1956,7 @@ test "packed union initialized via reintepreted struct field initializer" {
19631956}
19641957
19651958test "store of comptime reinterpreted memory to extern union" {
1959 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
19661960 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
19671961
19681962 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
......@@ -1985,6 +1979,8 @@ test "store of comptime reinterpreted memory to extern union" {
19851979}
19861980
19871981test "store of comptime reinterpreted memory to packed union" {
1982 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1983
19881984 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
19891985
19901986 const U = packed union {
......@@ -2005,7 +2001,6 @@ test "store of comptime reinterpreted memory to packed union" {
20052001}
20062002
20072003test "union field is a pointer to an aligned version of itself" {
2008 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
20092004 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20102005 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
20112006
......@@ -2019,6 +2014,7 @@ test "union field is a pointer to an aligned version of itself" {
20192014}
20202015
20212016test "pass register-sized field as non-register-sized union" {
2017 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
20222018 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20232019 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
20242020
......@@ -2067,6 +2063,7 @@ test "circular dependency through pointer field of a union" {
20672063}
20682064
20692065test "pass nested union with rls" {
2066 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
20702067 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
20712068 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
20722069
......@@ -2088,8 +2085,8 @@ test "pass nested union with rls" {
20882085}
20892086
20902087test "runtime union init, most-aligned field != largest" {
2088 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
20912089 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2092 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
20932090 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
20942091 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
20952092 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -2114,8 +2111,8 @@ test "runtime union init, most-aligned field != largest" {
21142111}
21152112
21162113test "copied union field doesn't alias source" {
2114 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
21172115 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2118 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
21192116 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
21202117 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
21212118
......@@ -2134,7 +2131,7 @@ test "copied union field doesn't alias source" {
21342131}
21352132
21362133test "create union(enum) from other union(enum)" {
2137 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2134 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
21382135 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
21392136 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
21402137 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -2258,7 +2255,7 @@ test "matching captures causes union equivalence" {
22582255}
22592256
22602257test "signed enum tag with negative value" {
2261 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2258 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
22622259 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
22632260 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
22642261 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -2315,6 +2312,7 @@ test "extern union @FieldType" {
23152312}
23162313
23172314test "assign global tagged union" {
2315 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
23182316 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
23192317
23202318 const U = union(enum) {
......@@ -2336,6 +2334,8 @@ test "assign global tagged union" {
23362334}
23372335
23382336test "set mutable union by switching on same union" {
2337 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2338
23392339 const U = union(enum) {
23402340 foo,
23412341 bar: usize,
test/behavior/union_with_members.zig+1-1
......@@ -17,8 +17,8 @@ const ET = union(enum) {
1717};
1818
1919test "enum with members" {
20 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2021 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
21 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2222 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2323 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2424
test/behavior/var_args.zig+10-12
......@@ -28,7 +28,6 @@ test "send void arg to var args" {
2828}
2929
3030test "pass args directly" {
31 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3231 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3332
3433 try expect(addSomeStuff(.{ @as(i32, 1), @as(i32, 2), @as(i32, 3), @as(i32, 4) }) == 10);
......@@ -41,7 +40,6 @@ fn addSomeStuff(args: anytype) i32 {
4140}
4241
4342test "runtime parameter before var args" {
44 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4543 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4644
4745 try expect((try extraFn(10, .{})) == 0);
......@@ -94,13 +92,13 @@ fn doNothingWithFirstArg(args: anytype) void {
9492}
9593
9694test "simple variadic function" {
97 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
95 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9896 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9997 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10098 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
10199 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
102100 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
103 if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
101 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
104102 // https://github.com/ziglang/zig/issues/14096
105103 return error.SkipZigTest;
106104 }
......@@ -156,13 +154,13 @@ test "simple variadic function" {
156154}
157155
158156test "coerce reference to var arg" {
159 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
157 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
160158 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
161159 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
162160 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
163161 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
164162 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
165 if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
163 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
166164 // https://github.com/ziglang/zig/issues/14096
167165 return error.SkipZigTest;
168166 }
......@@ -189,13 +187,13 @@ test "coerce reference to var arg" {
189187}
190188
191189test "variadic functions" {
192 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
190 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
193191 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
194192 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
195193 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
196194 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
197195 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
198 if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
196 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
199197 // https://github.com/ziglang/zig/issues/14096
200198 return error.SkipZigTest;
201199 }
......@@ -236,12 +234,12 @@ test "variadic functions" {
236234}
237235
238236test "copy VaList" {
239 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
237 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
240238 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
241239 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
242240 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
243241 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
244 if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
242 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
245243 // https://github.com/ziglang/zig/issues/14096
246244 return error.SkipZigTest;
247245 }
......@@ -271,12 +269,12 @@ test "copy VaList" {
271269}
272270
273271test "unused VaList arg" {
274 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
272 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
275273 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
276274 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
277275 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
278276 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
279 if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
277 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
280278 // https://github.com/ziglang/zig/issues/14096
281279 return error.SkipZigTest;
282280 }
test/behavior/vector.zig+43-55
......@@ -8,7 +8,6 @@ const expectEqual = std.testing.expectEqual;
88
99test "implicit cast vector to array - bool" {
1010 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1211 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1312 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1413 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -25,8 +24,8 @@ test "implicit cast vector to array - bool" {
2524}
2625
2726test "vector wrap operators" {
27 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2828 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3029 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
3130 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3231 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -49,8 +48,8 @@ test "vector wrap operators" {
4948}
5049
5150test "vector bin compares with mem.eql" {
51 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5252 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
53 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5453 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5554 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5655 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -74,8 +73,8 @@ test "vector bin compares with mem.eql" {
7473}
7574
7675test "vector int operators" {
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7777 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
78 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7978 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8079 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8180 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -97,8 +96,8 @@ test "vector int operators" {
9796}
9897
9998test "vector float operators" {
99 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
100100 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
101 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
102101 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
103102 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
104103 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -141,8 +140,8 @@ test "vector float operators" {
141140}
142141
143142test "vector bit operators" {
143 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
144144 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
145 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
146145 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
147146 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
148147 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -173,7 +172,7 @@ test "vector bit operators" {
173172}
174173
175174test "implicit cast vector to array" {
176 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
175 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
177176 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
178177 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
179178 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -193,7 +192,7 @@ test "implicit cast vector to array" {
193192}
194193
195194test "array to vector" {
196 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
195 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
197196 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
198197 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
199198 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -212,7 +211,7 @@ test "array to vector" {
212211}
213212
214213test "array vector coercion - odd sizes" {
215 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
214 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
216215 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
217216 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
218217 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
......@@ -251,7 +250,7 @@ test "array vector coercion - odd sizes" {
251250}
252251
253252test "array to vector with element type coercion" {
254 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
253 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
255254 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
256255 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
257256 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
......@@ -273,7 +272,6 @@ test "array to vector with element type coercion" {
273272
274273test "peer type resolution with coercible element types" {
275274 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
276 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
277275 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
278276 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
279277
......@@ -291,8 +289,8 @@ test "peer type resolution with coercible element types" {
291289}
292290
293291test "tuple to vector" {
292 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
294293 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
295 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
296294 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
297295 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
298296 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -314,8 +312,8 @@ test "tuple to vector" {
314312}
315313
316314test "vector casts of sizes not divisible by 8" {
315 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
317316 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
318 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
319317 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
320318 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
321319 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -354,7 +352,7 @@ test "vector casts of sizes not divisible by 8" {
354352}
355353
356354test "vector @splat" {
357 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
355 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
358356 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
359357 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
360358 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -395,7 +393,7 @@ test "vector @splat" {
395393}
396394
397395test "load vector elements via comptime index" {
398 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
396 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
399397 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
400398 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
401399
......@@ -416,7 +414,7 @@ test "load vector elements via comptime index" {
416414}
417415
418416test "store vector elements via comptime index" {
419 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
417 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
420418 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
421419 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
422420
......@@ -443,7 +441,6 @@ test "store vector elements via comptime index" {
443441}
444442
445443test "load vector elements via runtime index" {
446 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
447444 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
448445 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
449446
......@@ -465,7 +462,7 @@ test "load vector elements via runtime index" {
465462}
466463
467464test "store vector elements via runtime index" {
468 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
465 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
469466 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
470467 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
471468
......@@ -487,7 +484,6 @@ test "store vector elements via runtime index" {
487484}
488485
489486test "initialize vector which is a struct field" {
490 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
491487 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
492488 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
493489
......@@ -508,8 +504,8 @@ test "initialize vector which is a struct field" {
508504}
509505
510506test "vector comparison operators" {
507 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
511508 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
512 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
513509 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
514510 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
515511 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -554,8 +550,8 @@ test "vector comparison operators" {
554550}
555551
556552test "vector division operators" {
553 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
557554 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
558 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
559555 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
560556 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
561557 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -647,9 +643,9 @@ test "vector division operators" {
647643}
648644
649645test "vector bitwise not operator" {
646 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
650647 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
651648 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
652 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
653649 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
654650 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
655651 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -681,9 +677,9 @@ test "vector bitwise not operator" {
681677}
682678
683679test "vector boolean not operator" {
680 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
684681 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
685682 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
686 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
687683 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
688684 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
689685 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -705,8 +701,8 @@ test "vector boolean not operator" {
705701}
706702
707703test "vector shift operators" {
704 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
708705 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
709 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
710706 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
711707 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
712708 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -776,8 +772,8 @@ test "vector shift operators" {
776772}
777773
778774test "vector reduce operation" {
775 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
779776 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
780 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
781777 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
782778 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
783779 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -908,7 +904,6 @@ test "vector reduce operation" {
908904
909905test "vector @reduce comptime" {
910906 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
911 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
912907 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
913908 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
914909
......@@ -924,7 +919,7 @@ test "vector @reduce comptime" {
924919}
925920
926921test "mask parameter of @shuffle is comptime scope" {
927 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
922 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
928923 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
929924 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
930925 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -946,8 +941,8 @@ test "mask parameter of @shuffle is comptime scope" {
946941}
947942
948943test "saturating add" {
944 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
949945 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
950 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
951946 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
952947 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
953948 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -980,8 +975,8 @@ test "saturating add" {
980975}
981976
982977test "saturating subtraction" {
978 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
983979 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
984 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
985980 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
986981 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
987982 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1004,8 +999,8 @@ test "saturating subtraction" {
1004999}
10051000
10061001test "saturating multiplication" {
1002 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10071003 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1008 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10091004 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10101005 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10111006 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1032,8 +1027,8 @@ test "saturating multiplication" {
10321027}
10331028
10341029test "saturating shift-left" {
1030 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10351031 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1036 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10371032 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10381033 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10391034 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1056,8 +1051,8 @@ test "saturating shift-left" {
10561051}
10571052
10581053test "multiplication-assignment operator with an array operand" {
1054 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10591055 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1060 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10611056 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10621057 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10631058 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1077,8 +1072,8 @@ test "multiplication-assignment operator with an array operand" {
10771072}
10781073
10791074test "@addWithOverflow" {
1075 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10801076 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1081 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10821077 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10831078 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10841079 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1127,8 +1122,8 @@ test "@addWithOverflow" {
11271122}
11281123
11291124test "@subWithOverflow" {
1125 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11301126 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1131 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11321127 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11331128 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11341129 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1161,8 +1156,8 @@ test "@subWithOverflow" {
11611156}
11621157
11631158test "@mulWithOverflow" {
1159 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11641160 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1165 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11661161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11671162 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11681163 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1184,8 +1179,8 @@ test "@mulWithOverflow" {
11841179}
11851180
11861181test "@shlWithOverflow" {
1182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
11871183 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11891184 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11901185 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11911186 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1229,8 +1224,8 @@ test "alignment of vectors" {
12291224}
12301225
12311226test "loading the second vector from a slice of vectors" {
1227 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12321228 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1233 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12341229 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12351230 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12361231 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1246,8 +1241,8 @@ test "loading the second vector from a slice of vectors" {
12461241}
12471242
12481243test "array of vectors is copied" {
1244 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12491245 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1250 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12511246 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12521247 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12531248 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -1270,8 +1265,8 @@ test "array of vectors is copied" {
12701265}
12711266
12721267test "byte vector initialized in inline function" {
1268 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12731269 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1274 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12751270 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12761271 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12771272 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1297,7 +1292,6 @@ test "byte vector initialized in inline function" {
12971292
12981293test "zero divisor" {
12991294 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1300 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13011295 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13021296 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13031297
......@@ -1317,7 +1311,6 @@ test "zero divisor" {
13171311
13181312test "zero multiplicand" {
13191313 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1320 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13211314 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13221315 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13231316 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
......@@ -1341,7 +1334,6 @@ test "zero multiplicand" {
13411334
13421335test "@intCast to u0" {
13431336 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1344 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13451337 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13461338 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13471339 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1364,8 +1356,8 @@ test "modRem with zero divisor" {
13641356}
13651357
13661358test "array operands to shuffle are coerced to vectors" {
1359 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13671360 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1368 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13691361 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13701362 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13711363 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
......@@ -1379,7 +1371,7 @@ test "array operands to shuffle are coerced to vectors" {
13791371}
13801372
13811373test "load packed vector element" {
1382 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1374 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13831375 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13841376 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13851377 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
......@@ -1391,7 +1383,7 @@ test "load packed vector element" {
13911383}
13921384
13931385test "store packed vector element" {
1394 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1386 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
13951387 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13961388 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13971389 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
......@@ -1408,7 +1400,7 @@ test "store packed vector element" {
14081400}
14091401
14101402test "store to vector in slice" {
1411 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1403 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14121404 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14131405 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
14141406 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1426,7 +1418,7 @@ test "store to vector in slice" {
14261418}
14271419
14281420test "store vector with memset" {
1429 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1421 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14301422 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14311423 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
14321424 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1459,7 +1451,7 @@ test "store vector with memset" {
14591451}
14601452
14611453test "addition of vectors represented as strings" {
1462 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1454 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14631455 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14641456
14651457 const V = @Vector(3, u8);
......@@ -1469,7 +1461,7 @@ test "addition of vectors represented as strings" {
14691461}
14701462
14711463test "compare vectors with different element types" {
1472 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1464 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14731465 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14741466 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
14751467 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1482,7 +1474,6 @@ test "compare vectors with different element types" {
14821474}
14831475
14841476test "vector pointer is indexable" {
1485 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14861477 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14871478 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
14881479 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1506,7 +1497,6 @@ test "vector pointer is indexable" {
15061497}
15071498
15081499test "boolean vector with 2 or more booleans" {
1509 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15101500 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15111501 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
15121502 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1519,7 +1509,7 @@ test "boolean vector with 2 or more booleans" {
15191509}
15201510
15211511test "bitcast to vector with different child type" {
1522 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1512 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
15231513 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15241514 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
15251515 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -1551,7 +1541,6 @@ test "index into comptime-known vector is comptime-known" {
15511541
15521542test "arithmetic on zero-length vectors" {
15531543 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1554 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15551544 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15561545
15571546 {
......@@ -1568,7 +1557,6 @@ test "arithmetic on zero-length vectors" {
15681557
15691558test "@reduce on bool vector" {
15701559 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1571 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15721560 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15731561
15741562 const a = @Vector(2, bool){ true, true };
......@@ -1578,7 +1566,7 @@ test "@reduce on bool vector" {
15781566}
15791567
15801568test "bitcast vector to array of smaller vectors" {
1581 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1569 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
15821570 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15831571 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
15841572
test/behavior/void.zig-1
......@@ -36,7 +36,6 @@ fn times(n: usize) []const void {
3636
3737test "void optional" {
3838 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
39 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4039 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4140
4241 var x: ?void = {};
test/behavior/while.zig+3-9
......@@ -124,8 +124,6 @@ test "while copies its payload" {
124124}
125125
126126test "continue and break" {
127 if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
128
129127 try runContinueAndBreakTest();
130128 try expect(continue_and_break_counter == 8);
131129}
......@@ -176,6 +174,7 @@ test "while with optional as condition with else" {
176174}
177175
178176test "while with error union condition" {
177 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
179178 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
180179 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
181180 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -209,7 +208,6 @@ test "while on bool with else result follow break prong" {
209208
210209test "while on optional with else result follow else prong" {
211210 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
212 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
213211 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
214212
215213 const result = while (returnNull()) |value| {
......@@ -220,7 +218,6 @@ test "while on optional with else result follow else prong" {
220218
221219test "while on optional with else result follow break prong" {
222220 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
223 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
224221 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
225222
226223 const result = while (returnOptional(10)) |value| {
......@@ -292,7 +289,6 @@ test "while bool 2 break statements and an else" {
292289
293290test "while optional 2 break statements and an else" {
294291 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
295 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
296292 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
297293
298294 const S = struct {
......@@ -310,8 +306,8 @@ test "while optional 2 break statements and an else" {
310306}
311307
312308test "while error 2 break statements and an else" {
309 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
313310 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
314 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
315311 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
316312
317313 const S = struct {
......@@ -348,8 +344,8 @@ test "else continue outer while" {
348344}
349345
350346test "try terminating an infinite loop" {
347 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
351348 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
352 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
353349 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
354350
355351 // Test coverage for https://github.com/ziglang/zig/issues/13546
......@@ -376,7 +372,6 @@ test "while loop with comptime true condition needs no else block to return valu
376372}
377373
378374test "int returned from switch in while" {
379 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
380375 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
381376
382377 var x: u32 = 3;
......@@ -389,7 +384,6 @@ test "int returned from switch in while" {
389384
390385test "breaking from a loop in an if statement" {
391386 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
392 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
393387 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
394388
395389 const S = struct {
test/behavior/widening.zig-5
......@@ -4,7 +4,6 @@ const mem = std.mem;
44const builtin = @import("builtin");
55
66test "integer widening" {
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -29,7 +28,6 @@ test "integer widening u0 to u8" {
2928}
3029
3130test "implicit unsigned integer to signed integer" {
32 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
3331 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3432 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
3533
......@@ -40,7 +38,6 @@ test "implicit unsigned integer to signed integer" {
4038}
4139
4240test "float widening" {
43 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4441 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
4542 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4643 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -60,7 +57,6 @@ test "float widening" {
6057}
6158
6259test "float widening f16 to f128" {
63 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6460 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
6561 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6662 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
......@@ -73,7 +69,6 @@ test "float widening f16 to f128" {
7369}
7470
7571test "cast small unsigned to larger signed" {
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7772 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7873 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7974 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/c_import/macros.zig-12
......@@ -25,7 +25,6 @@ test "casting to void with a macro" {
2525
2626test "initializer list expression" {
2727 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2928 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3029 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
3130
......@@ -38,7 +37,6 @@ test "initializer list expression" {
3837}
3938
4039test "sizeof in macros" {
41 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4240 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4341 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4442
......@@ -55,7 +53,6 @@ test "reference to a struct type" {
5553
5654test "cast negative integer to pointer" {
5755 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
58 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5956 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6057 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
6158
......@@ -64,7 +61,6 @@ test "cast negative integer to pointer" {
6461
6562test "casting to union with a macro" {
6663 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
67 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6864 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6965 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
7066
......@@ -80,7 +76,6 @@ test "casting to union with a macro" {
8076
8177test "casting or calling a value with a paren-surrounded macro" {
8278 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
83 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8479 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8580 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
8681
......@@ -99,7 +94,6 @@ test "casting or calling a value with a paren-surrounded macro" {
9994
10095test "nested comma operator" {
10196 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
102 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10397 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10498 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10599
......@@ -109,7 +103,6 @@ test "nested comma operator" {
109103
110104test "cast functions" {
111105 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
112 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
113106 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
114107 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
115108
......@@ -123,7 +116,6 @@ test "cast functions" {
123116test "large integer macro" {
124117 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
125118 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
126 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
127119 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
128120 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
129121
......@@ -132,7 +124,6 @@ test "large integer macro" {
132124
133125test "string literal macro with embedded tab character" {
134126 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
136127 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
137128 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
138129
......@@ -141,7 +132,6 @@ test "string literal macro with embedded tab character" {
141132
142133test "string and char literals that are not UTF-8 encoded. Issue #12784" {
143134 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
144 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
145135 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
146136 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
147137
......@@ -152,7 +142,6 @@ test "string and char literals that are not UTF-8 encoded. Issue #12784" {
152142test "Macro that uses division operator. Issue #13162" {
153143 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
154144 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
156145 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
157146 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
158147 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
......@@ -196,7 +185,6 @@ test "Macro that uses division operator. Issue #13162" {
196185test "Macro that uses remainder operator. Issue #13346" {
197186 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
198187 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
199 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
200188 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
201189 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
202190
test/tests.zig+37-1
......@@ -191,6 +191,30 @@ const test_targets = blk: {
191191 .link_libc = true,
192192 },
193193
194 .{
195 .target = .{
196 .cpu_arch = .aarch64,
197 .os_tag = .linux,
198 .abi = .none,
199 },
200 .use_llvm = false,
201 .use_lld = false,
202 .optimize_mode = .ReleaseFast,
203 .strip = true,
204 },
205 .{
206 .target = .{
207 .cpu_arch = .aarch64,
208 .cpu_model = .{ .explicit = &std.Target.aarch64.cpu.neoverse_n1 },
209 .os_tag = .linux,
210 .abi = .none,
211 },
212 .use_llvm = false,
213 .use_lld = false,
214 .optimize_mode = .ReleaseFast,
215 .strip = true,
216 },
217
194218 .{
195219 .target = .{
196220 .cpu_arch = .aarch64_be,
......@@ -1182,6 +1206,18 @@ const test_targets = blk: {
11821206 },
11831207 },
11841208
1209 .{
1210 .target = .{
1211 .cpu_arch = .aarch64,
1212 .os_tag = .macos,
1213 .abi = .none,
1214 },
1215 .use_llvm = false,
1216 .use_lld = false,
1217 .optimize_mode = .ReleaseFast,
1218 .strip = true,
1219 },
1220
11851221 .{
11861222 .target = .{
11871223 .cpu_arch = .x86_64,
......@@ -2260,7 +2296,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
22602296 continue;
22612297
22622298 // TODO get compiler-rt tests passing for self-hosted backends.
2263 if ((target.cpu.arch != .x86_64 or target.ofmt != .elf) and
2299 if (((target.cpu.arch != .x86_64 and target.cpu.arch != .aarch64) or target.ofmt == .coff) and
22642300 test_target.use_llvm == false and mem.eql(u8, options.name, "compiler-rt"))
22652301 continue;
22662302