| author | |
| committer | |
| log | dfbb6e9879693331c7b8ea57eb7aa8bdf934403f |
| tree | 7e924c23a4469c6ff554c3bc40609f8873a95376 |
| parent | 1d2b870501ab4ef6adb38c817976669c0329329c |
| parent | bc8e1a74c514e487842c03ab32d7f6e49f42c529 |
181 files changed, 28727 insertions(+), 4297 deletions(-)
CMakeLists.txt+8-9| ... | ... | @@ -390,15 +390,6 @@ set(ZIG_STAGE2_SOURCES |
| 390 | 390 | lib/std/Io.zig |
| 391 | 391 | lib/std/Io/Reader.zig |
| 392 | 392 | lib/std/Io/Writer.zig |
| 393 | lib/std/Io/buffered_atomic_file.zig | |
| 394 | lib/std/Io/buffered_writer.zig | |
| 395 | lib/std/Io/change_detection_stream.zig | |
| 396 | lib/std/Io/counting_reader.zig | |
| 397 | lib/std/Io/counting_writer.zig | |
| 398 | lib/std/Io/find_byte_writer.zig | |
| 399 | lib/std/Io/fixed_buffer_stream.zig | |
| 400 | lib/std/Io/limited_reader.zig | |
| 401 | lib/std/Io/seekable_stream.zig | |
| 402 | 393 | lib/std/Progress.zig |
| 403 | 394 | lib/std/Random.zig |
| 404 | 395 | lib/std/Target.zig |
| ... | ... | @@ -550,6 +541,14 @@ set(ZIG_STAGE2_SOURCES |
| 550 | 541 | src/clang_options.zig |
| 551 | 542 | src/clang_options_data.zig |
| 552 | 543 | src/codegen.zig |
| 544 | src/codegen/aarch64.zig | |
| 545 | src/codegen/aarch64/abi.zig | |
| 546 | src/codegen/aarch64/Assemble.zig | |
| 547 | src/codegen/aarch64/Disassemble.zig | |
| 548 | src/codegen/aarch64/encoding.zig | |
| 549 | src/codegen/aarch64/instructions.zon | |
| 550 | src/codegen/aarch64/Mir.zig | |
| 551 | src/codegen/aarch64/Select.zig | |
| 553 | 552 | src/codegen/c.zig |
| 554 | 553 | src/codegen/c/Type.zig |
| 555 | 554 | src/codegen/llvm.zig |
lib/compiler/std-docs.zig+9-2| ... | ... | @@ -59,7 +59,9 @@ pub fn main() !void { |
| 59 | 59 | const should_open_browser = force_open_browser orelse (listen_port == 0); |
| 60 | 60 | |
| 61 | 61 | const address = std.net.Address.parseIp("127.0.0.1", listen_port) catch unreachable; |
| 62 | var http_server = try address.listen(.{}); | |
| 62 | var http_server = try address.listen(.{ | |
| 63 | .reuse_address = true, | |
| 64 | }); | |
| 63 | 65 | const port = http_server.listen_address.in.getPort(); |
| 64 | 66 | const url_with_newline = try std.fmt.allocPrint(arena, "http://127.0.0.1:{d}/\n", .{port}); |
| 65 | 67 | std.fs.File.stdout().writeAll(url_with_newline) catch {}; |
| ... | ... | @@ -218,7 +220,12 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void { |
| 218 | 220 | var file = try entry.dir.openFile(entry.basename, .{}); |
| 219 | 221 | defer file.close(); |
| 220 | 222 | const stat = try file.stat(); |
| 221 | try tar_writer.writeFile(entry.path, file, stat); | |
| 223 | var file_reader: std.fs.File.Reader = .{ | |
| 224 | .file = file, | |
| 225 | .interface = std.fs.File.Reader.initInterface(&.{}), | |
| 226 | .size = stat.size, | |
| 227 | }; | |
| 228 | try tar_writer.writeFile(entry.path, &file_reader, stat.mtime); | |
| 222 | 229 | } |
| 223 | 230 | |
| 224 | 231 | { |
lib/compiler/test_runner.zig+19-20| ... | ... | @@ -16,6 +16,7 @@ var stdin_buffer: [4096]u8 = undefined; |
| 16 | 16 | var stdout_buffer: [4096]u8 = undefined; |
| 17 | 17 | |
| 18 | 18 | const crippled = switch (builtin.zig_backend) { |
| 19 | .stage2_aarch64, | |
| 19 | 20 | .stage2_powerpc, |
| 20 | 21 | .stage2_riscv64, |
| 21 | 22 | => true, |
| ... | ... | @@ -287,13 +288,14 @@ pub fn log( |
| 287 | 288 | /// work-in-progress backends can handle it. |
| 288 | 289 | pub fn mainSimple() anyerror!void { |
| 289 | 290 | @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, | |
| 292 | 294 | else => false, |
| 293 | 295 | }; |
| 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, | |
| 297 | 299 | else => false, |
| 298 | 300 | }; |
| 299 | 301 | |
| ... | ... | @@ -302,34 +304,31 @@ pub fn mainSimple() anyerror!void { |
| 302 | 304 | var failed: u64 = 0; |
| 303 | 305 | |
| 304 | 306 | // 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 {}; | |
| 306 | 308 | |
| 307 | 309 | for (builtin.test_functions) |test_fn| { |
| 310 | if (enable_write) { | |
| 311 | stdout.writeAll(test_fn.name) catch {}; | |
| 312 | stdout.writeAll("... ") catch {}; | |
| 313 | } | |
| 308 | 314 | 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 {}; | |
| 314 | 316 | } else |err| { |
| 315 | if (enable_print) { | |
| 316 | stderr.writeAll(test_fn.name) catch {}; | |
| 317 | stderr.writeAll("... ") catch {}; | |
| 318 | } | |
| 319 | 317 | if (err != error.SkipZigTest) { |
| 320 | if (enable_print) stderr.writeAll("FAIL\n") catch {}; | |
| 318 | if (enable_write) stdout.writeAll("FAIL\n") catch {}; | |
| 321 | 319 | failed += 1; |
| 322 | if (!enable_print) return err; | |
| 320 | if (!enable_write) return err; | |
| 323 | 321 | continue; |
| 324 | 322 | } |
| 325 | if (enable_print) stderr.writeAll("SKIP\n") catch {}; | |
| 323 | if (enable_write) stdout.writeAll("SKIP\n") catch {}; | |
| 326 | 324 | skipped += 1; |
| 327 | 325 | continue; |
| 328 | 326 | } |
| 329 | 327 | passed += 1; |
| 330 | 328 | } |
| 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 {}; | |
| 333 | 332 | } |
| 334 | 333 | if (failed != 0) std.process.exit(1); |
| 335 | 334 | } |
lib/compiler_rt.zig+3-3| ... | ... | @@ -240,7 +240,7 @@ comptime { |
| 240 | 240 | _ = @import("compiler_rt/udivmodti4.zig"); |
| 241 | 241 | |
| 242 | 242 | // extra |
| 243 | _ = @import("compiler_rt/os_version_check.zig"); | |
| 243 | if (builtin.zig_backend != .stage2_aarch64) _ = @import("compiler_rt/os_version_check.zig"); | |
| 244 | 244 | _ = @import("compiler_rt/emutls.zig"); |
| 245 | 245 | _ = @import("compiler_rt/arm.zig"); |
| 246 | 246 | _ = @import("compiler_rt/aulldiv.zig"); |
| ... | ... | @@ -249,12 +249,12 @@ comptime { |
| 249 | 249 | _ = @import("compiler_rt/hexagon.zig"); |
| 250 | 250 | |
| 251 | 251 | if (@import("builtin").object_format != .c) { |
| 252 | _ = @import("compiler_rt/atomics.zig"); | |
| 252 | if (builtin.zig_backend != .stage2_aarch64) _ = @import("compiler_rt/atomics.zig"); | |
| 253 | 253 | _ = @import("compiler_rt/stack_probe.zig"); |
| 254 | 254 | |
| 255 | 255 | // macOS has these functions inside libSystem. |
| 256 | 256 | 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"); | |
| 258 | 258 | } |
| 259 | 259 | |
| 260 | 260 | _ = @import("compiler_rt/memcpy.zig"); |
lib/compiler_rt/addo.zig+1-3| ... | ... | @@ -1,6 +1,4 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | |
| 3 | const is_test = builtin.is_test; | |
| 4 | 2 | const common = @import("./common.zig"); |
| 5 | 3 | pub const panic = @import("common.zig").panic; |
| 6 | 4 | |
| ... | ... | @@ -16,7 +14,7 @@ comptime { |
| 16 | 14 | // - addoXi4_generic as default |
| 17 | 15 | |
| 18 | 16 | inline fn addoXi4_generic(comptime ST: type, a: ST, b: ST, overflow: *c_int) ST { |
| 19 | @setRuntimeSafety(builtin.is_test); | |
| 17 | @setRuntimeSafety(common.test_safety); | |
| 20 | 18 | overflow.* = 0; |
| 21 | 19 | const sum: ST = a +% b; |
| 22 | 20 | // Hackers Delight: section Overflow Detection, subsection Signed Add/Subtract |
lib/compiler_rt/addoti4_test.zig+3| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | const addv = @import("addo.zig"); |
| 2 | const builtin = @import("builtin"); | |
| 2 | 3 | const std = @import("std"); |
| 3 | 4 | const testing = std.testing; |
| 4 | 5 | const math = std.math; |
| ... | ... | @@ -23,6 +24,8 @@ fn simple_addoti4(a: i128, b: i128, overflow: *c_int) i128 { |
| 23 | 24 | } |
| 24 | 25 | |
| 25 | 26 | test "addoti4" { |
| 27 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 28 | ||
| 26 | 29 | const min: i128 = math.minInt(i128); |
| 27 | 30 | const max: i128 = math.maxInt(i128); |
| 28 | 31 | 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 { |
| 97 | 97 | .nbytes = end - start, |
| 98 | 98 | .whichcache = 3, // ICACHE | DCACHE |
| 99 | 99 | }; |
| 100 | asm volatile ( | |
| 101 | \\ syscall | |
| 100 | asm volatile ("syscall" | |
| 102 | 101 | : |
| 103 | 102 | : [_] "{$2}" (165), // nr = SYS_sysarch |
| 104 | 103 | [_] "{$4}" (0), // op = MIPS_CACHEFLUSH |
| ... | ... | @@ -116,11 +115,8 @@ fn clear_cache(start: usize, end: usize) callconv(.c) void { |
| 116 | 115 | } else if (arm64 and !apple) { |
| 117 | 116 | // Get Cache Type Info. |
| 118 | 117 | // 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), | |
| 124 | 120 | ); |
| 125 | 121 | // The DC and IC instructions must use 64-bit registers so we don't use |
| 126 | 122 | // uintptr_t in case this runs in an IPL32 environment. |
| ... | ... | @@ -187,9 +183,7 @@ fn clear_cache(start: usize, end: usize) callconv(.c) void { |
| 187 | 183 | exportIt(); |
| 188 | 184 | } else if (os == .linux and loongarch) { |
| 189 | 185 | // 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"); | |
| 193 | 187 | exportIt(); |
| 194 | 188 | } |
| 195 | 189 |
lib/compiler_rt/cmp.zig-1| ... | ... | @@ -1,6 +1,5 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | const is_test = builtin.is_test; | |
| 4 | 3 | const common = @import("common.zig"); |
| 5 | 4 | |
| 6 | 5 | pub const panic = common.panic; |
lib/compiler_rt/common.zig+6-1| ... | ... | @@ -102,9 +102,14 @@ pub const gnu_f16_abi = switch (builtin.cpu.arch) { |
| 102 | 102 | |
| 103 | 103 | pub const want_sparc_abi = builtin.cpu.arch.isSPARC(); |
| 104 | 104 | |
| 105 | pub const test_safety = switch (builtin.zig_backend) { | |
| 106 | .stage2_aarch64 => false, | |
| 107 | else => builtin.is_test, | |
| 108 | }; | |
| 109 | ||
| 105 | 110 | // Avoid dragging in the runtime safety mechanisms into this .o file, unless |
| 106 | 111 | // we're trying to test compiler-rt. |
| 107 | pub const panic = if (builtin.is_test) std.debug.FullPanic(std.debug.defaultPanic) else std.debug.no_panic; | |
| 112 | pub const panic = if (test_safety) std.debug.FullPanic(std.debug.defaultPanic) else std.debug.no_panic; | |
| 108 | 113 | |
| 109 | 114 | /// This seems to mostly correspond to `clang::TargetInfo::HasFloat16`. |
| 110 | 115 | pub fn F16T(comptime OtherType: type) type { |
lib/compiler_rt/comparedf2_test.zig-1| ... | ... | @@ -4,7 +4,6 @@ |
| 4 | 4 | |
| 5 | 5 | const std = @import("std"); |
| 6 | 6 | const builtin = @import("builtin"); |
| 7 | const is_test = builtin.is_test; | |
| 8 | 7 | |
| 9 | 8 | const __eqdf2 = @import("./cmpdf2.zig").__eqdf2; |
| 10 | 9 | const __ledf2 = @import("./cmpdf2.zig").__ledf2; |
lib/compiler_rt/comparesf2_test.zig-1| ... | ... | @@ -4,7 +4,6 @@ |
| 4 | 4 | |
| 5 | 5 | const std = @import("std"); |
| 6 | 6 | const builtin = @import("builtin"); |
| 7 | const is_test = builtin.is_test; | |
| 8 | 7 | |
| 9 | 8 | const __eqsf2 = @import("./cmpsf2.zig").__eqsf2; |
| 10 | 9 | const __lesf2 = @import("./cmpsf2.zig").__lesf2; |
lib/compiler_rt/count0bits.zig-1| ... | ... | @@ -1,6 +1,5 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | const is_test = builtin.is_test; | |
| 4 | 3 | const common = @import("common.zig"); |
| 5 | 4 | |
| 6 | 5 | pub const panic = common.panic; |
lib/compiler_rt/divdf3.zig-1| ... | ... | @@ -5,7 +5,6 @@ |
| 5 | 5 | const std = @import("std"); |
| 6 | 6 | const builtin = @import("builtin"); |
| 7 | 7 | const arch = builtin.cpu.arch; |
| 8 | const is_test = builtin.is_test; | |
| 9 | 8 | const common = @import("common.zig"); |
| 10 | 9 | |
| 11 | 10 | const 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 { |
| 34 | 34 | } |
| 35 | 35 | |
| 36 | 36 | pub 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); | |
| 38 | 38 | const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); |
| 39 | 39 | const q: []u32 = @ptrCast(@alignCast(q_p[0..byte_size])); |
| 40 | 40 | 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 |
| 43 | 43 | } |
| 44 | 44 | |
| 45 | 45 | pub 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); | |
| 47 | 47 | const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); |
| 48 | 48 | const r: []u32 = @ptrCast(@alignCast(r_p[0..byte_size])); |
| 49 | 49 | const u: []u32 = @ptrCast(@alignCast(u_p[0..byte_size])); |
lib/compiler_rt/fixint_test.zig-1| ... | ... | @@ -1,4 +1,3 @@ |
| 1 | const is_test = @import("builtin").is_test; | |
| 2 | 1 | const std = @import("std"); |
| 3 | 2 | const math = std.math; |
| 4 | 3 | const testing = std.testing; |
lib/compiler_rt/int.zig-1| ... | ... | @@ -6,7 +6,6 @@ const testing = std.testing; |
| 6 | 6 | const maxInt = std.math.maxInt; |
| 7 | 7 | const minInt = std.math.minInt; |
| 8 | 8 | const arch = builtin.cpu.arch; |
| 9 | const is_test = builtin.is_test; | |
| 10 | 9 | const common = @import("common.zig"); |
| 11 | 10 | const udivmod = @import("udivmod.zig").udivmod; |
| 12 | 11 | const __divti3 = @import("divti3.zig").__divti3; |
lib/compiler_rt/memcpy.zig+3-1| ... | ... | @@ -11,7 +11,7 @@ comptime { |
| 11 | 11 | .visibility = common.visibility, |
| 12 | 12 | }; |
| 13 | 13 | |
| 14 | if (builtin.mode == .ReleaseSmall) | |
| 14 | if (builtin.mode == .ReleaseSmall or builtin.zig_backend == .stage2_aarch64) | |
| 15 | 15 | @export(&memcpySmall, export_options) |
| 16 | 16 | else |
| 17 | 17 | @export(&memcpyFast, export_options); |
| ... | ... | @@ -195,6 +195,8 @@ inline fn copyRange4( |
| 195 | 195 | } |
| 196 | 196 | |
| 197 | 197 | test "memcpy" { |
| 198 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 199 | ||
| 198 | 200 | const S = struct { |
| 199 | 201 | fn testFunc(comptime copy_func: anytype) !void { |
| 200 | 202 | const max_len = 1024; |
lib/compiler_rt/memmove.zig+9-7| ... | ... | @@ -14,7 +14,7 @@ comptime { |
| 14 | 14 | .visibility = common.visibility, |
| 15 | 15 | }; |
| 16 | 16 | |
| 17 | if (builtin.mode == .ReleaseSmall) | |
| 17 | if (builtin.mode == .ReleaseSmall or builtin.zig_backend == .stage2_aarch64) | |
| 18 | 18 | @export(&memmoveSmall, export_options) |
| 19 | 19 | else |
| 20 | 20 | @export(&memmoveFast, export_options); |
| ... | ... | @@ -39,7 +39,7 @@ fn memmoveSmall(opt_dest: ?[*]u8, opt_src: ?[*]const u8, len: usize) callconv(.c |
| 39 | 39 | } |
| 40 | 40 | |
| 41 | 41 | fn memmoveFast(dest: ?[*]u8, src: ?[*]u8, len: usize) callconv(.c) ?[*]u8 { |
| 42 | @setRuntimeSafety(builtin.is_test); | |
| 42 | @setRuntimeSafety(common.test_safety); | |
| 43 | 43 | const small_limit = @max(2 * @sizeOf(Element), @sizeOf(Element)); |
| 44 | 44 | |
| 45 | 45 | if (copySmallLength(small_limit, dest.?, src.?, len)) return dest; |
| ... | ... | @@ -79,7 +79,7 @@ inline fn copyLessThan16( |
| 79 | 79 | src: [*]const u8, |
| 80 | 80 | len: usize, |
| 81 | 81 | ) void { |
| 82 | @setRuntimeSafety(builtin.is_test); | |
| 82 | @setRuntimeSafety(common.test_safety); | |
| 83 | 83 | if (len < 4) { |
| 84 | 84 | if (len == 0) return; |
| 85 | 85 | const b = len / 2; |
| ... | ... | @@ -100,7 +100,7 @@ inline fn copy16ToSmallLimit( |
| 100 | 100 | src: [*]const u8, |
| 101 | 101 | len: usize, |
| 102 | 102 | ) bool { |
| 103 | @setRuntimeSafety(builtin.is_test); | |
| 103 | @setRuntimeSafety(common.test_safety); | |
| 104 | 104 | inline for (2..(std.math.log2(small_limit) + 1) / 2 + 1) |p| { |
| 105 | 105 | const limit = 1 << (2 * p); |
| 106 | 106 | if (len < limit) { |
| ... | ... | @@ -119,7 +119,7 @@ inline fn copyRange4( |
| 119 | 119 | src: [*]const u8, |
| 120 | 120 | len: usize, |
| 121 | 121 | ) void { |
| 122 | @setRuntimeSafety(builtin.is_test); | |
| 122 | @setRuntimeSafety(common.test_safety); | |
| 123 | 123 | comptime assert(std.math.isPowerOfTwo(copy_len)); |
| 124 | 124 | assert(len >= copy_len); |
| 125 | 125 | assert(len < 4 * copy_len); |
| ... | ... | @@ -147,7 +147,7 @@ inline fn copyForwards( |
| 147 | 147 | src: [*]const u8, |
| 148 | 148 | len: usize, |
| 149 | 149 | ) void { |
| 150 | @setRuntimeSafety(builtin.is_test); | |
| 150 | @setRuntimeSafety(common.test_safety); | |
| 151 | 151 | assert(len >= 2 * @sizeOf(Element)); |
| 152 | 152 | |
| 153 | 153 | const head = src[0..@sizeOf(Element)].*; |
| ... | ... | @@ -181,7 +181,7 @@ inline fn copyBlocks( |
| 181 | 181 | src: anytype, |
| 182 | 182 | max_bytes: usize, |
| 183 | 183 | ) void { |
| 184 | @setRuntimeSafety(builtin.is_test); | |
| 184 | @setRuntimeSafety(common.test_safety); | |
| 185 | 185 | |
| 186 | 186 | const T = @typeInfo(@TypeOf(dest)).pointer.child; |
| 187 | 187 | comptime assert(T == @typeInfo(@TypeOf(src)).pointer.child); |
| ... | ... | @@ -217,6 +217,8 @@ inline fn copyBackwards( |
| 217 | 217 | } |
| 218 | 218 | |
| 219 | 219 | test memmoveFast { |
| 220 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 221 | ||
| 220 | 222 | const max_len = 1024; |
| 221 | 223 | var buffer: [max_len + @alignOf(Element) - 1]u8 = undefined; |
| 222 | 224 | for (&buffer, 0..) |*b, i| { |
lib/compiler_rt/mulf3.zig+2-2| ... | ... | @@ -6,7 +6,7 @@ const common = @import("./common.zig"); |
| 6 | 6 | /// Ported from: |
| 7 | 7 | /// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/lib/builtins/fp_mul_impl.inc |
| 8 | 8 | pub inline fn mulf3(comptime T: type, a: T, b: T) T { |
| 9 | @setRuntimeSafety(builtin.is_test); | |
| 9 | @setRuntimeSafety(common.test_safety); | |
| 10 | 10 | const typeWidth = @typeInfo(T).float.bits; |
| 11 | 11 | const significandBits = math.floatMantissaBits(T); |
| 12 | 12 | const fractionalBits = math.floatFractionalBits(T); |
| ... | ... | @@ -163,7 +163,7 @@ pub inline fn mulf3(comptime T: type, a: T, b: T) T { |
| 163 | 163 | /// |
| 164 | 164 | /// This is analogous to an shr version of `@shlWithOverflow` |
| 165 | 165 | fn wideShrWithTruncation(comptime Z: type, hi: *Z, lo: *Z, count: u32) bool { |
| 166 | @setRuntimeSafety(builtin.is_test); | |
| 166 | @setRuntimeSafety(common.test_safety); | |
| 167 | 167 | const typeWidth = @typeInfo(Z).int.bits; |
| 168 | 168 | var inexact = false; |
| 169 | 169 | if (count < typeWidth) { |
lib/compiler_rt/rem_pio2_large.zig+1-1| ... | ... | @@ -251,7 +251,7 @@ const PIo2 = [_]f64{ |
| 251 | 251 | /// compiler will convert from decimal to binary accurately enough |
| 252 | 252 | /// to produce the hexadecimal values shown. |
| 253 | 253 | /// |
| 254 | pub fn rem_pio2_large(x: []f64, y: []f64, e0: i32, nx: i32, prec: usize) i32 { | |
| 254 | pub fn rem_pio2_large(x: []const f64, y: []f64, e0: i32, nx: i32, prec: usize) i32 { | |
| 255 | 255 | var jz: i32 = undefined; |
| 256 | 256 | var jx: i32 = undefined; |
| 257 | 257 | var jv: i32 = undefined; |
lib/compiler_rt/stack_probe.zig-1| ... | ... | @@ -4,7 +4,6 @@ const common = @import("common.zig"); |
| 4 | 4 | const os_tag = builtin.os.tag; |
| 5 | 5 | const arch = builtin.cpu.arch; |
| 6 | 6 | const abi = builtin.abi; |
| 7 | const is_test = builtin.is_test; | |
| 8 | 7 | |
| 9 | 8 | pub const panic = common.panic; |
| 10 | 9 |
lib/compiler_rt/suboti4_test.zig+3| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | const subo = @import("subo.zig"); |
| 2 | const builtin = @import("builtin"); | |
| 2 | 3 | const std = @import("std"); |
| 3 | 4 | const testing = std.testing; |
| 4 | 5 | const math = std.math; |
| ... | ... | @@ -27,6 +28,8 @@ pub fn simple_suboti4(a: i128, b: i128, overflow: *c_int) i128 { |
| 27 | 28 | } |
| 28 | 29 | |
| 29 | 30 | test "suboti3" { |
| 31 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 32 | ||
| 30 | 33 | const min: i128 = math.minInt(i128); |
| 31 | 34 | const max: i128 = math.maxInt(i128); |
| 32 | 35 | var i: i128 = 1; |
lib/compiler_rt/udivmod.zig+5-5| ... | ... | @@ -1,8 +1,8 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | const is_test = builtin.is_test; | |
| 4 | 3 | const Log2Int = std.math.Log2Int; |
| 5 | const HalveInt = @import("common.zig").HalveInt; | |
| 4 | const common = @import("common.zig"); | |
| 5 | const HalveInt = common.HalveInt; | |
| 6 | 6 | |
| 7 | 7 | const lo = switch (builtin.cpu.arch.endian()) { |
| 8 | 8 | .big => 1, |
| ... | ... | @@ -14,7 +14,7 @@ const hi = 1 - lo; |
| 14 | 14 | // Returns U / v_ and sets r = U % v_. |
| 15 | 15 | fn divwide_generic(comptime T: type, _u1: T, _u0: T, v_: T, r: *T) T { |
| 16 | 16 | const HalfT = HalveInt(T, false).HalfT; |
| 17 | @setRuntimeSafety(is_test); | |
| 17 | @setRuntimeSafety(common.test_safety); | |
| 18 | 18 | var v = v_; |
| 19 | 19 | |
| 20 | 20 | 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 { |
| 70 | 70 | } |
| 71 | 71 | |
| 72 | 72 | fn divwide(comptime T: type, _u1: T, _u0: T, v: T, r: *T) T { |
| 73 | @setRuntimeSafety(is_test); | |
| 73 | @setRuntimeSafety(common.test_safety); | |
| 74 | 74 | if (T == u64 and builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag != .windows) { |
| 75 | 75 | var rem: T = undefined; |
| 76 | 76 | const quo = asm ( |
| ... | ... | @@ -90,7 +90,7 @@ fn divwide(comptime T: type, _u1: T, _u0: T, v: T, r: *T) T { |
| 90 | 90 | |
| 91 | 91 | // Returns a_ / b_ and sets maybe_rem = a_ % b. |
| 92 | 92 | pub fn udivmod(comptime T: type, a_: T, b_: T, maybe_rem: ?*T) T { |
| 93 | @setRuntimeSafety(is_test); | |
| 93 | @setRuntimeSafety(common.test_safety); | |
| 94 | 94 | const HalfT = HalveInt(T, false).HalfT; |
| 95 | 95 | const SignedT = std.meta.Int(.signed, @bitSizeOf(T)); |
| 96 | 96 |
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 { |
| 113 | 113 | } |
| 114 | 114 | |
| 115 | 115 | pub 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); | |
| 117 | 117 | const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); |
| 118 | 118 | const q: []u32 = @ptrCast(@alignCast(q_p[0..byte_size])); |
| 119 | 119 | 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 |
| 122 | 122 | } |
| 123 | 123 | |
| 124 | 124 | pub 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); | |
| 126 | 126 | const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); |
| 127 | 127 | const r: []u32 = @ptrCast(@alignCast(r_p[0..byte_size])); |
| 128 | 128 | 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 |
| 131 | 131 | } |
| 132 | 132 | |
| 133 | 133 | test "__udivei4/__umodei4" { |
| 134 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 134 | 135 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 135 | 136 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 136 | 137 |
lib/docs/wasm/main.zig+3-3| ... | ... | @@ -779,10 +779,10 @@ export fn decl_type_html(decl_index: Decl.Index) String { |
| 779 | 779 | const Oom = error{OutOfMemory}; |
| 780 | 780 | |
| 781 | 781 | fn unpackInner(tar_bytes: []u8) !void { |
| 782 | var br: std.io.Reader = .fixed(tar_bytes); | |
| 782 | var reader: std.Io.Reader = .fixed(tar_bytes); | |
| 783 | 783 | var file_name_buffer: [1024]u8 = undefined; |
| 784 | 784 | var link_name_buffer: [1024]u8 = undefined; |
| 785 | var it = std.tar.Iterator.init(&br, .{ | |
| 785 | var it: std.tar.Iterator = .init(&reader, .{ | |
| 786 | 786 | .file_name_buffer = &file_name_buffer, |
| 787 | 787 | .link_name_buffer = &link_name_buffer, |
| 788 | 788 | }); |
| ... | ... | @@ -803,7 +803,7 @@ fn unpackInner(tar_bytes: []u8) !void { |
| 803 | 803 | { |
| 804 | 804 | gop.value_ptr.* = file; |
| 805 | 805 | } |
| 806 | const file_bytes = tar_bytes[br.seek..][0..@intCast(tar_file.size)]; | |
| 806 | const file_bytes = tar_bytes[reader.seek..][0..@intCast(tar_file.size)]; | |
| 807 | 807 | assert(file == try Walk.add_file(file_name, file_bytes)); |
| 808 | 808 | } |
| 809 | 809 | } else { |
lib/std/Build/Fuzz/WebServer.zig+4-2| ... | ... | @@ -519,6 +519,7 @@ fn serveSourcesTar(ws: *WebServer, request: *std.http.Server.Request) !void { |
| 519 | 519 | |
| 520 | 520 | var response_writer = body.writer().unbuffered(); |
| 521 | 521 | var archiver: std.tar.Writer = .{ .underlying_writer = &response_writer }; |
| 522 | var read_buffer: [1024]u8 = undefined; | |
| 522 | 523 | |
| 523 | 524 | for (deduped_paths) |joined_path| { |
| 524 | 525 | var file = joined_path.root_dir.handle.openFile(joined_path.sub_path, .{}) catch |err| { |
| ... | ... | @@ -526,9 +527,10 @@ fn serveSourcesTar(ws: *WebServer, request: *std.http.Server.Request) !void { |
| 526 | 527 | continue; |
| 527 | 528 | }; |
| 528 | 529 | defer file.close(); |
| 529 | ||
| 530 | const stat = try file.stat(); | |
| 531 | var file_reader: std.fs.File.Reader = .initSize(file, &read_buffer, stat.size); | |
| 530 | 532 | archiver.prefix = joined_path.root_dir.path orelse try memoizedCwd(arena, &cwd_cache); |
| 531 | try archiver.writeFile(joined_path.sub_path, file, try file.stat()); | |
| 533 | try archiver.writeFile(joined_path.sub_path, &file_reader, stat.mtime); | |
| 532 | 534 | } |
| 533 | 535 | |
| 534 | 536 | try body.end(); |
lib/std/Io.zig+1| ... | ... | @@ -493,5 +493,6 @@ test { |
| 493 | 493 | _ = Reader; |
| 494 | 494 | _ = Reader.Limited; |
| 495 | 495 | _ = Writer; |
| 496 | _ = tty; | |
| 496 | 497 | _ = @import("Io/test.zig"); |
| 497 | 498 | } |
lib/std/Io/DeprecatedReader.zig+3-1| ... | ... | @@ -393,10 +393,12 @@ pub const Adapter = struct { |
| 393 | 393 | fn stream(r: *std.io.Reader, w: *std.io.Writer, limit: std.io.Limit) std.io.Reader.StreamError!usize { |
| 394 | 394 | const a: *@This() = @alignCast(@fieldParentPtr("new_interface", r)); |
| 395 | 395 | const buf = limit.slice(try w.writableSliceGreedy(1)); |
| 396 | return a.derp_reader.read(buf) catch |err| { | |
| 396 | const n = a.derp_reader.read(buf) catch |err| { | |
| 397 | 397 | a.err = err; |
| 398 | 398 | return error.ReadFailed; |
| 399 | 399 | }; |
| 400 | w.advance(n); | |
| 401 | return n; | |
| 400 | 402 | } |
| 401 | 403 | }; |
| 402 | 404 |
lib/std/Io/DeprecatedWriter.zig+6-1| ... | ... | @@ -100,7 +100,12 @@ pub const Adapter = struct { |
| 100 | 100 | |
| 101 | 101 | fn drain(w: *std.io.Writer, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { |
| 102 | 102 | _ = splat; |
| 103 | const a: *@This() = @fieldParentPtr("new_interface", w); | |
| 103 | const a: *@This() = @alignCast(@fieldParentPtr("new_interface", w)); | |
| 104 | const buffered = w.buffered(); | |
| 105 | if (buffered.len != 0) return w.consume(a.derp_writer.write(buffered) catch |err| { | |
| 106 | a.err = err; | |
| 107 | return error.WriteFailed; | |
| 108 | }); | |
| 104 | 109 | return a.derp_writer.write(data[0]) catch |err| { |
| 105 | 110 | a.err = err; |
| 106 | 111 | return error.WriteFailed; |
lib/std/Io/Reader.zig+6| ... | ... | @@ -179,6 +179,12 @@ pub fn streamExact(r: *Reader, w: *Writer, n: usize) StreamError!void { |
| 179 | 179 | while (remaining != 0) remaining -= try r.stream(w, .limited(remaining)); |
| 180 | 180 | } |
| 181 | 181 | |
| 182 | /// "Pump" exactly `n` bytes from the reader to the writer. | |
| 183 | pub fn streamExact64(r: *Reader, w: *Writer, n: u64) StreamError!void { | |
| 184 | var remaining = n; | |
| 185 | while (remaining != 0) remaining -= try r.stream(w, .limited64(remaining)); | |
| 186 | } | |
| 187 | ||
| 182 | 188 | /// "Pump" data from the reader to the writer, handling `error.EndOfStream` as |
| 183 | 189 | /// a success case. |
| 184 | 190 | /// |
lib/std/Io/Writer.zig+4| ... | ... | @@ -2242,6 +2242,10 @@ pub const Discarding = struct { |
| 2242 | 2242 | |
| 2243 | 2243 | pub fn sendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize { |
| 2244 | 2244 | if (File.Handle == void) return error.Unimplemented; |
| 2245 | switch (builtin.zig_backend) { | |
| 2246 | else => {}, | |
| 2247 | .stage2_aarch64 => return error.Unimplemented, | |
| 2248 | } | |
| 2245 | 2249 | const d: *Discarding = @alignCast(@fieldParentPtr("writer", w)); |
| 2246 | 2250 | d.count += w.end; |
| 2247 | 2251 | w.end = 0; |
lib/std/Io/find_byte_writer.zig deleted-40| ... | ... | @@ -1,40 +0,0 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const io = std.io; | |
| 3 | const assert = std.debug.assert; | |
| 4 | ||
| 5 | /// A Writer that returns whether the given character has been written to it. | |
| 6 | /// The contents are not written to anything. | |
| 7 | pub fn FindByteWriter(comptime UnderlyingWriter: type) type { | |
| 8 | return struct { | |
| 9 | const Self = @This(); | |
| 10 | pub const Error = UnderlyingWriter.Error; | |
| 11 | pub const Writer = io.GenericWriter(*Self, Error, write); | |
| 12 | ||
| 13 | underlying_writer: UnderlyingWriter, | |
| 14 | byte_found: bool, | |
| 15 | byte: u8, | |
| 16 | ||
| 17 | pub fn writer(self: *Self) Writer { | |
| 18 | return .{ .context = self }; | |
| 19 | } | |
| 20 | ||
| 21 | fn write(self: *Self, bytes: []const u8) Error!usize { | |
| 22 | if (!self.byte_found) { | |
| 23 | self.byte_found = blk: { | |
| 24 | for (bytes) |b| | |
| 25 | if (b == self.byte) break :blk true; | |
| 26 | break :blk false; | |
| 27 | }; | |
| 28 | } | |
| 29 | return self.underlying_writer.write(bytes); | |
| 30 | } | |
| 31 | }; | |
| 32 | } | |
| 33 | ||
| 34 | pub fn findByteWriter(byte: u8, underlying_writer: anytype) FindByteWriter(@TypeOf(underlying_writer)) { | |
| 35 | return FindByteWriter(@TypeOf(underlying_writer)){ | |
| 36 | .underlying_writer = underlying_writer, | |
| 37 | .byte = byte, | |
| 38 | .byte_found = false, | |
| 39 | }; | |
| 40 | } |
lib/std/Progress.zig+4-1| ... | ... | @@ -408,6 +408,9 @@ pub const have_ipc = switch (builtin.os.tag) { |
| 408 | 408 | const noop_impl = builtin.single_threaded or switch (builtin.os.tag) { |
| 409 | 409 | .wasi, .freestanding => true, |
| 410 | 410 | else => false, |
| 411 | } or switch (builtin.zig_backend) { | |
| 412 | .stage2_aarch64 => true, | |
| 413 | else => false, | |
| 411 | 414 | }; |
| 412 | 415 | |
| 413 | 416 | /// Initializes a global Progress instance. |
| ... | ... | @@ -754,7 +757,7 @@ fn appendTreeSymbol(symbol: TreeSymbol, buf: []u8, start_i: usize) usize { |
| 754 | 757 | } |
| 755 | 758 | |
| 756 | 759 | fn clearWrittenWithEscapeCodes() anyerror!void { |
| 757 | if (!global_progress.need_clear) return; | |
| 760 | if (noop_impl or !global_progress.need_clear) return; | |
| 758 | 761 | |
| 759 | 762 | global_progress.need_clear = false; |
| 760 | 763 | try write(clear); |
lib/std/builtin.zig+5-2| ... | ... | @@ -774,7 +774,7 @@ pub const Endian = enum { |
| 774 | 774 | |
| 775 | 775 | /// This data structure is used by the Zig language code generation and |
| 776 | 776 | /// therefore must be kept in sync with the compiler implementation. |
| 777 | pub const Signedness = enum { | |
| 777 | pub const Signedness = enum(u1) { | |
| 778 | 778 | signed, |
| 779 | 779 | unsigned, |
| 780 | 780 | }; |
| ... | ... | @@ -896,7 +896,10 @@ pub const VaList = switch (builtin.cpu.arch) { |
| 896 | 896 | .aarch64, .aarch64_be => switch (builtin.os.tag) { |
| 897 | 897 | .windows => *u8, |
| 898 | 898 | .ios, .macos, .tvos, .watchos, .visionos => *u8, |
| 899 | else => @compileError("disabled due to miscompilations"), // VaListAarch64, | |
| 899 | else => switch (builtin.zig_backend) { | |
| 900 | .stage2_aarch64 => VaListAarch64, | |
| 901 | else => @compileError("disabled due to miscompilations"), | |
| 902 | }, | |
| 900 | 903 | }, |
| 901 | 904 | .arm, .armeb, .thumb, .thumbeb => switch (builtin.os.tag) { |
| 902 | 905 | .ios, .macos, .tvos, .watchos, .visionos => *u8, |
lib/std/crypto/md5.zig+10-2| ... | ... | @@ -54,12 +54,20 @@ pub const Md5 = struct { |
| 54 | 54 | }; |
| 55 | 55 | } |
| 56 | 56 | |
| 57 | pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void { | |
| 57 | pub fn hash(data: []const u8, out: *[digest_length]u8, options: Options) void { | |
| 58 | 58 | var d = Md5.init(options); |
| 59 | d.update(b); | |
| 59 | d.update(data); | |
| 60 | 60 | d.final(out); |
| 61 | 61 | } |
| 62 | 62 | |
| 63 | pub fn hashResult(data: []const u8) [digest_length]u8 { | |
| 64 | var out: [digest_length]u8 = undefined; | |
| 65 | var d = Md5.init(.{}); | |
| 66 | d.update(data); | |
| 67 | d.final(&out); | |
| 68 | return out; | |
| 69 | } | |
| 70 | ||
| 63 | 71 | pub fn update(d: *Self, b: []const u8) void { |
| 64 | 72 | var off: usize = 0; |
| 65 | 73 |
lib/std/elf.zig+1-1| ... | ... | @@ -2001,7 +2001,7 @@ pub const R_AARCH64 = enum(u32) { |
| 2001 | 2001 | TLSLE_LDST64_TPREL_LO12 = 558, |
| 2002 | 2002 | /// Likewise; no check. |
| 2003 | 2003 | TLSLE_LDST64_TPREL_LO12_NC = 559, |
| 2004 | /// PC-rel. load immediate 20:2. | |
| 2004 | /// PC-rel. load immediate 20:2. | |
| 2005 | 2005 | TLSDESC_LD_PREL19 = 560, |
| 2006 | 2006 | /// PC-rel. ADR immediate 20:0. |
| 2007 | 2007 | TLSDESC_ADR_PREL21 = 561, |
lib/std/fs/File.zig+4-1| ... | ... | @@ -1337,7 +1337,10 @@ pub const Writer = struct { |
| 1337 | 1337 | return .{ |
| 1338 | 1338 | .vtable = &.{ |
| 1339 | 1339 | .drain = drain, |
| 1340 | .sendFile = sendFile, | |
| 1340 | .sendFile = switch (builtin.zig_backend) { | |
| 1341 | else => sendFile, | |
| 1342 | .stage2_aarch64 => std.io.Writer.unimplementedSendFile, | |
| 1343 | }, | |
| 1341 | 1344 | }, |
| 1342 | 1345 | .buffer = buffer, |
| 1343 | 1346 | }; |
lib/std/math.zig+55-38| ... | ... | @@ -45,6 +45,7 @@ pub const rad_per_deg = 0.017453292519943295769236907684886127134428718885417254 |
| 45 | 45 | /// 180.0/pi |
| 46 | 46 | pub const deg_per_rad = 57.295779513082320876798154814105170332405472466564321549160243861; |
| 47 | 47 | |
| 48 | pub const Sign = enum(u1) { positive, negative }; | |
| 48 | 49 | pub const FloatRepr = float.FloatRepr; |
| 49 | 50 | pub const floatExponentBits = float.floatExponentBits; |
| 50 | 51 | pub const floatMantissaBits = float.floatMantissaBits; |
| ... | ... | @@ -607,27 +608,30 @@ pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T { |
| 607 | 608 | /// Shifts left. Overflowed bits are truncated. |
| 608 | 609 | /// A negative shift amount results in a right shift. |
| 609 | 610 | pub fn shl(comptime T: type, a: T, shift_amt: anytype) T { |
| 611 | const is_shl = shift_amt >= 0; | |
| 610 | 612 | const abs_shift_amt = @abs(shift_amt); |
| 611 | ||
| 612 | const casted_shift_amt = blk: { | |
| 613 | if (@typeInfo(T) == .vector) { | |
| 614 | const C = @typeInfo(T).vector.child; | |
| 615 | const len = @typeInfo(T).vector.len; | |
| 616 | if (abs_shift_amt >= @typeInfo(C).int.bits) return @splat(0); | |
| 617 | break :blk @as(@Vector(len, Log2Int(C)), @splat(@as(Log2Int(C), @intCast(abs_shift_amt)))); | |
| 618 | } else { | |
| 619 | if (abs_shift_amt >= @typeInfo(T).int.bits) return 0; | |
| 620 | break :blk @as(Log2Int(T), @intCast(abs_shift_amt)); | |
| 621 | } | |
| 613 | const casted_shift_amt = casted_shift_amt: switch (@typeInfo(T)) { | |
| 614 | .int => |info| { | |
| 615 | if (abs_shift_amt < info.bits) break :casted_shift_amt @as( | |
| 616 | Log2Int(T), | |
| 617 | @intCast(abs_shift_amt), | |
| 618 | ); | |
| 619 | if (info.signedness == .unsigned or is_shl) return 0; | |
| 620 | return a >> (info.bits - 1); | |
| 621 | }, | |
| 622 | .vector => |info| { | |
| 623 | const Child = info.child; | |
| 624 | const child_info = @typeInfo(Child).int; | |
| 625 | if (abs_shift_amt < child_info.bits) break :casted_shift_amt @as( | |
| 626 | @Vector(info.len, Log2Int(Child)), | |
| 627 | @splat(@as(Log2Int(Child), @intCast(abs_shift_amt))), | |
| 628 | ); | |
| 629 | if (child_info.signedness == .unsigned or is_shl) return @splat(0); | |
| 630 | return a >> @splat(child_info.bits - 1); | |
| 631 | }, | |
| 632 | else => comptime unreachable, | |
| 622 | 633 | }; |
| 623 | ||
| 624 | if (@TypeOf(shift_amt) == comptime_int or @typeInfo(@TypeOf(shift_amt)).int.signedness == .signed) { | |
| 625 | if (shift_amt < 0) { | |
| 626 | return a >> casted_shift_amt; | |
| 627 | } | |
| 628 | } | |
| 629 | ||
| 630 | return a << casted_shift_amt; | |
| 634 | return if (is_shl) a << casted_shift_amt else a >> casted_shift_amt; | |
| 631 | 635 | } |
| 632 | 636 | |
| 633 | 637 | test shl { |
| ... | ... | @@ -642,32 +646,40 @@ test shl { |
| 642 | 646 | try testing.expect(shl(@Vector(1, u32), @Vector(1, u32){42}, @as(usize, 1))[0] == @as(u32, 42) << 1); |
| 643 | 647 | try testing.expect(shl(@Vector(1, u32), @Vector(1, u32){42}, @as(isize, -1))[0] == @as(u32, 42) >> 1); |
| 644 | 648 | try testing.expect(shl(@Vector(1, u32), @Vector(1, u32){42}, 33)[0] == 0); |
| 649 | ||
| 650 | try testing.expect(shl(i8, -1, -100) == -1); | |
| 651 | try testing.expect(shl(i8, -1, 100) == 0); | |
| 652 | try testing.expect(@reduce(.And, shl(@Vector(2, i8), .{ -1, 1 }, -100) == @Vector(2, i8){ -1, 0 })); | |
| 653 | try testing.expect(@reduce(.And, shl(@Vector(2, i8), .{ -1, 1 }, 100) == @Vector(2, i8){ 0, 0 })); | |
| 645 | 654 | } |
| 646 | 655 | |
| 647 | 656 | /// Shifts right. Overflowed bits are truncated. |
| 648 | 657 | /// A negative shift amount results in a left shift. |
| 649 | 658 | pub fn shr(comptime T: type, a: T, shift_amt: anytype) T { |
| 659 | const is_shl = shift_amt < 0; | |
| 650 | 660 | const abs_shift_amt = @abs(shift_amt); |
| 651 | ||
| 652 | const casted_shift_amt = blk: { | |
| 653 | if (@typeInfo(T) == .vector) { | |
| 654 | const C = @typeInfo(T).vector.child; | |
| 655 | const len = @typeInfo(T).vector.len; | |
| 656 | if (abs_shift_amt >= @typeInfo(C).int.bits) return @splat(0); | |
| 657 | break :blk @as(@Vector(len, Log2Int(C)), @splat(@as(Log2Int(C), @intCast(abs_shift_amt)))); | |
| 658 | } else { | |
| 659 | if (abs_shift_amt >= @typeInfo(T).int.bits) return 0; | |
| 660 | break :blk @as(Log2Int(T), @intCast(abs_shift_amt)); | |
| 661 | } | |
| 661 | const casted_shift_amt = casted_shift_amt: switch (@typeInfo(T)) { | |
| 662 | .int => |info| { | |
| 663 | if (abs_shift_amt < info.bits) break :casted_shift_amt @as( | |
| 664 | Log2Int(T), | |
| 665 | @intCast(abs_shift_amt), | |
| 666 | ); | |
| 667 | if (info.signedness == .unsigned or is_shl) return 0; | |
| 668 | return a >> (info.bits - 1); | |
| 669 | }, | |
| 670 | .vector => |info| { | |
| 671 | const Child = info.child; | |
| 672 | const child_info = @typeInfo(Child).int; | |
| 673 | if (abs_shift_amt < child_info.bits) break :casted_shift_amt @as( | |
| 674 | @Vector(info.len, Log2Int(Child)), | |
| 675 | @splat(@as(Log2Int(Child), @intCast(abs_shift_amt))), | |
| 676 | ); | |
| 677 | if (child_info.signedness == .unsigned or is_shl) return @splat(0); | |
| 678 | return a >> @splat(child_info.bits - 1); | |
| 679 | }, | |
| 680 | else => comptime unreachable, | |
| 662 | 681 | }; |
| 663 | ||
| 664 | if (@TypeOf(shift_amt) == comptime_int or @typeInfo(@TypeOf(shift_amt)).int.signedness == .signed) { | |
| 665 | if (shift_amt < 0) { | |
| 666 | return a << casted_shift_amt; | |
| 667 | } | |
| 668 | } | |
| 669 | ||
| 670 | return a >> casted_shift_amt; | |
| 682 | return if (is_shl) a << casted_shift_amt else a >> casted_shift_amt; | |
| 671 | 683 | } |
| 672 | 684 | |
| 673 | 685 | test shr { |
| ... | ... | @@ -682,6 +694,11 @@ test shr { |
| 682 | 694 | try testing.expect(shr(@Vector(1, u32), @Vector(1, u32){42}, @as(usize, 1))[0] == @as(u32, 42) >> 1); |
| 683 | 695 | try testing.expect(shr(@Vector(1, u32), @Vector(1, u32){42}, @as(isize, -1))[0] == @as(u32, 42) << 1); |
| 684 | 696 | try testing.expect(shr(@Vector(1, u32), @Vector(1, u32){42}, 33)[0] == 0); |
| 697 | ||
| 698 | try testing.expect(shr(i8, -1, -100) == 0); | |
| 699 | try testing.expect(shr(i8, -1, 100) == -1); | |
| 700 | try testing.expect(@reduce(.And, shr(@Vector(2, i8), .{ -1, 1 }, -100) == @Vector(2, i8){ 0, 0 })); | |
| 701 | try testing.expect(@reduce(.And, shr(@Vector(2, i8), .{ -1, 1 }, 100) == @Vector(2, i8){ -1, 0 })); | |
| 685 | 702 | } |
| 686 | 703 | |
| 687 | 704 | /// 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" { |
| 2774 | 2774 | // This test requires int sizes greater than 128 bits. |
| 2775 | 2775 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 2776 | 2776 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 2777 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2778 | 2777 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2779 | 2778 | // LLVM: unexpected runtime library name: __umodei4 |
| 2780 | 2779 | 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; |
| 4 | 4 | const expect = std.testing.expect; |
| 5 | 5 | const expectEqual = std.testing.expectEqual; |
| 6 | 6 | |
| 7 | pub const Sign = enum(u1) { positive, negative }; | |
| 8 | ||
| 9 | 7 | pub fn FloatRepr(comptime Float: type) type { |
| 10 | 8 | const fractional_bits = floatFractionalBits(Float); |
| 11 | 9 | const exponent_bits = floatExponentBits(Float); |
| ... | ... | @@ -14,7 +12,7 @@ pub fn FloatRepr(comptime Float: type) type { |
| 14 | 12 | |
| 15 | 13 | mantissa: StoredMantissa, |
| 16 | 14 | exponent: BiasedExponent, |
| 17 | sign: Sign, | |
| 15 | sign: std.math.Sign, | |
| 18 | 16 | |
| 19 | 17 | pub const StoredMantissa = @Type(.{ .int = .{ |
| 20 | 18 | .signedness = .unsigned, |
| ... | ... | @@ -69,7 +67,7 @@ pub fn FloatRepr(comptime Float: type) type { |
| 69 | 67 | |
| 70 | 68 | /// This currently truncates denormal values, which needs to be fixed before this can be used to |
| 71 | 69 | /// produce a rounded value. |
| 72 | pub fn reconstruct(normalized: Normalized, sign: Sign) Float { | |
| 70 | pub fn reconstruct(normalized: Normalized, sign: std.math.Sign) Float { | |
| 73 | 71 | if (normalized.exponent > BiasedExponent.max_normal.unbias()) return @bitCast(Repr{ |
| 74 | 72 | .mantissa = 0, |
| 75 | 73 | .exponent = .infinite, |
lib/std/math/log10.zig-1| ... | ... | @@ -132,7 +132,6 @@ inline fn less_than_5(x: u32) u32 { |
| 132 | 132 | test log10_int { |
| 133 | 133 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 134 | 134 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 135 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 136 | 135 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 137 | 136 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 138 | 137 | 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 { |
| 676 | 676 | |
| 677 | 677 | const eqlBytes_allowed = switch (builtin.zig_backend) { |
| 678 | 678 | // These backends don't support vectors yet. |
| 679 | .stage2_aarch64, | |
| 679 | 680 | .stage2_powerpc, |
| 680 | 681 | .stage2_riscv64, |
| 681 | 682 | => false, |
| ... | ... | @@ -4482,7 +4483,7 @@ pub fn doNotOptimizeAway(val: anytype) void { |
| 4482 | 4483 | ); |
| 4483 | 4484 | asm volatile ("" |
| 4484 | 4485 | : |
| 4485 | : [val2] "r" (val2), | |
| 4486 | : [_] "r" (val2), | |
| 4486 | 4487 | ); |
| 4487 | 4488 | } else doNotOptimizeAway(&val); |
| 4488 | 4489 | }, |
| ... | ... | @@ -4490,7 +4491,7 @@ pub fn doNotOptimizeAway(val: anytype) void { |
| 4490 | 4491 | if ((t.float.bits == 32 or t.float.bits == 64) and builtin.zig_backend != .stage2_c) { |
| 4491 | 4492 | asm volatile ("" |
| 4492 | 4493 | : |
| 4493 | : [val] "rm" (val), | |
| 4494 | : [_] "rm" (val), | |
| 4494 | 4495 | ); |
| 4495 | 4496 | } else doNotOptimizeAway(&val); |
| 4496 | 4497 | }, |
| ... | ... | @@ -4500,7 +4501,7 @@ pub fn doNotOptimizeAway(val: anytype) void { |
| 4500 | 4501 | } else { |
| 4501 | 4502 | asm volatile ("" |
| 4502 | 4503 | : |
| 4503 | : [val] "m" (val), | |
| 4504 | : [_] "m" (val), | |
| 4504 | 4505 | : .{ .memory = true }); |
| 4505 | 4506 | } |
| 4506 | 4507 | }, |
lib/std/os/linux.zig-1| ... | ... | @@ -503,7 +503,6 @@ pub var elf_aux_maybe: ?[*]std.elf.Auxv = null; |
| 503 | 503 | /// Whether an external or internal getauxval implementation is used. |
| 504 | 504 | const extern_getauxval = switch (builtin.zig_backend) { |
| 505 | 505 | // Calling extern functions is not yet supported with these backends |
| 506 | .stage2_aarch64, | |
| 507 | 506 | .stage2_arm, |
| 508 | 507 | .stage2_powerpc, |
| 509 | 508 | .stage2_riscv64, |
lib/std/start.zig+5-54| ... | ... | @@ -101,17 +101,11 @@ comptime { |
| 101 | 101 | // Simplified start code for stage2 until it supports more language features /// |
| 102 | 102 | |
| 103 | 103 | fn main2() callconv(.c) c_int { |
| 104 | root.main(); | |
| 105 | return 0; | |
| 104 | return callMain(); | |
| 106 | 105 | } |
| 107 | 106 | |
| 108 | 107 | fn _start2() callconv(.withStackAlign(.c, 1)) noreturn { |
| 109 | callMain2(); | |
| 110 | } | |
| 111 | ||
| 112 | fn callMain2() noreturn { | |
| 113 | root.main(); | |
| 114 | exit2(0); | |
| 108 | std.posix.exit(callMain()); | |
| 115 | 109 | } |
| 116 | 110 | |
| 117 | 111 | fn spirvMain2() callconv(.kernel) void { |
| ... | ... | @@ -119,51 +113,7 @@ fn spirvMain2() callconv(.kernel) void { |
| 119 | 113 | } |
| 120 | 114 | |
| 121 | 115 | fn wWinMainCRTStartup2() callconv(.c) noreturn { |
| 122 | root.main(); | |
| 123 | exit2(0); | |
| 124 | } | |
| 125 | ||
| 126 | fn 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()); | |
| 167 | 117 | } |
| 168 | 118 | |
| 169 | 119 | //////////////////////////////////////////////////////////////////////////////// |
| ... | ... | @@ -676,10 +626,11 @@ pub inline fn callMain() u8 { |
| 676 | 626 | |
| 677 | 627 | const result = root.main() catch |err| { |
| 678 | 628 | switch (builtin.zig_backend) { |
| 629 | .stage2_aarch64, | |
| 679 | 630 | .stage2_powerpc, |
| 680 | 631 | .stage2_riscv64, |
| 681 | 632 | => { |
| 682 | std.debug.print("error: failed with error\n", .{}); | |
| 633 | _ = std.posix.write(std.posix.STDERR_FILENO, "error: failed with error\n") catch {}; | |
| 683 | 634 | return 1; |
| 684 | 635 | }, |
| 685 | 636 | else => {}, |
lib/std/tar.zig+51-83| ... | ... | @@ -302,7 +302,7 @@ pub const FileKind = enum { |
| 302 | 302 | |
| 303 | 303 | /// Iterator over entries in the tar file represented by reader. |
| 304 | 304 | pub const Iterator = struct { |
| 305 | reader: *std.io.Reader, | |
| 305 | reader: *std.Io.Reader, | |
| 306 | 306 | diagnostics: ?*Diagnostics = null, |
| 307 | 307 | |
| 308 | 308 | // buffers for heeader and file attributes |
| ... | ... | @@ -328,7 +328,7 @@ pub const Iterator = struct { |
| 328 | 328 | |
| 329 | 329 | /// Iterates over files in tar archive. |
| 330 | 330 | /// `next` returns each file in tar archive. |
| 331 | pub fn init(reader: *std.io.Reader, options: Options) Iterator { | |
| 331 | pub fn init(reader: *std.Io.Reader, options: Options) Iterator { | |
| 332 | 332 | return .{ |
| 333 | 333 | .reader = reader, |
| 334 | 334 | .diagnostics = options.diagnostics, |
| ... | ... | @@ -343,47 +343,6 @@ pub const Iterator = struct { |
| 343 | 343 | size: u64 = 0, // size of the file in bytes |
| 344 | 344 | mode: u32 = 0, |
| 345 | 345 | kind: FileKind = .file, |
| 346 | ||
| 347 | unread_bytes: *u64, | |
| 348 | parent_reader: *std.io.Reader, | |
| 349 | ||
| 350 | pub fn reader(self: *File) std.io.Reader { | |
| 351 | return .{ | |
| 352 | .context = self, | |
| 353 | .vtable = &.{ | |
| 354 | .read = read, | |
| 355 | .readVec = readVec, | |
| 356 | .discard = discard, | |
| 357 | }, | |
| 358 | }; | |
| 359 | } | |
| 360 | ||
| 361 | fn read(context: ?*anyopaque, bw: *std.io.Writer, limit: std.io.Limit) std.io.Reader.StreamError!usize { | |
| 362 | const file: *File = @ptrCast(@alignCast(context)); | |
| 363 | if (file.unread_bytes.* == 0) return error.EndOfStream; | |
| 364 | const n = try file.parent_reader.read(bw, limit.min(.limited(file.unread_bytes.*))); | |
| 365 | file.unread_bytes.* -= n; | |
| 366 | return n; | |
| 367 | } | |
| 368 | ||
| 369 | fn readVec(context: ?*anyopaque, data: []const []u8) std.io.Reader.Error!usize { | |
| 370 | const file: *File = @ptrCast(@alignCast(context)); | |
| 371 | if (file.unread_bytes.* == 0) return error.EndOfStream; | |
| 372 | const n = try file.parent_reader.readVecLimit(data, .limited(file.unread_bytes.*)); | |
| 373 | file.unread_bytes.* -= n; | |
| 374 | return n; | |
| 375 | } | |
| 376 | ||
| 377 | fn discard(context: ?*anyopaque, limit: std.io.Limit) std.io.Reader.Error!usize { | |
| 378 | const file: *File = @ptrCast(@alignCast(context)); | |
| 379 | const n = limit.minInt(file.unread_bytes.*); | |
| 380 | file.unread_bytes.* -= n; | |
| 381 | return n; | |
| 382 | } | |
| 383 | ||
| 384 | pub fn streamRemaining(file: *File, out: *std.io.Writer) std.io.Reader.StreamRemainingError!usize { | |
| 385 | return file.reader().streamRemaining(out); | |
| 386 | } | |
| 387 | 346 | }; |
| 388 | 347 | |
| 389 | 348 | fn readHeader(self: *Iterator) !?Header { |
| ... | ... | @@ -401,7 +360,7 @@ pub const Iterator = struct { |
| 401 | 360 | fn readString(self: *Iterator, size: usize, buffer: []u8) ![]const u8 { |
| 402 | 361 | if (size > buffer.len) return error.TarInsufficientBuffer; |
| 403 | 362 | const buf = buffer[0..size]; |
| 404 | try self.reader.readSlice(buf); | |
| 363 | try self.reader.readSliceAll(buf); | |
| 405 | 364 | return nullStr(buf); |
| 406 | 365 | } |
| 407 | 366 | |
| ... | ... | @@ -409,8 +368,6 @@ pub const Iterator = struct { |
| 409 | 368 | return .{ |
| 410 | 369 | .name = self.file_name_buffer[0..0], |
| 411 | 370 | .link_name = self.link_name_buffer[0..0], |
| 412 | .parent_reader = self.reader, | |
| 413 | .unread_bytes = &self.unread_file_bytes, | |
| 414 | 371 | }; |
| 415 | 372 | } |
| 416 | 373 | |
| ... | ... | @@ -516,11 +473,16 @@ pub const Iterator = struct { |
| 516 | 473 | return null; |
| 517 | 474 | } |
| 518 | 475 | |
| 476 | pub fn streamRemaining(it: *Iterator, file: File, w: *std.Io.Writer) std.Io.Reader.StreamError!void { | |
| 477 | try it.reader.streamExact64(w, file.size); | |
| 478 | it.unread_file_bytes = 0; | |
| 479 | } | |
| 480 | ||
| 519 | 481 | fn skipGnuSparseExtendedHeaders(self: *Iterator, header: Header) !void { |
| 520 | 482 | var is_extended = header.bytes[482] > 0; |
| 521 | 483 | while (is_extended) { |
| 522 | 484 | var buf: [Header.SIZE]u8 = undefined; |
| 523 | try self.reader.readSlice(&buf); | |
| 485 | try self.reader.readSliceAll(&buf); | |
| 524 | 486 | is_extended = buf[504] > 0; |
| 525 | 487 | } |
| 526 | 488 | } |
| ... | ... | @@ -537,14 +499,14 @@ const pax_max_size_attr_len = 64; |
| 537 | 499 | |
| 538 | 500 | pub const PaxIterator = struct { |
| 539 | 501 | size: usize, // cumulative size of all pax attributes |
| 540 | reader: *std.io.Reader, | |
| 502 | reader: *std.Io.Reader, | |
| 541 | 503 | |
| 542 | 504 | const Self = @This(); |
| 543 | 505 | |
| 544 | 506 | const Attribute = struct { |
| 545 | 507 | kind: PaxAttributeKind, |
| 546 | 508 | len: usize, // length of the attribute value |
| 547 | reader: *std.io.Reader, // reader positioned at value start | |
| 509 | reader: *std.Io.Reader, // reader positioned at value start | |
| 548 | 510 | |
| 549 | 511 | // Copies pax attribute value into destination buffer. |
| 550 | 512 | // Must be called with destination buffer of size at least Attribute.len. |
| ... | ... | @@ -611,22 +573,23 @@ pub const PaxIterator = struct { |
| 611 | 573 | } |
| 612 | 574 | |
| 613 | 575 | // Checks that each record ends with new line. |
| 614 | fn validateAttributeEnding(reader: *std.io.Reader) !void { | |
| 576 | fn validateAttributeEnding(reader: *std.Io.Reader) !void { | |
| 615 | 577 | if (try reader.takeByte() != '\n') return error.PaxInvalidAttributeEnd; |
| 616 | 578 | } |
| 617 | 579 | }; |
| 618 | 580 | |
| 619 | 581 | /// Saves tar file content to the file systems. |
| 620 | pub fn pipeToFileSystem(dir: std.fs.Dir, reader: *std.io.Reader, options: PipeOptions) !void { | |
| 582 | pub fn pipeToFileSystem(dir: std.fs.Dir, reader: *std.Io.Reader, options: PipeOptions) !void { | |
| 621 | 583 | var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined; |
| 622 | 584 | var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined; |
| 623 | var iter: Iterator = .init(reader, .{ | |
| 585 | var file_contents_buffer: [1024]u8 = undefined; | |
| 586 | var it: Iterator = .init(reader, .{ | |
| 624 | 587 | .file_name_buffer = &file_name_buffer, |
| 625 | 588 | .link_name_buffer = &link_name_buffer, |
| 626 | 589 | .diagnostics = options.diagnostics, |
| 627 | 590 | }); |
| 628 | 591 | |
| 629 | while (try iter.next()) |file| { | |
| 592 | while (try it.next()) |file| { | |
| 630 | 593 | const file_name = stripComponents(file.name, options.strip_components); |
| 631 | 594 | if (file_name.len == 0 and file.kind != .directory) { |
| 632 | 595 | const d = options.diagnostics orelse return error.TarComponentsOutsideStrippedPrefix; |
| ... | ... | @@ -648,7 +611,9 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: *std.io.Reader, options: PipeOp |
| 648 | 611 | .file => { |
| 649 | 612 | if (createDirAndFile(dir, file_name, fileMode(file.mode, options))) |fs_file| { |
| 650 | 613 | defer fs_file.close(); |
| 651 | try file.writeAll(fs_file); | |
| 614 | var file_writer = fs_file.writer(&file_contents_buffer); | |
| 615 | try it.streamRemaining(file, &file_writer.interface); | |
| 616 | try file_writer.interface.flush(); | |
| 652 | 617 | } else |err| { |
| 653 | 618 | const d = options.diagnostics orelse return err; |
| 654 | 619 | try d.errors.append(d.allocator, .{ .unable_to_create_file = .{ |
| ... | ... | @@ -818,11 +783,14 @@ test PaxIterator { |
| 818 | 783 | var buffer: [1024]u8 = undefined; |
| 819 | 784 | |
| 820 | 785 | outer: for (cases) |case| { |
| 821 | var br: std.io.Reader = .fixed(case.data); | |
| 822 | var iter: PaxIterator = .init(&br, case.data.len); | |
| 786 | var reader: std.Io.Reader = .fixed(case.data); | |
| 787 | var it: PaxIterator = .{ | |
| 788 | .size = case.data.len, | |
| 789 | .reader = &reader, | |
| 790 | }; | |
| 823 | 791 | |
| 824 | 792 | var i: usize = 0; |
| 825 | while (iter.next() catch |err| { | |
| 793 | while (it.next() catch |err| { | |
| 826 | 794 | if (case.err) |e| { |
| 827 | 795 | try testing.expectEqual(e, err); |
| 828 | 796 | continue; |
| ... | ... | @@ -845,12 +813,6 @@ test PaxIterator { |
| 845 | 813 | } |
| 846 | 814 | } |
| 847 | 815 | |
| 848 | test { | |
| 849 | _ = @import("tar/test.zig"); | |
| 850 | _ = Writer; | |
| 851 | _ = Diagnostics; | |
| 852 | } | |
| 853 | ||
| 854 | 816 | test "header parse size" { |
| 855 | 817 | const cases = [_]struct { |
| 856 | 818 | in: []const u8, |
| ... | ... | @@ -954,19 +916,19 @@ test Iterator { |
| 954 | 916 | // example/empty/ |
| 955 | 917 | |
| 956 | 918 | const data = @embedFile("tar/testdata/example.tar"); |
| 957 | var br: std.io.Reader = .fixed(data); | |
| 919 | var reader: std.Io.Reader = .fixed(data); | |
| 958 | 920 | |
| 959 | 921 | // User provided buffers to the iterator |
| 960 | 922 | var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined; |
| 961 | 923 | var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined; |
| 962 | 924 | // Create iterator |
| 963 | var iter: Iterator = .init(&br, .{ | |
| 925 | var it: Iterator = .init(&reader, .{ | |
| 964 | 926 | .file_name_buffer = &file_name_buffer, |
| 965 | 927 | .link_name_buffer = &link_name_buffer, |
| 966 | 928 | }); |
| 967 | 929 | // Iterate over files in example.tar |
| 968 | 930 | var file_no: usize = 0; |
| 969 | while (try iter.next()) |file| : (file_no += 1) { | |
| 931 | while (try it.next()) |file| : (file_no += 1) { | |
| 970 | 932 | switch (file.kind) { |
| 971 | 933 | .directory => { |
| 972 | 934 | switch (file_no) { |
| ... | ... | @@ -979,10 +941,10 @@ test Iterator { |
| 979 | 941 | }, |
| 980 | 942 | .file => { |
| 981 | 943 | try testing.expectEqualStrings("example/a/file", file.name); |
| 982 | // Read file content | |
| 983 | 944 | var buf: [16]u8 = undefined; |
| 984 | const n = try file.reader().readAll(&buf); | |
| 985 | try testing.expectEqualStrings("content\n", buf[0..n]); | |
| 945 | var w: std.Io.Writer = .fixed(&buf); | |
| 946 | try it.streamRemaining(file, &w); | |
| 947 | try testing.expectEqualStrings("content\n", w.buffered()); | |
| 986 | 948 | }, |
| 987 | 949 | .sym_link => { |
| 988 | 950 | try testing.expectEqualStrings("example/b/symlink", file.name); |
| ... | ... | @@ -1013,14 +975,14 @@ test pipeToFileSystem { |
| 1013 | 975 | // example/empty/ |
| 1014 | 976 | |
| 1015 | 977 | const data = @embedFile("tar/testdata/example.tar"); |
| 1016 | var br: std.io.Reader = .fixed(data); | |
| 978 | var reader: std.Io.Reader = .fixed(data); | |
| 1017 | 979 | |
| 1018 | 980 | var tmp = testing.tmpDir(.{ .no_follow = true }); |
| 1019 | 981 | defer tmp.cleanup(); |
| 1020 | 982 | const dir = tmp.dir; |
| 1021 | 983 | |
| 1022 | 984 | // Save tar from reader to the file system `dir` |
| 1023 | pipeToFileSystem(dir, &br, .{ | |
| 985 | pipeToFileSystem(dir, &reader, .{ | |
| 1024 | 986 | .mode_mode = .ignore, |
| 1025 | 987 | .strip_components = 1, |
| 1026 | 988 | .exclude_empty_directories = true, |
| ... | ... | @@ -1044,7 +1006,7 @@ test pipeToFileSystem { |
| 1044 | 1006 | |
| 1045 | 1007 | test "pipeToFileSystem root_dir" { |
| 1046 | 1008 | const data = @embedFile("tar/testdata/example.tar"); |
| 1047 | var br: std.io.Reader = .fixed(data); | |
| 1009 | var reader: std.Io.Reader = .fixed(data); | |
| 1048 | 1010 | |
| 1049 | 1011 | // with strip_components = 1 |
| 1050 | 1012 | { |
| ... | ... | @@ -1053,7 +1015,7 @@ test "pipeToFileSystem root_dir" { |
| 1053 | 1015 | var diagnostics: Diagnostics = .{ .allocator = testing.allocator }; |
| 1054 | 1016 | defer diagnostics.deinit(); |
| 1055 | 1017 | |
| 1056 | pipeToFileSystem(tmp.dir, &br, .{ | |
| 1018 | pipeToFileSystem(tmp.dir, &reader, .{ | |
| 1057 | 1019 | .strip_components = 1, |
| 1058 | 1020 | .diagnostics = &diagnostics, |
| 1059 | 1021 | }) catch |err| { |
| ... | ... | @@ -1069,13 +1031,13 @@ test "pipeToFileSystem root_dir" { |
| 1069 | 1031 | |
| 1070 | 1032 | // with strip_components = 0 |
| 1071 | 1033 | { |
| 1072 | br = .fixed(data); | |
| 1034 | reader = .fixed(data); | |
| 1073 | 1035 | var tmp = testing.tmpDir(.{ .no_follow = true }); |
| 1074 | 1036 | defer tmp.cleanup(); |
| 1075 | 1037 | var diagnostics: Diagnostics = .{ .allocator = testing.allocator }; |
| 1076 | 1038 | defer diagnostics.deinit(); |
| 1077 | 1039 | |
| 1078 | pipeToFileSystem(tmp.dir, &br, .{ | |
| 1040 | pipeToFileSystem(tmp.dir, &reader, .{ | |
| 1079 | 1041 | .strip_components = 0, |
| 1080 | 1042 | .diagnostics = &diagnostics, |
| 1081 | 1043 | }) catch |err| { |
| ... | ... | @@ -1092,42 +1054,42 @@ test "pipeToFileSystem root_dir" { |
| 1092 | 1054 | |
| 1093 | 1055 | test "findRoot with single file archive" { |
| 1094 | 1056 | const data = @embedFile("tar/testdata/22752.tar"); |
| 1095 | var br: std.io.Reader = .fixed(data); | |
| 1057 | var reader: std.Io.Reader = .fixed(data); | |
| 1096 | 1058 | |
| 1097 | 1059 | var tmp = testing.tmpDir(.{}); |
| 1098 | 1060 | defer tmp.cleanup(); |
| 1099 | 1061 | |
| 1100 | 1062 | var diagnostics: Diagnostics = .{ .allocator = testing.allocator }; |
| 1101 | 1063 | defer diagnostics.deinit(); |
| 1102 | try pipeToFileSystem(tmp.dir, &br, .{ .diagnostics = &diagnostics }); | |
| 1064 | try pipeToFileSystem(tmp.dir, &reader, .{ .diagnostics = &diagnostics }); | |
| 1103 | 1065 | |
| 1104 | 1066 | try testing.expectEqualStrings("", diagnostics.root_dir); |
| 1105 | 1067 | } |
| 1106 | 1068 | |
| 1107 | 1069 | test "findRoot without explicit root dir" { |
| 1108 | 1070 | const data = @embedFile("tar/testdata/19820.tar"); |
| 1109 | var br: std.io.Reader = .fixed(data); | |
| 1071 | var reader: std.Io.Reader = .fixed(data); | |
| 1110 | 1072 | |
| 1111 | 1073 | var tmp = testing.tmpDir(.{}); |
| 1112 | 1074 | defer tmp.cleanup(); |
| 1113 | 1075 | |
| 1114 | 1076 | var diagnostics: Diagnostics = .{ .allocator = testing.allocator }; |
| 1115 | 1077 | defer diagnostics.deinit(); |
| 1116 | try pipeToFileSystem(tmp.dir, &br, .{ .diagnostics = &diagnostics }); | |
| 1078 | try pipeToFileSystem(tmp.dir, &reader, .{ .diagnostics = &diagnostics }); | |
| 1117 | 1079 | |
| 1118 | 1080 | try testing.expectEqualStrings("root", diagnostics.root_dir); |
| 1119 | 1081 | } |
| 1120 | 1082 | |
| 1121 | 1083 | test "pipeToFileSystem strip_components" { |
| 1122 | 1084 | const data = @embedFile("tar/testdata/example.tar"); |
| 1123 | var br: std.io.Reader = .fixed(data); | |
| 1085 | var reader: std.Io.Reader = .fixed(data); | |
| 1124 | 1086 | |
| 1125 | 1087 | var tmp = testing.tmpDir(.{ .no_follow = true }); |
| 1126 | 1088 | defer tmp.cleanup(); |
| 1127 | 1089 | var diagnostics: Diagnostics = .{ .allocator = testing.allocator }; |
| 1128 | 1090 | defer diagnostics.deinit(); |
| 1129 | 1091 | |
| 1130 | pipeToFileSystem(tmp.dir, &br, .{ | |
| 1092 | pipeToFileSystem(tmp.dir, &reader, .{ | |
| 1131 | 1093 | .strip_components = 3, |
| 1132 | 1094 | .diagnostics = &diagnostics, |
| 1133 | 1095 | }) catch |err| { |
| ... | ... | @@ -1181,12 +1143,12 @@ test "executable bit" { |
| 1181 | 1143 | const data = @embedFile("tar/testdata/example.tar"); |
| 1182 | 1144 | |
| 1183 | 1145 | for ([_]PipeOptions.ModeMode{ .ignore, .executable_bit_only }) |opt| { |
| 1184 | var br: std.io.Reader = .fixed(data); | |
| 1146 | var reader: std.Io.Reader = .fixed(data); | |
| 1185 | 1147 | |
| 1186 | 1148 | var tmp = testing.tmpDir(.{ .no_follow = true }); |
| 1187 | 1149 | //defer tmp.cleanup(); |
| 1188 | 1150 | |
| 1189 | pipeToFileSystem(tmp.dir, &br, .{ | |
| 1151 | pipeToFileSystem(tmp.dir, &reader, .{ | |
| 1190 | 1152 | .strip_components = 1, |
| 1191 | 1153 | .exclude_empty_directories = true, |
| 1192 | 1154 | .mode_mode = opt, |
| ... | ... | @@ -1212,3 +1174,9 @@ test "executable bit" { |
| 1212 | 1174 | } |
| 1213 | 1175 | } |
| 1214 | 1176 | } |
| 1177 | ||
| 1178 | test { | |
| 1179 | _ = @import("tar/test.zig"); | |
| 1180 | _ = Writer; | |
| 1181 | _ = Diagnostics; | |
| 1182 | } |
lib/std/tar/Writer.zig+56-93| ... | ... | @@ -14,7 +14,7 @@ pub const Options = struct { |
| 14 | 14 | mtime: u64 = 0, |
| 15 | 15 | }; |
| 16 | 16 | |
| 17 | underlying_writer: *std.io.Writer, | |
| 17 | underlying_writer: *std.Io.Writer, | |
| 18 | 18 | prefix: []const u8 = "", |
| 19 | 19 | mtime_now: u64 = 0, |
| 20 | 20 | |
| ... | ... | @@ -36,48 +36,47 @@ pub fn writeDir(w: *Writer, sub_path: []const u8, options: Options) Error!void { |
| 36 | 36 | try w.writeHeader(.directory, sub_path, "", 0, options); |
| 37 | 37 | } |
| 38 | 38 | |
| 39 | pub const WriteFileError = std.io.Writer.FileError || Error; | |
| 39 | pub const WriteFileError = std.Io.Writer.FileError || Error || std.fs.File.GetEndPosError; | |
| 40 | 40 | |
| 41 | 41 | pub fn writeFile( |
| 42 | 42 | w: *Writer, |
| 43 | 43 | sub_path: []const u8, |
| 44 | file: std.fs.File, | |
| 45 | stat: std.fs.File.Stat, | |
| 44 | file_reader: *std.fs.File.Reader, | |
| 45 | stat_mtime: i128, | |
| 46 | 46 | ) WriteFileError!void { |
| 47 | const mtime: u64 = @intCast(@divFloor(stat.mtime, std.time.ns_per_s)); | |
| 47 | const size = try file_reader.getSize(); | |
| 48 | const mtime: u64 = @intCast(@divFloor(stat_mtime, std.time.ns_per_s)); | |
| 48 | 49 | |
| 49 | 50 | var header: Header = .{}; |
| 50 | 51 | try w.setPath(&header, sub_path); |
| 51 | try header.setSize(stat.size); | |
| 52 | try header.setSize(size); | |
| 52 | 53 | try header.setMtime(mtime); |
| 53 | 54 | try header.updateChecksum(); |
| 54 | 55 | |
| 55 | var vec: [1][]const u8 = .{@ptrCast((&header)[0..1])}; | |
| 56 | try w.underlying_writer.writeFileAll(file, .{ | |
| 57 | .limit = .limited(stat.size), | |
| 58 | .headers_and_trailers = &vec, | |
| 59 | .headers_len = 1, | |
| 60 | }); | |
| 61 | try w.writePadding(stat.size); | |
| 56 | try w.underlying_writer.writeAll(@ptrCast((&header)[0..1])); | |
| 57 | _ = try w.underlying_writer.sendFileAll(file_reader, .unlimited); | |
| 58 | try w.writePadding64(size); | |
| 62 | 59 | } |
| 63 | 60 | |
| 61 | pub const WriteFileStreamError = Error || std.Io.Reader.StreamError; | |
| 62 | ||
| 64 | 63 | /// Writes file reading file content from `reader`. Reads exactly `size` bytes |
| 65 | 64 | /// from `reader`, or returns `error.EndOfStream`. |
| 66 | 65 | pub fn writeFileStream( |
| 67 | 66 | w: *Writer, |
| 68 | 67 | sub_path: []const u8, |
| 69 | size: usize, | |
| 70 | reader: *std.io.Reader, | |
| 68 | size: u64, | |
| 69 | reader: *std.Io.Reader, | |
| 71 | 70 | options: Options, |
| 72 | ) std.io.Reader.StreamError!void { | |
| 73 | try w.writeHeader(.regular, sub_path, "", @intCast(size), options); | |
| 74 | try reader.readAll(w.underlying_writer, .limited(size)); | |
| 75 | try w.writePadding(size); | |
| 71 | ) WriteFileStreamError!void { | |
| 72 | try w.writeHeader(.regular, sub_path, "", size, options); | |
| 73 | try reader.streamExact64(w.underlying_writer, size); | |
| 74 | try w.writePadding64(size); | |
| 76 | 75 | } |
| 77 | 76 | |
| 78 | 77 | /// Writes file using bytes buffer `content` for size and file content. |
| 79 | 78 | pub fn writeFileBytes(w: *Writer, sub_path: []const u8, content: []const u8, options: Options) Error!void { |
| 80 | try w.writeHeader(.regular, sub_path, "", @intCast(content.len), options); | |
| 79 | try w.writeHeader(.regular, sub_path, "", content.len, options); | |
| 81 | 80 | try w.underlying_writer.writeAll(content); |
| 82 | 81 | try w.writePadding(content.len); |
| 83 | 82 | } |
| ... | ... | @@ -86,30 +85,6 @@ pub fn writeLink(w: *Writer, sub_path: []const u8, link_name: []const u8, option |
| 86 | 85 | try w.writeHeader(.symbolic_link, sub_path, link_name, 0, options); |
| 87 | 86 | } |
| 88 | 87 | |
| 89 | /// Writes fs.Dir.WalkerEntry. Uses `mtime` from file system entry and | |
| 90 | /// default for entry mode . | |
| 91 | pub fn writeEntry(w: *Writer, entry: std.fs.Dir.Walker.Entry) Error!void { | |
| 92 | switch (entry.kind) { | |
| 93 | .directory => { | |
| 94 | try w.writeDir(entry.path, .{ .mtime = try entryMtime(entry) }); | |
| 95 | }, | |
| 96 | .file => { | |
| 97 | var file = try entry.dir.openFile(entry.basename, .{}); | |
| 98 | defer file.close(); | |
| 99 | const stat = try file.stat(); | |
| 100 | try w.writeFile(entry.path, file, stat); | |
| 101 | }, | |
| 102 | .sym_link => { | |
| 103 | var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined; | |
| 104 | const link_name = try entry.dir.readLink(entry.basename, &link_name_buffer); | |
| 105 | try w.writeLink(entry.path, link_name, .{ .mtime = try entryMtime(entry) }); | |
| 106 | }, | |
| 107 | else => { | |
| 108 | return error.UnsupportedWalkerEntryKind; | |
| 109 | }, | |
| 110 | } | |
| 111 | } | |
| 112 | ||
| 113 | 88 | fn writeHeader( |
| 114 | 89 | w: *Writer, |
| 115 | 90 | typeflag: Header.FileType, |
| ... | ... | @@ -121,7 +96,7 @@ fn writeHeader( |
| 121 | 96 | var header = Header.init(typeflag); |
| 122 | 97 | try w.setPath(&header, sub_path); |
| 123 | 98 | try header.setSize(size); |
| 124 | try header.setMtime(if (options.mtime != 0) options.mtime else w.mtimeNow()); | |
| 99 | try header.setMtime(options.mtime); | |
| 125 | 100 | if (options.mode != 0) |
| 126 | 101 | try header.setMode(options.mode); |
| 127 | 102 | if (typeflag == .symbolic_link) |
| ... | ... | @@ -132,17 +107,6 @@ fn writeHeader( |
| 132 | 107 | try header.write(w.underlying_writer); |
| 133 | 108 | } |
| 134 | 109 | |
| 135 | fn mtimeNow(w: *Writer) u64 { | |
| 136 | if (w.mtime_now == 0) | |
| 137 | w.mtime_now = @intCast(std.time.timestamp()); | |
| 138 | return w.mtime_now; | |
| 139 | } | |
| 140 | ||
| 141 | fn entryMtime(entry: std.fs.Dir.Walker.Entry) !u64 { | |
| 142 | const stat = try entry.dir.statFile(entry.basename); | |
| 143 | return @intCast(@divFloor(stat.mtime, std.time.ns_per_s)); | |
| 144 | } | |
| 145 | ||
| 146 | 110 | /// Writes path in posix header, if don't fit (in name+prefix; 100+155 |
| 147 | 111 | /// bytes) writes it in gnu extended header. |
| 148 | 112 | fn setPath(w: *Writer, header: *Header, sub_path: []const u8) Error!void { |
| ... | ... | @@ -172,8 +136,15 @@ fn writeExtendedHeader(w: *Writer, typeflag: Header.FileType, buffers: []const [ |
| 172 | 136 | try w.writePadding(len); |
| 173 | 137 | } |
| 174 | 138 | |
| 175 | fn writePadding(w: *Writer, bytes: usize) std.io.Writer.Error!void { | |
| 176 | const pos = bytes % block_size; | |
| 139 | fn writePadding(w: *Writer, bytes: usize) std.Io.Writer.Error!void { | |
| 140 | return writePaddingPos(w, bytes % block_size); | |
| 141 | } | |
| 142 | ||
| 143 | fn writePadding64(w: *Writer, bytes: u64) std.Io.Writer.Error!void { | |
| 144 | return writePaddingPos(w, @intCast(bytes % block_size)); | |
| 145 | } | |
| 146 | ||
| 147 | fn writePaddingPos(w: *Writer, pos: usize) std.Io.Writer.Error!void { | |
| 177 | 148 | if (pos == 0) return; |
| 178 | 149 | try w.underlying_writer.splatByteAll(0, block_size - pos); |
| 179 | 150 | } |
| ... | ... | @@ -182,8 +153,8 @@ fn writePadding(w: *Writer, bytes: usize) std.io.Writer.Error!void { |
| 182 | 153 | /// "reasonable system must not assume that such a block exists when reading an |
| 183 | 154 | /// archive". Therefore, the Zig standard library recommends to not call this |
| 184 | 155 | /// function. |
| 185 | pub fn finishPedantically(w: *Writer) std.io.Writer.Error!void { | |
| 186 | try w.underlying_writer.writeSplatAll(&.{&.{0}}, block_size * 2); | |
| 156 | pub fn finishPedantically(w: *Writer) std.Io.Writer.Error!void { | |
| 157 | try w.underlying_writer.splatByteAll(0, block_size * 2); | |
| 187 | 158 | } |
| 188 | 159 | |
| 189 | 160 | /// A struct that is exactly 512 bytes and matches tar file format. This is |
| ... | ... | @@ -277,7 +248,7 @@ pub const Header = extern struct { |
| 277 | 248 | try octal(&w.checksum, checksum); |
| 278 | 249 | } |
| 279 | 250 | |
| 280 | pub fn write(h: *Header, bw: *std.io.Writer) error{ OctalOverflow, WriteFailed }!void { | |
| 251 | pub fn write(h: *Header, bw: *std.Io.Writer) error{ OctalOverflow, WriteFailed }!void { | |
| 281 | 252 | try h.updateChecksum(); |
| 282 | 253 | try bw.writeAll(std.mem.asBytes(h)); |
| 283 | 254 | } |
| ... | ... | @@ -375,8 +346,8 @@ pub const Header = extern struct { |
| 375 | 346 | for (cases) |case| { |
| 376 | 347 | var header = Header.init(.regular); |
| 377 | 348 | try header.setPath(case.in[0], case.in[1]); |
| 378 | try testing.expectEqualStrings(case.out[0], str(&header.prefix)); | |
| 379 | try testing.expectEqualStrings(case.out[1], str(&header.name)); | |
| 349 | try testing.expectEqualStrings(case.out[0], std.mem.sliceTo(&header.prefix, 0)); | |
| 350 | try testing.expectEqualStrings(case.out[1], std.mem.sliceTo(&header.name, 0)); | |
| 380 | 351 | } |
| 381 | 352 | |
| 382 | 353 | const error_cases = [_]struct { |
| ... | ... | @@ -399,14 +370,6 @@ pub const Header = extern struct { |
| 399 | 370 | ); |
| 400 | 371 | } |
| 401 | 372 | } |
| 402 | ||
| 403 | // Breaks string on first null character. | |
| 404 | fn str(s: []const u8) []const u8 { | |
| 405 | for (s, 0..) |c, i| { | |
| 406 | if (c == 0) return s[0..i]; | |
| 407 | } | |
| 408 | return s; | |
| 409 | } | |
| 410 | 373 | }; |
| 411 | 374 | |
| 412 | 375 | test { |
| ... | ... | @@ -433,67 +396,67 @@ test "write files" { |
| 433 | 396 | { |
| 434 | 397 | const root = "root"; |
| 435 | 398 | |
| 436 | var output: std.io.Writer.Allocating = .init(testing.allocator); | |
| 437 | var wrt: Writer = .{ .underlying_writer = &output.interface }; | |
| 399 | var output: std.Io.Writer.Allocating = .init(testing.allocator); | |
| 400 | var w: Writer = .{ .underlying_writer = &output.writer }; | |
| 438 | 401 | defer output.deinit(); |
| 439 | try wrt.setRoot(root); | |
| 402 | try w.setRoot(root); | |
| 440 | 403 | for (files) |file| |
| 441 | try wrt.writeFileBytes(file.path, file.content, .{}); | |
| 404 | try w.writeFileBytes(file.path, file.content, .{}); | |
| 442 | 405 | |
| 443 | var input: std.io.Reader = .fixed(output.getWritten()); | |
| 444 | var iter = std.tar.iterator(&input, .{ | |
| 406 | var input: std.Io.Reader = .fixed(output.getWritten()); | |
| 407 | var it: std.tar.Iterator = .init(&input, .{ | |
| 445 | 408 | .file_name_buffer = &file_name_buffer, |
| 446 | 409 | .link_name_buffer = &link_name_buffer, |
| 447 | 410 | }); |
| 448 | 411 | |
| 449 | 412 | // first entry is directory with prefix |
| 450 | 413 | { |
| 451 | const actual = (try iter.next()).?; | |
| 414 | const actual = (try it.next()).?; | |
| 452 | 415 | try testing.expectEqualStrings(root, actual.name); |
| 453 | 416 | try testing.expectEqual(std.tar.FileKind.directory, actual.kind); |
| 454 | 417 | } |
| 455 | 418 | |
| 456 | 419 | var i: usize = 0; |
| 457 | while (try iter.next()) |actual| { | |
| 420 | while (try it.next()) |actual| { | |
| 458 | 421 | defer i += 1; |
| 459 | 422 | const expected = files[i]; |
| 460 | 423 | try testing.expectEqualStrings(root, actual.name[0..root.len]); |
| 461 | 424 | try testing.expectEqual('/', actual.name[root.len..][0]); |
| 462 | 425 | try testing.expectEqualStrings(expected.path, actual.name[root.len + 1 ..]); |
| 463 | 426 | |
| 464 | var content = std.ArrayList(u8).init(testing.allocator); | |
| 427 | var content: std.Io.Writer.Allocating = .init(testing.allocator); | |
| 465 | 428 | defer content.deinit(); |
| 466 | try actual.writeAll(content.writer()); | |
| 467 | try testing.expectEqualSlices(u8, expected.content, content.items); | |
| 429 | try it.streamRemaining(actual, &content.writer); | |
| 430 | try testing.expectEqualSlices(u8, expected.content, content.getWritten()); | |
| 468 | 431 | } |
| 469 | 432 | } |
| 470 | 433 | // without root |
| 471 | 434 | { |
| 472 | var output: std.io.Writer.Allocating = .init(testing.allocator); | |
| 473 | var wrt: Writer = .{ .underlying_writer = &output.interface }; | |
| 435 | var output: std.Io.Writer.Allocating = .init(testing.allocator); | |
| 436 | var w: Writer = .{ .underlying_writer = &output.writer }; | |
| 474 | 437 | defer output.deinit(); |
| 475 | 438 | for (files) |file| { |
| 476 | var content: std.io.Reader = .fixed(file.content); | |
| 477 | try wrt.writeFileStream(file.path, file.content.len, &content, .{}); | |
| 439 | var content: std.Io.Reader = .fixed(file.content); | |
| 440 | try w.writeFileStream(file.path, file.content.len, &content, .{}); | |
| 478 | 441 | } |
| 479 | 442 | |
| 480 | var input: std.io.Reader = .fixed(output.getWritten()); | |
| 481 | var iter = std.tar.iterator(&input, .{ | |
| 443 | var input: std.Io.Reader = .fixed(output.getWritten()); | |
| 444 | var it: std.tar.Iterator = .init(&input, .{ | |
| 482 | 445 | .file_name_buffer = &file_name_buffer, |
| 483 | 446 | .link_name_buffer = &link_name_buffer, |
| 484 | 447 | }); |
| 485 | 448 | |
| 486 | 449 | var i: usize = 0; |
| 487 | while (try iter.next()) |actual| { | |
| 450 | while (try it.next()) |actual| { | |
| 488 | 451 | defer i += 1; |
| 489 | 452 | const expected = files[i]; |
| 490 | 453 | try testing.expectEqualStrings(expected.path, actual.name); |
| 491 | 454 | |
| 492 | var content = std.ArrayList(u8).init(testing.allocator); | |
| 455 | var content: std.Io.Writer.Allocating = .init(testing.allocator); | |
| 493 | 456 | defer content.deinit(); |
| 494 | try actual.writeAll(content.writer()); | |
| 495 | try testing.expectEqualSlices(u8, expected.content, content.items); | |
| 457 | try it.streamRemaining(actual, &content.writer); | |
| 458 | try testing.expectEqualSlices(u8, expected.content, content.getWritten()); | |
| 496 | 459 | } |
| 497 | try wrt.finish(); | |
| 460 | try w.finishPedantically(); | |
| 498 | 461 | } |
| 499 | 462 | } |
lib/std/tar/test.zig+166-170| ... | ... | @@ -18,31 +18,72 @@ const Case = struct { |
| 18 | 18 | err: ?anyerror = null, // parsing should fail with this error |
| 19 | 19 | }; |
| 20 | 20 | |
| 21 | const cases = [_]Case{ | |
| 22 | .{ | |
| 23 | .data = @embedFile("testdata/gnu.tar"), | |
| 24 | .files = &[_]Case.File{ | |
| 25 | .{ | |
| 26 | .name = "small.txt", | |
| 27 | .size = 5, | |
| 28 | .mode = 0o640, | |
| 29 | }, | |
| 30 | .{ | |
| 31 | .name = "small2.txt", | |
| 32 | .size = 11, | |
| 33 | .mode = 0o640, | |
| 34 | }, | |
| 21 | const gnu_case: Case = .{ | |
| 22 | .data = @embedFile("testdata/gnu.tar"), | |
| 23 | .files = &[_]Case.File{ | |
| 24 | .{ | |
| 25 | .name = "small.txt", | |
| 26 | .size = 5, | |
| 27 | .mode = 0o640, | |
| 35 | 28 | }, |
| 36 | .chksums = &[_][]const u8{ | |
| 37 | "e38b27eaccb4391bdec553a7f3ae6b2f", | |
| 38 | "c65bd2e50a56a2138bf1716f2fd56fe9", | |
| 29 | .{ | |
| 30 | .name = "small2.txt", | |
| 31 | .size = 11, | |
| 32 | .mode = 0o640, | |
| 33 | }, | |
| 34 | }, | |
| 35 | .chksums = &[_][]const u8{ | |
| 36 | "e38b27eaccb4391bdec553a7f3ae6b2f", | |
| 37 | "c65bd2e50a56a2138bf1716f2fd56fe9", | |
| 38 | }, | |
| 39 | }; | |
| 40 | ||
| 41 | const gnu_multi_headers_case: Case = .{ | |
| 42 | .data = @embedFile("testdata/gnu-multi-hdrs.tar"), | |
| 43 | .files = &[_]Case.File{ | |
| 44 | .{ | |
| 45 | .name = "GNU2/GNU2/long-path-name", | |
| 46 | .link_name = "GNU4/GNU4/long-linkpath-name", | |
| 47 | .kind = .sym_link, | |
| 39 | 48 | }, |
| 40 | 49 | }, |
| 41 | .{ | |
| 50 | }; | |
| 51 | ||
| 52 | const trailing_slash_case: Case = .{ | |
| 53 | .data = @embedFile("testdata/trailing-slash.tar"), | |
| 54 | .files = &[_]Case.File{ | |
| 55 | .{ | |
| 56 | .name = "123456789/" ** 30, | |
| 57 | .kind = .directory, | |
| 58 | }, | |
| 59 | }, | |
| 60 | }; | |
| 61 | ||
| 62 | const writer_big_long_case: Case = .{ | |
| 63 | // Size in gnu extended format, and name in pax attribute. | |
| 64 | .data = @embedFile("testdata/writer-big-long.tar"), | |
| 65 | .files = &[_]Case.File{ | |
| 66 | .{ | |
| 67 | .name = "longname/" ** 15 ++ "16gig.txt", | |
| 68 | .size = 16 * 1024 * 1024 * 1024, | |
| 69 | .mode = 0o644, | |
| 70 | .truncated = true, | |
| 71 | }, | |
| 72 | }, | |
| 73 | }; | |
| 74 | ||
| 75 | const fuzz1_case: Case = .{ | |
| 76 | .data = @embedFile("testdata/fuzz1.tar"), | |
| 77 | .err = error.TarInsufficientBuffer, | |
| 78 | }; | |
| 79 | ||
| 80 | test "run test cases" { | |
| 81 | try testCase(gnu_case); | |
| 82 | try testCase(.{ | |
| 42 | 83 | .data = @embedFile("testdata/sparse-formats.tar"), |
| 43 | 84 | .err = error.TarUnsupportedHeader, |
| 44 | }, | |
| 45 | .{ | |
| 85 | }); | |
| 86 | try testCase(.{ | |
| 46 | 87 | .data = @embedFile("testdata/star.tar"), |
| 47 | 88 | .files = &[_]Case.File{ |
| 48 | 89 | .{ |
| ... | ... | @@ -60,8 +101,8 @@ const cases = [_]Case{ |
| 60 | 101 | "e38b27eaccb4391bdec553a7f3ae6b2f", |
| 61 | 102 | "c65bd2e50a56a2138bf1716f2fd56fe9", |
| 62 | 103 | }, |
| 63 | }, | |
| 64 | .{ | |
| 104 | }); | |
| 105 | try testCase(.{ | |
| 65 | 106 | .data = @embedFile("testdata/v7.tar"), |
| 66 | 107 | .files = &[_]Case.File{ |
| 67 | 108 | .{ |
| ... | ... | @@ -79,8 +120,8 @@ const cases = [_]Case{ |
| 79 | 120 | "e38b27eaccb4391bdec553a7f3ae6b2f", |
| 80 | 121 | "c65bd2e50a56a2138bf1716f2fd56fe9", |
| 81 | 122 | }, |
| 82 | }, | |
| 83 | .{ | |
| 123 | }); | |
| 124 | try testCase(.{ | |
| 84 | 125 | .data = @embedFile("testdata/pax.tar"), |
| 85 | 126 | .files = &[_]Case.File{ |
| 86 | 127 | .{ |
| ... | ... | @@ -99,13 +140,13 @@ const cases = [_]Case{ |
| 99 | 140 | .chksums = &[_][]const u8{ |
| 100 | 141 | "3c382e8f5b6631aa2db52643912ffd4a", |
| 101 | 142 | }, |
| 102 | }, | |
| 103 | .{ | |
| 143 | }); | |
| 144 | try testCase(.{ | |
| 104 | 145 | // pax attribute don't end with \n |
| 105 | 146 | .data = @embedFile("testdata/pax-bad-hdr-file.tar"), |
| 106 | 147 | .err = error.PaxInvalidAttributeEnd, |
| 107 | }, | |
| 108 | .{ | |
| 148 | }); | |
| 149 | try testCase(.{ | |
| 109 | 150 | // size is in pax attribute |
| 110 | 151 | .data = @embedFile("testdata/pax-pos-size-file.tar"), |
| 111 | 152 | .files = &[_]Case.File{ |
| ... | ... | @@ -119,8 +160,8 @@ const cases = [_]Case{ |
| 119 | 160 | .chksums = &[_][]const u8{ |
| 120 | 161 | "0afb597b283fe61b5d4879669a350556", |
| 121 | 162 | }, |
| 122 | }, | |
| 123 | .{ | |
| 163 | }); | |
| 164 | try testCase(.{ | |
| 124 | 165 | // has pax records which we are not interested in |
| 125 | 166 | .data = @embedFile("testdata/pax-records.tar"), |
| 126 | 167 | .files = &[_]Case.File{ |
| ... | ... | @@ -128,8 +169,8 @@ const cases = [_]Case{ |
| 128 | 169 | .name = "file", |
| 129 | 170 | }, |
| 130 | 171 | }, |
| 131 | }, | |
| 132 | .{ | |
| 172 | }); | |
| 173 | try testCase(.{ | |
| 133 | 174 | // has global records which we are ignoring |
| 134 | 175 | .data = @embedFile("testdata/pax-global-records.tar"), |
| 135 | 176 | .files = &[_]Case.File{ |
| ... | ... | @@ -146,8 +187,8 @@ const cases = [_]Case{ |
| 146 | 187 | .name = "file4", |
| 147 | 188 | }, |
| 148 | 189 | }, |
| 149 | }, | |
| 150 | .{ | |
| 190 | }); | |
| 191 | try testCase(.{ | |
| 151 | 192 | .data = @embedFile("testdata/nil-uid.tar"), |
| 152 | 193 | .files = &[_]Case.File{ |
| 153 | 194 | .{ |
| ... | ... | @@ -160,8 +201,8 @@ const cases = [_]Case{ |
| 160 | 201 | .chksums = &[_][]const u8{ |
| 161 | 202 | "08d504674115e77a67244beac19668f5", |
| 162 | 203 | }, |
| 163 | }, | |
| 164 | .{ | |
| 204 | }); | |
| 205 | try testCase(.{ | |
| 165 | 206 | // has xattrs and pax records which we are ignoring |
| 166 | 207 | .data = @embedFile("testdata/xattrs.tar"), |
| 167 | 208 | .files = &[_]Case.File{ |
| ... | ... | @@ -182,23 +223,14 @@ const cases = [_]Case{ |
| 182 | 223 | "e38b27eaccb4391bdec553a7f3ae6b2f", |
| 183 | 224 | "c65bd2e50a56a2138bf1716f2fd56fe9", |
| 184 | 225 | }, |
| 185 | }, | |
| 186 | .{ | |
| 187 | .data = @embedFile("testdata/gnu-multi-hdrs.tar"), | |
| 188 | .files = &[_]Case.File{ | |
| 189 | .{ | |
| 190 | .name = "GNU2/GNU2/long-path-name", | |
| 191 | .link_name = "GNU4/GNU4/long-linkpath-name", | |
| 192 | .kind = .sym_link, | |
| 193 | }, | |
| 194 | }, | |
| 195 | }, | |
| 196 | .{ | |
| 226 | }); | |
| 227 | try testCase(gnu_multi_headers_case); | |
| 228 | try testCase(.{ | |
| 197 | 229 | // has gnu type D (directory) and S (sparse) blocks |
| 198 | 230 | .data = @embedFile("testdata/gnu-incremental.tar"), |
| 199 | 231 | .err = error.TarUnsupportedHeader, |
| 200 | }, | |
| 201 | .{ | |
| 232 | }); | |
| 233 | try testCase(.{ | |
| 202 | 234 | // should use values only from last pax header |
| 203 | 235 | .data = @embedFile("testdata/pax-multi-hdrs.tar"), |
| 204 | 236 | .files = &[_]Case.File{ |
| ... | ... | @@ -208,8 +240,8 @@ const cases = [_]Case{ |
| 208 | 240 | .kind = .sym_link, |
| 209 | 241 | }, |
| 210 | 242 | }, |
| 211 | }, | |
| 212 | .{ | |
| 243 | }); | |
| 244 | try testCase(.{ | |
| 213 | 245 | .data = @embedFile("testdata/gnu-long-nul.tar"), |
| 214 | 246 | .files = &[_]Case.File{ |
| 215 | 247 | .{ |
| ... | ... | @@ -217,8 +249,8 @@ const cases = [_]Case{ |
| 217 | 249 | .mode = 0o644, |
| 218 | 250 | }, |
| 219 | 251 | }, |
| 220 | }, | |
| 221 | .{ | |
| 252 | }); | |
| 253 | try testCase(.{ | |
| 222 | 254 | .data = @embedFile("testdata/gnu-utf8.tar"), |
| 223 | 255 | .files = &[_]Case.File{ |
| 224 | 256 | .{ |
| ... | ... | @@ -226,8 +258,8 @@ const cases = [_]Case{ |
| 226 | 258 | .mode = 0o644, |
| 227 | 259 | }, |
| 228 | 260 | }, |
| 229 | }, | |
| 230 | .{ | |
| 261 | }); | |
| 262 | try testCase(.{ | |
| 231 | 263 | .data = @embedFile("testdata/gnu-not-utf8.tar"), |
| 232 | 264 | .files = &[_]Case.File{ |
| 233 | 265 | .{ |
| ... | ... | @@ -235,33 +267,33 @@ const cases = [_]Case{ |
| 235 | 267 | .mode = 0o644, |
| 236 | 268 | }, |
| 237 | 269 | }, |
| 238 | }, | |
| 239 | .{ | |
| 270 | }); | |
| 271 | try testCase(.{ | |
| 240 | 272 | // null in pax key |
| 241 | 273 | .data = @embedFile("testdata/pax-nul-xattrs.tar"), |
| 242 | 274 | .err = error.PaxNullInKeyword, |
| 243 | }, | |
| 244 | .{ | |
| 275 | }); | |
| 276 | try testCase(.{ | |
| 245 | 277 | .data = @embedFile("testdata/pax-nul-path.tar"), |
| 246 | 278 | .err = error.PaxNullInValue, |
| 247 | }, | |
| 248 | .{ | |
| 279 | }); | |
| 280 | try testCase(.{ | |
| 249 | 281 | .data = @embedFile("testdata/neg-size.tar"), |
| 250 | 282 | .err = error.TarHeader, |
| 251 | }, | |
| 252 | .{ | |
| 283 | }); | |
| 284 | try testCase(.{ | |
| 253 | 285 | .data = @embedFile("testdata/issue10968.tar"), |
| 254 | 286 | .err = error.TarHeader, |
| 255 | }, | |
| 256 | .{ | |
| 287 | }); | |
| 288 | try testCase(.{ | |
| 257 | 289 | .data = @embedFile("testdata/issue11169.tar"), |
| 258 | 290 | .err = error.TarHeader, |
| 259 | }, | |
| 260 | .{ | |
| 291 | }); | |
| 292 | try testCase(.{ | |
| 261 | 293 | .data = @embedFile("testdata/issue12435.tar"), |
| 262 | 294 | .err = error.TarHeaderChksum, |
| 263 | }, | |
| 264 | .{ | |
| 295 | }); | |
| 296 | try testCase(.{ | |
| 265 | 297 | // has magic with space at end instead of null |
| 266 | 298 | .data = @embedFile("testdata/invalid-go17.tar"), |
| 267 | 299 | .files = &[_]Case.File{ |
| ... | ... | @@ -269,8 +301,8 @@ const cases = [_]Case{ |
| 269 | 301 | .name = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/foo", |
| 270 | 302 | }, |
| 271 | 303 | }, |
| 272 | }, | |
| 273 | .{ | |
| 304 | }); | |
| 305 | try testCase(.{ | |
| 274 | 306 | .data = @embedFile("testdata/ustar-file-devs.tar"), |
| 275 | 307 | .files = &[_]Case.File{ |
| 276 | 308 | .{ |
| ... | ... | @@ -278,17 +310,9 @@ const cases = [_]Case{ |
| 278 | 310 | .mode = 0o644, |
| 279 | 311 | }, |
| 280 | 312 | }, |
| 281 | }, | |
| 282 | .{ | |
| 283 | .data = @embedFile("testdata/trailing-slash.tar"), | |
| 284 | .files = &[_]Case.File{ | |
| 285 | .{ | |
| 286 | .name = "123456789/" ** 30, | |
| 287 | .kind = .directory, | |
| 288 | }, | |
| 289 | }, | |
| 290 | }, | |
| 291 | .{ | |
| 313 | }); | |
| 314 | try testCase(trailing_slash_case); | |
| 315 | try testCase(.{ | |
| 292 | 316 | // Has size in gnu extended format. To represent size bigger than 8 GB. |
| 293 | 317 | .data = @embedFile("testdata/writer-big.tar"), |
| 294 | 318 | .files = &[_]Case.File{ |
| ... | ... | @@ -299,119 +323,91 @@ const cases = [_]Case{ |
| 299 | 323 | .mode = 0o640, |
| 300 | 324 | }, |
| 301 | 325 | }, |
| 302 | }, | |
| 303 | .{ | |
| 304 | // Size in gnu extended format, and name in pax attribute. | |
| 305 | .data = @embedFile("testdata/writer-big-long.tar"), | |
| 306 | .files = &[_]Case.File{ | |
| 307 | .{ | |
| 308 | .name = "longname/" ** 15 ++ "16gig.txt", | |
| 309 | .size = 16 * 1024 * 1024 * 1024, | |
| 310 | .mode = 0o644, | |
| 311 | .truncated = true, | |
| 312 | }, | |
| 313 | }, | |
| 314 | }, | |
| 315 | .{ | |
| 316 | .data = @embedFile("testdata/fuzz1.tar"), | |
| 317 | .err = error.TarInsufficientBuffer, | |
| 318 | }, | |
| 319 | .{ | |
| 326 | }); | |
| 327 | try testCase(writer_big_long_case); | |
| 328 | try testCase(fuzz1_case); | |
| 329 | try testCase(.{ | |
| 320 | 330 | .data = @embedFile("testdata/fuzz2.tar"), |
| 321 | 331 | .err = error.PaxSizeAttrOverflow, |
| 322 | }, | |
| 323 | }; | |
| 324 | ||
| 325 | // used in test to calculate file chksum | |
| 326 | const Md5Writer = struct { | |
| 327 | h: std.crypto.hash.Md5 = std.crypto.hash.Md5.init(.{}), | |
| 328 | ||
| 329 | pub fn writeAll(self: *Md5Writer, buf: []const u8) !void { | |
| 330 | self.h.update(buf); | |
| 331 | } | |
| 332 | ||
| 333 | pub fn writeByte(self: *Md5Writer, byte: u8) !void { | |
| 334 | self.h.update(&[_]u8{byte}); | |
| 335 | } | |
| 336 | ||
| 337 | pub fn chksum(self: *Md5Writer) [32]u8 { | |
| 338 | var s = [_]u8{0} ** 16; | |
| 339 | self.h.final(&s); | |
| 340 | return std.fmt.bytesToHex(s, .lower); | |
| 341 | } | |
| 342 | }; | |
| 332 | }); | |
| 333 | } | |
| 343 | 334 | |
| 344 | test "run test cases" { | |
| 335 | fn testCase(case: Case) !void { | |
| 345 | 336 | var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined; |
| 346 | 337 | var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined; |
| 347 | 338 | |
| 348 | for (cases) |case| { | |
| 349 | var br: std.io.Reader = .fixed(case.data); | |
| 350 | var iter: tar.Iterator = .init(&br, .{ | |
| 351 | .file_name_buffer = &file_name_buffer, | |
| 352 | .link_name_buffer = &link_name_buffer, | |
| 353 | }); | |
| 354 | var i: usize = 0; | |
| 355 | while (iter.next() catch |err| { | |
| 356 | if (case.err) |e| { | |
| 357 | try testing.expectEqual(e, err); | |
| 358 | continue; | |
| 359 | } else { | |
| 360 | return err; | |
| 361 | } | |
| 362 | }) |actual| : (i += 1) { | |
| 363 | const expected = case.files[i]; | |
| 364 | try testing.expectEqualStrings(expected.name, actual.name); | |
| 365 | try testing.expectEqual(expected.size, actual.size); | |
| 366 | try testing.expectEqual(expected.kind, actual.kind); | |
| 367 | try testing.expectEqual(expected.mode, actual.mode); | |
| 368 | try testing.expectEqualStrings(expected.link_name, actual.link_name); | |
| 339 | var br: std.io.Reader = .fixed(case.data); | |
| 340 | var it: tar.Iterator = .init(&br, .{ | |
| 341 | .file_name_buffer = &file_name_buffer, | |
| 342 | .link_name_buffer = &link_name_buffer, | |
| 343 | }); | |
| 344 | var i: usize = 0; | |
| 345 | while (it.next() catch |err| { | |
| 346 | if (case.err) |e| { | |
| 347 | try testing.expectEqual(e, err); | |
| 348 | return; | |
| 349 | } else { | |
| 350 | return err; | |
| 351 | } | |
| 352 | }) |actual| : (i += 1) { | |
| 353 | const expected = case.files[i]; | |
| 354 | try testing.expectEqualStrings(expected.name, actual.name); | |
| 355 | try testing.expectEqual(expected.size, actual.size); | |
| 356 | try testing.expectEqual(expected.kind, actual.kind); | |
| 357 | try testing.expectEqual(expected.mode, actual.mode); | |
| 358 | try testing.expectEqualStrings(expected.link_name, actual.link_name); | |
| 369 | 359 | |
| 370 | if (case.chksums.len > i) { | |
| 371 | var md5writer = Md5Writer{}; | |
| 372 | try actual.writeAll(&md5writer); | |
| 373 | const chksum = md5writer.chksum(); | |
| 374 | try testing.expectEqualStrings(case.chksums[i], &chksum); | |
| 375 | } else { | |
| 376 | if (expected.truncated) { | |
| 377 | iter.unread_file_bytes = 0; | |
| 378 | } | |
| 360 | if (case.chksums.len > i) { | |
| 361 | var aw: std.Io.Writer.Allocating = .init(std.testing.allocator); | |
| 362 | defer aw.deinit(); | |
| 363 | try it.streamRemaining(actual, &aw.writer); | |
| 364 | const chksum = std.fmt.bytesToHex(std.crypto.hash.Md5.hashResult(aw.getWritten()), .lower); | |
| 365 | try testing.expectEqualStrings(case.chksums[i], &chksum); | |
| 366 | } else { | |
| 367 | if (expected.truncated) { | |
| 368 | it.unread_file_bytes = 0; | |
| 379 | 369 | } |
| 380 | 370 | } |
| 381 | try testing.expectEqual(case.files.len, i); | |
| 382 | 371 | } |
| 372 | try testing.expectEqual(case.files.len, i); | |
| 383 | 373 | } |
| 384 | 374 | |
| 385 | 375 | test "pax/gnu long names with small buffer" { |
| 376 | try testLongNameCase(gnu_multi_headers_case); | |
| 377 | try testLongNameCase(trailing_slash_case); | |
| 378 | try testLongNameCase(.{ | |
| 379 | .data = @embedFile("testdata/fuzz1.tar"), | |
| 380 | .err = error.TarInsufficientBuffer, | |
| 381 | }); | |
| 382 | } | |
| 383 | ||
| 384 | fn testLongNameCase(case: Case) !void { | |
| 386 | 385 | // should fail with insufficient buffer error |
| 387 | 386 | |
| 388 | 387 | var min_file_name_buffer: [256]u8 = undefined; |
| 389 | 388 | var min_link_name_buffer: [100]u8 = undefined; |
| 390 | const long_name_cases = [_]Case{ cases[11], cases[25], cases[28] }; | |
| 391 | 389 | |
| 392 | for (long_name_cases) |case| { | |
| 393 | var br: std.io.Reader = .fixed(case.data); | |
| 394 | var iter: tar.Iterator = .init(&br, .{ | |
| 395 | .file_name_buffer = &min_file_name_buffer, | |
| 396 | .link_name_buffer = &min_link_name_buffer, | |
| 397 | }); | |
| 390 | var br: std.io.Reader = .fixed(case.data); | |
| 391 | var iter: tar.Iterator = .init(&br, .{ | |
| 392 | .file_name_buffer = &min_file_name_buffer, | |
| 393 | .link_name_buffer = &min_link_name_buffer, | |
| 394 | }); | |
| 398 | 395 | |
| 399 | var iter_err: ?anyerror = null; | |
| 400 | while (iter.next() catch |err| brk: { | |
| 401 | iter_err = err; | |
| 402 | break :brk null; | |
| 403 | }) |_| {} | |
| 396 | var iter_err: ?anyerror = null; | |
| 397 | while (iter.next() catch |err| brk: { | |
| 398 | iter_err = err; | |
| 399 | break :brk null; | |
| 400 | }) |_| {} | |
| 404 | 401 | |
| 405 | try testing.expect(iter_err != null); | |
| 406 | try testing.expectEqual(error.TarInsufficientBuffer, iter_err.?); | |
| 407 | } | |
| 402 | try testing.expect(iter_err != null); | |
| 403 | try testing.expectEqual(error.TarInsufficientBuffer, iter_err.?); | |
| 408 | 404 | } |
| 409 | 405 | |
| 410 | 406 | test "insufficient buffer in Header name filed" { |
| 411 | 407 | var min_file_name_buffer: [9]u8 = undefined; |
| 412 | 408 | var min_link_name_buffer: [100]u8 = undefined; |
| 413 | 409 | |
| 414 | var br: std.io.Reader = .fixed(cases[0].data); | |
| 410 | var br: std.io.Reader = .fixed(gnu_case.data); | |
| 415 | 411 | var iter: tar.Iterator = .init(&br, .{ |
| 416 | 412 | .file_name_buffer = &min_file_name_buffer, |
| 417 | 413 | .link_name_buffer = &min_link_name_buffer, |
lib/std/testing.zig+1| ... | ... | @@ -34,6 +34,7 @@ pub var log_level = std.log.Level.warn; |
| 34 | 34 | |
| 35 | 35 | // Disable printing in tests for simple backends. |
| 36 | 36 | pub const backend_can_print = switch (builtin.zig_backend) { |
| 37 | .stage2_aarch64, | |
| 37 | 38 | .stage2_powerpc, |
| 38 | 39 | .stage2_riscv64, |
| 39 | 40 | .stage2_spirv, |
src/Compilation.zig+24-15| ... | ... | @@ -1850,7 +1850,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1850 | 1850 | // approach, since the ubsan runtime uses quite a lot of the standard library |
| 1851 | 1851 | // and this reduces unnecessary bloat. |
| 1852 | 1852 | 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); | |
| 1854 | 1854 | const want_ubsan_rt = options.want_ubsan_rt orelse (can_build_ubsan_rt and any_sanitize_c == .full and is_exe_or_dyn_lib); |
| 1855 | 1855 | if (!want_ubsan_rt) break :s .none; |
| 1856 | 1856 | if (options.skip_linker_dependencies) break :s .none; |
| ... | ... | @@ -4862,6 +4862,9 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void { |
| 4862 | 4862 | }; |
| 4863 | 4863 | defer tar_file.close(); |
| 4864 | 4864 | |
| 4865 | var buffer: [1024]u8 = undefined; | |
| 4866 | var tar_file_writer = tar_file.writer(&buffer); | |
| 4867 | ||
| 4865 | 4868 | var seen_table: std.AutoArrayHashMapUnmanaged(*Package.Module, []const u8) = .empty; |
| 4866 | 4869 | defer seen_table.deinit(comp.gpa); |
| 4867 | 4870 | |
| ... | ... | @@ -4871,7 +4874,7 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void { |
| 4871 | 4874 | var i: usize = 0; |
| 4872 | 4875 | while (i < seen_table.count()) : (i += 1) { |
| 4873 | 4876 | const mod = seen_table.keys()[i]; |
| 4874 | try comp.docsCopyModule(mod, seen_table.values()[i], tar_file); | |
| 4877 | try comp.docsCopyModule(mod, seen_table.values()[i], &tar_file_writer); | |
| 4875 | 4878 | |
| 4876 | 4879 | const deps = mod.deps.values(); |
| 4877 | 4880 | try seen_table.ensureUnusedCapacity(comp.gpa, deps.len); |
| ... | ... | @@ -4879,24 +4882,29 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void { |
| 4879 | 4882 | } |
| 4880 | 4883 | } |
| 4881 | 4884 | |
| 4882 | fn docsCopyModule(comp: *Compilation, module: *Package.Module, name: []const u8, tar_file: fs.File) !void { | |
| 4885 | fn docsCopyModule( | |
| 4886 | comp: *Compilation, | |
| 4887 | module: *Package.Module, | |
| 4888 | name: []const u8, | |
| 4889 | tar_file_writer: *fs.File.Writer, | |
| 4890 | ) !void { | |
| 4883 | 4891 | const root = module.root; |
| 4884 | 4892 | var mod_dir = d: { |
| 4885 | 4893 | const root_dir, const sub_path = root.openInfo(comp.dirs); |
| 4886 | 4894 | break :d root_dir.openDir(sub_path, .{ .iterate = true }); |
| 4887 | 4895 | } catch |err| { |
| 4888 | return comp.lockAndSetMiscFailure(.docs_copy, "unable to open directory '{f}': {s}", .{ | |
| 4889 | root.fmt(comp), @errorName(err), | |
| 4890 | }); | |
| 4896 | return comp.lockAndSetMiscFailure(.docs_copy, "unable to open directory '{f}': {t}", .{ root.fmt(comp), err }); | |
| 4891 | 4897 | }; |
| 4892 | 4898 | defer mod_dir.close(); |
| 4893 | 4899 | |
| 4894 | 4900 | var walker = try mod_dir.walk(comp.gpa); |
| 4895 | 4901 | defer walker.deinit(); |
| 4896 | 4902 | |
| 4897 | var archiver = std.tar.writer(tar_file.deprecatedWriter().any()); | |
| 4903 | var archiver: std.tar.Writer = .{ .underlying_writer = &tar_file_writer.interface }; | |
| 4898 | 4904 | archiver.prefix = name; |
| 4899 | 4905 | |
| 4906 | var buffer: [1024]u8 = undefined; | |
| 4907 | ||
| 4900 | 4908 | while (try walker.next()) |entry| { |
| 4901 | 4909 | switch (entry.kind) { |
| 4902 | 4910 | .file => { |
| ... | ... | @@ -4907,14 +4915,17 @@ fn docsCopyModule(comp: *Compilation, module: *Package.Module, name: []const u8, |
| 4907 | 4915 | else => continue, |
| 4908 | 4916 | } |
| 4909 | 4917 | var file = mod_dir.openFile(entry.path, .{}) catch |err| { |
| 4910 | return comp.lockAndSetMiscFailure(.docs_copy, "unable to open '{f}{s}': {s}", .{ | |
| 4911 | root.fmt(comp), entry.path, @errorName(err), | |
| 4918 | return comp.lockAndSetMiscFailure(.docs_copy, "unable to open {f}{s}: {t}", .{ | |
| 4919 | root.fmt(comp), entry.path, err, | |
| 4912 | 4920 | }); |
| 4913 | 4921 | }; |
| 4914 | 4922 | defer file.close(); |
| 4915 | archiver.writeFile(entry.path, file) catch |err| { | |
| 4916 | return comp.lockAndSetMiscFailure(.docs_copy, "unable to archive '{f}{s}': {s}", .{ | |
| 4917 | root.fmt(comp), entry.path, @errorName(err), | |
| 4923 | const stat = try file.stat(); | |
| 4924 | var file_reader: fs.File.Reader = .initSize(file, &buffer, stat.size); | |
| 4925 | ||
| 4926 | archiver.writeFile(entry.path, &file_reader, stat.mtime) catch |err| { | |
| 4927 | return comp.lockAndSetMiscFailure(.docs_copy, "unable to archive {f}{s}: {t}", .{ | |
| 4928 | root.fmt(comp), entry.path, err, | |
| 4918 | 4929 | }); |
| 4919 | 4930 | }; |
| 4920 | 4931 | } |
| ... | ... | @@ -4926,9 +4937,7 @@ fn workerDocsWasm(comp: *Compilation, parent_prog_node: std.Progress.Node) void |
| 4926 | 4937 | |
| 4927 | 4938 | workerDocsWasmFallible(comp, prog_node) catch |err| switch (err) { |
| 4928 | 4939 | error.SubCompilationFailed => return, // error reported already |
| 4929 | else => comp.lockAndSetMiscFailure(.docs_wasm, "unable to build autodocs: {s}", .{ | |
| 4930 | @errorName(err), | |
| 4931 | }), | |
| 4940 | else => comp.lockAndSetMiscFailure(.docs_wasm, "unable to build autodocs: {t}", .{err}), | |
| 4932 | 4941 | }; |
| 4933 | 4942 | } |
| 4934 | 4943 |
src/InternPool.zig+10-4| ... | ... | @@ -7556,12 +7556,18 @@ fn extraFuncCoerced(ip: *const InternPool, extra: Local.Extra, extra_index: u32) |
| 7556 | 7556 | fn indexToKeyBigInt(ip: *const InternPool, tid: Zcu.PerThread.Id, limb_index: u32, positive: bool) Key { |
| 7557 | 7557 | const limbs_items = ip.getLocalShared(tid).getLimbs().view().items(.@"0"); |
| 7558 | 7558 | 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 | }; | |
| 7559 | 7563 | return .{ .int = .{ |
| 7560 | 7564 | .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 }, | |
| 7565 | 7571 | } }; |
| 7566 | 7572 | } |
| 7567 | 7573 |
src/Package/Fetch.zig+18-9| ... | ... | @@ -1197,12 +1197,17 @@ fn unpackResource( |
| 1197 | 1197 | }; |
| 1198 | 1198 | |
| 1199 | 1199 | switch (file_type) { |
| 1200 | .tar => return try unpackTarball(f, tmp_directory.handle, resource.reader()), | |
| 1200 | .tar => { | |
| 1201 | var adapter = resource.reader().adaptToNewApi(); | |
| 1202 | return unpackTarball(f, tmp_directory.handle, &adapter.new_interface); | |
| 1203 | }, | |
| 1201 | 1204 | .@"tar.gz" => { |
| 1202 | 1205 | const reader = resource.reader(); |
| 1203 | 1206 | var br = std.io.bufferedReaderSize(std.crypto.tls.max_ciphertext_record_len, reader); |
| 1204 | 1207 | var dcp = std.compress.gzip.decompressor(br.reader()); |
| 1205 | return try unpackTarball(f, tmp_directory.handle, dcp.reader()); | |
| 1208 | var adapter_buffer: [1024]u8 = undefined; | |
| 1209 | var adapter = dcp.reader().adaptToNewApi(&adapter_buffer); | |
| 1210 | return try unpackTarball(f, tmp_directory.handle, &adapter.new_interface); | |
| 1206 | 1211 | }, |
| 1207 | 1212 | .@"tar.xz" => { |
| 1208 | 1213 | const gpa = f.arena.child_allocator; |
| ... | ... | @@ -1215,7 +1220,9 @@ fn unpackResource( |
| 1215 | 1220 | )); |
| 1216 | 1221 | }; |
| 1217 | 1222 | defer dcp.deinit(); |
| 1218 | return try unpackTarball(f, tmp_directory.handle, dcp.reader()); | |
| 1223 | var adapter_buffer: [1024]u8 = undefined; | |
| 1224 | var adapter = dcp.reader().adaptToNewApi(&adapter_buffer); | |
| 1225 | return try unpackTarball(f, tmp_directory.handle, &adapter.new_interface); | |
| 1219 | 1226 | }, |
| 1220 | 1227 | .@"tar.zst" => { |
| 1221 | 1228 | const window_size = std.compress.zstd.default_window_len; |
| ... | ... | @@ -1225,7 +1232,9 @@ fn unpackResource( |
| 1225 | 1232 | var dcp = std.compress.zstd.decompressor(br.reader(), .{ |
| 1226 | 1233 | .window_buffer = window_buffer, |
| 1227 | 1234 | }); |
| 1228 | return try unpackTarball(f, tmp_directory.handle, dcp.reader()); | |
| 1235 | var adapter_buffer: [1024]u8 = undefined; | |
| 1236 | var adapter = dcp.reader().adaptToNewApi(&adapter_buffer); | |
| 1237 | return try unpackTarball(f, tmp_directory.handle, &adapter.new_interface); | |
| 1229 | 1238 | }, |
| 1230 | 1239 | .git_pack => return unpackGitPack(f, tmp_directory.handle, &resource.git) catch |err| switch (err) { |
| 1231 | 1240 | error.FetchFailed => return error.FetchFailed, |
| ... | ... | @@ -1239,7 +1248,7 @@ fn unpackResource( |
| 1239 | 1248 | } |
| 1240 | 1249 | } |
| 1241 | 1250 | |
| 1242 | fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!UnpackResult { | |
| 1251 | fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: *std.Io.Reader) RunError!UnpackResult { | |
| 1243 | 1252 | const eb = &f.error_bundle; |
| 1244 | 1253 | const arena = f.arena.allocator(); |
| 1245 | 1254 | |
| ... | ... | @@ -1250,10 +1259,10 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!UnpackRes |
| 1250 | 1259 | .strip_components = 0, |
| 1251 | 1260 | .mode_mode = .ignore, |
| 1252 | 1261 | .exclude_empty_directories = true, |
| 1253 | }) catch |err| return f.fail(f.location_tok, try eb.printString( | |
| 1254 | "unable to unpack tarball to temporary directory: {s}", | |
| 1255 | .{@errorName(err)}, | |
| 1256 | )); | |
| 1262 | }) catch |err| return f.fail( | |
| 1263 | f.location_tok, | |
| 1264 | try eb.printString("unable to unpack tarball to temporary directory: {t}", .{err}), | |
| 1265 | ); | |
| 1257 | 1266 | |
| 1258 | 1267 | var res: UnpackResult = .{ .root_dir = diagnostics.root_dir }; |
| 1259 | 1268 | if (diagnostics.errors.items.len > 0) { |
src/Sema.zig+5-4| ... | ... | @@ -16522,7 +16522,7 @@ fn zirAsm( |
| 16522 | 16522 | break :empty try sema.structInitEmpty(block, clobbers_ty, src, src); |
| 16523 | 16523 | } else try sema.resolveInst(extra.data.clobbers); // Already coerced by AstGen. |
| 16524 | 16524 | 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; | |
| 16526 | 16526 | |
| 16527 | 16527 | const gpa = sema.gpa; |
| 16528 | 16528 | try sema.air_extra.ensureUnusedCapacity(gpa, needed_capacity); |
| ... | ... | @@ -16562,7 +16562,8 @@ fn zirAsm( |
| 16562 | 16562 | { |
| 16563 | 16563 | const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice()); |
| 16564 | 16564 | @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; | |
| 16566 | 16567 | } |
| 16567 | 16568 | return asm_air; |
| 16568 | 16569 | } |
| ... | ... | @@ -24846,7 +24847,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins |
| 24846 | 24847 | }, |
| 24847 | 24848 | .@"packed" => { |
| 24848 | 24849 | 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) - | |
| 24850 | 24851 | actual_field_ptr_info.packed_offset.bit_offset), 8) catch |
| 24851 | 24852 | return sema.fail(block, inst_src, "pointer bit-offset mismatch", .{}); |
| 24852 | 24853 | 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 |
| 24873 | 24874 | // Logic lifted from type computation above - I'm just assuming it's correct. |
| 24874 | 24875 | // `catch unreachable` since error case handled above. |
| 24875 | 24876 | 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) - | |
| 24877 | 24878 | actual_field_ptr_info.packed_offset.bit_offset), 8) catch unreachable; |
| 24878 | 24879 | const parent_ptr_val = try sema.ptrSubtract(block, field_ptr_src, field_ptr_val, byte_offset, actual_parent_ptr_ty); |
| 24879 | 24880 | break :result Air.internedToRef(parent_ptr_val.toIntern()); |
src/Type.zig+1-1| ... | ... | @@ -4163,7 +4163,7 @@ pub const generic_poison: Type = .{ .ip_index = .generic_poison_type }; |
| 4163 | 4163 | pub fn smallestUnsignedBits(max: u64) u16 { |
| 4164 | 4164 | return switch (max) { |
| 4165 | 4165 | 0 => 0, |
| 4166 | else => 1 + std.math.log2_int(u64, max), | |
| 4166 | else => @as(u16, 1) + std.math.log2_int(u64, max), | |
| 4167 | 4167 | }; |
| 4168 | 4168 | } |
| 4169 | 4169 |
src/Zcu.zig+24-5| ... | ... | @@ -3891,6 +3891,29 @@ pub fn typeToPackedStruct(zcu: *const Zcu, ty: Type) ?InternPool.LoadedStructTyp |
| 3891 | 3891 | return s; |
| 3892 | 3892 | } |
| 3893 | 3893 | |
| 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. | |
| 3898 | pub 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 | ||
| 3894 | 3917 | pub fn typeToUnion(zcu: *const Zcu, ty: Type) ?InternPool.LoadedUnionType { |
| 3895 | 3918 | if (ty.ip_index == .none) return null; |
| 3896 | 3919 | const ip = &zcu.intern_pool; |
| ... | ... | @@ -4436,11 +4459,7 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu |
| 4436 | 4459 | else => false, |
| 4437 | 4460 | }, |
| 4438 | 4461 | .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, | |
| 4444 | 4463 | else => false, |
| 4445 | 4464 | }, |
| 4446 | 4465 | .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 { |
| 3737 | 3737 | } |
| 3738 | 3738 | } |
| 3739 | 3739 | |
| 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. | |
| 3744 | pub 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 | ||
| 3764 | 3740 | pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Error!Type { |
| 3765 | 3741 | const zcu = pt.zcu; |
| 3766 | 3742 | const ip = &zcu.intern_pool; |
| ... | ... | @@ -4381,8 +4357,11 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e |
| 4381 | 4357 | try air.legalize(pt, features); |
| 4382 | 4358 | } |
| 4383 | 4359 | |
| 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); | |
| 4386 | 4365 | |
| 4387 | 4366 | if (build_options.enable_debug_extensions and comp.verbose_air) { |
| 4388 | 4367 | const stderr = std.debug.lockStderrWriter(&.{}); |
| ... | ... | @@ -4392,12 +4371,12 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e |
| 4392 | 4371 | stderr.print("# End Function AIR: {f}\n\n", .{fqn.fmt(ip)}) catch {}; |
| 4393 | 4372 | } |
| 4394 | 4373 | |
| 4395 | if (std.debug.runtime_safety) { | |
| 4374 | if (std.debug.runtime_safety) verify_liveness: { | |
| 4396 | 4375 | var verify: Air.Liveness.Verify = .{ |
| 4397 | 4376 | .gpa = gpa, |
| 4398 | 4377 | .zcu = zcu, |
| 4399 | 4378 | .air = air.*, |
| 4400 | .liveness = liveness, | |
| 4379 | .liveness = liveness orelse break :verify_liveness, | |
| 4401 | 4380 | .intern_pool = ip, |
| 4402 | 4381 | }; |
| 4403 | 4382 | defer verify.deinit(); |
src/arch/aarch64/bits.zig deleted-2063| ... | ... | @@ -1,2063 +0,0 @@ |
| 1 | const std = @import("std"); | |
| 2 | const builtin = @import("builtin"); | |
| 3 | const assert = std.debug.assert; | |
| 4 | const testing = std.testing; | |
| 5 | ||
| 6 | /// Disjoint sets of registers. Every register must belong to | |
| 7 | /// exactly one register class. | |
| 8 | pub const RegisterClass = enum { | |
| 9 | general_purpose, | |
| 10 | stack_pointer, | |
| 11 | floating_point, | |
| 12 | }; | |
| 13 | ||
| 14 | /// Registers in the AArch64 instruction set | |
| 15 | pub 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 | ||
| 302 | test "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 | ||
| 313 | test "Register.size" { | |
| 314 | try testing.expectEqual(@as(u8, 64), Register.x19.size()); | |
| 315 | try testing.expectEqual(@as(u8, 32), Register.w3.size()); | |
| 316 | } | |
| 317 | ||
| 318 | test "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 | |
| 327 | pub 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 | ||
| 1838 | test { | |
| 1839 | testing.refAllDecls(@This()); | |
| 1840 | } | |
| 1841 | ||
| 1842 | test "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| ... | ... | @@ -745,7 +745,7 @@ pub fn generate( |
| 745 | 745 | src_loc: Zcu.LazySrcLoc, |
| 746 | 746 | func_index: InternPool.Index, |
| 747 | 747 | air: *const Air, |
| 748 | liveness: *const Air.Liveness, | |
| 748 | liveness: *const ?Air.Liveness, | |
| 749 | 749 | ) CodeGenError!Mir { |
| 750 | 750 | const zcu = pt.zcu; |
| 751 | 751 | const gpa = zcu.gpa; |
| ... | ... | @@ -768,7 +768,7 @@ pub fn generate( |
| 768 | 768 | .pt = pt, |
| 769 | 769 | .mod = mod, |
| 770 | 770 | .bin_file = bin_file, |
| 771 | .liveness = liveness.*, | |
| 771 | .liveness = liveness.*.?, | |
| 772 | 772 | .target = &mod.resolved_target.result, |
| 773 | 773 | .owner = .{ .nav_index = func.owner_nav }, |
| 774 | 774 | .args = undefined, // populated after `resolveCallingConventionValues` |
| ... | ... | @@ -4585,7 +4585,7 @@ fn structFieldPtr(func: *Func, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde |
| 4585 | 4585 | const field_offset: i32 = switch (container_ty.containerLayout(zcu)) { |
| 4586 | 4586 | .auto, .@"extern" => @intCast(container_ty.structFieldOffset(index, zcu)), |
| 4587 | 4587 | .@"packed" => @divExact(@as(i32, ptr_container_ty.ptrInfo(zcu).packed_offset.bit_offset) + |
| 4588 | (if (zcu.typeToStruct(container_ty)) |struct_obj| pt.structPackedFieldBitOffset(struct_obj, index) else 0) - | |
| 4588 | (if (zcu.typeToStruct(container_ty)) |struct_obj| zcu.structPackedFieldBitOffset(struct_obj, index) else 0) - | |
| 4589 | 4589 | ptr_field_ty.ptrInfo(zcu).packed_offset.bit_offset, 8), |
| 4590 | 4590 | }; |
| 4591 | 4591 | |
| ... | ... | @@ -4616,7 +4616,7 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void { |
| 4616 | 4616 | const field_off: u32 = switch (struct_ty.containerLayout(zcu)) { |
| 4617 | 4617 | .auto, .@"extern" => @intCast(struct_ty.structFieldOffset(index, zcu) * 8), |
| 4618 | 4618 | .@"packed" => if (zcu.typeToStruct(struct_ty)) |struct_type| |
| 4619 | pt.structPackedFieldBitOffset(struct_type, index) | |
| 4619 | zcu.structPackedFieldBitOffset(struct_type, index) | |
| 4620 | 4620 | else |
| 4621 | 4621 | 0, |
| 4622 | 4622 | }; |
| ... | ... | @@ -8060,7 +8060,7 @@ fn airAggregateInit(func: *Func, inst: Air.Inst.Index) !void { |
| 8060 | 8060 | |
| 8061 | 8061 | const elem_abi_size: u32 = @intCast(elem_ty.abiSize(zcu)); |
| 8062 | 8062 | const elem_abi_bits = elem_abi_size * 8; |
| 8063 | const elem_off = pt.structPackedFieldBitOffset(struct_obj, elem_i); | |
| 8063 | const elem_off = zcu.structPackedFieldBitOffset(struct_obj, elem_i); | |
| 8064 | 8064 | const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size); |
| 8065 | 8065 | const elem_bit_off = elem_off % elem_abi_bits; |
| 8066 | 8066 | const elem_mcv = try func.resolveInst(elem); |
src/arch/sparc64/CodeGen.zig+2-2| ... | ... | @@ -267,7 +267,7 @@ pub fn generate( |
| 267 | 267 | src_loc: Zcu.LazySrcLoc, |
| 268 | 268 | func_index: InternPool.Index, |
| 269 | 269 | air: *const Air, |
| 270 | liveness: *const Air.Liveness, | |
| 270 | liveness: *const ?Air.Liveness, | |
| 271 | 271 | ) CodeGenError!Mir { |
| 272 | 272 | const zcu = pt.zcu; |
| 273 | 273 | const gpa = zcu.gpa; |
| ... | ... | @@ -288,7 +288,7 @@ pub fn generate( |
| 288 | 288 | .gpa = gpa, |
| 289 | 289 | .pt = pt, |
| 290 | 290 | .air = air.*, |
| 291 | .liveness = liveness.*, | |
| 291 | .liveness = liveness.*.?, | |
| 292 | 292 | .target = target, |
| 293 | 293 | .bin_file = lf, |
| 294 | 294 | .func_index = func_index, |
src/arch/wasm/CodeGen.zig+5-5| ... | ... | @@ -1174,7 +1174,7 @@ pub fn generate( |
| 1174 | 1174 | src_loc: Zcu.LazySrcLoc, |
| 1175 | 1175 | func_index: InternPool.Index, |
| 1176 | 1176 | air: *const Air, |
| 1177 | liveness: *const Air.Liveness, | |
| 1177 | liveness: *const ?Air.Liveness, | |
| 1178 | 1178 | ) Error!Mir { |
| 1179 | 1179 | _ = src_loc; |
| 1180 | 1180 | _ = bin_file; |
| ... | ... | @@ -1195,7 +1195,7 @@ pub fn generate( |
| 1195 | 1195 | .gpa = gpa, |
| 1196 | 1196 | .pt = pt, |
| 1197 | 1197 | .air = air.*, |
| 1198 | .liveness = liveness.*, | |
| 1198 | .liveness = liveness.*.?, | |
| 1199 | 1199 | .owner_nav = cg.owner_nav, |
| 1200 | 1200 | .target = target, |
| 1201 | 1201 | .ptr_size = switch (target.cpu.arch) { |
| ... | ... | @@ -3777,7 +3777,7 @@ fn structFieldPtr( |
| 3777 | 3777 | break :offset @as(u32, 0); |
| 3778 | 3778 | } |
| 3779 | 3779 | const struct_type = zcu.typeToStruct(struct_ty).?; |
| 3780 | break :offset @divExact(pt.structPackedFieldBitOffset(struct_type, index) + struct_ptr_ty_info.packed_offset.bit_offset, 8); | |
| 3780 | break :offset @divExact(zcu.structPackedFieldBitOffset(struct_type, index) + struct_ptr_ty_info.packed_offset.bit_offset, 8); | |
| 3781 | 3781 | }, |
| 3782 | 3782 | .@"union" => 0, |
| 3783 | 3783 | else => unreachable, |
| ... | ... | @@ -3813,7 +3813,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3813 | 3813 | .@"packed" => switch (struct_ty.zigTypeTag(zcu)) { |
| 3814 | 3814 | .@"struct" => result: { |
| 3815 | 3815 | const packed_struct = zcu.typeToPackedStruct(struct_ty).?; |
| 3816 | const offset = pt.structPackedFieldBitOffset(packed_struct, field_index); | |
| 3816 | const offset = zcu.structPackedFieldBitOffset(packed_struct, field_index); | |
| 3817 | 3817 | const backing_ty = Type.fromInterned(packed_struct.backingIntTypeUnordered(ip)); |
| 3818 | 3818 | const host_bits = backing_ty.intInfo(zcu).bits; |
| 3819 | 3819 | |
| ... | ... | @@ -5697,7 +5697,7 @@ fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5697 | 5697 | .auto, .@"extern" => parent_ty.structFieldOffset(field_index, zcu), |
| 5698 | 5698 | .@"packed" => offset: { |
| 5699 | 5699 | const parent_ptr_offset = parent_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset; |
| 5700 | const field_offset = if (zcu.typeToStruct(parent_ty)) |loaded_struct| pt.structPackedFieldBitOffset(loaded_struct, field_index) else 0; | |
| 5700 | const field_offset = if (zcu.typeToStruct(parent_ty)) |loaded_struct| zcu.structPackedFieldBitOffset(loaded_struct, field_index) else 0; | |
| 5701 | 5701 | const field_ptr_offset = field_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset; |
| 5702 | 5702 | break :offset @divExact(parent_ptr_offset + field_offset - field_ptr_offset, 8); |
| 5703 | 5703 | }, |
src/arch/x86_64/CodeGen.zig+20-31| ... | ... | @@ -878,7 +878,7 @@ pub fn generate( |
| 878 | 878 | src_loc: Zcu.LazySrcLoc, |
| 879 | 879 | func_index: InternPool.Index, |
| 880 | 880 | air: *const Air, |
| 881 | liveness: *const Air.Liveness, | |
| 881 | liveness: *const ?Air.Liveness, | |
| 882 | 882 | ) codegen.CodeGenError!Mir { |
| 883 | 883 | _ = bin_file; |
| 884 | 884 | const zcu = pt.zcu; |
| ... | ... | @@ -894,7 +894,7 @@ pub fn generate( |
| 894 | 894 | .gpa = gpa, |
| 895 | 895 | .pt = pt, |
| 896 | 896 | .air = air.*, |
| 897 | .liveness = liveness.*, | |
| 897 | .liveness = liveness.*.?, | |
| 898 | 898 | .target = &mod.resolved_target.result, |
| 899 | 899 | .mod = mod, |
| 900 | 900 | .owner = .{ .nav_index = func.owner_nav }, |
| ... | ... | @@ -100674,11 +100674,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 100674 | 100674 | const ty_pl = air_datas[@intFromEnum(inst)].ty_pl; |
| 100675 | 100675 | const struct_field = cg.air.extraData(Air.StructField, ty_pl.payload).data; |
| 100676 | 100676 | 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( | |
| 100678 | 100678 | cg.typeOf(struct_field.struct_operand), |
| 100679 | 100679 | ty_pl.ty.toType(), |
| 100680 | 100680 | struct_field.field_index, |
| 100681 | ), cg); | |
| 100681 | zcu, | |
| 100682 | )), cg); | |
| 100682 | 100683 | try ops[0].finish(inst, &.{struct_field.struct_operand}, &ops, cg); |
| 100683 | 100684 | }, |
| 100684 | 100685 | .struct_field_ptr_index_0, |
| ... | ... | @@ -100688,7 +100689,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 100688 | 100689 | => |air_tag| { |
| 100689 | 100690 | const ty_op = air_datas[@intFromEnum(inst)].ty_op; |
| 100690 | 100691 | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); |
| 100691 | try ops[0].toOffset(cg.fieldOffset( | |
| 100692 | try ops[0].toOffset(@intCast(codegen.fieldOffset( | |
| 100692 | 100693 | cg.typeOf(ty_op.operand), |
| 100693 | 100694 | ty_op.ty.toType(), |
| 100694 | 100695 | switch (air_tag) { |
| ... | ... | @@ -100698,7 +100699,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 100698 | 100699 | .struct_field_ptr_index_2 => 2, |
| 100699 | 100700 | .struct_field_ptr_index_3 => 3, |
| 100700 | 100701 | }, |
| 100701 | ), cg); | |
| 100702 | zcu, | |
| 100703 | )), cg); | |
| 100702 | 100704 | try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg); |
| 100703 | 100705 | }, |
| 100704 | 100706 | .struct_field_val => { |
| ... | ... | @@ -168108,11 +168110,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 168108 | 168110 | const ty_pl = air_datas[@intFromEnum(inst)].ty_pl; |
| 168109 | 168111 | const field_parent_ptr = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; |
| 168110 | 168112 | 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( | |
| 168112 | 168114 | ty_pl.ty.toType(), |
| 168113 | 168115 | cg.typeOf(field_parent_ptr.field_ptr), |
| 168114 | 168116 | field_parent_ptr.field_index, |
| 168115 | ), cg); | |
| 168117 | zcu, | |
| 168118 | ))), cg); | |
| 168116 | 168119 | try ops[0].finish(inst, &.{field_parent_ptr.field_ptr}, &ops, cg); |
| 168117 | 168120 | }, |
| 168118 | 168121 | .wasm_memory_size, .wasm_memory_grow => unreachable, |
| ... | ... | @@ -174809,18 +174812,6 @@ fn airStore(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void { |
| 174809 | 174812 | return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 174810 | 174813 | } |
| 174811 | 174814 | |
| 174812 | fn 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 | ||
| 174824 | 174815 | fn genUnOp(self: *CodeGen, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: Air.Inst.Ref) !MCValue { |
| 174825 | 174816 | const pt = self.pt; |
| 174826 | 174817 | const zcu = pt.zcu; |
| ... | ... | @@ -184575,7 +184566,7 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 184575 | 184566 | } |
| 184576 | 184567 | const elem_abi_size: u32 = @intCast(elem_ty.abiSize(zcu)); |
| 184577 | 184568 | 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); | |
| 184579 | 184570 | const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size); |
| 184580 | 184571 | const elem_bit_off = elem_off % elem_abi_bits; |
| 184581 | 184572 | const elem_mcv = try self.resolveInst(elem); |
| ... | ... | @@ -185625,21 +185616,19 @@ fn resolveCallingConventionValues( |
| 185625 | 185616 | fn fail(cg: *CodeGen, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } { |
| 185626 | 185617 | @branchHint(.cold); |
| 185627 | 185618 | 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 | }; | |
| 185633 | 185623 | } |
| 185634 | 185624 | |
| 185635 | 185625 | fn failMsg(cg: *CodeGen, msg: *Zcu.ErrorMsg) error{ OutOfMemory, CodegenFail } { |
| 185636 | 185626 | @branchHint(.cold); |
| 185637 | 185627 | 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 | }; | |
| 185643 | 185632 | } |
| 185644 | 185633 | |
| 185645 | 185634 | fn parseRegName(name: []const u8) ?Register { |
src/codegen.zig+48-13| ... | ... | @@ -23,6 +23,8 @@ const Zir = std.zig.Zir; |
| 23 | 23 | const Alignment = InternPool.Alignment; |
| 24 | 24 | const dev = @import("dev.zig"); |
| 25 | 25 | |
| 26 | pub const aarch64 = @import("codegen/aarch64.zig"); | |
| 27 | ||
| 26 | 28 | pub const CodeGenError = GenerateSymbolError || error{ |
| 27 | 29 | /// Indicates the error is already stored in Zcu `failed_codegen`. |
| 28 | 30 | CodegenFail, |
| ... | ... | @@ -49,7 +51,7 @@ fn devFeatureForBackend(backend: std.builtin.CompilerBackend) dev.Feature { |
| 49 | 51 | fn importBackend(comptime backend: std.builtin.CompilerBackend) type { |
| 50 | 52 | return switch (backend) { |
| 51 | 53 | .other, .stage1 => unreachable, |
| 52 | .stage2_aarch64 => unreachable, | |
| 54 | .stage2_aarch64 => aarch64, | |
| 53 | 55 | .stage2_arm => unreachable, |
| 54 | 56 | .stage2_c => @import("codegen/c.zig"), |
| 55 | 57 | .stage2_llvm => @import("codegen/llvm.zig"), |
| ... | ... | @@ -72,6 +74,7 @@ pub fn legalizeFeatures(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) ?*co |
| 72 | 74 | .stage2_c, |
| 73 | 75 | .stage2_wasm, |
| 74 | 76 | .stage2_x86_64, |
| 77 | .stage2_aarch64, | |
| 75 | 78 | .stage2_x86, |
| 76 | 79 | .stage2_riscv64, |
| 77 | 80 | .stage2_sparc64, |
| ... | ... | @@ -83,20 +86,29 @@ pub fn legalizeFeatures(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) ?*co |
| 83 | 86 | } |
| 84 | 87 | } |
| 85 | 88 | |
| 89 | pub fn wantsLiveness(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) bool { | |
| 90 | const zcu = pt.zcu; | |
| 91 | const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result; | |
| 92 | return switch (target_util.zigBackend(target, zcu.comp.config.use_llvm)) { | |
| 93 | else => true, | |
| 94 | .stage2_aarch64 => false, | |
| 95 | }; | |
| 96 | } | |
| 97 | ||
| 86 | 98 | /// Every code generation backend has a different MIR representation. However, we want to pass |
| 87 | 99 | /// MIR from codegen to the linker *regardless* of which backend is in use. So, we use this: a |
| 88 | 100 | /// union of all MIR types. The active tag is known from the backend in use; see `AnyMir.tag`. |
| 89 | 101 | pub const AnyMir = union { |
| 90 | riscv64: @import("arch/riscv64/Mir.zig"), | |
| 91 | sparc64: @import("arch/sparc64/Mir.zig"), | |
| 92 | x86_64: @import("arch/x86_64/Mir.zig"), | |
| 93 | wasm: @import("arch/wasm/Mir.zig"), | |
| 94 | c: @import("codegen/c.zig").Mir, | |
| 102 | aarch64: if (dev.env.supports(.aarch64_backend)) @import("codegen/aarch64/Mir.zig") else noreturn, | |
| 103 | riscv64: if (dev.env.supports(.riscv64_backend)) @import("arch/riscv64/Mir.zig") else noreturn, | |
| 104 | sparc64: if (dev.env.supports(.sparc64_backend)) @import("arch/sparc64/Mir.zig") else noreturn, | |
| 105 | x86_64: if (dev.env.supports(.x86_64_backend)) @import("arch/x86_64/Mir.zig") else noreturn, | |
| 106 | wasm: if (dev.env.supports(.wasm_backend)) @import("arch/wasm/Mir.zig") else noreturn, | |
| 107 | c: if (dev.env.supports(.c_backend)) @import("codegen/c.zig").Mir else noreturn, | |
| 95 | 108 | |
| 96 | 109 | pub inline fn tag(comptime backend: std.builtin.CompilerBackend) []const u8 { |
| 97 | 110 | return switch (backend) { |
| 98 | 111 | .stage2_aarch64 => "aarch64", |
| 99 | .stage2_arm => "arm", | |
| 100 | 112 | .stage2_riscv64 => "riscv64", |
| 101 | 113 | .stage2_sparc64 => "sparc64", |
| 102 | 114 | .stage2_x86_64 => "x86_64", |
| ... | ... | @@ -111,7 +123,8 @@ pub const AnyMir = union { |
| 111 | 123 | const backend = target_util.zigBackend(&zcu.root_mod.resolved_target.result, zcu.comp.config.use_llvm); |
| 112 | 124 | switch (backend) { |
| 113 | 125 | else => unreachable, |
| 114 | inline .stage2_riscv64, | |
| 126 | inline .stage2_aarch64, | |
| 127 | .stage2_riscv64, | |
| 115 | 128 | .stage2_sparc64, |
| 116 | 129 | .stage2_x86_64, |
| 117 | 130 | .stage2_wasm, |
| ... | ... | @@ -132,14 +145,15 @@ pub fn generateFunction( |
| 132 | 145 | src_loc: Zcu.LazySrcLoc, |
| 133 | 146 | func_index: InternPool.Index, |
| 134 | 147 | air: *const Air, |
| 135 | liveness: *const Air.Liveness, | |
| 148 | liveness: *const ?Air.Liveness, | |
| 136 | 149 | ) CodeGenError!AnyMir { |
| 137 | 150 | const zcu = pt.zcu; |
| 138 | 151 | const func = zcu.funcInfo(func_index); |
| 139 | 152 | const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result; |
| 140 | 153 | switch (target_util.zigBackend(target, false)) { |
| 141 | 154 | else => unreachable, |
| 142 | inline .stage2_riscv64, | |
| 155 | inline .stage2_aarch64, | |
| 156 | .stage2_riscv64, | |
| 143 | 157 | .stage2_sparc64, |
| 144 | 158 | .stage2_x86_64, |
| 145 | 159 | .stage2_wasm, |
| ... | ... | @@ -174,7 +188,8 @@ pub fn emitFunction( |
| 174 | 188 | const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result; |
| 175 | 189 | switch (target_util.zigBackend(target, zcu.comp.config.use_llvm)) { |
| 176 | 190 | else => unreachable, |
| 177 | inline .stage2_riscv64, | |
| 191 | inline .stage2_aarch64, | |
| 192 | .stage2_riscv64, | |
| 178 | 193 | .stage2_sparc64, |
| 179 | 194 | .stage2_x86_64, |
| 180 | 195 | => |backend| { |
| ... | ... | @@ -419,7 +434,7 @@ pub fn generateSymbolInner( |
| 419 | 434 | const int_tag_ty = ty.intTagType(zcu); |
| 420 | 435 | try generateSymbolInner(bin_file, pt, src_loc, try pt.getCoerced(.fromInterned(enum_tag.int), int_tag_ty), bw, reloc_parent); |
| 421 | 436 | }, |
| 422 | .float => |float| switch (float.storage) { | |
| 437 | .float => |float| storage: switch (float.storage) { | |
| 423 | 438 | .f16 => |f16_val| try bw.writeInt(u16, @bitCast(f16_val), endian), |
| 424 | 439 | .f32 => |f32_val| try bw.writeInt(u32, @bitCast(f32_val), endian), |
| 425 | 440 | .f64 => |f64_val| try bw.writeInt(u64, @bitCast(f64_val), endian), |
| ... | ... | @@ -428,7 +443,13 @@ pub fn generateSymbolInner( |
| 428 | 443 | const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; |
| 429 | 444 | try bw.splatByteAll(0, abi_size - 10); |
| 430 | 445 | }, |
| 431 | .f128 => |f128_val| try bw.writeInt(u128, @bitCast(f128_val), endian), | |
| 446 | .f128 => |f128_val| switch (Type.fromInterned(float.ty).floatBits(target)) { | |
| 447 | else => unreachable, | |
| 448 | 16 => continue :storage .{ .f16 = @floatCast(f128_val) }, | |
| 449 | 32 => continue :storage .{ .f32 = @floatCast(f128_val) }, | |
| 450 | 64 => continue :storage .{ .f64 = @floatCast(f128_val) }, | |
| 451 | 128 => try bw.writeInt(u128, @bitCast(f128_val), target, endian), | |
| 452 | }, | |
| 432 | 453 | }, |
| 433 | 454 | .ptr => try lowerPtr(bin_file, pt, src_loc, val.toIntern(), bw, reloc_parent, 0), |
| 434 | 455 | .slice => |slice| { |
| ... | ... | @@ -1196,3 +1217,17 @@ pub fn errUnionErrorOffset(payload_ty: Type, zcu: *Zcu) u64 { |
| 1196 | 1217 | return 0; |
| 1197 | 1218 | } |
| 1198 | 1219 | } |
| 1220 | ||
| 1221 | pub fn fieldOffset(ptr_agg_ty: Type, ptr_field_ty: Type, field_index: u32, zcu: *Zcu) u64 { | |
| 1222 | const agg_ty = ptr_agg_ty.childType(zcu); | |
| 1223 | return switch (agg_ty.containerLayout(zcu)) { | |
| 1224 | .auto, .@"extern" => agg_ty.structFieldOffset(field_index, zcu), | |
| 1225 | .@"packed" => @divExact(@as(u64, ptr_agg_ty.ptrInfo(zcu).packed_offset.bit_offset) + | |
| 1226 | (if (zcu.typeToPackedStruct(agg_ty)) |loaded_struct| zcu.structPackedFieldBitOffset(loaded_struct, field_index) else 0) - | |
| 1227 | ptr_field_ty.ptrInfo(zcu).packed_offset.bit_offset, 8), | |
| 1228 | }; | |
| 1229 | } | |
| 1230 | ||
| 1231 | test { | |
| 1232 | _ = aarch64; | |
| 1233 | } |
src/codegen/aarch64.zig created+194| ... | ... | @@ -0,0 +1,194 @@ |
| 1 | pub const abi = @import("aarch64/abi.zig"); | |
| 2 | pub const Assemble = @import("aarch64/Assemble.zig"); | |
| 3 | pub const Disassemble = @import("aarch64/Disassemble.zig"); | |
| 4 | pub const encoding = @import("aarch64/encoding.zig"); | |
| 5 | pub const Mir = @import("aarch64/Mir.zig"); | |
| 6 | pub const Select = @import("aarch64/Select.zig"); | |
| 7 | ||
| 8 | pub fn legalizeFeatures(_: *const std.Target) ?*Air.Legalize.Features { | |
| 9 | return null; | |
| 10 | } | |
| 11 | ||
| 12 | pub 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 | ||
| 184 | test { | |
| 185 | _ = Assemble; | |
| 186 | } | |
| 187 | ||
| 188 | const Air = @import("../Air.zig"); | |
| 189 | const assert = std.debug.assert; | |
| 190 | const InternPool = @import("../InternPool.zig"); | |
| 191 | const link = @import("../link.zig"); | |
| 192 | const std = @import("std"); | |
| 193 | const tracking_log = std.log.scoped(.tracking); | |
| 194 | const Zcu = @import("../Zcu.zig"); |
src/codegen/aarch64/Assemble.zig created+1653| ... | ... | @@ -0,0 +1,1653 @@ |
| 1 | source: [*:0]const u8, | |
| 2 | operands: std.StringHashMapUnmanaged(Operand), | |
| 3 | ||
| 4 | pub const Operand = union(enum) { | |
| 5 | register: aarch64.encoding.Register, | |
| 6 | }; | |
| 7 | ||
| 8 | pub 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 | ||
| 78 | fn 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 | ||
| 128 | const token_buf_len = "v31.b[15]".len; | |
| 129 | fn 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 | ||
| 216 | const 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 | ||
| 341 | test "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 | } | |
| 749 | test "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 | } | |
| 793 | test "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 | } | |
| 823 | test "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 | } | |
| 857 | test "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 | } | |
| 881 | test "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 | } | |
| 917 | test "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 | } | |
| 1093 | test "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 | } | |
| 1469 | test "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 | } | |
| 1634 | test "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 | ||
| 1647 | const aarch64 = @import("../aarch64.zig"); | |
| 1648 | const Assemble = @This(); | |
| 1649 | const assert = std.debug.assert; | |
| 1650 | const Instruction = aarch64.encoding.Instruction; | |
| 1651 | const instructions = @import("instructions.zon"); | |
| 1652 | const std = @import("std"); | |
| 1653 | const log = std.log.scoped(.@"asm"); |
src/codegen/aarch64/Disassemble.zig created+905| ... | ... | @@ -0,0 +1,905 @@ |
| 1 | case: Case = .lower, | |
| 2 | mnemonic_operands_separator: []const u8 = " ", | |
| 3 | operands_separator: []const u8 = ", ", | |
| 4 | enable_aliases: bool = true, | |
| 5 | ||
| 6 | pub const Case = enum { lower, upper }; | |
| 7 | ||
| 8 | pub 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 | ||
| 818 | fn 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 | ||
| 831 | pub 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 | ||
| 902 | const aarch64 = @import("../aarch64.zig"); | |
| 903 | const Disassemble = @This(); | |
| 904 | const Instruction = aarch64.encoding.Instruction; | |
| 905 | const std = @import("std"); |
src/codegen/aarch64/Mir.zig created+275| ... | ... | @@ -0,0 +1,275 @@ |
| 1 | prologue: []const Instruction, | |
| 2 | body: []const Instruction, | |
| 3 | epilogue: []const Instruction, | |
| 4 | literals: []const u32, | |
| 5 | nav_relocs: []const Reloc.Nav, | |
| 6 | uav_relocs: []const Reloc.Uav, | |
| 7 | global_relocs: []const Reloc.Global, | |
| 8 | literal_relocs: []const Reloc.Literal, | |
| 9 | ||
| 10 | pub 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 | ||
| 34 | pub 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 | ||
| 46 | pub 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 | ||
| 148 | fn emitInstructionsForward(code: *std.ArrayListUnmanaged(u8), instructions: []const Instruction) void { | |
| 149 | for (instructions) |instruction| emitInstruction(code, instruction); | |
| 150 | } | |
| 151 | fn 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 | } | |
| 158 | fn emitInstruction(code: *std.ArrayListUnmanaged(u8), instruction: Instruction) void { | |
| 159 | mir_log.debug(" {f}", .{instruction}); | |
| 160 | instruction.write(code.addManyAsArrayAssumeCapacity(Instruction.size)); | |
| 161 | } | |
| 162 | ||
| 163 | fn 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 | ||
| 265 | const Air = @import("../../Air.zig"); | |
| 266 | const assert = std.debug.assert; | |
| 267 | const mir_log = std.log.scoped(.mir); | |
| 268 | const Instruction = @import("encoding.zig").Instruction; | |
| 269 | const InternPool = @import("../../InternPool.zig"); | |
| 270 | const link = @import("../../link.zig"); | |
| 271 | const Mir = @This(); | |
| 272 | const std = @import("std"); | |
| 273 | const target_util = @import("../../target.zig"); | |
| 274 | const Zcu = @import("../../Zcu.zig"); | |
| 275 | const ZigType = @import("../../Type.zig"); |
src/codegen/aarch64/Select.zig created+10981| ... | ... | @@ -0,0 +1,10981 @@ |
| 1 | pt: Zcu.PerThread, | |
| 2 | target: *const std.Target, | |
| 3 | air: Air, | |
| 4 | nav_index: InternPool.Nav.Index, | |
| 5 | ||
| 6 | // Blocks | |
| 7 | def_order: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, void), | |
| 8 | blocks: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, Block), | |
| 9 | loops: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, Loop), | |
| 10 | active_loops: std.ArrayListUnmanaged(Loop.Index), | |
| 11 | loop_live: struct { | |
| 12 | set: std.AutoArrayHashMapUnmanaged(struct { Loop.Index, Air.Inst.Index }, void), | |
| 13 | list: std.ArrayListUnmanaged(Air.Inst.Index), | |
| 14 | }, | |
| 15 | dom_start: u32, | |
| 16 | dom_len: u32, | |
| 17 | dom: std.ArrayListUnmanaged(DomInt), | |
| 18 | ||
| 19 | // Wip Mir | |
| 20 | saved_registers: std.enums.EnumSet(Register.Alias), | |
| 21 | instructions: std.ArrayListUnmanaged(codegen.aarch64.encoding.Instruction), | |
| 22 | literals: std.ArrayListUnmanaged(u32), | |
| 23 | nav_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Nav), | |
| 24 | uav_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Uav), | |
| 25 | global_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Global), | |
| 26 | literal_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Literal), | |
| 27 | ||
| 28 | // Stack Frame | |
| 29 | returns: bool, | |
| 30 | va_list: struct { | |
| 31 | __stack: Value.Indirect, | |
| 32 | __gr_top: Value.Indirect, | |
| 33 | __vr_top: Value.Indirect, | |
| 34 | }, | |
| 35 | stack_size: u24, | |
| 36 | stack_align: InternPool.Alignment, | |
| 37 | ||
| 38 | // Value Tracking | |
| 39 | live_registers: LiveRegisters, | |
| 40 | live_values: std.AutoHashMapUnmanaged(Air.Inst.Index, Value.Index), | |
| 41 | values: std.ArrayListUnmanaged(Value), | |
| 42 | ||
| 43 | pub const LiveRegisters = std.enums.EnumArray(Register.Alias, Value.Index); | |
| 44 | ||
| 45 | pub 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 | ||
| 61 | pub 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 | ||
| 96 | pub 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 | ||
| 120 | pub 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 | ||
| 817 | fn 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 | ||
| 837 | pub 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 | ||
| 867 | pub 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 | ||
| 6541 | pub 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 | |
| 6614 | pub 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 | ||
| 6900 | fn 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 | ||
| 6929 | fn 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 | ||
| 6955 | fn fmtType(isel: *Select, ty: ZigType) ZigType.Formatter { | |
| 6956 | return ty.fmt(isel.pt); | |
| 6957 | } | |
| 6958 | ||
| 6959 | fn fmtConstant(isel: *Select, constant: Constant) @typeInfo(@TypeOf(Constant.fmtValue)).@"fn".return_type.? { | |
| 6960 | return constant.fmtValue(isel.pt); | |
| 6961 | } | |
| 6962 | ||
| 6963 | fn 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 | ||
| 6968 | fn 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 | ||
| 6979 | fn 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 | |
| 6985 | fn 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 | |
| 7084 | fn 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 | ||
| 7204 | fn 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 | ||
| 7249 | fn 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 | ||
| 7286 | fn 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 | ||
| 7453 | const DomInt = u8; | |
| 7454 | ||
| 7455 | pub 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 | }; | |
| 9733 | fn 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 | } | |
| 9737 | fn 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 | } | |
| 9766 | pub 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 | ||
| 9890 | fn 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 | ||
| 9900 | fn 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 | ||
| 10011 | const TryAllocRegResult = union(enum) { | |
| 10012 | allocated: Register.Alias, | |
| 10013 | fill_candidate: Register.Alias, | |
| 10014 | out_of_registers, | |
| 10015 | }; | |
| 10016 | ||
| 10017 | fn 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 | ||
| 10041 | fn 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 | ||
| 10055 | fn 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 | ||
| 10077 | fn 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 | ||
| 10088 | const 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 | }; | |
| 10098 | fn 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 | } | |
| 10105 | fn 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 | ||
| 10118 | fn 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 | ||
| 10125 | fn 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 | ||
| 10160 | fn 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 | ||
| 10193 | fn 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 | |
| 10300 | fn 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 | ||
| 10359 | const 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 | ||
| 10549 | pub 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 | ||
| 10969 | const Air = @import("../../Air.zig"); | |
| 10970 | const assert = std.debug.assert; | |
| 10971 | const codegen = @import("../../codegen.zig"); | |
| 10972 | const Constant = @import("../../Value.zig"); | |
| 10973 | const InternPool = @import("../../InternPool.zig"); | |
| 10974 | const Package = @import("../../Package.zig"); | |
| 10975 | const Register = codegen.aarch64.encoding.Register; | |
| 10976 | const Select = @This(); | |
| 10977 | const std = @import("std"); | |
| 10978 | const tracking_log = std.log.scoped(.tracking); | |
| 10979 | const wip_mir_log = std.log.scoped(.@"wip-mir"); | |
| 10980 | const Zcu = @import("../../Zcu.zig"); | |
| 10981 | const ZigType = @import("../../Type.zig"); |
src/codegen/aarch64/abi.zig+4-16| ... | ... | @@ -1,7 +1,5 @@ |
| 1 | const assert = @import("std").debug.assert; | |
| 1 | 2 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | |
| 3 | const bits = @import("../../arch/aarch64/bits.zig"); | |
| 4 | const Register = bits.Register; | |
| 5 | 3 | const Type = @import("../../Type.zig"); |
| 6 | 4 | const Zcu = @import("../../Zcu.zig"); |
| 7 | 5 | |
| ... | ... | @@ -15,7 +13,7 @@ pub const Class = union(enum) { |
| 15 | 13 | |
| 16 | 14 | /// For `float_array` the second element will be the amount of floats. |
| 17 | 15 | pub fn classifyType(ty: Type, zcu: *Zcu) Class { |
| 18 | std.debug.assert(ty.hasRuntimeBitsIgnoreComptime(zcu)); | |
| 16 | assert(ty.hasRuntimeBitsIgnoreComptime(zcu)); | |
| 19 | 17 | |
| 20 | 18 | var maybe_float_bits: ?u16 = null; |
| 21 | 19 | switch (ty.zigTypeTag(zcu)) { |
| ... | ... | @@ -47,11 +45,11 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class { |
| 47 | 45 | return .byval; |
| 48 | 46 | }, |
| 49 | 47 | .optional => { |
| 50 | std.debug.assert(ty.isPtrLikeOptional(zcu)); | |
| 48 | assert(ty.isPtrLikeOptional(zcu)); | |
| 51 | 49 | return .byval; |
| 52 | 50 | }, |
| 53 | 51 | .pointer => { |
| 54 | std.debug.assert(!ty.isSlice(zcu)); | |
| 52 | assert(!ty.isSlice(zcu)); | |
| 55 | 53 | return .byval; |
| 56 | 54 | }, |
| 57 | 55 | .error_union, |
| ... | ... | @@ -138,13 +136,3 @@ pub fn getFloatArrayType(ty: Type, zcu: *Zcu) ?Type { |
| 138 | 136 | else => return null, |
| 139 | 137 | } |
| 140 | 138 | } |
| 141 | ||
| 142 | pub const callee_preserved_regs = [_]Register{ | |
| 143 | .x19, .x20, .x21, .x22, .x23, | |
| 144 | .x24, .x25, .x26, .x27, .x28, | |
| 145 | }; | |
| 146 | ||
| 147 | pub const c_abi_int_param_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 }; | |
| 148 | pub const c_abi_int_return_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 }; | |
| 149 | ||
| 150 | const allocatable_registers = callee_preserved_regs; |
src/codegen/aarch64/encoding.zig created+11799| ... | ... | @@ -0,0 +1,11799 @@ |
| 1 | /// B1.2 Registers in AArch64 Execution state | |
| 2 | pub 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 | |
| 1147 | pub 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 | |
| 1225 | pub 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 | ||
| 11797 | const aarch64 = @import("../aarch64.zig"); | |
| 11798 | const assert = std.debug.assert; | |
| 11799 | const 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 { |
| 449 | 449 | if (gop.found_existing) return gop.value_ptr.*; |
| 450 | 450 | |
| 451 | 451 | const pt = f.object.dg.pt; |
| 452 | const zcu = pt.zcu; | |
| 452 | 453 | const val = (try f.air.value(ref, pt)).?; |
| 453 | 454 | const ty = f.typeOf(ref); |
| 454 | 455 | |
| 455 | const result: CValue = if (lowersToArray(ty, pt)) result: { | |
| 456 | const result: CValue = if (lowersToArray(ty, zcu)) result: { | |
| 456 | 457 | const ch = &f.object.code_header.writer; |
| 457 | 458 | const decl_c_value = try f.allocLocalValue(.{ |
| 458 | 459 | .ctype = try f.ctypeFromType(ty, .complete), |
| 459 | .alignas = CType.AlignAs.fromAbiAlignment(ty.abiAlignment(pt.zcu)), | |
| 460 | .alignas = CType.AlignAs.fromAbiAlignment(ty.abiAlignment(zcu)), | |
| 460 | 461 | }); |
| 461 | 462 | const gpa = f.object.dg.gpa; |
| 462 | 463 | try f.allocs.put(gpa, decl_c_value.new_local, false); |
| ... | ... | @@ -916,7 +917,7 @@ pub const DeclGen = struct { |
| 916 | 917 | // Ensure complete type definition is available before accessing fields. |
| 917 | 918 | _ = try dg.ctypeFromType(parent_ptr_ty.childType(zcu), .complete); |
| 918 | 919 | |
| 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)) { | |
| 920 | 921 | .begin => { |
| 921 | 922 | const ptr_ctype = try dg.ctypeFromType(field.result_ptr_ty, .complete); |
| 922 | 923 | try w.writeByte('('); |
| ... | ... | @@ -3008,7 +3009,7 @@ pub fn generate( |
| 3008 | 3009 | src_loc: Zcu.LazySrcLoc, |
| 3009 | 3010 | func_index: InternPool.Index, |
| 3010 | 3011 | air: *const Air, |
| 3011 | liveness: *const Air.Liveness, | |
| 3012 | liveness: *const ?Air.Liveness, | |
| 3012 | 3013 | ) @import("../codegen.zig").CodeGenError!Mir { |
| 3013 | 3014 | const zcu = pt.zcu; |
| 3014 | 3015 | const gpa = zcu.gpa; |
| ... | ... | @@ -3021,7 +3022,7 @@ pub fn generate( |
| 3021 | 3022 | var function: Function = .{ |
| 3022 | 3023 | .value_map = .init(gpa), |
| 3023 | 3024 | .air = air.*, |
| 3024 | .liveness = liveness.*, | |
| 3025 | .liveness = liveness.*.?, | |
| 3025 | 3026 | .func_index = func_index, |
| 3026 | 3027 | .object = .{ |
| 3027 | 3028 | .dg = .{ |
| ... | ... | @@ -3961,7 +3962,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3961 | 3962 | ptr_info.flags.alignment.order(src_ty.abiAlignment(zcu)).compare(.gte) |
| 3962 | 3963 | else |
| 3963 | 3964 | true; |
| 3964 | const is_array = lowersToArray(src_ty, pt); | |
| 3965 | const is_array = lowersToArray(src_ty, zcu); | |
| 3965 | 3966 | const need_memcpy = !is_aligned or is_array; |
| 3966 | 3967 | |
| 3967 | 3968 | const w = &f.object.code.writer; |
| ... | ... | @@ -4044,7 +4045,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !void { |
| 4044 | 4045 | const operand = try f.resolveInst(un_op); |
| 4045 | 4046 | try reap(f, inst, &.{un_op}); |
| 4046 | 4047 | var deref = is_ptr; |
| 4047 | const is_array = lowersToArray(ret_ty, pt); | |
| 4048 | const is_array = lowersToArray(ret_ty, zcu); | |
| 4048 | 4049 | const ret_val = if (is_array) ret_val: { |
| 4049 | 4050 | const array_local = try f.allocAlignedLocal(inst, .{ |
| 4050 | 4051 | .ctype = ret_ctype, |
| ... | ... | @@ -4228,7 +4229,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 4228 | 4229 | ptr_info.flags.alignment.order(src_ty.abiAlignment(zcu)).compare(.gte) |
| 4229 | 4230 | else |
| 4230 | 4231 | true; |
| 4231 | const is_array = lowersToArray(.fromInterned(ptr_info.child), pt); | |
| 4232 | const is_array = lowersToArray(.fromInterned(ptr_info.child), zcu); | |
| 4232 | 4233 | const need_memcpy = !is_aligned or is_array; |
| 4233 | 4234 | |
| 4234 | 4235 | const src_val = try f.resolveInst(bin_op.rhs); |
| ... | ... | @@ -4873,7 +4874,7 @@ fn airCall( |
| 4873 | 4874 | } |
| 4874 | 4875 | |
| 4875 | 4876 | const result = result: { |
| 4876 | if (result_local == .none or !lowersToArray(ret_ty, pt)) | |
| 4877 | if (result_local == .none or !lowersToArray(ret_ty, zcu)) | |
| 4877 | 4878 | break :result result_local; |
| 4878 | 4879 | |
| 4879 | 4880 | const array_local = try f.allocLocal(inst, ret_ty); |
| ... | ... | @@ -5971,13 +5972,12 @@ fn fieldLocation( |
| 5971 | 5972 | container_ptr_ty: Type, |
| 5972 | 5973 | field_ptr_ty: Type, |
| 5973 | 5974 | field_index: u32, |
| 5974 | pt: Zcu.PerThread, | |
| 5975 | zcu: *Zcu, | |
| 5975 | 5976 | ) union(enum) { |
| 5976 | 5977 | begin: void, |
| 5977 | 5978 | field: CValue, |
| 5978 | 5979 | byte_offset: u64, |
| 5979 | 5980 | } { |
| 5980 | const zcu = pt.zcu; | |
| 5981 | 5981 | const ip = &zcu.intern_pool; |
| 5982 | 5982 | const container_ty: Type = .fromInterned(ip.indexToKey(container_ptr_ty.toIntern()).ptr_type.child); |
| 5983 | 5983 | switch (ip.indexToKey(container_ty.toIntern())) { |
| ... | ... | @@ -5994,7 +5994,7 @@ fn fieldLocation( |
| 5994 | 5994 | else |
| 5995 | 5995 | .{ .field = field_index } }, |
| 5996 | 5996 | .@"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) + | |
| 5998 | 5998 | container_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset, 8) } |
| 5999 | 5999 | else |
| 6000 | 6000 | .begin, |
| ... | ... | @@ -6076,7 +6076,7 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6076 | 6076 | try f.renderType(w, container_ptr_ty); |
| 6077 | 6077 | try w.writeByte(')'); |
| 6078 | 6078 | |
| 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)) { | |
| 6080 | 6080 | .begin => try f.writeCValue(w, field_ptr_val, .Other), |
| 6081 | 6081 | .field => |field| { |
| 6082 | 6082 | const u8_ptr_ty = try pt.adjustPtrTypeChild(field_ptr_ty, .u8); |
| ... | ... | @@ -6131,7 +6131,7 @@ fn fieldPtr( |
| 6131 | 6131 | try f.renderType(w, field_ptr_ty); |
| 6132 | 6132 | try w.writeByte(')'); |
| 6133 | 6133 | |
| 6134 | switch (fieldLocation(container_ptr_ty, field_ptr_ty, field_index, pt)) { | |
| 6134 | switch (fieldLocation(container_ptr_ty, field_ptr_ty, field_index, zcu)) { | |
| 6135 | 6135 | .begin => try f.writeCValue(w, container_ptr_val, .Other), |
| 6136 | 6136 | .field => |field| { |
| 6137 | 6137 | try w.writeByte('&'); |
| ... | ... | @@ -6189,7 +6189,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6189 | 6189 | |
| 6190 | 6190 | const bit_offset_ty = try pt.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1)); |
| 6191 | 6191 | |
| 6192 | const bit_offset = pt.structPackedFieldBitOffset(loaded_struct, extra.field_index); | |
| 6192 | const bit_offset = zcu.structPackedFieldBitOffset(loaded_struct, extra.field_index); | |
| 6193 | 6193 | |
| 6194 | 6194 | const field_int_signedness = if (inst_ty.isAbiInt(zcu)) |
| 6195 | 6195 | inst_ty.intInfo(zcu).signedness |
| ... | ... | @@ -8573,8 +8573,7 @@ const Vectorize = struct { |
| 8573 | 8573 | } |
| 8574 | 8574 | }; |
| 8575 | 8575 | |
| 8576 | fn lowersToArray(ty: Type, pt: Zcu.PerThread) bool { | |
| 8577 | const zcu = pt.zcu; | |
| 8576 | fn lowersToArray(ty: Type, zcu: *Zcu) bool { | |
| 8578 | 8577 | return switch (ty.zigTypeTag(zcu)) { |
| 8579 | 8578 | .array, .vector => return true, |
| 8580 | 8579 | else => return ty.isAbiInt(zcu) and toCIntBits(@as(u32, @intCast(ty.bitSize(zcu)))) == null, |
src/codegen/llvm.zig+9-8| ... | ... | @@ -20,6 +20,7 @@ const Package = @import("../Package.zig"); |
| 20 | 20 | const Air = @import("../Air.zig"); |
| 21 | 21 | const Value = @import("../Value.zig"); |
| 22 | 22 | const Type = @import("../Type.zig"); |
| 23 | const codegen = @import("../codegen.zig"); | |
| 23 | 24 | const x86_64_abi = @import("../arch/x86_64/abi.zig"); |
| 24 | 25 | const wasm_c_abi = @import("wasm/abi.zig"); |
| 25 | 26 | const aarch64_c_abi = @import("aarch64/abi.zig"); |
| ... | ... | @@ -1131,7 +1132,7 @@ pub const Object = struct { |
| 1131 | 1132 | pt: Zcu.PerThread, |
| 1132 | 1133 | func_index: InternPool.Index, |
| 1133 | 1134 | air: *const Air, |
| 1134 | liveness: *const Air.Liveness, | |
| 1135 | liveness: *const ?Air.Liveness, | |
| 1135 | 1136 | ) !void { |
| 1136 | 1137 | const zcu = pt.zcu; |
| 1137 | 1138 | const comp = zcu.comp; |
| ... | ... | @@ -1489,7 +1490,7 @@ pub const Object = struct { |
| 1489 | 1490 | var fg: FuncGen = .{ |
| 1490 | 1491 | .gpa = gpa, |
| 1491 | 1492 | .air = air.*, |
| 1492 | .liveness = liveness.*, | |
| 1493 | .liveness = liveness.*.?, | |
| 1493 | 1494 | .ng = &ng, |
| 1494 | 1495 | .wip = wip, |
| 1495 | 1496 | .is_naked = fn_info.cc == .naked, |
| ... | ... | @@ -4210,7 +4211,7 @@ pub const Object = struct { |
| 4210 | 4211 | .eu_payload => |eu_ptr| try o.lowerPtr( |
| 4211 | 4212 | pt, |
| 4212 | 4213 | eu_ptr, |
| 4213 | offset + @import("../codegen.zig").errUnionPayloadOffset( | |
| 4214 | offset + codegen.errUnionPayloadOffset( | |
| 4214 | 4215 | Value.fromInterned(eu_ptr).typeOf(zcu).childType(zcu), |
| 4215 | 4216 | zcu, |
| 4216 | 4217 | ), |
| ... | ... | @@ -6050,10 +6051,10 @@ pub const FuncGen = struct { |
| 6050 | 6051 | const target_blocks = dispatch_info.case_blocks[0..target_blocks_len]; |
| 6051 | 6052 | |
| 6052 | 6053 | // Make sure to cast the index to a usize so it's not treated as negative! |
| 6053 | const table_index = try self.wip.cast( | |
| 6054 | .zext, | |
| 6054 | const table_index = try self.wip.conv( | |
| 6055 | .unsigned, | |
| 6055 | 6056 | try self.wip.bin(.@"sub nuw", cond, jmp_table.min.toValue(), ""), |
| 6056 | try o.lowerType(pt, Type.usize), | |
| 6057 | try o.lowerType(pt, .usize), | |
| 6057 | 6058 | "", |
| 6058 | 6059 | ); |
| 6059 | 6060 | const target_ptr_ptr = try self.wip.gep( |
| ... | ... | @@ -6969,7 +6970,7 @@ pub const FuncGen = struct { |
| 6969 | 6970 | .@"struct" => switch (struct_ty.containerLayout(zcu)) { |
| 6970 | 6971 | .@"packed" => { |
| 6971 | 6972 | 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); | |
| 6973 | 6974 | const containing_int = struct_llvm_val; |
| 6974 | 6975 | const shift_amt = |
| 6975 | 6976 | try o.builder.intValue(containing_int.typeOfWip(&self.wip), bit_offset); |
| ... | ... | @@ -11364,7 +11365,7 @@ pub const FuncGen = struct { |
| 11364 | 11365 | |
| 11365 | 11366 | // We have a pointer to a packed struct field that happens to be byte-aligned. |
| 11366 | 11367 | // 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); | |
| 11368 | 11369 | if (byte_offset == 0) return struct_ptr; |
| 11369 | 11370 | const usize_ty = try o.lowerType(pt, Type.usize); |
| 11370 | 11371 | 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 { |
| 251 | 251 | pt: Zcu.PerThread, |
| 252 | 252 | func_index: InternPool.Index, |
| 253 | 253 | air: *const Air, |
| 254 | liveness: *const Air.Liveness, | |
| 254 | liveness: *const ?Air.Liveness, | |
| 255 | 255 | ) !void { |
| 256 | 256 | const nav = pt.zcu.funcInfo(func_index).owner_nav; |
| 257 | 257 | // 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); | |
| 259 | 259 | } |
| 260 | 260 | |
| 261 | 261 | pub fn updateNav( |
| ... | ... | @@ -5134,7 +5134,7 @@ const NavGen = struct { |
| 5134 | 5134 | .@"struct" => switch (object_ty.containerLayout(zcu)) { |
| 5135 | 5135 | .@"packed" => { |
| 5136 | 5136 | 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); | |
| 5138 | 5138 | const bit_offset_id = try self.constInt(.u16, bit_offset); |
| 5139 | 5139 | const signedness = if (field_ty.isInt(zcu)) field_ty.intInfo(zcu).signedness else .unsigned; |
| 5140 | 5140 | const field_bit_size: u16 = @intCast(field_ty.bitSize(zcu)); |
src/dev.zig+27-14| ... | ... | @@ -25,13 +25,13 @@ pub const Env = enum { |
| 25 | 25 | /// - `zig build-* -fno-emit-bin` |
| 26 | 26 | sema, |
| 27 | 27 | |
| 28 | /// - sema | |
| 29 | /// - `zig build-* -fincremental -fno-llvm -fno-lld -target aarch64-linux --listen=-` | |
| 30 | @"aarch64-linux", | |
| 31 | ||
| 28 | 32 | /// - `zig build-* -ofmt=c` |
| 29 | 33 | cbe, |
| 30 | 34 | |
| 31 | /// - sema | |
| 32 | /// - `zig build-* -fincremental -fno-llvm -fno-lld -target x86_64-linux --listen=-` | |
| 33 | @"x86_64-linux", | |
| 34 | ||
| 35 | 35 | /// - sema |
| 36 | 36 | /// - `zig build-* -fincremental -fno-llvm -fno-lld -target powerpc(64)(le)-linux --listen=-` |
| 37 | 37 | @"powerpc-linux", |
| ... | ... | @@ -48,6 +48,10 @@ pub const Env = enum { |
| 48 | 48 | /// - `zig build-* -fno-llvm -fno-lld -target wasm32-* --listen=-` |
| 49 | 49 | wasm, |
| 50 | 50 | |
| 51 | /// - sema | |
| 52 | /// - `zig build-* -fincremental -fno-llvm -fno-lld -target x86_64-linux --listen=-` | |
| 53 | @"x86_64-linux", | |
| 54 | ||
| 51 | 55 | pub inline fn supports(comptime dev_env: Env, comptime feature: Feature) bool { |
| 52 | 56 | return switch (dev_env) { |
| 53 | 57 | .full => true, |
| ... | ... | @@ -153,23 +157,22 @@ pub const Env = enum { |
| 153 | 157 | => true, |
| 154 | 158 | else => Env.ast_gen.supports(feature), |
| 155 | 159 | }, |
| 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) { | |
| 164 | 161 | .build_command, |
| 165 | 162 | .stdio_listen, |
| 166 | 163 | .incremental, |
| 167 | .legalize, | |
| 168 | .x86_64_backend, | |
| 164 | .aarch64_backend, | |
| 169 | 165 | .elf_linker, |
| 170 | 166 | => true, |
| 171 | 167 | else => Env.sema.supports(feature), |
| 172 | 168 | }, |
| 169 | .cbe => switch (feature) { | |
| 170 | .legalize, | |
| 171 | .c_backend, | |
| 172 | .c_linker, | |
| 173 | => true, | |
| 174 | else => Env.sema.supports(feature), | |
| 175 | }, | |
| 173 | 176 | .@"powerpc-linux" => switch (feature) { |
| 174 | 177 | .build_command, |
| 175 | 178 | .stdio_listen, |
| ... | ... | @@ -199,6 +202,16 @@ pub const Env = enum { |
| 199 | 202 | => true, |
| 200 | 203 | else => Env.sema.supports(feature), |
| 201 | 204 | }, |
| 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 | }, | |
| 202 | 215 | }; |
| 203 | 216 | } |
| 204 | 217 |
src/link.zig+1| ... | ... | @@ -23,6 +23,7 @@ const dev = @import("dev.zig"); |
| 23 | 23 | const target_util = @import("target.zig"); |
| 24 | 24 | const codegen = @import("codegen.zig"); |
| 25 | 25 | |
| 26 | pub const aarch64 = @import("link/aarch64.zig"); | |
| 26 | 27 | pub const LdScript = @import("link/LdScript.zig"); |
| 27 | 28 | pub const Queue = @import("link/Queue.zig"); |
| 28 | 29 |
src/link/Coff.zig+26-52| ... | ... | @@ -17,9 +17,9 @@ const Allocator = std.mem.Allocator; |
| 17 | 17 | const Path = std.Build.Cache.Path; |
| 18 | 18 | const Directory = std.Build.Cache.Directory; |
| 19 | 19 | const Cache = std.Build.Cache; |
| 20 | const Writer = std.io.Writer; | |
| 20 | const Writer = std.Io.Writer; | |
| 21 | 21 | |
| 22 | const aarch64_util = @import("../arch/aarch64/bits.zig"); | |
| 22 | const aarch64_util = link.aarch64; | |
| 23 | 23 | const allocPrint = std.fmt.allocPrint; |
| 24 | 24 | const codegen = @import("../codegen.zig"); |
| 25 | 25 | const link = @import("../link.zig"); |
| ... | ... | @@ -1371,9 +1371,13 @@ fn updateNavCode( |
| 1371 | 1371 | |
| 1372 | 1372 | log.debug("updateNavCode {f} 0x{x}", .{ nav.fqn.fmt(ip), nav_index }); |
| 1373 | 1373 | |
| 1374 | const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result; | |
| 1375 | const required_alignment = switch (pt.navAlignment(nav_index)) { | |
| 1376 | .none => target_util.defaultFunctionAlignment(target), | |
| 1374 | const mod = zcu.navFileScope(nav_index).mod.?; | |
| 1375 | const target = &mod.resolved_target.result; | |
| 1376 | const required_alignment = switch (nav.status.fully_resolved.alignment) { | |
| 1377 | .none => switch (mod.optimize_mode) { | |
| 1378 | .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target), | |
| 1379 | .ReleaseSmall => target_util.minFunctionAlignment(target), | |
| 1380 | }, | |
| 1377 | 1381 | else => |a| a.maxStrict(target_util.minFunctionAlignment(target)), |
| 1378 | 1382 | }; |
| 1379 | 1383 | |
| ... | ... | @@ -2867,58 +2871,33 @@ pub const Relocation = struct { |
| 2867 | 2871 | }; |
| 2868 | 2872 | |
| 2869 | 2873 | fn resolveAarch64(reloc: Relocation, ctx: Context) void { |
| 2874 | const Instruction = aarch64_util.encoding.Instruction; | |
| 2870 | 2875 | var buffer = ctx.code[reloc.offset..]; |
| 2871 | 2876 | switch (reloc.type) { |
| 2872 | 2877 | .got_page, .import_page, .page => { |
| 2873 | 2878 | const source_page = @as(i32, @intCast(ctx.source_vaddr >> 12)); |
| 2874 | 2879 | const target_page = @as(i32, @intCast(ctx.target_vaddr >> 12)); |
| 2875 | const pages = @as(u21, @bitCast(@as(i21, @intCast(target_page - source_page)))); | |
| 2876 | var inst = aarch64_util.Instruction{ | |
| 2877 | .pc_relative_address = mem.bytesToValue(@FieldType( | |
| 2878 | aarch64_util.Instruction, | |
| 2879 | @tagName(aarch64_util.Instruction.pc_relative_address), | |
| 2880 | ), buffer[0..4]), | |
| 2881 | }; | |
| 2882 | inst.pc_relative_address.immhi = @as(u19, @truncate(pages >> 2)); | |
| 2883 | inst.pc_relative_address.immlo = @as(u2, @truncate(pages)); | |
| 2884 | mem.writeInt(u32, buffer[0..4], inst.toU32(), .little); | |
| 2880 | const pages: i21 = @intCast(target_page - source_page); | |
| 2881 | var inst: Instruction = .read(buffer[0..Instruction.size]); | |
| 2882 | inst.data_processing_immediate.pc_relative_addressing.group.immhi = @intCast(pages >> 2); | |
| 2883 | inst.data_processing_immediate.pc_relative_addressing.group.immlo = @truncate(@as(u21, @bitCast(pages))); | |
| 2884 | inst.write(buffer[0..Instruction.size]); | |
| 2885 | 2885 | }, |
| 2886 | 2886 | .got_pageoff, .import_pageoff, .pageoff => { |
| 2887 | 2887 | assert(!reloc.pcrel); |
| 2888 | 2888 | |
| 2889 | const narrowed = @as(u12, @truncate(@as(u64, @intCast(ctx.target_vaddr)))); | |
| 2890 | if (isArithmeticOp(buffer[0..4])) { | |
| 2891 | var inst = aarch64_util.Instruction{ | |
| 2892 | .add_subtract_immediate = mem.bytesToValue(@FieldType( | |
| 2893 | aarch64_util.Instruction, | |
| 2894 | @tagName(aarch64_util.Instruction.add_subtract_immediate), | |
| 2895 | ), buffer[0..4]), | |
| 2896 | }; | |
| 2897 | inst.add_subtract_immediate.imm12 = narrowed; | |
| 2898 | mem.writeInt(u32, buffer[0..4], inst.toU32(), .little); | |
| 2899 | } else { | |
| 2900 | var inst = aarch64_util.Instruction{ | |
| 2901 | .load_store_register = mem.bytesToValue(@FieldType( | |
| 2902 | aarch64_util.Instruction, | |
| 2903 | @tagName(aarch64_util.Instruction.load_store_register), | |
| 2904 | ), buffer[0..4]), | |
| 2905 | }; | |
| 2906 | const offset: u12 = blk: { | |
| 2907 | if (inst.load_store_register.size == 0) { | |
| 2908 | if (inst.load_store_register.v == 1) { | |
| 2909 | // 128-bit SIMD is scaled by 16. | |
| 2910 | break :blk @divExact(narrowed, 16); | |
| 2911 | } | |
| 2912 | // Otherwise, 8-bit SIMD or ldrb. | |
| 2913 | break :blk narrowed; | |
| 2914 | } else { | |
| 2915 | const denom: u4 = math.powi(u4, 2, inst.load_store_register.size) catch unreachable; | |
| 2916 | break :blk @divExact(narrowed, denom); | |
| 2917 | } | |
| 2918 | }; | |
| 2919 | inst.load_store_register.offset = offset; | |
| 2920 | mem.writeInt(u32, buffer[0..4], inst.toU32(), .little); | |
| 2889 | const narrowed: u12 = @truncate(@as(u64, @intCast(ctx.target_vaddr))); | |
| 2890 | var inst: Instruction = .read(buffer[0..Instruction.size]); | |
| 2891 | switch (inst.decode()) { | |
| 2892 | else => unreachable, | |
| 2893 | .data_processing_immediate => inst.data_processing_immediate.add_subtract_immediate.group.imm12 = narrowed, | |
| 2894 | .load_store => |load_store| inst.load_store.register_unsigned_immediate.group.imm12 = | |
| 2895 | switch (load_store.register_unsigned_immediate.decode()) { | |
| 2896 | .integer => |integer| @shrExact(narrowed, @intFromEnum(integer.group.size)), | |
| 2897 | .vector => |vector| @shrExact(narrowed, @intFromEnum(vector.group.opc1.decode(vector.group.size))), | |
| 2898 | }, | |
| 2921 | 2899 | } |
| 2900 | inst.write(buffer[0..Instruction.size]); | |
| 2922 | 2901 | }, |
| 2923 | 2902 | .direct => { |
| 2924 | 2903 | assert(!reloc.pcrel); |
| ... | ... | @@ -2969,11 +2948,6 @@ pub const Relocation = struct { |
| 2969 | 2948 | }, |
| 2970 | 2949 | } |
| 2971 | 2950 | } |
| 2972 | ||
| 2973 | fn isArithmeticOp(inst: *const [4]u8) bool { | |
| 2974 | const group_decode = @as(u5, @truncate(inst[3])); | |
| 2975 | return ((group_decode >> 2) == 4); | |
| 2976 | } | |
| 2977 | 2951 | }; |
| 2978 | 2952 | |
| 2979 | 2953 | pub fn addRelocation(coff: *Coff, atom_index: Atom.Index, reloc: Relocation) !void { |
src/link/Dwarf.zig+7-1| ... | ... | @@ -2555,7 +2555,13 @@ fn initWipNavInner( |
| 2555 | 2555 | try wip_nav.strp(nav.fqn.toSlice(ip)); |
| 2556 | 2556 | const ty: Type = nav_val.typeOf(zcu); |
| 2557 | 2557 | const addr: Loc = .{ .addr_reloc = sym_index }; |
| 2558 | const loc: Loc = if (decl.is_threadlocal) .{ .form_tls_address = &addr } else addr; | |
| 2558 | const loc: Loc = if (decl.is_threadlocal) loc: { | |
| 2559 | const target = zcu.comp.root_mod.resolved_target.result; | |
| 2560 | break :loc switch (target.cpu.arch) { | |
| 2561 | .x86_64 => .{ .form_tls_address = &addr }, | |
| 2562 | else => .empty, | |
| 2563 | }; | |
| 2564 | } else addr; | |
| 2559 | 2565 | switch (decl.kind) { |
| 2560 | 2566 | .unnamed_test, .@"test", .decltest, .@"comptime" => unreachable, |
| 2561 | 2567 | .@"const" => { |
src/link/Elf/Atom.zig+27-43| ... | ... | @@ -1611,7 +1611,7 @@ const aarch64 = struct { |
| 1611 | 1611 | const S_ = th.targetAddress(target_index, elf_file); |
| 1612 | 1612 | break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow; |
| 1613 | 1613 | }; |
| 1614 | aarch64_util.writeBranchImm(disp, code); | |
| 1614 | util.writeBranchImm(disp, code); | |
| 1615 | 1615 | }, |
| 1616 | 1616 | |
| 1617 | 1617 | .PREL32 => { |
| ... | ... | @@ -1624,15 +1624,18 @@ const aarch64 = struct { |
| 1624 | 1624 | try bw.writeInt(u64, @bitCast(value), .little); |
| 1625 | 1625 | }, |
| 1626 | 1626 | |
| 1627 | .ADR_PREL_LO21 => { | |
| 1628 | const value = math.cast(i21, S + A - P) orelse return error.Overflow; | |
| 1629 | util.writeAdrInst(value, code); | |
| 1630 | }, | |
| 1631 | ||
| 1627 | 1632 | .ADR_PREL_PG_HI21 => { |
| 1628 | 1633 | // TODO: check for relaxation of ADRP+ADD |
| 1629 | const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(P, S + A))); | |
| 1630 | aarch64_util.writeAdrpInst(pages, code); | |
| 1634 | util.writeAdrInst(try util.calcNumberOfPages(P, S + A), code); | |
| 1631 | 1635 | }, |
| 1632 | 1636 | |
| 1633 | 1637 | .ADR_GOT_PAGE => if (target.flags.has_got) { |
| 1634 | const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(P, G + GOT + A))); | |
| 1635 | aarch64_util.writeAdrpInst(pages, code); | |
| 1638 | util.writeAdrInst(try util.calcNumberOfPages(P, G + GOT + A), code); | |
| 1636 | 1639 | } else { |
| 1637 | 1640 | // TODO: relax |
| 1638 | 1641 | var err = try diags.addErrorWithNotes(1); |
| ... | ... | @@ -1647,12 +1650,12 @@ const aarch64 = struct { |
| 1647 | 1650 | .LD64_GOT_LO12_NC => { |
| 1648 | 1651 | assert(target.flags.has_got); |
| 1649 | 1652 | const taddr = @as(u64, @intCast(G + GOT + A)); |
| 1650 | aarch64_util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code); | |
| 1653 | util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code); | |
| 1651 | 1654 | }, |
| 1652 | 1655 | |
| 1653 | 1656 | .ADD_ABS_LO12_NC => { |
| 1654 | 1657 | const taddr = @as(u64, @intCast(S + A)); |
| 1655 | aarch64_util.writeAddImmInst(@truncate(taddr), code); | |
| 1658 | util.writeAddImmInst(@truncate(taddr), code); | |
| 1656 | 1659 | }, |
| 1657 | 1660 | |
| 1658 | 1661 | .LDST8_ABS_LO12_NC, |
| ... | ... | @@ -1671,57 +1674,54 @@ const aarch64 = struct { |
| 1671 | 1674 | .LDST128_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 16), |
| 1672 | 1675 | else => unreachable, |
| 1673 | 1676 | }; |
| 1674 | aarch64_util.writeLoadStoreRegInst(off, code); | |
| 1677 | util.writeLoadStoreRegInst(off, code); | |
| 1675 | 1678 | }, |
| 1676 | 1679 | |
| 1677 | 1680 | .TLSLE_ADD_TPREL_HI12 => { |
| 1678 | 1681 | const value = math.cast(i12, (S + A - TP) >> 12) orelse |
| 1679 | 1682 | return error.Overflow; |
| 1680 | aarch64_util.writeAddImmInst(@bitCast(value), code); | |
| 1683 | util.writeAddImmInst(@bitCast(value), code); | |
| 1681 | 1684 | }, |
| 1682 | 1685 | |
| 1683 | 1686 | .TLSLE_ADD_TPREL_LO12_NC => { |
| 1684 | 1687 | const value: i12 = @truncate(S + A - TP); |
| 1685 | aarch64_util.writeAddImmInst(@bitCast(value), code); | |
| 1688 | util.writeAddImmInst(@bitCast(value), code); | |
| 1686 | 1689 | }, |
| 1687 | 1690 | |
| 1688 | 1691 | .TLSIE_ADR_GOTTPREL_PAGE21 => { |
| 1689 | 1692 | const S_ = target.gotTpAddress(elf_file); |
| 1690 | 1693 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1691 | const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A)); | |
| 1692 | aarch64_util.writeAdrpInst(pages, code); | |
| 1694 | util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code); | |
| 1693 | 1695 | }, |
| 1694 | 1696 | |
| 1695 | 1697 | .TLSIE_LD64_GOTTPREL_LO12_NC => { |
| 1696 | 1698 | const S_ = target.gotTpAddress(elf_file); |
| 1697 | 1699 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1698 | 1700 | const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8); |
| 1699 | aarch64_util.writeLoadStoreRegInst(off, code); | |
| 1701 | util.writeLoadStoreRegInst(off, code); | |
| 1700 | 1702 | }, |
| 1701 | 1703 | |
| 1702 | 1704 | .TLSGD_ADR_PAGE21 => { |
| 1703 | 1705 | const S_ = target.tlsGdAddress(elf_file); |
| 1704 | 1706 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1705 | const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A)); | |
| 1706 | aarch64_util.writeAdrpInst(pages, code); | |
| 1707 | util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code); | |
| 1707 | 1708 | }, |
| 1708 | 1709 | |
| 1709 | 1710 | .TLSGD_ADD_LO12_NC => { |
| 1710 | 1711 | const S_ = target.tlsGdAddress(elf_file); |
| 1711 | 1712 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1712 | 1713 | const off: u12 = @truncate(@as(u64, @bitCast(S_ + A))); |
| 1713 | aarch64_util.writeAddImmInst(off, code); | |
| 1714 | util.writeAddImmInst(off, code); | |
| 1714 | 1715 | }, |
| 1715 | 1716 | |
| 1716 | 1717 | .TLSDESC_ADR_PAGE21 => { |
| 1717 | 1718 | if (target.flags.has_tlsdesc) { |
| 1718 | 1719 | const S_ = target.tlsDescAddress(elf_file); |
| 1719 | 1720 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1720 | const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A)); | |
| 1721 | aarch64_util.writeAdrpInst(pages, code); | |
| 1721 | util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code); | |
| 1722 | 1722 | } else { |
| 1723 | 1723 | relocs_log.debug(" relaxing adrp => nop", .{}); |
| 1724 | mem.writeInt(u32, code, Instruction.nop().toU32(), .little); | |
| 1724 | util.encoding.Instruction.nop().write(code); | |
| 1725 | 1725 | } |
| 1726 | 1726 | }, |
| 1727 | 1727 | |
| ... | ... | @@ -1730,10 +1730,10 @@ const aarch64 = struct { |
| 1730 | 1730 | const S_ = target.tlsDescAddress(elf_file); |
| 1731 | 1731 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1732 | 1732 | const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8); |
| 1733 | aarch64_util.writeLoadStoreRegInst(off, code); | |
| 1733 | util.writeLoadStoreRegInst(off, code); | |
| 1734 | 1734 | } else { |
| 1735 | 1735 | relocs_log.debug(" relaxing ldr => nop", .{}); |
| 1736 | mem.writeInt(u32, code, Instruction.nop().toU32(), .little); | |
| 1736 | util.encoding.Instruction.nop().write(code); | |
| 1737 | 1737 | } |
| 1738 | 1738 | }, |
| 1739 | 1739 | |
| ... | ... | @@ -1742,32 +1742,18 @@ const aarch64 = struct { |
| 1742 | 1742 | const S_ = target.tlsDescAddress(elf_file); |
| 1743 | 1743 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1744 | 1744 | const off: u12 = @truncate(@as(u64, @bitCast(S_ + A))); |
| 1745 | aarch64_util.writeAddImmInst(off, code); | |
| 1745 | util.writeAddImmInst(off, code); | |
| 1746 | 1746 | } else { |
| 1747 | const old_inst: Instruction = .{ | |
| 1748 | .add_subtract_immediate = mem.bytesToValue(@FieldType( | |
| 1749 | Instruction, | |
| 1750 | @tagName(Instruction.add_subtract_immediate), | |
| 1751 | ), code), | |
| 1752 | }; | |
| 1753 | const rd: Register = @enumFromInt(old_inst.add_subtract_immediate.rd); | |
| 1754 | relocs_log.debug(" relaxing add({s}) => movz(x0, {x})", .{ @tagName(rd), S + A - TP }); | |
| 1747 | relocs_log.debug(" relaxing add => movz(x0, {x})", .{S + A - TP}); | |
| 1755 | 1748 | const value: u16 = @bitCast(math.cast(i16, (S + A - TP) >> 16) orelse return error.Overflow); |
| 1756 | mem.writeInt(u32, code, Instruction.movz(.x0, value, 16).toU32(), .little); | |
| 1749 | util.encoding.Instruction.movz(.x0, value, .{ .lsl = .@"16" }).write(code); | |
| 1757 | 1750 | } |
| 1758 | 1751 | }, |
| 1759 | 1752 | |
| 1760 | 1753 | .TLSDESC_CALL => if (!target.flags.has_tlsdesc) { |
| 1761 | const old_inst: Instruction = .{ | |
| 1762 | .unconditional_branch_register = mem.bytesToValue(@FieldType( | |
| 1763 | Instruction, | |
| 1764 | @tagName(Instruction.unconditional_branch_register), | |
| 1765 | ), code), | |
| 1766 | }; | |
| 1767 | const rn: Register = @enumFromInt(old_inst.unconditional_branch_register.rn); | |
| 1768 | relocs_log.debug(" relaxing br({s}) => movk(x0, {x})", .{ @tagName(rn), S + A - TP }); | |
| 1754 | relocs_log.debug(" relaxing br => movk(x0, {x})", .{S + A - TP}); | |
| 1769 | 1755 | const value: u16 = @bitCast(@as(i16, @truncate(S + A - TP))); |
| 1770 | mem.writeInt(u32, code, Instruction.movk(.x0, value, 0).toU32(), .little); | |
| 1756 | util.encoding.Instruction.movk(.x0, value, .{}).write(code); | |
| 1771 | 1757 | }, |
| 1772 | 1758 | |
| 1773 | 1759 | else => try atom.reportUnhandledRelocError(rel, elf_file), |
| ... | ... | @@ -1796,9 +1782,7 @@ const aarch64 = struct { |
| 1796 | 1782 | } |
| 1797 | 1783 | } |
| 1798 | 1784 | |
| 1799 | const aarch64_util = @import("../aarch64.zig"); | |
| 1800 | const Instruction = aarch64_util.Instruction; | |
| 1801 | const Register = aarch64_util.Register; | |
| 1785 | const util = @import("../aarch64.zig"); | |
| 1802 | 1786 | }; |
| 1803 | 1787 | |
| 1804 | 1788 | const riscv = struct { |
src/link/Elf/Thunk.zig+9-6| ... | ... | @@ -95,18 +95,21 @@ const aarch64 = struct { |
| 95 | 95 | const sym = elf_file.symbol(ref).?; |
| 96 | 96 | const saddr = thunk.address(elf_file) + @as(i64, @intCast(i * trampoline_size)); |
| 97 | 97 | 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); | |
| 103 | 107 | } |
| 104 | 108 | } |
| 105 | 109 | |
| 106 | 110 | const trampoline_size = 3 * @sizeOf(u32); |
| 107 | 111 | |
| 108 | 112 | const util = @import("../aarch64.zig"); |
| 109 | const Instruction = util.Instruction; | |
| 110 | 113 | }; |
| 111 | 114 | |
| 112 | 115 | const std = @import("std"); |
src/link/Elf/ZigObject.zig+7-3| ... | ... | @@ -1266,9 +1266,13 @@ fn updateNavCode( |
| 1266 | 1266 | |
| 1267 | 1267 | log.debug("updateNavCode {f}({d})", .{ nav.fqn.fmt(ip), nav_index }); |
| 1268 | 1268 | |
| 1269 | const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result; | |
| 1270 | const required_alignment = switch (pt.navAlignment(nav_index)) { | |
| 1271 | .none => target_util.defaultFunctionAlignment(target), | |
| 1269 | const mod = zcu.navFileScope(nav_index).mod.?; | |
| 1270 | const target = &mod.resolved_target.result; | |
| 1271 | const required_alignment = switch (nav.status.fully_resolved.alignment) { | |
| 1272 | .none => switch (mod.optimize_mode) { | |
| 1273 | .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target), | |
| 1274 | .ReleaseSmall => target_util.minFunctionAlignment(target), | |
| 1275 | }, | |
| 1272 | 1276 | else => |a| a.maxStrict(target_util.minFunctionAlignment(target)), |
| 1273 | 1277 | }; |
| 1274 | 1278 |
src/link/Elf/relocation.zig+18-6| ... | ... | @@ -94,14 +94,18 @@ pub fn encode(comptime kind: Kind, cpu_arch: std.Target.Cpu.Arch) u32 { |
| 94 | 94 | pub const dwarf = struct { |
| 95 | 95 | pub fn crossSectionRelocType(format: DW.Format, cpu_arch: std.Target.Cpu.Arch) u32 { |
| 96 | 96 | 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", | |
| 99 | 99 | .@"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", | |
| 103 | 107 | .@"64" => .@"64", |
| 104 | }), | |
| 108 | })), | |
| 105 | 109 | else => @panic("TODO unhandled cpu arch"), |
| 106 | 110 | }; |
| 107 | 111 | } |
| ... | ... | @@ -121,6 +125,14 @@ pub const dwarf = struct { |
| 121 | 125 | }, |
| 122 | 126 | .debug_frame => .PC32, |
| 123 | 127 | })), |
| 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 | })), | |
| 124 | 136 | .riscv64 => @intFromEnum(@as(elf.R_RISCV, switch (source_section) { |
| 125 | 137 | else => switch (address_size) { |
| 126 | 138 | .@"32" => .@"32", |
src/link/Elf/synthetic_sections.zig+109-124| ... | ... | @@ -94,115 +94,115 @@ pub const DynamicSection = struct { |
| 94 | 94 | return nentries * @sizeOf(elf.Elf64_Dyn); |
| 95 | 95 | } |
| 96 | 96 | |
| 97 | pub fn write(dt: DynamicSection, elf_file: *Elf, bw: *Writer) Writer.Error!void { | |
| 97 | pub fn write(dt: DynamicSection, elf_file: *Elf, writer: *Writer) Writer.Error!void { | |
| 98 | 98 | const shdrs = elf_file.sections.items(.shdr); |
| 99 | 99 | |
| 100 | 100 | // NEEDED |
| 101 | 101 | for (dt.needed.items) |off| { |
| 102 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_NEEDED, .d_val = off }); | |
| 102 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_NEEDED, .d_val = off }); | |
| 103 | 103 | } |
| 104 | 104 | |
| 105 | 105 | if (dt.soname) |off| { |
| 106 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_SONAME, .d_val = off }); | |
| 106 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_SONAME, .d_val = off }); | |
| 107 | 107 | } |
| 108 | 108 | |
| 109 | 109 | // RUNPATH |
| 110 | 110 | // TODO add option in Options to revert to old RPATH tag |
| 111 | 111 | if (dt.rpath > 0) { |
| 112 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RUNPATH, .d_val = dt.rpath }); | |
| 112 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RUNPATH, .d_val = dt.rpath }); | |
| 113 | 113 | } |
| 114 | 114 | |
| 115 | 115 | // INIT |
| 116 | 116 | if (elf_file.sectionByName(".init")) |shndx| { |
| 117 | 117 | const addr = shdrs[shndx].sh_addr; |
| 118 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_INIT, .d_val = addr }); | |
| 118 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_INIT, .d_val = addr }); | |
| 119 | 119 | } |
| 120 | 120 | |
| 121 | 121 | // FINI |
| 122 | 122 | if (elf_file.sectionByName(".fini")) |shndx| { |
| 123 | 123 | const addr = shdrs[shndx].sh_addr; |
| 124 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FINI, .d_val = addr }); | |
| 124 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FINI, .d_val = addr }); | |
| 125 | 125 | } |
| 126 | 126 | |
| 127 | 127 | // INIT_ARRAY |
| 128 | 128 | if (elf_file.sectionByName(".init_array")) |shndx| { |
| 129 | 129 | const shdr = shdrs[shndx]; |
| 130 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_INIT_ARRAY, .d_val = shdr.sh_addr }); | |
| 131 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_INIT_ARRAYSZ, .d_val = shdr.sh_size }); | |
| 130 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_INIT_ARRAY, .d_val = shdr.sh_addr }); | |
| 131 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_INIT_ARRAYSZ, .d_val = shdr.sh_size }); | |
| 132 | 132 | } |
| 133 | 133 | |
| 134 | 134 | // FINI_ARRAY |
| 135 | 135 | if (elf_file.sectionByName(".fini_array")) |shndx| { |
| 136 | 136 | const shdr = shdrs[shndx]; |
| 137 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FINI_ARRAY, .d_val = shdr.sh_addr }); | |
| 138 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FINI_ARRAYSZ, .d_val = shdr.sh_size }); | |
| 137 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FINI_ARRAY, .d_val = shdr.sh_addr }); | |
| 138 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FINI_ARRAYSZ, .d_val = shdr.sh_size }); | |
| 139 | 139 | } |
| 140 | 140 | |
| 141 | 141 | // RELA |
| 142 | 142 | if (elf_file.section_indexes.rela_dyn) |shndx| { |
| 143 | 143 | const shdr = shdrs[shndx]; |
| 144 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RELA, .d_val = shdr.sh_addr }); | |
| 145 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RELASZ, .d_val = shdr.sh_size }); | |
| 146 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RELAENT, .d_val = shdr.sh_entsize }); | |
| 144 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RELA, .d_val = shdr.sh_addr }); | |
| 145 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RELASZ, .d_val = shdr.sh_size }); | |
| 146 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RELAENT, .d_val = shdr.sh_entsize }); | |
| 147 | 147 | } |
| 148 | 148 | |
| 149 | 149 | // JMPREL |
| 150 | 150 | if (elf_file.section_indexes.rela_plt) |shndx| { |
| 151 | 151 | const shdr = shdrs[shndx]; |
| 152 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_JMPREL, .d_val = shdr.sh_addr }); | |
| 153 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_PLTRELSZ, .d_val = shdr.sh_size }); | |
| 154 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_PLTREL, .d_val = elf.DT_RELA }); | |
| 152 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_JMPREL, .d_val = shdr.sh_addr }); | |
| 153 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_PLTRELSZ, .d_val = shdr.sh_size }); | |
| 154 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_PLTREL, .d_val = elf.DT_RELA }); | |
| 155 | 155 | } |
| 156 | 156 | |
| 157 | 157 | // PLTGOT |
| 158 | 158 | if (elf_file.section_indexes.got_plt) |shndx| { |
| 159 | 159 | const addr = shdrs[shndx].sh_addr; |
| 160 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_PLTGOT, .d_val = addr }); | |
| 160 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_PLTGOT, .d_val = addr }); | |
| 161 | 161 | } |
| 162 | 162 | |
| 163 | 163 | { |
| 164 | 164 | assert(elf_file.section_indexes.hash != null); |
| 165 | 165 | const addr = shdrs[elf_file.section_indexes.hash.?].sh_addr; |
| 166 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_HASH, .d_val = addr }); | |
| 166 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_HASH, .d_val = addr }); | |
| 167 | 167 | } |
| 168 | 168 | |
| 169 | 169 | if (elf_file.section_indexes.gnu_hash) |shndx| { |
| 170 | 170 | const addr = shdrs[shndx].sh_addr; |
| 171 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_GNU_HASH, .d_val = addr }); | |
| 171 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_GNU_HASH, .d_val = addr }); | |
| 172 | 172 | } |
| 173 | 173 | |
| 174 | 174 | // TEXTREL |
| 175 | 175 | if (elf_file.has_text_reloc) { |
| 176 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_TEXTREL, .d_val = 0 }); | |
| 176 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_TEXTREL, .d_val = 0 }); | |
| 177 | 177 | } |
| 178 | 178 | |
| 179 | 179 | // SYMTAB + SYMENT |
| 180 | 180 | { |
| 181 | 181 | assert(elf_file.section_indexes.dynsymtab != null); |
| 182 | 182 | const shdr = shdrs[elf_file.section_indexes.dynsymtab.?]; |
| 183 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_SYMTAB, .d_val = shdr.sh_addr }); | |
| 184 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_SYMENT, .d_val = shdr.sh_entsize }); | |
| 183 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_SYMTAB, .d_val = shdr.sh_addr }); | |
| 184 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_SYMENT, .d_val = shdr.sh_entsize }); | |
| 185 | 185 | } |
| 186 | 186 | |
| 187 | 187 | // STRTAB + STRSZ |
| 188 | 188 | { |
| 189 | 189 | assert(elf_file.section_indexes.dynstrtab != null); |
| 190 | 190 | const shdr = shdrs[elf_file.section_indexes.dynstrtab.?]; |
| 191 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_STRTAB, .d_val = shdr.sh_addr }); | |
| 192 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_STRSZ, .d_val = shdr.sh_size }); | |
| 191 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_STRTAB, .d_val = shdr.sh_addr }); | |
| 192 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_STRSZ, .d_val = shdr.sh_size }); | |
| 193 | 193 | } |
| 194 | 194 | |
| 195 | 195 | // VERSYM |
| 196 | 196 | if (elf_file.section_indexes.versym) |shndx| { |
| 197 | 197 | const addr = shdrs[shndx].sh_addr; |
| 198 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_VERSYM, .d_val = addr }); | |
| 198 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_VERSYM, .d_val = addr }); | |
| 199 | 199 | } |
| 200 | 200 | |
| 201 | 201 | // VERNEED + VERNEEDNUM |
| 202 | 202 | if (elf_file.section_indexes.verneed) |shndx| { |
| 203 | 203 | const addr = shdrs[shndx].sh_addr; |
| 204 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_VERNEED, .d_val = addr }); | |
| 205 | try bw.writeStruct(elf.Elf64_Dyn{ | |
| 204 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_VERNEED, .d_val = addr }); | |
| 205 | try writer.writeStruct(elf.Elf64_Dyn{ | |
| 206 | 206 | .d_tag = elf.DT_VERNEEDNUM, |
| 207 | 207 | .d_val = elf_file.verneed.verneed.items.len, |
| 208 | 208 | }); |
| ... | ... | @@ -210,18 +210,18 @@ pub const DynamicSection = struct { |
| 210 | 210 | |
| 211 | 211 | // FLAGS |
| 212 | 212 | if (dt.getFlags(elf_file)) |flags| { |
| 213 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FLAGS, .d_val = flags }); | |
| 213 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FLAGS, .d_val = flags }); | |
| 214 | 214 | } |
| 215 | 215 | // FLAGS_1 |
| 216 | 216 | if (dt.getFlags1(elf_file)) |flags_1| { |
| 217 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FLAGS_1, .d_val = flags_1 }); | |
| 217 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FLAGS_1, .d_val = flags_1 }); | |
| 218 | 218 | } |
| 219 | 219 | |
| 220 | 220 | // DEBUG |
| 221 | if (!elf_file.isEffectivelyDynLib()) try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_DEBUG, .d_val = 0 }); | |
| 221 | if (!elf_file.isEffectivelyDynLib()) try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_DEBUG, .d_val = 0 }); | |
| 222 | 222 | |
| 223 | 223 | // NULL |
| 224 | try bw.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_NULL, .d_val = 0 }); | |
| 224 | try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_NULL, .d_val = 0 }); | |
| 225 | 225 | } |
| 226 | 226 | }; |
| 227 | 227 | |
| ... | ... | @@ -360,7 +360,7 @@ pub const GotSection = struct { |
| 360 | 360 | return s; |
| 361 | 361 | } |
| 362 | 362 | |
| 363 | pub fn write(got: GotSection, elf_file: *Elf, bw: *Writer) Writer.Error!void { | |
| 363 | pub fn write(got: GotSection, elf_file: *Elf, writer: *Writer) Writer.Error!void { | |
| 364 | 364 | const comp = elf_file.base.comp; |
| 365 | 365 | const is_dyn_lib = elf_file.isEffectivelyDynLib(); |
| 366 | 366 | const apply_relocs = true; // TODO add user option for this |
| ... | ... | @@ -381,47 +381,47 @@ pub const GotSection = struct { |
| 381 | 381 | } |
| 382 | 382 | break :blk value; |
| 383 | 383 | }; |
| 384 | try writeInt(value, elf_file, bw); | |
| 384 | try writeInt(value, elf_file, writer); | |
| 385 | 385 | }, |
| 386 | 386 | .tlsld => { |
| 387 | try writeInt(if (is_dyn_lib) @as(u64, 0) else 1, elf_file, bw); | |
| 388 | try writeInt(0, elf_file, bw); | |
| 387 | try writeInt(if (is_dyn_lib) @as(u64, 0) else 1, elf_file, writer); | |
| 388 | try writeInt(0, elf_file, writer); | |
| 389 | 389 | }, |
| 390 | 390 | .tlsgd => { |
| 391 | 391 | if (symbol.?.flags.import) { |
| 392 | try writeInt(0, elf_file, bw); | |
| 393 | try writeInt(0, elf_file, bw); | |
| 392 | try writeInt(0, elf_file, writer); | |
| 393 | try writeInt(0, elf_file, writer); | |
| 394 | 394 | } else { |
| 395 | try writeInt(if (is_dyn_lib) @as(u64, 0) else 1, elf_file, bw); | |
| 395 | try writeInt(if (is_dyn_lib) @as(u64, 0) else 1, elf_file, writer); | |
| 396 | 396 | const offset = symbol.?.address(.{}, elf_file) - elf_file.dtpAddress(); |
| 397 | try writeInt(offset, elf_file, bw); | |
| 397 | try writeInt(offset, elf_file, writer); | |
| 398 | 398 | } |
| 399 | 399 | }, |
| 400 | 400 | .gottp => { |
| 401 | 401 | if (symbol.?.flags.import) { |
| 402 | try writeInt(0, elf_file, bw); | |
| 402 | try writeInt(0, elf_file, writer); | |
| 403 | 403 | } else if (is_dyn_lib) { |
| 404 | 404 | const offset = if (apply_relocs) |
| 405 | 405 | symbol.?.address(.{}, elf_file) - elf_file.tlsAddress() |
| 406 | 406 | else |
| 407 | 407 | 0; |
| 408 | try writeInt(offset, elf_file, bw); | |
| 408 | try writeInt(offset, elf_file, writer); | |
| 409 | 409 | } else { |
| 410 | 410 | const offset = symbol.?.address(.{}, elf_file) - elf_file.tpAddress(); |
| 411 | try writeInt(offset, elf_file, bw); | |
| 411 | try writeInt(offset, elf_file, writer); | |
| 412 | 412 | } |
| 413 | 413 | }, |
| 414 | 414 | .tlsdesc => { |
| 415 | 415 | if (symbol.?.flags.import) { |
| 416 | try writeInt(0, elf_file, bw); | |
| 417 | try writeInt(0, elf_file, bw); | |
| 416 | try writeInt(0, elf_file, writer); | |
| 417 | try writeInt(0, elf_file, writer); | |
| 418 | 418 | } else { |
| 419 | try writeInt(0, elf_file, bw); | |
| 419 | try writeInt(0, elf_file, writer); | |
| 420 | 420 | const offset = if (apply_relocs) |
| 421 | 421 | symbol.?.address(.{}, elf_file) - elf_file.tlsAddress() |
| 422 | 422 | else |
| 423 | 423 | 0; |
| 424 | try writeInt(offset, elf_file, bw); | |
| 424 | try writeInt(offset, elf_file, writer); | |
| 425 | 425 | } |
| 426 | 426 | }, |
| 427 | 427 | } |
| ... | ... | @@ -671,11 +671,11 @@ pub const PltSection = struct { |
| 671 | 671 | }; |
| 672 | 672 | } |
| 673 | 673 | |
| 674 | pub fn write(plt: PltSection, elf_file: *Elf, bw: *Writer) Writer.Error!void { | |
| 674 | pub fn write(plt: PltSection, elf_file: *Elf, writer: *Writer) Writer.Error!void { | |
| 675 | 675 | const cpu_arch = elf_file.getTarget().cpu.arch; |
| 676 | 676 | switch (cpu_arch) { |
| 677 | .x86_64 => try x86_64.write(plt, elf_file, bw), | |
| 678 | .aarch64 => try aarch64.write(plt, elf_file, bw), | |
| 677 | .x86_64 => try x86_64.write(plt, elf_file, writer), | |
| 678 | .aarch64 => try aarch64.write(plt, elf_file, writer), | |
| 679 | 679 | else => return error.UnsupportedCpuArch, |
| 680 | 680 | } |
| 681 | 681 | } |
| ... | ... | @@ -768,7 +768,7 @@ pub const PltSection = struct { |
| 768 | 768 | } |
| 769 | 769 | |
| 770 | 770 | const x86_64 = struct { |
| 771 | fn write(plt: PltSection, elf_file: *Elf, bw: *Writer) Writer.Error!void { | |
| 771 | fn write(plt: PltSection, elf_file: *Elf, writer: *Writer) Writer.Error!void { | |
| 772 | 772 | const shdrs = elf_file.sections.items(.shdr); |
| 773 | 773 | const plt_addr = shdrs[elf_file.section_indexes.plt.?].sh_addr; |
| 774 | 774 | const got_plt_addr = shdrs[elf_file.section_indexes.got_plt.?].sh_addr; |
| ... | ... | @@ -782,8 +782,8 @@ pub const PltSection = struct { |
| 782 | 782 | mem.writeInt(i32, preamble[8..][0..4], @as(i32, @intCast(disp)), .little); |
| 783 | 783 | disp = @as(i64, @intCast(got_plt_addr + 16)) - @as(i64, @intCast(plt_addr + 14)) - 4; |
| 784 | 784 | mem.writeInt(i32, preamble[14..][0..4], @as(i32, @intCast(disp)), .little); |
| 785 | try bw.writeAll(&preamble); | |
| 786 | try bw.splatByteAll(0xcc, preambleSize(.x86_64) - preamble.len); | |
| 785 | try writer.writeAll(&preamble); | |
| 786 | try writer.splatByteAll(0xcc, preambleSize(.x86_64) - preamble.len); | |
| 787 | 787 | |
| 788 | 788 | for (plt.symbols.items, 0..) |ref, i| { |
| 789 | 789 | const sym = elf_file.symbol(ref).?; |
| ... | ... | @@ -797,67 +797,56 @@ pub const PltSection = struct { |
| 797 | 797 | }; |
| 798 | 798 | mem.writeInt(i32, entry[6..][0..4], @as(i32, @intCast(i)), .little); |
| 799 | 799 | mem.writeInt(i32, entry[12..][0..4], @as(i32, @intCast(disp)), .little); |
| 800 | try bw.writeAll(&entry); | |
| 800 | try writer.writeAll(&entry); | |
| 801 | 801 | } |
| 802 | 802 | } |
| 803 | 803 | }; |
| 804 | 804 | |
| 805 | 805 | const aarch64 = struct { |
| 806 | fn write(plt: PltSection, elf_file: *Elf, bw: *Writer) Writer.Error!void { | |
| 806 | fn write(plt: PltSection, elf_file: *Elf, writer: *Writer) Writer.Error!void { | |
| 807 | 807 | { |
| 808 | 808 | const shdrs = elf_file.sections.items(.shdr); |
| 809 | 809 | const plt_addr: i64 = @intCast(shdrs[elf_file.section_indexes.plt.?].sh_addr); |
| 810 | 810 | const got_plt_addr: i64 = @intCast(shdrs[elf_file.section_indexes.got_plt.?].sh_addr); |
| 811 | 811 | // TODO: relax if possible |
| 812 | 812 | // .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))); | |
| 815 | 815 | const add_off: u12 = @truncate(@as(u64, @bitCast(got_plt_addr + 16))); |
| 816 | 816 | |
| 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(), | |
| 831 | 826 | }; |
| 832 | 827 | comptime assert(preamble.len == 8); |
| 833 | for (preamble) |inst| { | |
| 834 | try bw.writeInt(u32, inst.toU32(), .little); | |
| 835 | } | |
| 828 | for (preamble) |inst| try writer.writeInt(util.encoding.Instruction.Backing, @bitCast(inst), .little); | |
| 836 | 829 | } |
| 837 | 830 | |
| 838 | 831 | for (plt.symbols.items) |ref| { |
| 839 | 832 | const sym = elf_file.symbol(ref).?; |
| 840 | 833 | const target_addr = sym.gotPltAddress(elf_file); |
| 841 | 834 | 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))); | |
| 844 | 837 | 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), | |
| 850 | 843 | }; |
| 851 | 844 | comptime assert(insts.len == 4); |
| 852 | for (insts) |inst| { | |
| 853 | try bw.writeInt(u32, inst.toU32(), .little); | |
| 854 | } | |
| 845 | for (insts) |inst| try writer.writeInt(util.encoding.Instruction.Backing, @bitCast(inst), .little); | |
| 855 | 846 | } |
| 856 | 847 | } |
| 857 | 848 | |
| 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"); | |
| 861 | 850 | }; |
| 862 | 851 | }; |
| 863 | 852 | |
| ... | ... | @@ -869,22 +858,22 @@ pub const GotPltSection = struct { |
| 869 | 858 | return preamble_size + elf_file.plt.symbols.items.len * 8; |
| 870 | 859 | } |
| 871 | 860 | |
| 872 | pub fn write(got_plt: GotPltSection, elf_file: *Elf, bw: *Writer) Writer.Error!void { | |
| 861 | pub fn write(got_plt: GotPltSection, elf_file: *Elf, writer: *Writer) Writer.Error!void { | |
| 873 | 862 | _ = got_plt; |
| 874 | 863 | { |
| 875 | 864 | // [0]: _DYNAMIC |
| 876 | 865 | const symbol = elf_file.linkerDefinedPtr().?.dynamicSymbol(elf_file).?; |
| 877 | try bw.writeInt(u64, @intCast(symbol.address(.{}, elf_file)), .little); | |
| 866 | try writer.writeInt(u64, @intCast(symbol.address(.{}, elf_file)), .little); | |
| 878 | 867 | } |
| 879 | 868 | // [1]: 0x0 |
| 880 | 869 | // [2]: 0x0 |
| 881 | try bw.writeInt(u64, 0x0, .little); | |
| 882 | try bw.writeInt(u64, 0x0, .little); | |
| 870 | try writer.writeInt(u64, 0x0, .little); | |
| 871 | try writer.writeInt(u64, 0x0, .little); | |
| 883 | 872 | if (elf_file.section_indexes.plt) |shndx| { |
| 884 | 873 | const plt_addr = elf_file.sections.items(.shdr)[shndx].sh_addr; |
| 885 | 874 | for (0..elf_file.plt.symbols.items.len) |_| { |
| 886 | 875 | // [N]: .plt |
| 887 | try bw.writeInt(u64, plt_addr, .little); | |
| 876 | try writer.writeInt(u64, plt_addr, .little); | |
| 888 | 877 | } |
| 889 | 878 | } |
| 890 | 879 | } |
| ... | ... | @@ -920,11 +909,11 @@ pub const PltGotSection = struct { |
| 920 | 909 | }; |
| 921 | 910 | } |
| 922 | 911 | |
| 923 | pub fn write(plt_got: PltGotSection, elf_file: *Elf, bw: *Writer) Writer.Error!void { | |
| 912 | pub fn write(plt_got: PltGotSection, elf_file: *Elf, writer: *Writer) Writer.Error!void { | |
| 924 | 913 | const cpu_arch = elf_file.getTarget().cpu.arch; |
| 925 | 914 | switch (cpu_arch) { |
| 926 | .x86_64 => try x86_64.write(plt_got, elf_file, bw), | |
| 927 | .aarch64 => try aarch64.write(plt_got, elf_file, bw), | |
| 915 | .x86_64 => try x86_64.write(plt_got, elf_file, writer), | |
| 916 | .aarch64 => try aarch64.write(plt_got, elf_file, writer), | |
| 928 | 917 | else => return error.UnsupportedCpuArch, |
| 929 | 918 | } |
| 930 | 919 | } |
| ... | ... | @@ -956,7 +945,7 @@ pub const PltGotSection = struct { |
| 956 | 945 | } |
| 957 | 946 | |
| 958 | 947 | const x86_64 = struct { |
| 959 | pub fn write(plt_got: PltGotSection, elf_file: *Elf, bw: *Writer) Writer.Error!void { | |
| 948 | pub fn write(plt_got: PltGotSection, elf_file: *Elf, writer: *Writer) Writer.Error!void { | |
| 960 | 949 | for (plt_got.symbols.items) |ref| { |
| 961 | 950 | const sym = elf_file.symbol(ref).?; |
| 962 | 951 | const target_addr = sym.gotAddress(elf_file); |
| ... | ... | @@ -968,35 +957,31 @@ pub const PltGotSection = struct { |
| 968 | 957 | 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, |
| 969 | 958 | }; |
| 970 | 959 | mem.writeInt(i32, entry[6..][0..4], @as(i32, @intCast(disp)), .little); |
| 971 | try bw.writeAll(&entry); | |
| 960 | try writer.writeAll(&entry); | |
| 972 | 961 | } |
| 973 | 962 | } |
| 974 | 963 | }; |
| 975 | 964 | |
| 976 | 965 | const aarch64 = struct { |
| 977 | fn write(plt_got: PltGotSection, elf_file: *Elf, bw: *Writer) Writer.Error!void { | |
| 966 | fn write(plt_got: PltGotSection, elf_file: *Elf, writer: *Writer) Writer.Error!void { | |
| 978 | 967 | for (plt_got.symbols.items) |ref| { |
| 979 | 968 | const sym = elf_file.symbol(ref).?; |
| 980 | 969 | const target_addr = sym.gotAddress(elf_file); |
| 981 | 970 | 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(), | |
| 989 | 978 | }; |
| 990 | 979 | comptime assert(insts.len == 4); |
| 991 | for (insts) |inst| { | |
| 992 | try bw.writeInt(u32, inst.toU32(), .little); | |
| 993 | } | |
| 980 | for (insts) |inst| try writer.writeInt(util.encoding.Instruction.Backing, @bitCast(inst), .little); | |
| 994 | 981 | } |
| 995 | 982 | } |
| 996 | 983 | |
| 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"); | |
| 1000 | 985 | }; |
| 1001 | 986 | }; |
| 1002 | 987 | |
| ... | ... | @@ -1153,14 +1138,14 @@ pub const DynsymSection = struct { |
| 1153 | 1138 | return @as(u32, @intCast(dynsym.entries.items.len + 1)); |
| 1154 | 1139 | } |
| 1155 | 1140 | |
| 1156 | pub fn write(dynsym: DynsymSection, elf_file: *Elf, bw: *Writer) Writer.Error!void { | |
| 1157 | try bw.writeStruct(Elf.null_sym); | |
| 1141 | pub fn write(dynsym: DynsymSection, elf_file: *Elf, writer: *Writer) Writer.Error!void { | |
| 1142 | try writer.writeStruct(Elf.null_sym); | |
| 1158 | 1143 | for (dynsym.entries.items) |entry| { |
| 1159 | 1144 | const sym = elf_file.symbol(entry.ref).?; |
| 1160 | 1145 | var out_sym: elf.Elf64_Sym = Elf.null_sym; |
| 1161 | 1146 | sym.setOutputSym(elf_file, &out_sym); |
| 1162 | 1147 | out_sym.st_name = entry.off; |
| 1163 | try bw.writeStruct(out_sym); | |
| 1148 | try writer.writeStruct(out_sym); | |
| 1164 | 1149 | } |
| 1165 | 1150 | } |
| 1166 | 1151 | }; |
| ... | ... | @@ -1456,9 +1441,9 @@ pub const VerneedSection = struct { |
| 1456 | 1441 | return vern.verneed.items.len * @sizeOf(elf.Elf64_Verneed) + vern.vernaux.items.len * @sizeOf(elf.Vernaux); |
| 1457 | 1442 | } |
| 1458 | 1443 | |
| 1459 | pub fn write(vern: VerneedSection, bw: *Writer) Writer.Error!void { | |
| 1460 | try bw.writeAll(mem.sliceAsBytes(vern.verneed.items)); | |
| 1461 | try bw.writeAll(mem.sliceAsBytes(vern.vernaux.items)); | |
| 1444 | pub fn write(vern: VerneedSection, writer: *Writer) Writer.Error!void { | |
| 1445 | try writer.writeAll(mem.sliceAsBytes(vern.verneed.items)); | |
| 1446 | try writer.writeAll(mem.sliceAsBytes(vern.vernaux.items)); | |
| 1462 | 1447 | } |
| 1463 | 1448 | }; |
| 1464 | 1449 | |
| ... | ... | @@ -1484,11 +1469,11 @@ pub const GroupSection = struct { |
| 1484 | 1469 | return (members.len + 1) * @sizeOf(u32); |
| 1485 | 1470 | } |
| 1486 | 1471 | |
| 1487 | pub fn write(cgs: GroupSection, elf_file: *Elf, bw: *Writer) Writer.Error!void { | |
| 1472 | pub fn write(cgs: GroupSection, elf_file: *Elf, writer: *Writer) Writer.Error!void { | |
| 1488 | 1473 | const cg = cgs.comdatGroup(elf_file); |
| 1489 | 1474 | const object = cg.file(elf_file).object; |
| 1490 | 1475 | const members = cg.members(elf_file); |
| 1491 | try bw.writeInt(u32, if (cg.is_comdat) elf.GRP_COMDAT else 0, .little); | |
| 1476 | try writer.writeInt(u32, if (cg.is_comdat) elf.GRP_COMDAT else 0, .little); | |
| 1492 | 1477 | for (members) |shndx| { |
| 1493 | 1478 | const shdr = object.shdrs.items[shndx]; |
| 1494 | 1479 | switch (shdr.sh_type) { |
| ... | ... | @@ -1500,26 +1485,26 @@ pub const GroupSection = struct { |
| 1500 | 1485 | atom.output_section_index == rela_shdr.sh_info) |
| 1501 | 1486 | break rela_shndx; |
| 1502 | 1487 | } else unreachable; |
| 1503 | try bw.writeInt(u32, @intCast(rela_shndx), .little); | |
| 1488 | try writer.writeInt(u32, @intCast(rela_shndx), .little); | |
| 1504 | 1489 | }, |
| 1505 | 1490 | else => { |
| 1506 | 1491 | const atom_index = object.atoms_indexes.items[shndx]; |
| 1507 | 1492 | const atom = object.atom(atom_index).?; |
| 1508 | try bw.writeInt(u32, atom.output_section_index, .little); | |
| 1493 | try writer.writeInt(u32, atom.output_section_index, .little); | |
| 1509 | 1494 | }, |
| 1510 | 1495 | } |
| 1511 | 1496 | } |
| 1512 | 1497 | } |
| 1513 | 1498 | }; |
| 1514 | 1499 | |
| 1515 | fn writeInt(value: anytype, elf_file: *Elf, bw: *Writer) Writer.Error!void { | |
| 1500 | fn writeInt(value: anytype, elf_file: *Elf, writer: *Writer) Writer.Error!void { | |
| 1516 | 1501 | const entry_size = elf_file.archPtrWidthBytes(); |
| 1517 | 1502 | const target = elf_file.getTarget(); |
| 1518 | 1503 | const endian = target.cpu.arch.endian(); |
| 1519 | 1504 | switch (entry_size) { |
| 1520 | 2 => try bw.writeInt(u16, @intCast(value), endian), | |
| 1521 | 4 => try bw.writeInt(u32, @intCast(value), endian), | |
| 1522 | 8 => try bw.writeInt(u64, @intCast(value), endian), | |
| 1505 | 2 => try writer.writeInt(u16, @intCast(value), endian), | |
| 1506 | 4 => try writer.writeInt(u32, @intCast(value), endian), | |
| 1507 | 8 => try writer.writeInt(u64, @intCast(value), endian), | |
| 1523 | 1508 | else => unreachable, |
| 1524 | 1509 | } |
| 1525 | 1510 | } |
src/link/MachO.zig+2-1| ... | ... | @@ -328,6 +328,7 @@ pub fn deinit(self: *MachO) void { |
| 328 | 328 | self.unwind_info.deinit(gpa); |
| 329 | 329 | self.data_in_code.deinit(gpa); |
| 330 | 330 | |
| 331 | for (self.thunks.items) |*thunk| thunk.deinit(gpa); | |
| 331 | 332 | self.thunks.deinit(gpa); |
| 332 | 333 | } |
| 333 | 334 | |
| ... | ... | @@ -5374,7 +5375,7 @@ const mem = std.mem; |
| 5374 | 5375 | const meta = std.meta; |
| 5375 | 5376 | const Writer = std.io.Writer; |
| 5376 | 5377 | |
| 5377 | const aarch64 = @import("../arch/aarch64/bits.zig"); | |
| 5378 | const aarch64 = codegen.aarch64.encoding; | |
| 5378 | 5379 | const bind = @import("MachO/dyld_info/bind.zig"); |
| 5379 | 5380 | const calcUuid = @import("MachO/uuid.zig").calcUuid; |
| 5380 | 5381 | const codegen = @import("../codegen.zig"); |
src/link/MachO/Atom.zig+43-85| ... | ... | @@ -580,7 +580,7 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { |
| 580 | 580 | |
| 581 | 581 | relocs_log.debug("{x}: {s}", .{ self.value, name }); |
| 582 | 582 | |
| 583 | var bw: Writer = .fixed(buffer); | |
| 583 | var writer: Writer = .fixed(buffer); | |
| 584 | 584 | |
| 585 | 585 | var has_error = false; |
| 586 | 586 | var i: usize = 0; |
| ... | ... | @@ -593,8 +593,8 @@ pub fn resolveRelocs(self: Atom, macho_file: *MachO, buffer: []u8) !void { |
| 593 | 593 | if (rel.getTargetSymbol(self, macho_file).getFile(macho_file) == null) continue; |
| 594 | 594 | } |
| 595 | 595 | |
| 596 | bw.end = std.math.cast(usize, rel_offset) orelse return error.Overflow; | |
| 597 | self.resolveRelocInner(rel, subtractor, buffer, macho_file, &bw) catch |err| switch (err) { | |
| 596 | writer.end = std.math.cast(usize, rel_offset) orelse return error.Overflow; | |
| 597 | self.resolveRelocInner(rel, subtractor, buffer, macho_file, &writer) catch |err| switch (err) { | |
| 598 | 598 | error.RelaxFail => { |
| 599 | 599 | const target = switch (rel.tag) { |
| 600 | 600 | .@"extern" => rel.getTargetSymbol(self, macho_file).getName(macho_file), |
| ... | ... | @@ -637,7 +637,7 @@ fn resolveRelocInner( |
| 637 | 637 | subtractor: ?Relocation, |
| 638 | 638 | code: []u8, |
| 639 | 639 | macho_file: *MachO, |
| 640 | bw: *Writer, | |
| 640 | writer: *Writer, | |
| 641 | 641 | ) Writer.Error!void { |
| 642 | 642 | const t = &macho_file.base.comp.root_mod.resolved_target.result; |
| 643 | 643 | const cpu_arch = t.cpu.arch; |
| ... | ... | @@ -689,14 +689,14 @@ fn resolveRelocInner( |
| 689 | 689 | if (rel.tag == .@"extern") { |
| 690 | 690 | const sym = rel.getTargetSymbol(self, macho_file); |
| 691 | 691 | if (sym.isTlvInit(macho_file)) { |
| 692 | try bw.writeInt(u64, @intCast(S - TLS), .little); | |
| 692 | try writer.writeInt(u64, @intCast(S - TLS), .little); | |
| 693 | 693 | return; |
| 694 | 694 | } |
| 695 | 695 | if (sym.flags.import) return; |
| 696 | 696 | } |
| 697 | try bw.writeInt(u64, @bitCast(S + A - SUB), .little); | |
| 697 | try writer.writeInt(u64, @bitCast(S + A - SUB), .little); | |
| 698 | 698 | } else if (rel.meta.length == 2) { |
| 699 | try bw.writeInt(u32, @bitCast(@as(i32, @truncate(S + A - SUB))), .little); | |
| 699 | try writer.writeInt(u32, @bitCast(@as(i32, @truncate(S + A - SUB))), .little); | |
| 700 | 700 | } else unreachable; |
| 701 | 701 | }, |
| 702 | 702 | |
| ... | ... | @@ -704,7 +704,7 @@ fn resolveRelocInner( |
| 704 | 704 | assert(rel.tag == .@"extern"); |
| 705 | 705 | assert(rel.meta.length == 2); |
| 706 | 706 | assert(rel.meta.pcrel); |
| 707 | try bw.writeInt(i32, @intCast(G + A - P), .little); | |
| 707 | try writer.writeInt(i32, @intCast(G + A - P), .little); | |
| 708 | 708 | }, |
| 709 | 709 | |
| 710 | 710 | .branch => { |
| ... | ... | @@ -713,7 +713,7 @@ fn resolveRelocInner( |
| 713 | 713 | assert(rel.tag == .@"extern"); |
| 714 | 714 | |
| 715 | 715 | switch (cpu_arch) { |
| 716 | .x86_64 => try bw.writeInt(i32, @intCast(S + A - P), .little), | |
| 716 | .x86_64 => try writer.writeInt(i32, @intCast(S + A - P), .little), | |
| 717 | 717 | .aarch64 => { |
| 718 | 718 | const disp: i28 = math.cast(i28, S + A - P) orelse blk: { |
| 719 | 719 | const thunk = self.getThunk(macho_file); |
| ... | ... | @@ -731,10 +731,10 @@ fn resolveRelocInner( |
| 731 | 731 | assert(rel.meta.length == 2); |
| 732 | 732 | assert(rel.meta.pcrel); |
| 733 | 733 | if (rel.getTargetSymbol(self, macho_file).getSectionFlags().has_got) { |
| 734 | try bw.writeInt(i32, @intCast(G + A - P), .little); | |
| 734 | try writer.writeInt(i32, @intCast(G + A - P), .little); | |
| 735 | 735 | } else { |
| 736 | 736 | try x86_64.relaxGotLoad(self, code[rel_offset - 3 ..], rel, macho_file); |
| 737 | try bw.writeInt(i32, @intCast(S + A - P), .little); | |
| 737 | try writer.writeInt(i32, @intCast(S + A - P), .little); | |
| 738 | 738 | } |
| 739 | 739 | }, |
| 740 | 740 | |
| ... | ... | @@ -745,17 +745,17 @@ fn resolveRelocInner( |
| 745 | 745 | const sym = rel.getTargetSymbol(self, macho_file); |
| 746 | 746 | if (sym.getSectionFlags().tlv_ptr) { |
| 747 | 747 | const S_: i64 = @intCast(sym.getTlvPtrAddress(macho_file)); |
| 748 | try bw.writeInt(i32, @intCast(S_ + A - P), .little); | |
| 748 | try writer.writeInt(i32, @intCast(S_ + A - P), .little); | |
| 749 | 749 | } else { |
| 750 | 750 | try x86_64.relaxTlv(code[rel_offset - 3 ..], t); |
| 751 | try bw.writeInt(i32, @intCast(S + A - P), .little); | |
| 751 | try writer.writeInt(i32, @intCast(S + A - P), .little); | |
| 752 | 752 | } |
| 753 | 753 | }, |
| 754 | 754 | |
| 755 | 755 | .signed, .signed1, .signed2, .signed4 => { |
| 756 | 756 | assert(rel.meta.length == 2); |
| 757 | 757 | assert(rel.meta.pcrel); |
| 758 | try bw.writeInt(i32, @intCast(S + A - P), .little); | |
| 758 | try writer.writeInt(i32, @intCast(S + A - P), .little); | |
| 759 | 759 | }, |
| 760 | 760 | |
| 761 | 761 | .page, |
| ... | ... | @@ -779,8 +779,7 @@ fn resolveRelocInner( |
| 779 | 779 | }; |
| 780 | 780 | break :target math.cast(u64, target) orelse return error.Overflow; |
| 781 | 781 | }; |
| 782 | const pages = @as(u21, @bitCast(try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)))); | |
| 783 | aarch64.writeAdrpInst(pages, code[rel_offset..][0..4]); | |
| 782 | aarch64.writeAdrInst(try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)), code[rel_offset..][0..aarch64.encoding.Instruction.size]); | |
| 784 | 783 | }, |
| 785 | 784 | |
| 786 | 785 | .pageoff => { |
| ... | ... | @@ -788,26 +787,18 @@ fn resolveRelocInner( |
| 788 | 787 | assert(rel.meta.length == 2); |
| 789 | 788 | assert(!rel.meta.pcrel); |
| 790 | 789 | const target = math.cast(u64, S + A) orelse return error.Overflow; |
| 791 | const inst_code = code[rel_offset..][0..4]; | |
| 792 | if (aarch64.isArithmeticOp(inst_code)) { | |
| 793 | aarch64.writeAddImmInst(@truncate(target), inst_code); | |
| 794 | } else { | |
| 795 | var inst = aarch64.Instruction{ | |
| 796 | .load_store_register = mem.bytesToValue(@FieldType( | |
| 797 | aarch64.Instruction, | |
| 798 | @tagName(aarch64.Instruction.load_store_register), | |
| 799 | ), inst_code), | |
| 800 | }; | |
| 801 | inst.load_store_register.offset = switch (inst.load_store_register.size) { | |
| 802 | 0 => if (inst.load_store_register.v == 1) | |
| 803 | try divExact(self, rel, @truncate(target), 16, macho_file) | |
| 804 | else | |
| 805 | @truncate(target), | |
| 806 | 1 => try divExact(self, rel, @truncate(target), 2, macho_file), | |
| 807 | 2 => try divExact(self, rel, @truncate(target), 4, macho_file), | |
| 808 | 3 => try divExact(self, rel, @truncate(target), 8, macho_file), | |
| 809 | }; | |
| 810 | try bw.writeInt(u32, inst.toU32(), .little); | |
| 790 | const inst_code = code[rel_offset..][0..aarch64.encoding.Instruction.size]; | |
| 791 | var inst: aarch64.encoding.Instruction = .read(inst_code); | |
| 792 | switch (inst.decode()) { | |
| 793 | else => unreachable, | |
| 794 | .data_processing_immediate => aarch64.writeAddImmInst(@truncate(target), inst_code), | |
| 795 | .load_store => |load_store| { | |
| 796 | inst.load_store.register_unsigned_immediate.group.imm12 = switch (load_store.register_unsigned_immediate.decode()) { | |
| 797 | .integer => |integer| try divExact(self, rel, @truncate(target), @as(u4, 1) << @intFromEnum(integer.group.size), macho_file), | |
| 798 | .vector => |vector| try divExact(self, rel, @truncate(target), @as(u5, 1) << @intFromEnum(vector.group.opc1.decode(vector.group.size)), macho_file), | |
| 799 | }; | |
| 800 | try writer.writeInt(u32, @bitCast(inst), .little); | |
| 801 | }, | |
| 811 | 802 | } |
| 812 | 803 | }, |
| 813 | 804 | |
| ... | ... | @@ -833,59 +824,26 @@ fn resolveRelocInner( |
| 833 | 824 | break :target math.cast(u64, target) orelse return error.Overflow; |
| 834 | 825 | }; |
| 835 | 826 | |
| 836 | const RegInfo = struct { | |
| 837 | rd: u5, | |
| 838 | rn: u5, | |
| 839 | size: u2, | |
| 840 | }; | |
| 841 | ||
| 842 | 827 | const inst_code = code[rel_offset..][0..4]; |
| 843 | const reg_info: RegInfo = blk: { | |
| 844 | if (aarch64.isArithmeticOp(inst_code)) { | |
| 845 | const inst = mem.bytesToValue(@FieldType( | |
| 846 | aarch64.Instruction, | |
| 847 | @tagName(aarch64.Instruction.add_subtract_immediate), | |
| 848 | ), inst_code); | |
| 849 | break :blk .{ | |
| 850 | .rd = inst.rd, | |
| 851 | .rn = inst.rn, | |
| 852 | .size = inst.sf, | |
| 853 | }; | |
| 854 | } else { | |
| 855 | const inst = mem.bytesToValue(@FieldType( | |
| 856 | aarch64.Instruction, | |
| 857 | @tagName(aarch64.Instruction.load_store_register), | |
| 858 | ), inst_code); | |
| 859 | break :blk .{ | |
| 860 | .rd = inst.rt, | |
| 861 | .rn = inst.rn, | |
| 862 | .size = inst.size, | |
| 863 | }; | |
| 864 | } | |
| 865 | }; | |
| 866 | ||
| 867 | var inst = if (sym.getSectionFlags().tlv_ptr) aarch64.Instruction{ | |
| 868 | .load_store_register = .{ | |
| 869 | .rt = reg_info.rd, | |
| 870 | .rn = reg_info.rn, | |
| 871 | .offset = try divExact(self, rel, @truncate(target), 8, macho_file), | |
| 872 | .opc = 0b01, | |
| 873 | .op1 = 0b01, | |
| 874 | .v = 0, | |
| 875 | .size = reg_info.size, | |
| 828 | const rd, const rn = switch (aarch64.encoding.Instruction.read(inst_code).decode()) { | |
| 829 | else => unreachable, | |
| 830 | .data_processing_immediate => |decoded| .{ | |
| 831 | decoded.add_subtract_immediate.group.Rd.decodeInteger(.doubleword, .{ .sp = true }), | |
| 832 | decoded.add_subtract_immediate.group.Rn.decodeInteger(.doubleword, .{ .sp = true }), | |
| 876 | 833 | }, |
| 877 | } else aarch64.Instruction{ | |
| 878 | .add_subtract_immediate = .{ | |
| 879 | .rd = reg_info.rd, | |
| 880 | .rn = reg_info.rn, | |
| 881 | .imm12 = @truncate(target), | |
| 882 | .sh = 0, | |
| 883 | .s = 0, | |
| 884 | .op = 0, | |
| 885 | .sf = @as(u1, @truncate(reg_info.size)), | |
| 834 | .load_store => |decoded| .{ | |
| 835 | decoded.register_unsigned_immediate.integer.group.Rt.decodeInteger(.doubleword, .{}), | |
| 836 | decoded.register_unsigned_immediate.group.Rn.decodeInteger(.doubleword, .{ .sp = true }), | |
| 886 | 837 | }, |
| 887 | 838 | }; |
| 888 | try bw.writeInt(u32, inst.toU32(), .little); | |
| 839 | ||
| 840 | try writer.writeInt(u32, @bitCast(@as( | |
| 841 | aarch64.encoding.Instruction, | |
| 842 | if (sym.getSectionFlags().tlv_ptr) .ldr(rd, .{ .unsigned_offset = .{ | |
| 843 | .base = rn, | |
| 844 | .offset = try divExact(self, rel, @truncate(target), 8, macho_file) * 8, | |
| 845 | } }) else .add(rd, rn, .{ .immediate = @truncate(target) }), | |
| 846 | )), .little); | |
| 889 | 847 | }, |
| 890 | 848 | } |
| 891 | 849 | } |
src/link/MachO/Thunk.zig+7-5| ... | ... | @@ -20,16 +20,18 @@ pub fn getTargetAddress(thunk: Thunk, ref: MachO.Ref, macho_file: *MachO) u64 { |
| 20 | 20 | return thunk.getAddress(macho_file) + thunk.symbols.getIndex(ref).? * trampoline_size; |
| 21 | 21 | } |
| 22 | 22 | |
| 23 | pub fn write(thunk: Thunk, macho_file: *MachO, bw: *Writer) !void { | |
| 23 | pub fn write(thunk: Thunk, macho_file: *MachO, writer: *Writer) !void { | |
| 24 | const Instruction = aarch64.encoding.Instruction; | |
| 24 | 25 | for (thunk.symbols.keys(), 0..) |ref, i| { |
| 25 | 26 | const sym = ref.getSymbol(macho_file).?; |
| 26 | 27 | const saddr = thunk.getAddress(macho_file) + i * trampoline_size; |
| 27 | 28 | const taddr = sym.getAddress(.{}, macho_file); |
| 28 | 29 | const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr)); |
| 29 | try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); | |
| 30 | const off: u12 = @truncate(taddr); | |
| 31 | try bw.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little); | |
| 32 | try bw.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); | |
| 33 | 35 | } |
| 34 | 36 | } |
| 35 | 37 |
src/link/MachO/ZigObject.zig+7-3| ... | ... | @@ -943,9 +943,13 @@ fn updateNavCode( |
| 943 | 943 | |
| 944 | 944 | log.debug("updateNavCode {f} 0x{x}", .{ nav.fqn.fmt(ip), nav_index }); |
| 945 | 945 | |
| 946 | const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result; | |
| 947 | const required_alignment = switch (pt.navAlignment(nav_index)) { | |
| 948 | .none => target_util.defaultFunctionAlignment(target), | |
| 946 | const mod = zcu.navFileScope(nav_index).mod.?; | |
| 947 | const target = &mod.resolved_target.result; | |
| 948 | const required_alignment = switch (nav.status.fully_resolved.alignment) { | |
| 949 | .none => switch (mod.optimize_mode) { | |
| 950 | .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target), | |
| 951 | .ReleaseSmall => target_util.minFunctionAlignment(target), | |
| 952 | }, | |
| 949 | 953 | else => |a| a.maxStrict(target_util.minFunctionAlignment(target)), |
| 950 | 954 | }; |
| 951 | 955 |
src/link/MachO/synthetic.zig+77-86| ... | ... | @@ -27,13 +27,13 @@ pub const GotSection = struct { |
| 27 | 27 | return got.symbols.items.len * @sizeOf(u64); |
| 28 | 28 | } |
| 29 | 29 | |
| 30 | pub fn write(got: GotSection, macho_file: *MachO, bw: *Writer) !void { | |
| 30 | pub fn write(got: GotSection, macho_file: *MachO, writer: *Writer) !void { | |
| 31 | 31 | const tracy = trace(@src()); |
| 32 | 32 | defer tracy.end(); |
| 33 | 33 | for (got.symbols.items) |ref| { |
| 34 | 34 | const sym = ref.getSymbol(macho_file).?; |
| 35 | 35 | const value = if (sym.flags.import) @as(u64, 0) else sym.getAddress(.{}, macho_file); |
| 36 | try bw.writeInt(u64, value, .little); | |
| 36 | try writer.writeInt(u64, value, .little); | |
| 37 | 37 | } |
| 38 | 38 | } |
| 39 | 39 | |
| ... | ... | @@ -89,7 +89,7 @@ pub const StubsSection = struct { |
| 89 | 89 | return stubs.symbols.items.len * header.reserved2; |
| 90 | 90 | } |
| 91 | 91 | |
| 92 | pub fn write(stubs: StubsSection, macho_file: *MachO, bw: *Writer) !void { | |
| 92 | pub fn write(stubs: StubsSection, macho_file: *MachO, writer: *Writer) !void { | |
| 93 | 93 | const tracy = trace(@src()); |
| 94 | 94 | defer tracy.end(); |
| 95 | 95 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| ... | ... | @@ -101,20 +101,19 @@ pub const StubsSection = struct { |
| 101 | 101 | const target = laptr_sect.addr + idx * @sizeOf(u64); |
| 102 | 102 | switch (cpu_arch) { |
| 103 | 103 | .x86_64 => { |
| 104 | try bw.writeAll(&.{ 0xff, 0x25 }); | |
| 105 | try bw.writeInt(i32, @intCast(target - source - 2 - 4), .little); | |
| 104 | try writer.writeAll(&.{ 0xff, 0x25 }); | |
| 105 | try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little); | |
| 106 | 106 | }, |
| 107 | 107 | .aarch64 => { |
| 108 | const Instruction = aarch64.encoding.Instruction; | |
| 108 | 109 | // TODO relax if possible |
| 109 | 110 | const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)); |
| 110 | try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); | |
| 111 | const off = try math.divExact(u12, @truncate(target), 8); | |
| 112 | try bw.writeInt( | |
| 113 | u32, | |
| 114 | aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(), | |
| 115 | .little, | |
| 116 | ); | |
| 117 | try bw.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); | |
| 118 | 117 | }, |
| 119 | 118 | else => unreachable, |
| 120 | 119 | } |
| ... | ... | @@ -175,11 +174,11 @@ pub const StubsHelperSection = struct { |
| 175 | 174 | return s; |
| 176 | 175 | } |
| 177 | 176 | |
| 178 | pub fn write(stubs_helper: StubsHelperSection, macho_file: *MachO, bw: *Writer) !void { | |
| 177 | pub fn write(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: *Writer) !void { | |
| 179 | 178 | const tracy = trace(@src()); |
| 180 | 179 | defer tracy.end(); |
| 181 | 180 | |
| 182 | try stubs_helper.writePreamble(macho_file, bw); | |
| 181 | try stubs_helper.writePreamble(macho_file, writer); | |
| 183 | 182 | |
| 184 | 183 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| 185 | 184 | const sect = macho_file.sections.items(.header)[macho_file.stubs_helper_sect_index.?]; |
| ... | ... | @@ -195,24 +194,22 @@ pub const StubsHelperSection = struct { |
| 195 | 194 | const target: i64 = @intCast(sect.addr); |
| 196 | 195 | switch (cpu_arch) { |
| 197 | 196 | .x86_64 => { |
| 198 | try bw.writeByte(0x68); | |
| 199 | try bw.writeInt(u32, offset, .little); | |
| 200 | try bw.writeByte(0xe9); | |
| 201 | try bw.writeInt(i32, @intCast(target - source - 6 - 4), .little); | |
| 197 | try writer.writeByte(0x68); | |
| 198 | try writer.writeInt(u32, offset, .little); | |
| 199 | try writer.writeByte(0xe9); | |
| 200 | try writer.writeInt(i32, @intCast(target - source - 6 - 4), .little); | |
| 202 | 201 | }, |
| 203 | 202 | .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 bw.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); | |
| 212 | 209 | const disp = math.cast(i28, @as(i64, @intCast(target)) - @as(i64, @intCast(source + 4))) orelse |
| 213 | 210 | return error.Overflow; |
| 214 | try bw.writeInt(u32, aarch64.Instruction.b(disp).toU32(), .little); | |
| 215 | try bw.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); | |
| 216 | 213 | }, |
| 217 | 214 | else => unreachable, |
| 218 | 215 | } |
| ... | ... | @@ -220,7 +217,7 @@ pub const StubsHelperSection = struct { |
| 220 | 217 | } |
| 221 | 218 | } |
| 222 | 219 | |
| 223 | fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, bw: *Writer) !void { | |
| 220 | fn writePreamble(stubs_helper: StubsHelperSection, macho_file: *MachO, writer: *Writer) !void { | |
| 224 | 221 | _ = stubs_helper; |
| 225 | 222 | const obj = macho_file.getInternalObject().?; |
| 226 | 223 | const cpu_arch = macho_file.getTarget().cpu.arch; |
| ... | ... | @@ -235,38 +232,35 @@ pub const StubsHelperSection = struct { |
| 235 | 232 | }; |
| 236 | 233 | switch (cpu_arch) { |
| 237 | 234 | .x86_64 => { |
| 238 | try bw.writeAll(&.{ 0x4c, 0x8d, 0x1d }); | |
| 239 | try bw.writeInt(i32, @intCast(dyld_private_addr - sect.addr - 3 - 4), .little); | |
| 240 | try bw.writeAll(&.{ 0x41, 0x53, 0xff, 0x25 }); | |
| 241 | try bw.writeInt(i32, @intCast(dyld_stub_binder_addr - sect.addr - 11 - 4), .little); | |
| 242 | try bw.writeByte(0x90); | |
| 235 | try writer.writeAll(&.{ 0x4c, 0x8d, 0x1d }); | |
| 236 | try writer.writeInt(i32, @intCast(dyld_private_addr - sect.addr - 3 - 4), .little); | |
| 237 | try writer.writeAll(&.{ 0x41, 0x53, 0xff, 0x25 }); | |
| 238 | try writer.writeInt(i32, @intCast(dyld_stub_binder_addr - sect.addr - 11 - 4), .little); | |
| 239 | try writer.writeByte(0x90); | |
| 243 | 240 | }, |
| 244 | 241 | .aarch64 => { |
| 242 | const Instruction = aarch64.encoding.Instruction; | |
| 245 | 243 | { |
| 246 | 244 | // TODO relax if possible |
| 247 | 245 | const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr), @intCast(dyld_private_addr)); |
| 248 | try bw.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little); | |
| 249 | const off: u12 = @truncate(dyld_private_addr); | |
| 250 | try bw.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); | |
| 251 | 250 | } |
| 252 | try bw.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); | |
| 258 | 254 | { |
| 259 | 255 | // TODO relax if possible |
| 260 | 256 | const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr + 12), @intCast(dyld_stub_binder_addr)); |
| 261 | try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); | |
| 262 | const off = try math.divExact(u12, @truncate(dyld_stub_binder_addr), 8); | |
| 263 | try bw.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( | |
| 265 | 259 | .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); | |
| 268 | 262 | } |
| 269 | try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little); | |
| 263 | try writer.writeInt(Instruction.Backing, @bitCast(Instruction.br(.x16)), .little); | |
| 270 | 264 | }, |
| 271 | 265 | else => unreachable, |
| 272 | 266 | } |
| ... | ... | @@ -279,7 +273,7 @@ pub const LaSymbolPtrSection = struct { |
| 279 | 273 | return macho_file.stubs.symbols.items.len * @sizeOf(u64); |
| 280 | 274 | } |
| 281 | 275 | |
| 282 | pub fn write(laptr: LaSymbolPtrSection, macho_file: *MachO, bw: *Writer) !void { | |
| 276 | pub fn write(laptr: LaSymbolPtrSection, macho_file: *MachO, writer: *Writer) !void { | |
| 283 | 277 | const tracy = trace(@src()); |
| 284 | 278 | defer tracy.end(); |
| 285 | 279 | _ = laptr; |
| ... | ... | @@ -290,12 +284,12 @@ pub const LaSymbolPtrSection = struct { |
| 290 | 284 | const sym = ref.getSymbol(macho_file).?; |
| 291 | 285 | if (sym.flags.weak) { |
| 292 | 286 | const value = sym.getAddress(.{ .stubs = false }, macho_file); |
| 293 | try bw.writeInt(u64, @intCast(value), .little); | |
| 287 | try writer.writeInt(u64, @intCast(value), .little); | |
| 294 | 288 | } else { |
| 295 | 289 | const value = sect.addr + StubsHelperSection.preambleSize(cpu_arch) + |
| 296 | 290 | StubsHelperSection.entrySize(cpu_arch) * stub_helper_idx; |
| 297 | 291 | stub_helper_idx += 1; |
| 298 | try bw.writeInt(u64, @intCast(value), .little); | |
| 292 | try writer.writeInt(u64, @intCast(value), .little); | |
| 299 | 293 | } |
| 300 | 294 | } |
| 301 | 295 | } |
| ... | ... | @@ -329,16 +323,16 @@ pub const TlvPtrSection = struct { |
| 329 | 323 | return tlv.symbols.items.len * @sizeOf(u64); |
| 330 | 324 | } |
| 331 | 325 | |
| 332 | pub fn write(tlv: TlvPtrSection, macho_file: *MachO, bw: *Writer) !void { | |
| 326 | pub fn write(tlv: TlvPtrSection, macho_file: *MachO, writer: *Writer) !void { | |
| 333 | 327 | const tracy = trace(@src()); |
| 334 | 328 | defer tracy.end(); |
| 335 | 329 | |
| 336 | 330 | for (tlv.symbols.items) |ref| { |
| 337 | 331 | const sym = ref.getSymbol(macho_file).?; |
| 338 | 332 | if (sym.flags.import) { |
| 339 | try bw.writeInt(u64, 0, .little); | |
| 333 | try writer.writeInt(u64, 0, .little); | |
| 340 | 334 | } else { |
| 341 | try bw.writeInt(u64, sym.getAddress(.{}, macho_file), .little); | |
| 335 | try writer.writeInt(u64, sym.getAddress(.{}, macho_file), .little); | |
| 342 | 336 | } |
| 343 | 337 | } |
| 344 | 338 | } |
| ... | ... | @@ -400,7 +394,7 @@ pub const ObjcStubsSection = struct { |
| 400 | 394 | return objc.symbols.items.len * entrySize(macho_file.getTarget().cpu.arch); |
| 401 | 395 | } |
| 402 | 396 | |
| 403 | pub fn write(objc: ObjcStubsSection, macho_file: *MachO, bw: *Writer) !void { | |
| 397 | pub fn write(objc: ObjcStubsSection, macho_file: *MachO, writer: *Writer) !void { | |
| 404 | 398 | const tracy = trace(@src()); |
| 405 | 399 | defer tracy.end(); |
| 406 | 400 | |
| ... | ... | @@ -411,50 +405,47 @@ pub const ObjcStubsSection = struct { |
| 411 | 405 | const addr = objc.getAddress(@intCast(idx), macho_file); |
| 412 | 406 | switch (macho_file.getTarget().cpu.arch) { |
| 413 | 407 | .x86_64 => { |
| 414 | try bw.writeAll(&.{ 0x48, 0x8b, 0x35 }); | |
| 408 | try writer.writeAll(&.{ 0x48, 0x8b, 0x35 }); | |
| 415 | 409 | { |
| 416 | 410 | const target = sym.getObjcSelrefsAddress(macho_file); |
| 417 | 411 | const source = addr; |
| 418 | try bw.writeInt(i32, @intCast(target - source - 3 - 4), .little); | |
| 412 | try writer.writeInt(i32, @intCast(target - source - 3 - 4), .little); | |
| 419 | 413 | } |
| 420 | try bw.writeAll(&.{ 0xff, 0x25 }); | |
| 414 | try writer.writeAll(&.{ 0xff, 0x25 }); | |
| 421 | 415 | { |
| 422 | 416 | const target_sym = obj.getObjcMsgSendRef(macho_file).?.getSymbol(macho_file).?; |
| 423 | 417 | const target = target_sym.getGotAddress(macho_file); |
| 424 | 418 | const source = addr + 7; |
| 425 | try bw.writeInt(i32, @intCast(target - source - 2 - 4), .little); | |
| 419 | try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little); | |
| 426 | 420 | } |
| 427 | 421 | }, |
| 428 | 422 | .aarch64 => { |
| 423 | const Instruction = aarch64.encoding.Instruction; | |
| 429 | 424 | { |
| 430 | 425 | const target = sym.getObjcSelrefsAddress(macho_file); |
| 431 | 426 | const source = addr; |
| 432 | 427 | const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)); |
| 433 | try bw.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little); | |
| 434 | const off = try math.divExact(u12, @truncate(target), 8); | |
| 435 | try bw.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); | |
| 440 | 433 | } |
| 441 | 434 | { |
| 442 | 435 | const target_sym = obj.getObjcMsgSendRef(macho_file).?.getSymbol(macho_file).?; |
| 443 | 436 | const target = target_sym.getGotAddress(macho_file); |
| 444 | 437 | const source = addr + 2 * @sizeOf(u32); |
| 445 | 438 | const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)); |
| 446 | try bw.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); | |
| 447 | const off = try math.divExact(u12, @truncate(target), 8); | |
| 448 | try bw.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); | |
| 453 | 444 | } |
| 454 | try bw.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little); | |
| 455 | try bw.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little); | |
| 456 | try bw.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little); | |
| 457 | try bw.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); | |
| 458 | 449 | }, |
| 459 | 450 | else => unreachable, |
| 460 | 451 | } |
| ... | ... | @@ -496,7 +487,7 @@ pub const Indsymtab = struct { |
| 496 | 487 | macho_file.dysymtab_cmd.nindirectsyms = ind.nsyms(macho_file); |
| 497 | 488 | } |
| 498 | 489 | |
| 499 | pub fn write(ind: Indsymtab, macho_file: *MachO, bw: *Writer) !void { | |
| 490 | pub fn write(ind: Indsymtab, macho_file: *MachO, writer: *Writer) !void { | |
| 500 | 491 | const tracy = trace(@src()); |
| 501 | 492 | defer tracy.end(); |
| 502 | 493 | |
| ... | ... | @@ -505,21 +496,21 @@ pub const Indsymtab = struct { |
| 505 | 496 | for (macho_file.stubs.symbols.items) |ref| { |
| 506 | 497 | const sym = ref.getSymbol(macho_file).?; |
| 507 | 498 | if (sym.getOutputSymtabIndex(macho_file)) |idx| { |
| 508 | try bw.writeInt(u32, idx, .little); | |
| 499 | try writer.writeInt(u32, idx, .little); | |
| 509 | 500 | } |
| 510 | 501 | } |
| 511 | 502 | |
| 512 | 503 | for (macho_file.got.symbols.items) |ref| { |
| 513 | 504 | const sym = ref.getSymbol(macho_file).?; |
| 514 | 505 | if (sym.getOutputSymtabIndex(macho_file)) |idx| { |
| 515 | try bw.writeInt(u32, idx, .little); | |
| 506 | try writer.writeInt(u32, idx, .little); | |
| 516 | 507 | } |
| 517 | 508 | } |
| 518 | 509 | |
| 519 | 510 | for (macho_file.stubs.symbols.items) |ref| { |
| 520 | 511 | const sym = ref.getSymbol(macho_file).?; |
| 521 | 512 | if (sym.getOutputSymtabIndex(macho_file)) |idx| { |
| 522 | try bw.writeInt(u32, idx, .little); | |
| 513 | try writer.writeInt(u32, idx, .little); | |
| 523 | 514 | } |
| 524 | 515 | } |
| 525 | 516 | } |
| ... | ... | @@ -573,7 +564,7 @@ pub const DataInCode = struct { |
| 573 | 564 | macho_file.data_in_code_cmd.datasize = math.cast(u32, dice.size()) orelse return error.Overflow; |
| 574 | 565 | } |
| 575 | 566 | |
| 576 | pub fn write(dice: DataInCode, macho_file: *MachO, bw: *Writer) !void { | |
| 567 | pub fn write(dice: DataInCode, macho_file: *MachO, writer: *Writer) !void { | |
| 577 | 568 | const base_address = if (!macho_file.base.isRelocatable()) |
| 578 | 569 | macho_file.getTextSegment().vmaddr |
| 579 | 570 | else |
| ... | ... | @@ -581,7 +572,7 @@ pub const DataInCode = struct { |
| 581 | 572 | for (dice.entries.items) |entry| { |
| 582 | 573 | const atom_address = entry.atom_ref.getAtom(macho_file).?.getAddress(macho_file); |
| 583 | 574 | const offset = atom_address + entry.offset - base_address; |
| 584 | try bw.writeStruct(macho.data_in_code_entry{ | |
| 575 | try writer.writeStruct(macho.data_in_code_entry{ | |
| 585 | 576 | .offset = @intCast(offset), |
| 586 | 577 | .length = entry.length, |
| 587 | 578 | .kind = entry.kind, |
src/link/aarch64.zig+17-47| ... | ... | @@ -1,66 +1,36 @@ |
| 1 | pub inline fn isArithmeticOp(inst: *const [4]u8) bool { | |
| 2 | const group_decode = @as(u5, @truncate(inst[3])); | |
| 3 | return ((group_decode >> 2) == 4); | |
| 4 | } | |
| 1 | pub const encoding = @import("../codegen.zig").aarch64.encoding; | |
| 5 | 2 | |
| 6 | 3 | pub 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); | |
| 15 | 7 | } |
| 16 | 8 | |
| 17 | 9 | pub 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); | |
| 26 | 13 | } |
| 27 | 14 | |
| 28 | pub 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; | |
| 15 | pub fn calcNumberOfPages(saddr: i64, taddr: i64) error{Overflow}!i33 { | |
| 16 | return math.cast(i21, (taddr >> 12) - (saddr >> 12)) orelse error.Overflow; | |
| 33 | 17 | } |
| 34 | 18 | |
| 35 | pub 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); | |
| 19 | pub 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); | |
| 45 | 24 | } |
| 46 | 25 | |
| 47 | 26 | pub 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); | |
| 56 | 30 | } |
| 57 | 31 | |
| 58 | 32 | const assert = std.debug.assert; |
| 59 | const bits = @import("../arch/aarch64/bits.zig"); | |
| 60 | 33 | const builtin = @import("builtin"); |
| 61 | 34 | const math = std.math; |
| 62 | 35 | const mem = std.mem; |
| 63 | 36 | const std = @import("std"); |
| 64 | ||
| 65 | pub const Instruction = bits.Instruction; | |
| 66 | pub const Register = bits.Register; |
src/main.zig+1| ... | ... | @@ -37,6 +37,7 @@ const dev = @import("dev.zig"); |
| 37 | 37 | |
| 38 | 38 | test { |
| 39 | 39 | _ = Package; |
| 40 | _ = @import("codegen.zig"); | |
| 40 | 41 | } |
| 41 | 42 | |
| 42 | 43 | const thread_stack_size = 60 << 20; |
src/target.zig+14-4| ... | ... | @@ -347,7 +347,7 @@ pub fn defaultCompilerRtOptimizeMode(target: *const std.Target) std.builtin.Opti |
| 347 | 347 | } |
| 348 | 348 | } |
| 349 | 349 | |
| 350 | pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, have_llvm: bool) bool { | |
| 350 | pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, comptime have_llvm: bool) bool { | |
| 351 | 351 | switch (target.os.tag) { |
| 352 | 352 | .plan9 => return false, |
| 353 | 353 | else => {}, |
| ... | ... | @@ -359,6 +359,7 @@ pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, have_llv |
| 359 | 359 | else => {}, |
| 360 | 360 | } |
| 361 | 361 | return switch (zigBackend(target, use_llvm)) { |
| 362 | .stage2_aarch64 => true, | |
| 362 | 363 | .stage2_llvm => true, |
| 363 | 364 | .stage2_x86_64 => switch (target.ofmt) { |
| 364 | 365 | .elf, .macho => true, |
| ... | ... | @@ -368,13 +369,21 @@ pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, have_llv |
| 368 | 369 | }; |
| 369 | 370 | } |
| 370 | 371 | |
| 371 | pub fn canBuildLibUbsanRt(target: *const std.Target) bool { | |
| 372 | pub fn canBuildLibUbsanRt(target: *const std.Target, use_llvm: bool, comptime have_llvm: bool) bool { | |
| 372 | 373 | switch (target.cpu.arch) { |
| 373 | 374 | .spirv32, .spirv64 => return false, |
| 374 | 375 | // Remove this once https://github.com/ziglang/zig/issues/23715 is fixed |
| 375 | 376 | .nvptx, .nvptx64 => return false, |
| 376 | else => return true, | |
| 377 | else => {}, | |
| 377 | 378 | } |
| 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 | }; | |
| 378 | 387 | } |
| 379 | 388 | |
| 380 | 389 | pub fn hasRedZone(target: *const std.Target) bool { |
| ... | ... | @@ -767,6 +776,7 @@ pub fn supportsTailCall(target: *const std.Target, backend: std.builtin.Compiler |
| 767 | 776 | |
| 768 | 777 | pub fn supportsThreads(target: *const std.Target, backend: std.builtin.CompilerBackend) bool { |
| 769 | 778 | return switch (backend) { |
| 779 | .stage2_aarch64 => false, | |
| 770 | 780 | .stage2_powerpc => true, |
| 771 | 781 | .stage2_x86_64 => target.ofmt == .macho or target.ofmt == .elf, |
| 772 | 782 | else => true, |
| ... | ... | @@ -864,7 +874,7 @@ pub inline fn backendSupportsFeature(backend: std.builtin.CompilerBackend, compt |
| 864 | 874 | else => false, |
| 865 | 875 | }, |
| 866 | 876 | .field_reordering => switch (backend) { |
| 867 | .stage2_c, .stage2_llvm, .stage2_x86_64 => true, | |
| 877 | .stage2_aarch64, .stage2_c, .stage2_llvm, .stage2_x86_64 => true, | |
| 868 | 878 | else => false, |
| 869 | 879 | }, |
| 870 | 880 | .separate_thread => switch (backend) { |
stage1/zig1.wasm| Binary files a/stage1/zig1.wasm and b/stage1/zig1.wasm differ |
test/behavior.zig+2-2| ... | ... | @@ -123,7 +123,6 @@ test { |
| 123 | 123 | } |
| 124 | 124 | |
| 125 | 125 | if (builtin.zig_backend != .stage2_arm and |
| 126 | builtin.zig_backend != .stage2_aarch64 and | |
| 127 | 126 | builtin.zig_backend != .stage2_spirv) |
| 128 | 127 | { |
| 129 | 128 | _ = @import("behavior/export_keyword.zig"); |
| ... | ... | @@ -141,7 +140,8 @@ test { |
| 141 | 140 | } |
| 142 | 141 | |
| 143 | 142 | // This bug only repros in the root file |
| 144 | test "deference @embedFile() of a file full of zero bytes" { | |
| 143 | test "dereference @embedFile() of a file full of zero bytes" { | |
| 144 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 145 | 145 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 146 | 146 | |
| 147 | 147 | const contents = @embedFile("behavior/zero.bin").*; |
test/behavior/abs.zig+3-7| ... | ... | @@ -3,7 +3,6 @@ const std = @import("std"); |
| 3 | 3 | const expect = std.testing.expect; |
| 4 | 4 | |
| 5 | 5 | test "@abs integers" { |
| 6 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 7 | 6 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 8 | 7 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 9 | 8 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -50,7 +49,6 @@ fn testAbsIntegers() !void { |
| 50 | 49 | } |
| 51 | 50 | |
| 52 | 51 | test "@abs unsigned integers" { |
| 53 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 54 | 52 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 55 | 53 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 56 | 54 | |
| ... | ... | @@ -90,7 +88,6 @@ fn testAbsUnsignedIntegers() !void { |
| 90 | 88 | } |
| 91 | 89 | |
| 92 | 90 | test "@abs big int <= 128 bits" { |
| 93 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 94 | 91 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 95 | 92 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 96 | 93 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -153,7 +150,6 @@ fn testAbsUnsignedBigInt() !void { |
| 153 | 150 | } |
| 154 | 151 | |
| 155 | 152 | test "@abs floats" { |
| 156 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 157 | 153 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 158 | 154 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 159 | 155 | |
| ... | ... | @@ -207,9 +203,9 @@ fn testAbsFloats(comptime T: type) !void { |
| 207 | 203 | } |
| 208 | 204 | |
| 209 | 205 | test "@abs int vectors" { |
| 206 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 210 | 207 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 211 | 208 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 212 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 213 | 209 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 214 | 210 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 215 | 211 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -275,8 +271,8 @@ fn testAbsIntVectors(comptime len: comptime_int) !void { |
| 275 | 271 | } |
| 276 | 272 | |
| 277 | 273 | test "@abs unsigned int vectors" { |
| 274 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 278 | 275 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 279 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 280 | 276 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 281 | 277 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 282 | 278 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -334,8 +330,8 @@ fn testAbsUnsignedIntVectors(comptime len: comptime_int) !void { |
| 334 | 330 | } |
| 335 | 331 | |
| 336 | 332 | test "@abs float vectors" { |
| 333 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 337 | 334 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 338 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 339 | 335 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 340 | 336 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 341 | 337 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/align.zig+1-19| ... | ... | @@ -16,7 +16,6 @@ test "global variable alignment" { |
| 16 | 16 | } |
| 17 | 17 | |
| 18 | 18 | test "large alignment of local constant" { |
| 19 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 20 | 19 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 21 | 20 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky |
| 22 | 21 | |
| ... | ... | @@ -25,7 +24,6 @@ test "large alignment of local constant" { |
| 25 | 24 | } |
| 26 | 25 | |
| 27 | 26 | test "slicing array of length 1 can not assume runtime index is always zero" { |
| 28 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 29 | 27 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 30 | 28 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky |
| 31 | 29 | |
| ... | ... | @@ -74,7 +72,6 @@ test "alignment of struct with pointer has same alignment as usize" { |
| 74 | 72 | |
| 75 | 73 | test "alignment and size of structs with 128-bit fields" { |
| 76 | 74 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 77 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 78 | 75 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 79 | 76 | |
| 80 | 77 | const A = struct { |
| ... | ... | @@ -160,7 +157,6 @@ test "alignment and size of structs with 128-bit fields" { |
| 160 | 157 | } |
| 161 | 158 | |
| 162 | 159 | test "implicitly decreasing slice alignment" { |
| 163 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 164 | 160 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 165 | 161 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 166 | 162 | |
| ... | ... | @@ -173,7 +169,6 @@ fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 { |
| 173 | 169 | } |
| 174 | 170 | |
| 175 | 171 | test "specifying alignment allows pointer cast" { |
| 176 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 177 | 172 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 178 | 173 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 179 | 174 | |
| ... | ... | @@ -186,7 +181,6 @@ fn testBytesAlign(b: u8) !void { |
| 186 | 181 | } |
| 187 | 182 | |
| 188 | 183 | test "@alignCast slices" { |
| 189 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 190 | 184 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 191 | 185 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 192 | 186 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -205,7 +199,6 @@ fn sliceExpects4(slice: []align(4) u32) void { |
| 205 | 199 | |
| 206 | 200 | test "return error union with 128-bit integer" { |
| 207 | 201 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 208 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 209 | 202 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 210 | 203 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 211 | 204 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -218,7 +211,6 @@ fn give() anyerror!u128 { |
| 218 | 211 | |
| 219 | 212 | test "page aligned array on stack" { |
| 220 | 213 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 221 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 222 | 214 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 223 | 215 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 224 | 216 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -238,7 +230,6 @@ test "page aligned array on stack" { |
| 238 | 230 | } |
| 239 | 231 | |
| 240 | 232 | test "function alignment" { |
| 241 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 242 | 233 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 243 | 234 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 244 | 235 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -268,7 +259,6 @@ test "function alignment" { |
| 268 | 259 | } |
| 269 | 260 | |
| 270 | 261 | test "implicitly decreasing fn alignment" { |
| 271 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 272 | 262 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 273 | 263 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 274 | 264 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -292,7 +282,6 @@ fn alignedBig() align(16) i32 { |
| 292 | 282 | } |
| 293 | 283 | |
| 294 | 284 | test "@alignCast functions" { |
| 295 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 296 | 285 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 297 | 286 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 298 | 287 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -376,7 +365,6 @@ const DefaultAligned = struct { |
| 376 | 365 | |
| 377 | 366 | test "read 128-bit field from default aligned struct in stack memory" { |
| 378 | 367 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 379 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 380 | 368 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 381 | 369 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 382 | 370 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -396,7 +384,6 @@ var default_aligned_global = DefaultAligned{ |
| 396 | 384 | |
| 397 | 385 | test "read 128-bit field from default aligned struct in global memory" { |
| 398 | 386 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 399 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 400 | 387 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 401 | 388 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 402 | 389 | 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" { |
| 405 | 392 | } |
| 406 | 393 | |
| 407 | 394 | test "struct field explicit alignment" { |
| 408 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 409 | 395 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 396 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 410 | 397 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 411 | 398 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky |
| 412 | 399 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -426,7 +413,6 @@ test "struct field explicit alignment" { |
| 426 | 413 | } |
| 427 | 414 | |
| 428 | 415 | test "align(N) on functions" { |
| 429 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 430 | 416 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 431 | 417 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 432 | 418 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -455,7 +441,6 @@ test "comptime alloc alignment" { |
| 455 | 441 | // TODO: it's impossible to test this in Zig today, since comptime vars do not have runtime addresses. |
| 456 | 442 | if (true) return error.SkipZigTest; |
| 457 | 443 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 458 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 459 | 444 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 460 | 445 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky |
| 461 | 446 | |
| ... | ... | @@ -468,7 +453,6 @@ test "comptime alloc alignment" { |
| 468 | 453 | } |
| 469 | 454 | |
| 470 | 455 | test "@alignCast null" { |
| 471 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 472 | 456 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 473 | 457 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 474 | 458 | |
| ... | ... | @@ -484,7 +468,6 @@ test "alignment of slice element" { |
| 484 | 468 | } |
| 485 | 469 | |
| 486 | 470 | test "sub-aligned pointer field access" { |
| 487 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 488 | 471 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 489 | 472 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 490 | 473 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -538,7 +521,6 @@ test "alignment of zero-bit types is respected" { |
| 538 | 521 | |
| 539 | 522 | test "zero-bit fields in extern struct pad fields appropriately" { |
| 540 | 523 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 541 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 542 | 524 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 543 | 525 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 544 | 526 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/array.zig+5-37| ... | ... | @@ -19,7 +19,6 @@ test "array to slice" { |
| 19 | 19 | } |
| 20 | 20 | |
| 21 | 21 | test "arrays" { |
| 22 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 23 | 22 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 24 | 23 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 25 | 24 | |
| ... | ... | @@ -47,7 +46,6 @@ fn getArrayLen(a: []const u32) usize { |
| 47 | 46 | } |
| 48 | 47 | |
| 49 | 48 | test "array concat with undefined" { |
| 50 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 51 | 49 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 52 | 50 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 53 | 51 | |
| ... | ... | @@ -73,7 +71,6 @@ test "array concat with undefined" { |
| 73 | 71 | test "array concat with tuple" { |
| 74 | 72 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 75 | 73 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 76 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 77 | 74 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 78 | 75 | |
| 79 | 76 | const array: [2]u8 = .{ 1, 2 }; |
| ... | ... | @@ -89,7 +86,6 @@ test "array concat with tuple" { |
| 89 | 86 | |
| 90 | 87 | test "array init with concat" { |
| 91 | 88 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 92 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 93 | 89 | |
| 94 | 90 | const a = 'a'; |
| 95 | 91 | var i: [4]u8 = [2]u8{ a, 'b' } ++ [2]u8{ 'c', 'd' }; |
| ... | ... | @@ -98,7 +94,6 @@ test "array init with concat" { |
| 98 | 94 | |
| 99 | 95 | test "array init with mult" { |
| 100 | 96 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 101 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 102 | 97 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 103 | 98 | |
| 104 | 99 | const a = 'a'; |
| ... | ... | @@ -110,7 +105,6 @@ test "array init with mult" { |
| 110 | 105 | } |
| 111 | 106 | |
| 112 | 107 | test "array literal with explicit type" { |
| 113 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 114 | 108 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 115 | 109 | |
| 116 | 110 | const hex_mult: [4]u16 = .{ 4096, 256, 16, 1 }; |
| ... | ... | @@ -138,7 +132,6 @@ const ArrayDotLenConstExpr = struct { |
| 138 | 132 | const some_array = [_]u8{ 0, 1, 2, 3 }; |
| 139 | 133 | |
| 140 | 134 | test "array literal with specified size" { |
| 141 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 142 | 135 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 143 | 136 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 144 | 137 | |
| ... | ... | @@ -162,7 +155,6 @@ test "array len field" { |
| 162 | 155 | |
| 163 | 156 | test "array with sentinels" { |
| 164 | 157 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 165 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 166 | 158 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 167 | 159 | |
| 168 | 160 | const S = struct { |
| ... | ... | @@ -200,7 +192,6 @@ test "void arrays" { |
| 200 | 192 | |
| 201 | 193 | test "nested arrays of strings" { |
| 202 | 194 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 203 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 204 | 195 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 205 | 196 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 206 | 197 | |
| ... | ... | @@ -215,7 +206,6 @@ test "nested arrays of strings" { |
| 215 | 206 | } |
| 216 | 207 | |
| 217 | 208 | test "nested arrays of integers" { |
| 218 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 219 | 209 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 220 | 210 | |
| 221 | 211 | const array_of_numbers = [_][2]u8{ |
| ... | ... | @@ -230,7 +220,6 @@ test "nested arrays of integers" { |
| 230 | 220 | } |
| 231 | 221 | |
| 232 | 222 | test "implicit comptime in array type size" { |
| 233 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 234 | 223 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 235 | 224 | |
| 236 | 225 | var arr: [plusOne(10)]bool = undefined; |
| ... | ... | @@ -243,7 +232,6 @@ fn plusOne(x: u32) u32 { |
| 243 | 232 | } |
| 244 | 233 | |
| 245 | 234 | test "single-item pointer to array indexing and slicing" { |
| 246 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 247 | 235 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 248 | 236 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 249 | 237 | |
| ... | ... | @@ -285,7 +273,6 @@ test "implicit cast zero sized array ptr to slice" { |
| 285 | 273 | } |
| 286 | 274 | |
| 287 | 275 | test "anonymous list literal syntax" { |
| 288 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 289 | 276 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 290 | 277 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 291 | 278 | |
| ... | ... | @@ -308,7 +295,6 @@ const Sub = struct { b: u8 }; |
| 308 | 295 | const Str = struct { a: []Sub }; |
| 309 | 296 | test "set global var array via slice embedded in struct" { |
| 310 | 297 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 311 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 312 | 298 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 313 | 299 | |
| 314 | 300 | var s = Str{ .a = s_array[0..] }; |
| ... | ... | @@ -323,7 +309,6 @@ test "set global var array via slice embedded in struct" { |
| 323 | 309 | } |
| 324 | 310 | |
| 325 | 311 | test "read/write through global variable array of struct fields initialized via array mult" { |
| 326 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 327 | 312 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 328 | 313 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 329 | 314 | |
| ... | ... | @@ -345,7 +330,6 @@ test "read/write through global variable array of struct fields initialized via |
| 345 | 330 | |
| 346 | 331 | test "implicit cast single-item pointer" { |
| 347 | 332 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 348 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 349 | 333 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 350 | 334 | |
| 351 | 335 | try testImplicitCastSingleItemPtr(); |
| ... | ... | @@ -364,7 +348,6 @@ fn testArrayByValAtComptime(b: [2]u8) u8 { |
| 364 | 348 | } |
| 365 | 349 | |
| 366 | 350 | test "comptime evaluating function that takes array by value" { |
| 367 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 368 | 351 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 369 | 352 | |
| 370 | 353 | const arr = [_]u8{ 1, 2 }; |
| ... | ... | @@ -376,7 +359,6 @@ test "comptime evaluating function that takes array by value" { |
| 376 | 359 | |
| 377 | 360 | test "runtime initialize array elem and then implicit cast to slice" { |
| 378 | 361 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 379 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 380 | 362 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 381 | 363 | |
| 382 | 364 | var two: i32 = 2; |
| ... | ... | @@ -387,7 +369,6 @@ test "runtime initialize array elem and then implicit cast to slice" { |
| 387 | 369 | |
| 388 | 370 | test "array literal as argument to function" { |
| 389 | 371 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 390 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 391 | 372 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 392 | 373 | |
| 393 | 374 | const S = struct { |
| ... | ... | @@ -414,8 +395,8 @@ test "array literal as argument to function" { |
| 414 | 395 | } |
| 415 | 396 | |
| 416 | 397 | test "double nested array to const slice cast in array literal" { |
| 417 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 418 | 398 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 399 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 419 | 400 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 420 | 401 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 421 | 402 | |
| ... | ... | @@ -476,7 +457,6 @@ test "double nested array to const slice cast in array literal" { |
| 476 | 457 | } |
| 477 | 458 | |
| 478 | 459 | test "anonymous literal in array" { |
| 479 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 480 | 460 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 481 | 461 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 482 | 462 | |
| ... | ... | @@ -502,7 +482,6 @@ test "anonymous literal in array" { |
| 502 | 482 | } |
| 503 | 483 | |
| 504 | 484 | test "access the null element of a null terminated array" { |
| 505 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 506 | 485 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 507 | 486 | |
| 508 | 487 | const S = struct { |
| ... | ... | @@ -520,7 +499,6 @@ test "access the null element of a null terminated array" { |
| 520 | 499 | } |
| 521 | 500 | |
| 522 | 501 | test "type deduction for array subscript expression" { |
| 523 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 524 | 502 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 525 | 503 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 526 | 504 | |
| ... | ... | @@ -540,7 +518,6 @@ test "type deduction for array subscript expression" { |
| 540 | 518 | |
| 541 | 519 | test "sentinel element count towards the ABI size calculation" { |
| 542 | 520 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 543 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 544 | 521 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 545 | 522 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 546 | 523 | |
| ... | ... | @@ -564,7 +541,7 @@ test "sentinel element count towards the ABI size calculation" { |
| 564 | 541 | } |
| 565 | 542 | |
| 566 | 543 | test "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; | |
| 568 | 545 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 569 | 546 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 570 | 547 | |
| ... | ... | @@ -587,8 +564,8 @@ test "zero-sized array with recursive type definition" { |
| 587 | 564 | } |
| 588 | 565 | |
| 589 | 566 | test "type coercion of anon struct literal to array" { |
| 567 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 590 | 568 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 591 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 592 | 569 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 593 | 570 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 594 | 571 | |
| ... | ... | @@ -628,7 +605,6 @@ test "array with comptime-only element type" { |
| 628 | 605 | } |
| 629 | 606 | |
| 630 | 607 | test "tuple to array handles sentinel" { |
| 631 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 632 | 608 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 633 | 609 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 634 | 610 | |
| ... | ... | @@ -641,7 +617,6 @@ test "tuple to array handles sentinel" { |
| 641 | 617 | |
| 642 | 618 | test "array init of container level array variable" { |
| 643 | 619 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 644 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 645 | 620 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 646 | 621 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 647 | 622 | |
| ... | ... | @@ -675,8 +650,8 @@ test "runtime initialized sentinel-terminated array literal" { |
| 675 | 650 | } |
| 676 | 651 | |
| 677 | 652 | test "array of array agregate init" { |
| 653 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 678 | 654 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 679 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 680 | 655 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 681 | 656 | |
| 682 | 657 | var a = [1]u32{11} ** 10; |
| ... | ... | @@ -725,7 +700,6 @@ test "array init with no result location has result type" { |
| 725 | 700 | } |
| 726 | 701 | |
| 727 | 702 | test "slicing array of zero-sized values" { |
| 728 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 729 | 703 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 730 | 704 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 731 | 705 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -890,7 +864,6 @@ test "tuple initialized through reference to anonymous array init provides resul |
| 890 | 864 | |
| 891 | 865 | test "copied array element doesn't alias source" { |
| 892 | 866 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 893 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 894 | 867 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 895 | 868 | |
| 896 | 869 | var x: [10][10]u32 = undefined; |
| ... | ... | @@ -945,7 +918,6 @@ test "array initialized with array with sentinel" { |
| 945 | 918 | } |
| 946 | 919 | |
| 947 | 920 | test "store array of array of structs at comptime" { |
| 948 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 949 | 921 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 950 | 922 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 951 | 923 | |
| ... | ... | @@ -970,7 +942,6 @@ test "store array of array of structs at comptime" { |
| 970 | 942 | } |
| 971 | 943 | |
| 972 | 944 | test "accessing multidimensional global array at comptime" { |
| 973 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 974 | 945 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 975 | 946 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 976 | 947 | |
| ... | ... | @@ -986,8 +957,8 @@ test "accessing multidimensional global array at comptime" { |
| 986 | 957 | } |
| 987 | 958 | |
| 988 | 959 | test "union that needs padding bytes inside an array" { |
| 989 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 990 | 960 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 961 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 991 | 962 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 992 | 963 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 993 | 964 | |
| ... | ... | @@ -1023,7 +994,6 @@ test "runtime index of array of zero-bit values" { |
| 1023 | 994 | } |
| 1024 | 995 | |
| 1025 | 996 | test "@splat array" { |
| 1026 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1027 | 997 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 1028 | 998 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1029 | 999 | |
| ... | ... | @@ -1046,7 +1016,6 @@ test "@splat array" { |
| 1046 | 1016 | |
| 1047 | 1017 | test "@splat array with sentinel" { |
| 1048 | 1018 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1049 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1050 | 1019 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 1051 | 1020 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1052 | 1021 | |
| ... | ... | @@ -1070,7 +1039,6 @@ test "@splat array with sentinel" { |
| 1070 | 1039 | |
| 1071 | 1040 | test "@splat zero-length array" { |
| 1072 | 1041 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1073 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1074 | 1042 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 1075 | 1043 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1076 | 1044 |
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 |
| 7 | 7 | |
| 8 | 8 | comptime { |
| 9 | 9 | if (builtin.zig_backend != .stage2_arm and |
| 10 | builtin.zig_backend != .stage2_aarch64 and | |
| 11 | 10 | !(builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) and // MSVC doesn't support inline assembly |
| 12 | 11 | is_x86_64_linux) |
| 13 | 12 | { |
| ... | ... | @@ -30,7 +29,6 @@ test "module level assembly" { |
| 30 | 29 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 31 | 30 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 32 | 31 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 33 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 34 | 32 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 35 | 33 | |
| 36 | 34 | 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" { |
| 41 | 39 | } |
| 42 | 40 | |
| 43 | 41 | test "output constraint modifiers" { |
| 42 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 44 | 43 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 45 | 44 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 46 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 47 | 45 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 48 | 46 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 49 | 47 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -63,9 +61,9 @@ test "output constraint modifiers" { |
| 63 | 61 | } |
| 64 | 62 | |
| 65 | 63 | test "alternative constraints" { |
| 64 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 66 | 65 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 67 | 66 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 68 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 69 | 67 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 70 | 68 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 71 | 69 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -83,7 +81,6 @@ test "alternative constraints" { |
| 83 | 81 | test "sized integer/float in asm input" { |
| 84 | 82 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 85 | 83 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 86 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 87 | 84 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 88 | 85 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 89 | 86 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -127,7 +124,6 @@ test "sized integer/float in asm input" { |
| 127 | 124 | test "struct/array/union types as input values" { |
| 128 | 125 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 129 | 126 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 130 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 131 | 127 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 132 | 128 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 133 | 129 | |
| ... | ... | @@ -167,7 +163,6 @@ test "rw constraint (x86_64)" { |
| 167 | 163 | |
| 168 | 164 | test "asm modifiers (AArch64)" { |
| 169 | 165 | if (!builtin.target.cpu.arch.isAARCH64()) return error.SkipZigTest; |
| 170 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 171 | 166 | |
| 172 | 167 | if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly |
| 173 | 168 |
test/behavior/atomics.zig+12-13| ... | ... | @@ -12,7 +12,7 @@ const supports_128_bit_atomics = switch (builtin.cpu.arch) { |
| 12 | 12 | }; |
| 13 | 13 | |
| 14 | 14 | test "cmpxchg" { |
| 15 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 15 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 16 | 16 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 17 | 17 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 18 | 18 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -39,7 +39,7 @@ fn testCmpxchg() !void { |
| 39 | 39 | } |
| 40 | 40 | |
| 41 | 41 | test "atomicrmw and atomicload" { |
| 42 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 42 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 43 | 43 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 44 | 44 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 45 | 45 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -68,7 +68,7 @@ fn testAtomicLoad(ptr: *u8) !void { |
| 68 | 68 | } |
| 69 | 69 | |
| 70 | 70 | test "cmpxchg with ptr" { |
| 71 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 71 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 72 | 72 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 73 | 73 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 74 | 74 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -94,7 +94,7 @@ test "cmpxchg with ptr" { |
| 94 | 94 | } |
| 95 | 95 | |
| 96 | 96 | test "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; | |
| 98 | 98 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 99 | 99 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 100 | 100 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -110,8 +110,8 @@ test "128-bit cmpxchg" { |
| 110 | 110 | // TODO: this must appear first |
| 111 | 111 | if (!supports_128_bit_atomics) return error.SkipZigTest; |
| 112 | 112 | |
| 113 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 113 | 114 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 114 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 115 | 115 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 116 | 116 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 117 | 117 | |
| ... | ... | @@ -139,7 +139,7 @@ fn test_u128_cmpxchg() !void { |
| 139 | 139 | var a_global_variable = @as(u32, 1234); |
| 140 | 140 | |
| 141 | 141 | test "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; | |
| 143 | 143 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 144 | 144 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 145 | 145 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -149,7 +149,7 @@ test "cmpxchg on a global variable" { |
| 149 | 149 | } |
| 150 | 150 | |
| 151 | 151 | test "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; | |
| 153 | 153 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 154 | 154 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 155 | 155 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -167,7 +167,7 @@ test "atomic load and rmw with enum" { |
| 167 | 167 | } |
| 168 | 168 | |
| 169 | 169 | test "atomic store" { |
| 170 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 170 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 171 | 171 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 172 | 172 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 173 | 173 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -185,7 +185,7 @@ fn testAtomicStore() !void { |
| 185 | 185 | } |
| 186 | 186 | |
| 187 | 187 | test "atomicrmw with floats" { |
| 188 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 188 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 189 | 189 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 190 | 190 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 191 | 191 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -211,7 +211,7 @@ fn testAtomicRmwFloat() !void { |
| 211 | 211 | } |
| 212 | 212 | |
| 213 | 213 | test "atomicrmw with ints" { |
| 214 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 214 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 215 | 215 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 216 | 216 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 217 | 217 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -290,7 +290,7 @@ test "atomicrmw with 128-bit ints" { |
| 290 | 290 | // TODO: this must appear first |
| 291 | 291 | if (!supports_128_bit_atomics) return error.SkipZigTest; |
| 292 | 292 | |
| 293 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 293 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 294 | 294 | |
| 295 | 295 | try testAtomicRmwInt128(.signed); |
| 296 | 296 | try testAtomicRmwInt128(.unsigned); |
| ... | ... | @@ -359,7 +359,7 @@ fn testAtomicRmwInt128(comptime signedness: std.builtin.Signedness) !void { |
| 359 | 359 | } |
| 360 | 360 | |
| 361 | 361 | test "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; | |
| 363 | 363 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 364 | 364 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 365 | 365 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -409,7 +409,6 @@ fn testAtomicsWithPackedStruct(comptime T: type, a: T, b: T) !void { |
| 409 | 409 | } |
| 410 | 410 | |
| 411 | 411 | test "return @atomicStore, using it as a void value" { |
| 412 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 413 | 412 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 414 | 413 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 415 | 414 | 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" { |
| 39 | 39 | } |
| 40 | 40 | |
| 41 | 41 | test "truncate to non-power-of-two integers from 128-bit" { |
| 42 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 43 | 42 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 44 | 43 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 45 | 44 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -422,7 +421,6 @@ fn copy(src: *const u64, dst: *u64) void { |
| 422 | 421 | } |
| 423 | 422 | |
| 424 | 423 | test "call result of if else expression" { |
| 425 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 426 | 424 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 427 | 425 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 428 | 426 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -448,7 +446,6 @@ fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA { |
| 448 | 446 | } |
| 449 | 447 | |
| 450 | 448 | test "take address of parameter" { |
| 451 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 452 | 449 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 453 | 450 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 454 | 451 | |
| ... | ... | @@ -536,7 +533,6 @@ fn nine() u8 { |
| 536 | 533 | } |
| 537 | 534 | |
| 538 | 535 | test "struct inside function" { |
| 539 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 540 | 536 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 541 | 537 | |
| 542 | 538 | try testStructInFn(); |
| ... | ... | @@ -588,7 +584,6 @@ test "global variable assignment with optional unwrapping with var initialized t |
| 588 | 584 | var global_foo: *i32 = undefined; |
| 589 | 585 | |
| 590 | 586 | test "peer result location with typed parent, runtime condition, comptime prongs" { |
| 591 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 592 | 587 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 593 | 588 | |
| 594 | 589 | const S = struct { |
| ... | ... | @@ -719,7 +714,6 @@ test "global constant is loaded with a runtime-known index" { |
| 719 | 714 | } |
| 720 | 715 | |
| 721 | 716 | test "multiline string literal is null terminated" { |
| 722 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 723 | 717 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 724 | 718 | |
| 725 | 719 | const s1 = |
| ... | ... | @@ -732,7 +726,6 @@ test "multiline string literal is null terminated" { |
| 732 | 726 | } |
| 733 | 727 | |
| 734 | 728 | test "string escapes" { |
| 735 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 736 | 729 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 737 | 730 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 738 | 731 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -764,7 +757,6 @@ fn ptrEql(a: *const []const u8, b: *const []const u8) bool { |
| 764 | 757 | } |
| 765 | 758 | |
| 766 | 759 | test "string concatenation" { |
| 767 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 768 | 760 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 769 | 761 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 770 | 762 | |
| ... | ... | @@ -787,7 +779,6 @@ test "string concatenation" { |
| 787 | 779 | } |
| 788 | 780 | |
| 789 | 781 | test "result location is optional inside error union" { |
| 790 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 791 | 782 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 792 | 783 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 793 | 784 | |
| ... | ... | @@ -803,7 +794,6 @@ fn maybe(x: bool) anyerror!?u32 { |
| 803 | 794 | } |
| 804 | 795 | |
| 805 | 796 | test "auto created variables have correct alignment" { |
| 806 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 807 | 797 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 808 | 798 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 809 | 799 | |
| ... | ... | @@ -821,7 +811,6 @@ test "auto created variables have correct alignment" { |
| 821 | 811 | |
| 822 | 812 | test "extern variable with non-pointer opaque type" { |
| 823 | 813 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 824 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 825 | 814 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 826 | 815 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 827 | 816 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| ... | ... | @@ -866,7 +855,6 @@ test "if expression type coercion" { |
| 866 | 855 | } |
| 867 | 856 | |
| 868 | 857 | test "discarding the result of various expressions" { |
| 869 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 870 | 858 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 871 | 859 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 872 | 860 | |
| ... | ... | @@ -908,7 +896,6 @@ test "labeled block implicitly ends in a break" { |
| 908 | 896 | } |
| 909 | 897 | |
| 910 | 898 | test "catch in block has correct result location" { |
| 911 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 912 | 899 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 913 | 900 | |
| 914 | 901 | const S = struct { |
| ... | ... | @@ -964,7 +951,6 @@ test "vector initialized with array init syntax has proper type" { |
| 964 | 951 | } |
| 965 | 952 | |
| 966 | 953 | test "weird array and tuple initializations" { |
| 967 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 968 | 954 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 969 | 955 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 970 | 956 | |
| ... | ... | @@ -1010,7 +996,6 @@ test "generic function uses return type of other generic function" { |
| 1010 | 996 | // https://github.com/ziglang/zig/issues/12208 |
| 1011 | 997 | return error.SkipZigTest; |
| 1012 | 998 | } |
| 1013 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1014 | 999 | |
| 1015 | 1000 | const S = struct { |
| 1016 | 1001 | fn call( |
| ... | ... | @@ -1128,7 +1113,6 @@ test "returning an opaque type from a function" { |
| 1128 | 1113 | } |
| 1129 | 1114 | |
| 1130 | 1115 | test "orelse coercion as function argument" { |
| 1131 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1132 | 1116 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1133 | 1117 | |
| 1134 | 1118 | const Loc = struct { start: i32 = -1 }; |
| ... | ... | @@ -1378,7 +1362,6 @@ test "copy array of self-referential struct" { |
| 1378 | 1362 | |
| 1379 | 1363 | test "break out of block based on comptime known values" { |
| 1380 | 1364 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 1381 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1382 | 1365 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1383 | 1366 | |
| 1384 | 1367 | const S = struct { |
| ... | ... | @@ -1412,8 +1395,8 @@ test "break out of block based on comptime known values" { |
| 1412 | 1395 | } |
| 1413 | 1396 | |
| 1414 | 1397 | test "allocation and looping over 3-byte integer" { |
| 1398 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1415 | 1399 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1416 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1417 | 1400 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1418 | 1401 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1419 | 1402 | 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" { |
| 112 | 112 | } |
| 113 | 113 | |
| 114 | 114 | test "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; | |
| 116 | 116 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 117 | 117 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 118 | 118 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -161,6 +161,7 @@ comptime { |
| 161 | 161 | } |
| 162 | 162 | |
| 163 | 163 | test "Saturating Shift Left" { |
| 164 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 164 | 165 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 165 | 166 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 166 | 167 | 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)" { |
| 20 | 20 | } |
| 21 | 21 | |
| 22 | 22 | test "@bitCast iX -> uX (8, 16, 128)" { |
| 23 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 24 | 23 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 25 | 24 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 26 | 25 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -35,8 +34,8 @@ test "@bitCast iX -> uX (8, 16, 128)" { |
| 35 | 34 | } |
| 36 | 35 | |
| 37 | 36 | test "@bitCast iX -> uX exotic integers" { |
| 38 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 39 | 37 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 38 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 40 | 39 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 41 | 40 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 42 | 41 | 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 |
| 80 | 79 | } |
| 81 | 80 | |
| 82 | 81 | test "bitcast uX to bytes" { |
| 83 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 84 | 82 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 83 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 85 | 84 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 86 | 85 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 87 | 86 | 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 |
| 296 | 295 | } |
| 297 | 296 | |
| 298 | 297 | test "@bitCast packed struct of floats" { |
| 298 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 299 | 299 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 300 | 300 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 301 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 302 | 301 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 303 | 302 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 304 | 303 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -334,9 +333,9 @@ test "@bitCast packed struct of floats" { |
| 334 | 333 | } |
| 335 | 334 | |
| 336 | 335 | test "comptime @bitCast packed struct to int and back" { |
| 336 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 337 | 337 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 338 | 338 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 339 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 340 | 339 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 341 | 340 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 342 | 341 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -379,7 +378,6 @@ test "comptime bitcast with fields following f80" { |
| 379 | 378 | } |
| 380 | 379 | |
| 381 | 380 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 382 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 383 | 381 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 384 | 382 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 385 | 383 | |
| ... | ... | @@ -393,7 +391,7 @@ test "comptime bitcast with fields following f80" { |
| 393 | 391 | } |
| 394 | 392 | |
| 395 | 393 | test "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; | |
| 397 | 395 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 398 | 396 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 399 | 397 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -420,7 +418,6 @@ fn bitCastWrapper128(x: f128) u128 { |
| 420 | 418 | return @as(u128, @bitCast(x)); |
| 421 | 419 | } |
| 422 | 420 | test "bitcast nan float does not modify signaling bit" { |
| 423 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 424 | 421 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 425 | 422 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 426 | 423 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -473,7 +470,7 @@ test "bitcast nan float does not modify signaling bit" { |
| 473 | 470 | } |
| 474 | 471 | |
| 475 | 472 | test "@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; | |
| 477 | 474 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 478 | 475 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 479 | 476 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -494,7 +491,7 @@ test "@bitCast of packed struct of bools all true" { |
| 494 | 491 | } |
| 495 | 492 | |
| 496 | 493 | test "@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; | |
| 498 | 495 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 499 | 496 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 500 | 497 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -514,7 +511,7 @@ test "@bitCast of packed struct of bools all false" { |
| 514 | 511 | } |
| 515 | 512 | |
| 516 | 513 | test "@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; | |
| 518 | 515 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 519 | 516 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 520 | 517 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -544,7 +541,7 @@ test "@bitCast of packed struct containing pointer" { |
| 544 | 541 | } |
| 545 | 542 | |
| 546 | 543 | test "@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; | |
| 548 | 545 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 549 | 546 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 550 | 547 | 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" { |
| 8 | 8 | } |
| 9 | 9 | |
| 10 | 10 | test "@bitReverse" { |
| 11 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 12 | 11 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 12 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 13 | 13 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 14 | 14 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 15 | 15 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -121,9 +121,9 @@ fn vector8() !void { |
| 121 | 121 | } |
| 122 | 122 | |
| 123 | 123 | test "bitReverse vectors u8" { |
| 124 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 124 | 125 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 125 | 126 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 126 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 127 | 127 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 128 | 128 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 129 | 129 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -141,9 +141,9 @@ fn vector16() !void { |
| 141 | 141 | } |
| 142 | 142 | |
| 143 | 143 | test "bitReverse vectors u16" { |
| 144 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 144 | 145 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 145 | 146 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 146 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 147 | 147 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 148 | 148 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 149 | 149 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -161,9 +161,9 @@ fn vector24() !void { |
| 161 | 161 | } |
| 162 | 162 | |
| 163 | 163 | test "bitReverse vectors u24" { |
| 164 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 164 | 165 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 165 | 166 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 166 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 167 | 167 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 168 | 168 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 169 | 169 | 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; |
| 7 | 7 | // This excludes builtin functions that return void or noreturn that cannot be tested. |
| 8 | 8 | test { |
| 9 | 9 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 10 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 11 | 10 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 12 | 11 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 13 | 12 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/byteswap.zig+32-43| ... | ... | @@ -3,40 +3,8 @@ const builtin = @import("builtin"); |
| 3 | 3 | const expect = std.testing.expect; |
| 4 | 4 | |
| 5 | 5 | test "@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 | ||
| 38 | 6 | 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; | |
| 40 | 8 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 41 | 9 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 42 | 10 | |
| ... | ... | @@ -51,23 +19,44 @@ test "@byteSwap integers" { |
| 51 | 19 | try t(u32, 0x12345678, 0x78563412); |
| 52 | 20 | try t(i32, @as(i32, @bitCast(@as(u32, 0xf2345678))), 0x785634f2); |
| 53 | 21 | 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); | |
| 57 | 22 | try t(u64, 0x123456789abcdef1, 0xf1debc9a78563412); |
| 58 | try t(u88, 0x123456789abcdef1112131, 0x312111f1debc9a78563412); | |
| 59 | try t(u96, 0x123456789abcdef111213141, 0x41312111f1debc9a78563412); | |
| 60 | try t(u128, 0x123456789abcdef11121314151617181, 0x8171615141312111f1debc9a78563412); | |
| 61 | 23 | |
| 62 | 24 | try t(u0, @as(u0, 0), 0); |
| 63 | 25 | try t(i8, @as(i8, -50), -50); |
| 64 | 26 | try t(i16, @as(i16, @bitCast(@as(u16, 0x1234))), @as(i16, @bitCast(@as(u16, 0x3412)))); |
| 65 | 27 | try t(i24, @as(i24, @bitCast(@as(u24, 0x123456))), @as(i24, @bitCast(@as(u24, 0x563412)))); |
| 66 | 28 | 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 | ||
| 39 | test "@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 | ||
| 67 | 57 | try t(u40, @as(i40, @bitCast(@as(u40, 0x123456789a))), @as(u40, 0x9a78563412)); |
| 68 | 58 | try t(i48, @as(i48, @bitCast(@as(u48, 0x123456789abc))), @as(i48, @bitCast(@as(u48, 0xbc9a78563412)))); |
| 69 | 59 | 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)))); | |
| 71 | 60 | try t(i88, @as(i88, @bitCast(@as(u88, 0x123456789abcdef1112131))), @as(i88, @bitCast(@as(u88, 0x312111f1debc9a78563412)))); |
| 72 | 61 | try t(i96, @as(i96, @bitCast(@as(u96, 0x123456789abcdef111213141))), @as(i96, @bitCast(@as(u96, 0x41312111f1debc9a78563412)))); |
| 73 | 62 | try t( |
| ... | ... | @@ -93,9 +82,9 @@ fn vector8() !void { |
| 93 | 82 | } |
| 94 | 83 | |
| 95 | 84 | test "@byteSwap vectors u8" { |
| 85 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 96 | 86 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 97 | 87 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 98 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 99 | 88 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 100 | 89 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 101 | 90 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -113,9 +102,9 @@ fn vector16() !void { |
| 113 | 102 | } |
| 114 | 103 | |
| 115 | 104 | test "@byteSwap vectors u16" { |
| 105 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 116 | 106 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 117 | 107 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 118 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 119 | 108 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 120 | 109 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 121 | 110 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -133,9 +122,9 @@ fn vector24() !void { |
| 133 | 122 | } |
| 134 | 123 | |
| 135 | 124 | test "@byteSwap vectors u24" { |
| 125 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 136 | 126 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 137 | 127 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 138 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 139 | 128 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 140 | 129 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 141 | 130 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
test/behavior/call.zig+6-13| ... | ... | @@ -20,8 +20,8 @@ test "super basic invocations" { |
| 20 | 20 | } |
| 21 | 21 | |
| 22 | 22 | test "basic invocations" { |
| 23 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 23 | 24 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 24 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 25 | 25 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 26 | 26 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 27 | 27 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -60,7 +60,6 @@ test "basic invocations" { |
| 60 | 60 | } |
| 61 | 61 | |
| 62 | 62 | test "tuple parameters" { |
| 63 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 64 | 63 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 65 | 64 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 66 | 65 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -95,7 +94,6 @@ test "tuple parameters" { |
| 95 | 94 | |
| 96 | 95 | test "result location of function call argument through runtime condition and struct init" { |
| 97 | 96 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 98 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 99 | 97 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 100 | 98 | |
| 101 | 99 | const E = enum { a, b }; |
| ... | ... | @@ -115,6 +113,7 @@ test "result location of function call argument through runtime condition and st |
| 115 | 113 | } |
| 116 | 114 | |
| 117 | 115 | test "function call with 40 arguments" { |
| 116 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 118 | 117 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 119 | 118 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 120 | 119 | |
| ... | ... | @@ -270,7 +269,7 @@ test "arguments to comptime parameters generated in comptime blocks" { |
| 270 | 269 | } |
| 271 | 270 | |
| 272 | 271 | test "forced tail call" { |
| 273 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 272 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 274 | 273 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 275 | 274 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 276 | 275 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -305,7 +304,7 @@ test "forced tail call" { |
| 305 | 304 | } |
| 306 | 305 | |
| 307 | 306 | test "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; | |
| 309 | 308 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 310 | 309 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 311 | 310 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -342,7 +341,6 @@ test "inline call preserves tail call" { |
| 342 | 341 | } |
| 343 | 342 | |
| 344 | 343 | test "inline call doesn't re-evaluate non generic struct" { |
| 345 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 346 | 344 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 347 | 345 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 348 | 346 | |
| ... | ... | @@ -409,7 +407,6 @@ test "recursive inline call with comptime known argument" { |
| 409 | 407 | } |
| 410 | 408 | |
| 411 | 409 | test "inline while with @call" { |
| 412 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 413 | 410 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 414 | 411 | |
| 415 | 412 | const S = struct { |
| ... | ... | @@ -439,7 +436,6 @@ test "method call as parameter type" { |
| 439 | 436 | } |
| 440 | 437 | |
| 441 | 438 | test "non-anytype generic parameters provide result type" { |
| 442 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 443 | 439 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 444 | 440 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 445 | 441 | |
| ... | ... | @@ -468,7 +464,6 @@ test "non-anytype generic parameters provide result type" { |
| 468 | 464 | } |
| 469 | 465 | |
| 470 | 466 | test "argument to generic function has correct result type" { |
| 471 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 472 | 467 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 473 | 468 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 474 | 469 | |
| ... | ... | @@ -521,7 +516,6 @@ test "call function in comptime field" { |
| 521 | 516 | |
| 522 | 517 | test "call function pointer in comptime field" { |
| 523 | 518 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 524 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 525 | 519 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 526 | 520 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 527 | 521 | |
| ... | ... | @@ -573,7 +567,6 @@ test "value returned from comptime function is comptime known" { |
| 573 | 567 | } |
| 574 | 568 | |
| 575 | 569 | test "registers get overwritten when ignoring return" { |
| 576 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 577 | 570 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 578 | 571 | if (builtin.cpu.arch != .x86_64 or builtin.os.tag != .linux) return error.SkipZigTest; |
| 579 | 572 | |
| ... | ... | @@ -619,7 +612,6 @@ test "call with union with zero sized field is not memorized incorrectly" { |
| 619 | 612 | } |
| 620 | 613 | |
| 621 | 614 | test "function call with cast to anyopaque pointer" { |
| 622 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 623 | 615 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 624 | 616 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 625 | 617 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -637,6 +629,7 @@ test "function call with cast to anyopaque pointer" { |
| 637 | 629 | } |
| 638 | 630 | |
| 639 | 631 | test "arguments pointed to on stack into tailcall" { |
| 632 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 640 | 633 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 641 | 634 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 642 | 635 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -708,7 +701,7 @@ test "arguments pointed to on stack into tailcall" { |
| 708 | 701 | } |
| 709 | 702 | |
| 710 | 703 | test "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; | |
| 712 | 705 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 713 | 706 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 714 | 707 | 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" { |
| 21 | 21 | } |
| 22 | 22 | |
| 23 | 23 | test "peer type resolution: ?T and T" { |
| 24 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 25 | 24 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 26 | 25 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 27 | 26 | |
| ... | ... | @@ -100,7 +99,6 @@ test "comptime_int @floatFromInt" { |
| 100 | 99 | } |
| 101 | 100 | |
| 102 | 101 | test "@floatFromInt" { |
| 103 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 104 | 102 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 105 | 103 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 106 | 104 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -121,7 +119,6 @@ test "@floatFromInt" { |
| 121 | 119 | } |
| 122 | 120 | |
| 123 | 121 | test "@floatFromInt(f80)" { |
| 124 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 125 | 122 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 126 | 123 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 127 | 124 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -157,7 +154,6 @@ test "@floatFromInt(f80)" { |
| 157 | 154 | } |
| 158 | 155 | |
| 159 | 156 | test "@intFromFloat" { |
| 160 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 161 | 157 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 162 | 158 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 163 | 159 | 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 { |
| 181 | 177 | } |
| 182 | 178 | |
| 183 | 179 | test "implicitly cast indirect pointer to maybe-indirect pointer" { |
| 184 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 185 | 180 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 186 | 181 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 187 | 182 | |
| ... | ... | @@ -241,7 +236,6 @@ test "@floatCast comptime_int and comptime_float" { |
| 241 | 236 | } |
| 242 | 237 | |
| 243 | 238 | test "coerce undefined to optional" { |
| 244 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 245 | 239 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 246 | 240 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 247 | 241 | |
| ... | ... | @@ -262,7 +256,6 @@ fn MakeType(comptime T: type) type { |
| 262 | 256 | } |
| 263 | 257 | |
| 264 | 258 | test "implicit cast from *[N]T to [*c]T" { |
| 265 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 266 | 259 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 267 | 260 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 268 | 261 | |
| ... | ... | @@ -299,7 +292,6 @@ test "@intCast to u0 and use the result" { |
| 299 | 292 | } |
| 300 | 293 | |
| 301 | 294 | test "peer result null and comptime_int" { |
| 302 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 303 | 295 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 304 | 296 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 305 | 297 | |
| ... | ... | @@ -324,7 +316,6 @@ test "peer result null and comptime_int" { |
| 324 | 316 | } |
| 325 | 317 | |
| 326 | 318 | test "*const ?[*]const T to [*c]const [*c]const T" { |
| 327 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 328 | 319 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 329 | 320 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 330 | 321 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -338,7 +329,6 @@ test "*const ?[*]const T to [*c]const [*c]const T" { |
| 338 | 329 | } |
| 339 | 330 | |
| 340 | 331 | test "array coercion to undefined at runtime" { |
| 341 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 342 | 332 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 343 | 333 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 344 | 334 | |
| ... | ... | @@ -368,7 +358,6 @@ fn implicitIntLitToOptional() void { |
| 368 | 358 | } |
| 369 | 359 | |
| 370 | 360 | test "return u8 coercing into ?u32 return type" { |
| 371 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 372 | 361 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 373 | 362 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 374 | 363 | |
| ... | ... | @@ -390,7 +379,6 @@ test "cast from ?[*]T to ??[*]T" { |
| 390 | 379 | } |
| 391 | 380 | |
| 392 | 381 | test "peer type unsigned int to signed" { |
| 393 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 394 | 382 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 395 | 383 | |
| 396 | 384 | var w: u31 = 5; |
| ... | ... | @@ -403,7 +391,6 @@ test "peer type unsigned int to signed" { |
| 403 | 391 | } |
| 404 | 392 | |
| 405 | 393 | test "expected [*c]const u8, found [*:0]const u8" { |
| 406 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 407 | 394 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 408 | 395 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 409 | 396 | |
| ... | ... | @@ -415,7 +402,6 @@ test "expected [*c]const u8, found [*:0]const u8" { |
| 415 | 402 | } |
| 416 | 403 | |
| 417 | 404 | test "explicit cast from integer to error type" { |
| 418 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 419 | 405 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 420 | 406 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 421 | 407 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -431,7 +417,6 @@ fn testCastIntToErr(err: anyerror) !void { |
| 431 | 417 | } |
| 432 | 418 | |
| 433 | 419 | test "peer resolve array and const slice" { |
| 434 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 435 | 420 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 436 | 421 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 437 | 422 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -447,7 +432,6 @@ fn testPeerResolveArrayConstSlice(b: bool) !void { |
| 447 | 432 | } |
| 448 | 433 | |
| 449 | 434 | test "implicitly cast from T to anyerror!?T" { |
| 450 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 451 | 435 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 452 | 436 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 453 | 437 | |
| ... | ... | @@ -473,7 +457,6 @@ fn castToOptionalTypeError(z: i32) !void { |
| 473 | 457 | } |
| 474 | 458 | |
| 475 | 459 | test "implicitly cast from [0]T to anyerror![]T" { |
| 476 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 477 | 460 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 478 | 461 | |
| 479 | 462 | try testCastZeroArrayToErrSliceMut(); |
| ... | ... | @@ -489,7 +472,6 @@ fn gimmeErrOrSlice() anyerror![]u8 { |
| 489 | 472 | } |
| 490 | 473 | |
| 491 | 474 | test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" { |
| 492 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 493 | 475 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 494 | 476 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 495 | 477 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -522,7 +504,6 @@ fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 { |
| 522 | 504 | } |
| 523 | 505 | |
| 524 | 506 | test "implicit cast from *const [N]T to []const T" { |
| 525 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 526 | 507 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 527 | 508 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 528 | 509 | |
| ... | ... | @@ -548,7 +529,6 @@ fn testCastConstArrayRefToConstSlice() !void { |
| 548 | 529 | } |
| 549 | 530 | |
| 550 | 531 | test "peer type resolution: error and [N]T" { |
| 551 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 552 | 532 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 553 | 533 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 554 | 534 | |
| ... | ... | @@ -573,7 +553,6 @@ fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 { |
| 573 | 553 | } |
| 574 | 554 | |
| 575 | 555 | test "single-item pointer of array to slice to unknown length pointer" { |
| 576 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 577 | 556 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 578 | 557 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 579 | 558 | |
| ... | ... | @@ -603,7 +582,6 @@ fn testCastPtrOfArrayToSliceAndPtr() !void { |
| 603 | 582 | } |
| 604 | 583 | |
| 605 | 584 | test "cast *[1][*]const u8 to [*]const ?[*]const u8" { |
| 606 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 607 | 585 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 608 | 586 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 609 | 587 | |
| ... | ... | @@ -613,8 +591,8 @@ test "cast *[1][*]const u8 to [*]const ?[*]const u8" { |
| 613 | 591 | } |
| 614 | 592 | |
| 615 | 593 | test "@intCast on vector" { |
| 594 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 616 | 595 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 617 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 618 | 596 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 619 | 597 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 620 | 598 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -651,7 +629,6 @@ test "@intCast on vector" { |
| 651 | 629 | } |
| 652 | 630 | |
| 653 | 631 | test "@floatCast cast down" { |
| 654 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 655 | 632 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 656 | 633 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 657 | 634 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -670,7 +647,6 @@ test "@floatCast cast down" { |
| 670 | 647 | } |
| 671 | 648 | |
| 672 | 649 | test "peer type resolution: unreachable, error set, unreachable" { |
| 673 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 674 | 650 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 675 | 651 | |
| 676 | 652 | const Error = error{ |
| ... | ... | @@ -704,7 +680,6 @@ test "peer cast: error set any anyerror" { |
| 704 | 680 | } |
| 705 | 681 | |
| 706 | 682 | test "peer type resolution: error set supersets" { |
| 707 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 708 | 683 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 709 | 684 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 710 | 685 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -735,7 +710,6 @@ test "peer type resolution: error set supersets" { |
| 735 | 710 | |
| 736 | 711 | test "peer type resolution: disjoint error sets" { |
| 737 | 712 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 738 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 739 | 713 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 740 | 714 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 741 | 715 | |
| ... | ... | @@ -765,7 +739,6 @@ test "peer type resolution: disjoint error sets" { |
| 765 | 739 | |
| 766 | 740 | test "peer type resolution: error union and error set" { |
| 767 | 741 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 768 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 769 | 742 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 770 | 743 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 771 | 744 | |
| ... | ... | @@ -799,7 +772,6 @@ test "peer type resolution: error union and error set" { |
| 799 | 772 | |
| 800 | 773 | test "peer type resolution: error union after non-error" { |
| 801 | 774 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 802 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 803 | 775 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 804 | 776 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 805 | 777 | |
| ... | ... | @@ -833,7 +805,6 @@ test "peer type resolution: error union after non-error" { |
| 833 | 805 | |
| 834 | 806 | test "peer cast *[0]T to E![]const T" { |
| 835 | 807 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 836 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 837 | 808 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 838 | 809 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 839 | 810 | |
| ... | ... | @@ -849,7 +820,6 @@ test "peer cast *[0]T to E![]const T" { |
| 849 | 820 | |
| 850 | 821 | test "peer cast *[0]T to []const T" { |
| 851 | 822 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 852 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 853 | 823 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 854 | 824 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 855 | 825 | |
| ... | ... | @@ -872,7 +842,6 @@ test "peer cast *[N]T to [*]T" { |
| 872 | 842 | } |
| 873 | 843 | |
| 874 | 844 | test "peer resolution of string literals" { |
| 875 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 876 | 845 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 877 | 846 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 878 | 847 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -895,7 +864,6 @@ test "peer resolution of string literals" { |
| 895 | 864 | } |
| 896 | 865 | |
| 897 | 866 | test "peer cast [:x]T to []T" { |
| 898 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 899 | 867 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 900 | 868 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 901 | 869 | |
| ... | ... | @@ -912,7 +880,6 @@ test "peer cast [:x]T to []T" { |
| 912 | 880 | } |
| 913 | 881 | |
| 914 | 882 | test "peer cast [N:x]T to [N]T" { |
| 915 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 916 | 883 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 917 | 884 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 918 | 885 | |
| ... | ... | @@ -929,7 +896,6 @@ test "peer cast [N:x]T to [N]T" { |
| 929 | 896 | } |
| 930 | 897 | |
| 931 | 898 | test "peer cast *[N:x]T to *[N]T" { |
| 932 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 933 | 899 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 934 | 900 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 935 | 901 | |
| ... | ... | @@ -945,7 +911,6 @@ test "peer cast *[N:x]T to *[N]T" { |
| 945 | 911 | } |
| 946 | 912 | |
| 947 | 913 | test "peer cast [*:x]T to [*]T" { |
| 948 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 949 | 914 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 950 | 915 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 951 | 916 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -966,7 +931,6 @@ test "peer cast [*:x]T to [*]T" { |
| 966 | 931 | } |
| 967 | 932 | |
| 968 | 933 | test "peer cast [:x]T to [*:x]T" { |
| 969 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 970 | 934 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 971 | 935 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 972 | 936 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -988,7 +952,6 @@ test "peer cast [:x]T to [*:x]T" { |
| 988 | 952 | } |
| 989 | 953 | |
| 990 | 954 | test "peer type resolution implicit cast to return type" { |
| 991 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 992 | 955 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 993 | 956 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 994 | 957 | |
| ... | ... | @@ -1009,7 +972,6 @@ test "peer type resolution implicit cast to return type" { |
| 1009 | 972 | } |
| 1010 | 973 | |
| 1011 | 974 | test "peer type resolution implicit cast to variable type" { |
| 1012 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1013 | 975 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1014 | 976 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1015 | 977 | |
| ... | ... | @@ -1035,7 +997,6 @@ test "variable initialization uses result locations properly with regards to the |
| 1035 | 997 | } |
| 1036 | 998 | |
| 1037 | 999 | test "cast between C pointer with different but compatible types" { |
| 1038 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1039 | 1000 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1040 | 1001 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1041 | 1002 | |
| ... | ... | @@ -1053,7 +1014,6 @@ test "cast between C pointer with different but compatible types" { |
| 1053 | 1014 | } |
| 1054 | 1015 | |
| 1055 | 1016 | test "peer type resolve string lit with sentinel-terminated mutable slice" { |
| 1056 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1057 | 1017 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1058 | 1018 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1059 | 1019 | |
| ... | ... | @@ -1104,7 +1064,6 @@ test "comptime float casts" { |
| 1104 | 1064 | } |
| 1105 | 1065 | |
| 1106 | 1066 | test "pointer reinterpret const float to int" { |
| 1107 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1108 | 1067 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1109 | 1068 | |
| 1110 | 1069 | // The hex representation is 0x3fe3333333333303. |
| ... | ... | @@ -1119,7 +1078,6 @@ test "pointer reinterpret const float to int" { |
| 1119 | 1078 | } |
| 1120 | 1079 | |
| 1121 | 1080 | test "implicit cast from [*]T to ?*anyopaque" { |
| 1122 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1123 | 1081 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1124 | 1082 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1125 | 1083 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1184,7 +1142,6 @@ test "cast function with an opaque parameter" { |
| 1184 | 1142 | } |
| 1185 | 1143 | |
| 1186 | 1144 | test "implicit ptr to *anyopaque" { |
| 1187 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1188 | 1145 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1189 | 1146 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1190 | 1147 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1199,7 +1156,6 @@ test "implicit ptr to *anyopaque" { |
| 1199 | 1156 | } |
| 1200 | 1157 | |
| 1201 | 1158 | test "return null from fn () anyerror!?&T" { |
| 1202 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1203 | 1159 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1204 | 1160 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1205 | 1161 | |
| ... | ... | @@ -1216,7 +1172,6 @@ fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A { |
| 1216 | 1172 | } |
| 1217 | 1173 | |
| 1218 | 1174 | test "peer type resolution: [0]u8 and []const u8" { |
| 1219 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1220 | 1175 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1221 | 1176 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1222 | 1177 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1237,7 +1192,6 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 { |
| 1237 | 1192 | } |
| 1238 | 1193 | |
| 1239 | 1194 | test "implicitly cast from [N]T to ?[]const T" { |
| 1240 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1241 | 1195 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1242 | 1196 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1243 | 1197 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1251,7 +1205,6 @@ fn castToOptionalSlice() ?[]const u8 { |
| 1251 | 1205 | } |
| 1252 | 1206 | |
| 1253 | 1207 | test "cast u128 to f128 and back" { |
| 1254 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1255 | 1208 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1256 | 1209 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1257 | 1210 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1274,7 +1227,6 @@ fn cast128Float(x: u128) f128 { |
| 1274 | 1227 | } |
| 1275 | 1228 | |
| 1276 | 1229 | test "implicit cast from *[N]T to ?[*]T" { |
| 1277 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1278 | 1230 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1279 | 1231 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1280 | 1232 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1291,7 +1243,6 @@ test "implicit cast from *[N]T to ?[*]T" { |
| 1291 | 1243 | } |
| 1292 | 1244 | |
| 1293 | 1245 | test "implicit cast from *T to ?*anyopaque" { |
| 1294 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1295 | 1246 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1296 | 1247 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1297 | 1248 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1306,7 +1257,6 @@ fn incrementVoidPtrValue(value: ?*anyopaque) void { |
| 1306 | 1257 | } |
| 1307 | 1258 | |
| 1308 | 1259 | test "implicit cast *[0]T to E![]const u8" { |
| 1309 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1310 | 1260 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1311 | 1261 | |
| 1312 | 1262 | var x = @as(anyerror![]const u8, &[0]u8{}); |
| ... | ... | @@ -1330,7 +1280,6 @@ test "cast from array reference to fn: runtime fn ptr" { |
| 1330 | 1280 | } |
| 1331 | 1281 | |
| 1332 | 1282 | test "*const [N]null u8 to ?[]const u8" { |
| 1333 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1334 | 1283 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1335 | 1284 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1336 | 1285 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1367,7 +1316,6 @@ test "cast between [*c]T and ?[*:0]T on fn parameter" { |
| 1367 | 1316 | |
| 1368 | 1317 | var global_struct: struct { f0: usize } = undefined; |
| 1369 | 1318 | test "assignment to optional pointer result loc" { |
| 1370 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1371 | 1319 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1372 | 1320 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1373 | 1321 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1386,7 +1334,6 @@ test "cast between *[N]void and []void" { |
| 1386 | 1334 | } |
| 1387 | 1335 | |
| 1388 | 1336 | test "peer resolve arrays of different size to const slice" { |
| 1389 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1390 | 1337 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1391 | 1338 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1392 | 1339 | |
| ... | ... | @@ -1400,7 +1347,6 @@ fn boolToStr(b: bool) []const u8 { |
| 1400 | 1347 | } |
| 1401 | 1348 | |
| 1402 | 1349 | test "cast f16 to wider types" { |
| 1403 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1404 | 1350 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1405 | 1351 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1406 | 1352 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1421,7 +1367,6 @@ test "cast f16 to wider types" { |
| 1421 | 1367 | } |
| 1422 | 1368 | |
| 1423 | 1369 | test "cast f128 to narrower types" { |
| 1424 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1425 | 1370 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1426 | 1371 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1427 | 1372 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1441,7 +1386,6 @@ test "cast f128 to narrower types" { |
| 1441 | 1386 | } |
| 1442 | 1387 | |
| 1443 | 1388 | test "peer type resolution: unreachable, null, slice" { |
| 1444 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1445 | 1389 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1446 | 1390 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1447 | 1391 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1460,7 +1404,6 @@ test "peer type resolution: unreachable, null, slice" { |
| 1460 | 1404 | } |
| 1461 | 1405 | |
| 1462 | 1406 | test "cast i8 fn call peers to i32 result" { |
| 1463 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1464 | 1407 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1465 | 1408 | |
| 1466 | 1409 | const S = struct { |
| ... | ... | @@ -1482,7 +1425,6 @@ test "cast i8 fn call peers to i32 result" { |
| 1482 | 1425 | } |
| 1483 | 1426 | |
| 1484 | 1427 | test "cast compatible optional types" { |
| 1485 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1486 | 1428 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1487 | 1429 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1488 | 1430 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1494,7 +1436,6 @@ test "cast compatible optional types" { |
| 1494 | 1436 | } |
| 1495 | 1437 | |
| 1496 | 1438 | test "coerce undefined single-item pointer of array to error union of slice" { |
| 1497 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1498 | 1439 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1499 | 1440 | |
| 1500 | 1441 | const a = @as([*]u8, undefined)[0..0]; |
| ... | ... | @@ -1513,7 +1454,6 @@ test "pointer to empty struct literal to mutable slice" { |
| 1513 | 1454 | } |
| 1514 | 1455 | |
| 1515 | 1456 | test "coerce between pointers of compatible differently-named floats" { |
| 1516 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1517 | 1457 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1518 | 1458 | if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows and !builtin.link_libc) return error.SkipZigTest; |
| 1519 | 1459 | 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" { |
| 1548 | 1488 | } |
| 1549 | 1489 | |
| 1550 | 1490 | test "intFromFloat to zero-bit int" { |
| 1551 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1552 | 1491 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1553 | 1492 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1554 | 1493 | |
| ... | ... | @@ -1573,8 +1512,6 @@ test "cast typed undefined to int" { |
| 1573 | 1512 | } |
| 1574 | 1513 | |
| 1575 | 1514 | // test "implicit cast from [:0]T to [*c]T" { |
| 1576 | // if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1577 | ||
| 1578 | 1515 | // var a: [:0]const u8 = "foo"; |
| 1579 | 1516 | // _ = &a; |
| 1580 | 1517 | // const b: [*c]const u8 = a; |
| ... | ... | @@ -1584,7 +1521,6 @@ test "cast typed undefined to int" { |
| 1584 | 1521 | // } |
| 1585 | 1522 | |
| 1586 | 1523 | test "bitcast packed struct with u0" { |
| 1587 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1588 | 1524 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1589 | 1525 | |
| 1590 | 1526 | const S = packed struct(u2) { a: u0, b: u2 }; |
| ... | ... | @@ -1691,7 +1627,6 @@ test "coercion from single-item pointer to @as to slice" { |
| 1691 | 1627 | } |
| 1692 | 1628 | |
| 1693 | 1629 | test "peer type resolution: const sentinel slice and mutable non-sentinel slice" { |
| 1694 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1695 | 1630 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1696 | 1631 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1697 | 1632 | 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" |
| 1721 | 1656 | } |
| 1722 | 1657 | |
| 1723 | 1658 | test "peer type resolution: float and comptime-known fixed-width integer" { |
| 1724 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1725 | 1659 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1726 | 1660 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1727 | 1661 | |
| ... | ... | @@ -1743,7 +1677,7 @@ test "peer type resolution: float and comptime-known fixed-width integer" { |
| 1743 | 1677 | } |
| 1744 | 1678 | |
| 1745 | 1679 | test "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; | |
| 1747 | 1681 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1748 | 1682 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1749 | 1683 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1766,7 +1700,6 @@ test "peer type resolution: same array type with sentinel" { |
| 1766 | 1700 | } |
| 1767 | 1701 | |
| 1768 | 1702 | test "peer type resolution: array with sentinel and array without sentinel" { |
| 1769 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1770 | 1703 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1771 | 1704 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1772 | 1705 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1789,7 +1722,7 @@ test "peer type resolution: array with sentinel and array without sentinel" { |
| 1789 | 1722 | } |
| 1790 | 1723 | |
| 1791 | 1724 | test "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; | |
| 1793 | 1726 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1794 | 1727 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1795 | 1728 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1813,7 +1746,7 @@ test "peer type resolution: array and vector with same child type" { |
| 1813 | 1746 | } |
| 1814 | 1747 | |
| 1815 | 1748 | test "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; | |
| 1817 | 1750 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1818 | 1751 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1819 | 1752 | 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 |
| 1837 | 1770 | } |
| 1838 | 1771 | |
| 1839 | 1772 | test "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; | |
| 1841 | 1774 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1842 | 1775 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1843 | 1776 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1861,7 +1794,6 @@ test "peer type resolution: error union and optional of same type" { |
| 1861 | 1794 | } |
| 1862 | 1795 | |
| 1863 | 1796 | test "peer type resolution: C pointer and @TypeOf(null)" { |
| 1864 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1865 | 1797 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1866 | 1798 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1867 | 1799 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1884,7 +1816,7 @@ test "peer type resolution: C pointer and @TypeOf(null)" { |
| 1884 | 1816 | } |
| 1885 | 1817 | |
| 1886 | 1818 | test "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; | |
| 1888 | 1820 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1889 | 1821 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1890 | 1822 | 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 |
| 1927 | 1859 | } |
| 1928 | 1860 | |
| 1929 | 1861 | test "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; | |
| 1931 | 1863 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1932 | 1864 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1933 | 1865 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1952,7 +1884,6 @@ test "peer type resolution: vector and optional vector" { |
| 1952 | 1884 | } |
| 1953 | 1885 | |
| 1954 | 1886 | test "peer type resolution: optional fixed-width int and comptime_int" { |
| 1955 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1956 | 1887 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1957 | 1888 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1958 | 1889 | |
| ... | ... | @@ -1974,7 +1905,7 @@ test "peer type resolution: optional fixed-width int and comptime_int" { |
| 1974 | 1905 | } |
| 1975 | 1906 | |
| 1976 | 1907 | test "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; | |
| 1978 | 1909 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1979 | 1910 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1980 | 1911 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1998,7 +1929,7 @@ test "peer type resolution: array and tuple" { |
| 1998 | 1929 | } |
| 1999 | 1930 | |
| 2000 | 1931 | test "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; | |
| 2002 | 1933 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2003 | 1934 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 2004 | 1935 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -2022,7 +1953,7 @@ test "peer type resolution: vector and tuple" { |
| 2022 | 1953 | } |
| 2023 | 1954 | |
| 2024 | 1955 | test "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; | |
| 2026 | 1957 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2027 | 1958 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 2028 | 1959 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -2066,7 +1997,6 @@ test "peer type resolution: vector and array and tuple" { |
| 2066 | 1997 | } |
| 2067 | 1998 | |
| 2068 | 1999 | test "peer type resolution: empty tuple pointer and slice" { |
| 2069 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2070 | 2000 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2071 | 2001 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2072 | 2002 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -2088,7 +2018,6 @@ test "peer type resolution: empty tuple pointer and slice" { |
| 2088 | 2018 | } |
| 2089 | 2019 | |
| 2090 | 2020 | test "peer type resolution: tuple pointer and slice" { |
| 2091 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2092 | 2021 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2093 | 2022 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2094 | 2023 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -2110,7 +2039,6 @@ test "peer type resolution: tuple pointer and slice" { |
| 2110 | 2039 | } |
| 2111 | 2040 | |
| 2112 | 2041 | test "peer type resolution: tuple pointer and optional slice" { |
| 2113 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2114 | 2042 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2115 | 2043 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2116 | 2044 | // Miscompilation on Intel's OpenCL CPU runtime. |
| ... | ... | @@ -2133,7 +2061,6 @@ test "peer type resolution: tuple pointer and optional slice" { |
| 2133 | 2061 | } |
| 2134 | 2062 | |
| 2135 | 2063 | test "peer type resolution: many compatible pointers" { |
| 2136 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2137 | 2064 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2138 | 2065 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2139 | 2066 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -2200,7 +2127,6 @@ test "peer type resolution: many compatible pointers" { |
| 2200 | 2127 | } |
| 2201 | 2128 | |
| 2202 | 2129 | test "peer type resolution: tuples with comptime fields" { |
| 2203 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2204 | 2130 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2205 | 2131 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2206 | 2132 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -2232,7 +2158,6 @@ test "peer type resolution: tuples with comptime fields" { |
| 2232 | 2158 | } |
| 2233 | 2159 | |
| 2234 | 2160 | test "peer type resolution: C pointer and many pointer" { |
| 2235 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2236 | 2161 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2237 | 2162 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2238 | 2163 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -2256,7 +2181,6 @@ test "peer type resolution: C pointer and many pointer" { |
| 2256 | 2181 | } |
| 2257 | 2182 | |
| 2258 | 2183 | test "peer type resolution: pointer attributes are combined correctly" { |
| 2259 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2260 | 2184 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2261 | 2185 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2262 | 2186 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -2338,7 +2262,7 @@ test "peer type resolution: pointer attributes are combined correctly" { |
| 2338 | 2262 | } |
| 2339 | 2263 | |
| 2340 | 2264 | test "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; | |
| 2342 | 2266 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2343 | 2267 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2344 | 2268 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -2356,7 +2280,6 @@ test "peer type resolution: arrays of compatible types" { |
| 2356 | 2280 | } |
| 2357 | 2281 | |
| 2358 | 2282 | test "cast builtins can wrap result in optional" { |
| 2359 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2360 | 2283 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2361 | 2284 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2362 | 2285 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -2394,7 +2317,6 @@ test "cast builtins can wrap result in optional" { |
| 2394 | 2317 | } |
| 2395 | 2318 | |
| 2396 | 2319 | test "cast builtins can wrap result in error union" { |
| 2397 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2398 | 2320 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2399 | 2321 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2400 | 2322 | |
| ... | ... | @@ -2432,7 +2354,6 @@ test "cast builtins can wrap result in error union" { |
| 2432 | 2354 | } |
| 2433 | 2355 | |
| 2434 | 2356 | test "cast builtins can wrap result in error union and optional" { |
| 2435 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2436 | 2357 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2437 | 2358 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2438 | 2359 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -2471,8 +2392,8 @@ test "cast builtins can wrap result in error union and optional" { |
| 2471 | 2392 | } |
| 2472 | 2393 | |
| 2473 | 2394 | test "@floatCast on vector" { |
| 2395 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2474 | 2396 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 2475 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2476 | 2397 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2477 | 2398 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2478 | 2399 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -2512,8 +2433,8 @@ test "@floatCast on vector" { |
| 2512 | 2433 | } |
| 2513 | 2434 | |
| 2514 | 2435 | test "@ptrFromInt on vector" { |
| 2436 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2515 | 2437 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 2516 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2517 | 2438 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2518 | 2439 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2519 | 2440 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -2537,8 +2458,8 @@ test "@ptrFromInt on vector" { |
| 2537 | 2458 | } |
| 2538 | 2459 | |
| 2539 | 2460 | test "@intFromPtr on vector" { |
| 2461 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2540 | 2462 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 2541 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2542 | 2463 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2543 | 2464 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2544 | 2465 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -2562,8 +2483,8 @@ test "@intFromPtr on vector" { |
| 2562 | 2483 | } |
| 2563 | 2484 | |
| 2564 | 2485 | test "@floatFromInt on vector" { |
| 2486 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2565 | 2487 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 2566 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2567 | 2488 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2568 | 2489 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2569 | 2490 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -2582,8 +2503,8 @@ test "@floatFromInt on vector" { |
| 2582 | 2503 | } |
| 2583 | 2504 | |
| 2584 | 2505 | test "@intFromFloat on vector" { |
| 2506 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2585 | 2507 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 2586 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2587 | 2508 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2588 | 2509 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2589 | 2510 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -2602,8 +2523,8 @@ test "@intFromFloat on vector" { |
| 2602 | 2523 | } |
| 2603 | 2524 | |
| 2604 | 2525 | test "@intFromBool on vector" { |
| 2526 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2605 | 2527 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 2606 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2607 | 2528 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2608 | 2529 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2609 | 2530 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -2639,7 +2560,6 @@ test "15-bit int to float" { |
| 2639 | 2560 | } |
| 2640 | 2561 | |
| 2641 | 2562 | test "@as does not corrupt values with incompatible representations" { |
| 2642 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2643 | 2563 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2644 | 2564 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2645 | 2565 | |
| ... | ... | @@ -2654,7 +2574,6 @@ test "@as does not corrupt values with incompatible representations" { |
| 2654 | 2574 | } |
| 2655 | 2575 | |
| 2656 | 2576 | test "result information is preserved through many nested structures" { |
| 2657 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2658 | 2577 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2659 | 2578 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2660 | 2579 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -2679,7 +2598,7 @@ test "result information is preserved through many nested structures" { |
| 2679 | 2598 | } |
| 2680 | 2599 | |
| 2681 | 2600 | test "@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; | |
| 2683 | 2602 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2684 | 2603 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 2685 | 2604 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -2703,7 +2622,6 @@ test "result type is preserved into comptime block" { |
| 2703 | 2622 | } |
| 2704 | 2623 | |
| 2705 | 2624 | test "bitcast vector" { |
| 2706 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2707 | 2625 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2708 | 2626 | |
| 2709 | 2627 | const u8x32 = @Vector(32, u8); |
| ... | ... | @@ -2766,6 +2684,7 @@ test "@intFromFloat boundary cases" { |
| 2766 | 2684 | } |
| 2767 | 2685 | |
| 2768 | 2686 | test "@intFromFloat vector boundary cases" { |
| 2687 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2769 | 2688 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 2770 | 2689 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 2771 | 2690 | 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; |
| 5 | 5 | const maxInt = std.math.maxInt; |
| 6 | 6 | |
| 7 | 7 | test "@intCast i32 to u7" { |
| 8 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 9 | 8 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 10 | 9 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 11 | 10 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -19,7 +18,6 @@ test "@intCast i32 to u7" { |
| 19 | 18 | } |
| 20 | 19 | |
| 21 | 20 | test "coerce i8 to i32 and @intCast back" { |
| 22 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 23 | 21 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 24 | 22 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 25 | 23 | |
| ... | ... | @@ -36,6 +34,7 @@ test "coerce i8 to i32 and @intCast back" { |
| 36 | 34 | |
| 37 | 35 | test "coerce non byte-sized integers accross 32bits boundary" { |
| 38 | 36 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 37 | ||
| 39 | 38 | { |
| 40 | 39 | var v: u21 = 6417; |
| 41 | 40 | _ = &v; |
| ... | ... | @@ -164,8 +163,9 @@ const Piece = packed struct { |
| 164 | 163 | } |
| 165 | 164 | }; |
| 166 | 165 | |
| 166 | // Originally reported at https://github.com/ziglang/zig/issues/14200 | |
| 167 | 167 | test "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; | |
| 169 | 169 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 170 | 170 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 171 | 171 | |
| ... | ... | @@ -181,6 +181,7 @@ test "load non byte-sized optional value" { |
| 181 | 181 | } |
| 182 | 182 | |
| 183 | 183 | test "load non byte-sized value in struct" { |
| 184 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 184 | 185 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 185 | 186 | if (builtin.cpu.arch.endian() != .little) return error.SkipZigTest; // packed struct TODO |
| 186 | 187 | 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 { |
| 66 | 66 | return if (endian == .big) v else @byteSwap(v); |
| 67 | 67 | } |
| 68 | 68 | test "type pun endianness" { |
| 69 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 70 | 69 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 71 | 70 | |
| 72 | 71 | comptime { |
| ... | ... | @@ -360,7 +359,6 @@ test "offset field ptr by enclosing array element size" { |
| 360 | 359 | } |
| 361 | 360 | |
| 362 | 361 | test "accessing reinterpreted memory of parent object" { |
| 363 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 364 | 362 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 365 | 363 | |
| 366 | 364 | const S = extern struct { |
test/behavior/const_slice_child.zig-1| ... | ... | @@ -7,7 +7,6 @@ const expect = testing.expect; |
| 7 | 7 | var argv: [*]const [*]const u8 = undefined; |
| 8 | 8 | |
| 9 | 9 | test "const slice child" { |
| 10 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 11 | 10 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 12 | 11 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 13 | 12 | 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" { |
| 33 | 33 | } |
| 34 | 34 | |
| 35 | 35 | test "call decl literal with optional" { |
| 36 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 36 | 37 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 37 | 38 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 38 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 39 | 39 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 40 | 40 | |
| 41 | 41 | const S = struct { |
| ... | ... | @@ -74,6 +74,7 @@ test "call decl literal" { |
| 74 | 74 | } |
| 75 | 75 | |
| 76 | 76 | test "call decl literal with error union" { |
| 77 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 77 | 78 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| 78 | 79 | |
| 79 | 80 | const S = struct { |
test/behavior/defer.zig+2-6| ... | ... | @@ -32,7 +32,6 @@ test "defer and labeled break" { |
| 32 | 32 | } |
| 33 | 33 | |
| 34 | 34 | test "errdefer does not apply to fn inside fn" { |
| 35 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 36 | 35 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 37 | 36 | |
| 38 | 37 | if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| try expect(e == error.Bad); |
| ... | ... | @@ -51,7 +50,6 @@ fn testNestedFnErrDefer() anyerror!void { |
| 51 | 50 | |
| 52 | 51 | test "return variable while defer expression in scope to modify it" { |
| 53 | 52 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 54 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 55 | 53 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 56 | 54 | |
| 57 | 55 | const S = struct { |
| ... | ... | @@ -91,7 +89,6 @@ fn runSomeErrorDefers(x: bool) !bool { |
| 91 | 89 | } |
| 92 | 90 | |
| 93 | 91 | test "mixing normal and error defers" { |
| 94 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 95 | 92 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 96 | 93 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 97 | 94 | |
| ... | ... | @@ -110,7 +107,7 @@ test "mixing normal and error defers" { |
| 110 | 107 | } |
| 111 | 108 | |
| 112 | 109 | test "errdefer with payload" { |
| 113 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 110 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 114 | 111 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 115 | 112 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 116 | 113 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -132,8 +129,8 @@ test "errdefer with payload" { |
| 132 | 129 | } |
| 133 | 130 | |
| 134 | 131 | test "reference to errdefer payload" { |
| 132 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 135 | 133 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 136 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 137 | 134 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 138 | 135 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| 139 | 136 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -157,7 +154,6 @@ test "reference to errdefer payload" { |
| 157 | 154 | } |
| 158 | 155 | |
| 159 | 156 | test "simple else prong doesn't emit an error for unreachable else prong" { |
| 160 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 161 | 157 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 162 | 158 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 163 | 159 |
test/behavior/enum.zig+10-18| ... | ... | @@ -25,7 +25,6 @@ fn testEnumFromIntEval(x: i32) !void { |
| 25 | 25 | const EnumFromIntNumber = enum { Zero, One, Two, Three, Four }; |
| 26 | 26 | |
| 27 | 27 | test "int to enum" { |
| 28 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 29 | 28 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 30 | 29 | |
| 31 | 30 | try testEnumFromIntEval(3); |
| ... | ... | @@ -608,7 +607,6 @@ fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void { |
| 608 | 607 | } |
| 609 | 608 | |
| 610 | 609 | test "enum with specified tag values" { |
| 611 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 612 | 610 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 613 | 611 | |
| 614 | 612 | try testEnumWithSpecifiedTagValues(MultipleChoice.C); |
| ... | ... | @@ -616,7 +614,6 @@ test "enum with specified tag values" { |
| 616 | 614 | } |
| 617 | 615 | |
| 618 | 616 | test "non-exhaustive enum" { |
| 619 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 620 | 617 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 621 | 618 | |
| 622 | 619 | const S = struct { |
| ... | ... | @@ -680,7 +677,6 @@ test "empty non-exhaustive enum" { |
| 680 | 677 | } |
| 681 | 678 | |
| 682 | 679 | test "single field non-exhaustive enum" { |
| 683 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 684 | 680 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 685 | 681 | |
| 686 | 682 | const S = struct { |
| ... | ... | @@ -744,7 +740,6 @@ test "cast integer literal to enum" { |
| 744 | 740 | } |
| 745 | 741 | |
| 746 | 742 | test "enum with specified and unspecified tag values" { |
| 747 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 748 | 743 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 749 | 744 | |
| 750 | 745 | try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D); |
| ... | ... | @@ -904,8 +899,8 @@ test "enum value allocation" { |
| 904 | 899 | } |
| 905 | 900 | |
| 906 | 901 | test "enum literal casting to tagged union" { |
| 907 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 908 | 902 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 903 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 909 | 904 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 910 | 905 | |
| 911 | 906 | const Arch = union(enum) { |
| ... | ... | @@ -941,8 +936,8 @@ test "enum literal casting to error union with payload enum" { |
| 941 | 936 | } |
| 942 | 937 | |
| 943 | 938 | test "constant enum initialization with differing sizes" { |
| 944 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 945 | 939 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 940 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 946 | 941 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 947 | 942 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 948 | 943 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -985,8 +980,8 @@ fn test3_2(f: Test3Foo) !void { |
| 985 | 980 | } |
| 986 | 981 | |
| 987 | 982 | test "@tagName" { |
| 988 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 989 | 983 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 984 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 990 | 985 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 991 | 986 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 992 | 987 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1002,8 +997,8 @@ fn testEnumTagNameBare(n: anytype) []const u8 { |
| 1002 | 997 | const BareNumber = enum { One, Two, Three }; |
| 1003 | 998 | |
| 1004 | 999 | test "@tagName non-exhaustive enum" { |
| 1005 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1006 | 1000 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1001 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1007 | 1002 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1008 | 1003 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1009 | 1004 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1014,8 +1009,8 @@ test "@tagName non-exhaustive enum" { |
| 1014 | 1009 | const NonExhaustive = enum(u8) { A, B, _ }; |
| 1015 | 1010 | |
| 1016 | 1011 | test "@tagName is null-terminated" { |
| 1017 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1018 | 1012 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1013 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1019 | 1014 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1020 | 1015 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1021 | 1016 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1030,8 +1025,8 @@ test "@tagName is null-terminated" { |
| 1030 | 1025 | } |
| 1031 | 1026 | |
| 1032 | 1027 | test "tag name with assigned enum values" { |
| 1033 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1034 | 1028 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1029 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1035 | 1030 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1036 | 1031 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1037 | 1032 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1046,7 +1041,6 @@ test "tag name with assigned enum values" { |
| 1046 | 1041 | } |
| 1047 | 1042 | |
| 1048 | 1043 | test "@tagName on enum literals" { |
| 1049 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1050 | 1044 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1051 | 1045 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1052 | 1046 | |
| ... | ... | @@ -1055,8 +1049,8 @@ test "@tagName on enum literals" { |
| 1055 | 1049 | } |
| 1056 | 1050 | |
| 1057 | 1051 | test "tag name with signed enum values" { |
| 1058 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1059 | 1052 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1053 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1060 | 1054 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1061 | 1055 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1062 | 1056 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1073,8 +1067,8 @@ test "tag name with signed enum values" { |
| 1073 | 1067 | } |
| 1074 | 1068 | |
| 1075 | 1069 | test "@tagName in callconv(.c) function" { |
| 1076 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1077 | 1070 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1071 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1078 | 1072 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 1079 | 1073 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1080 | 1074 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1091,7 +1085,6 @@ fn testEnumTagNameCallconvC() callconv(.c) [*:0]const u8 { |
| 1091 | 1085 | |
| 1092 | 1086 | test "enum literal casting to optional" { |
| 1093 | 1087 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 1094 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1095 | 1088 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1096 | 1089 | |
| 1097 | 1090 | var bar: ?Bar = undefined; |
| ... | ... | @@ -1117,8 +1110,8 @@ const bit_field_1 = BitFieldOfEnums{ |
| 1117 | 1110 | }; |
| 1118 | 1111 | |
| 1119 | 1112 | test "bit field access with enum fields" { |
| 1120 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1121 | 1113 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1114 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1122 | 1115 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1123 | 1116 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1124 | 1117 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1158,8 +1151,8 @@ test "enum literal in array literal" { |
| 1158 | 1151 | } |
| 1159 | 1152 | |
| 1160 | 1153 | test "tag name functions are unique" { |
| 1161 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1162 | 1154 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1155 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1163 | 1156 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1164 | 1157 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1165 | 1158 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1179,7 +1172,6 @@ test "tag name functions are unique" { |
| 1179 | 1172 | } |
| 1180 | 1173 | |
| 1181 | 1174 | test "size of enum with only one tag which has explicit integer tag type" { |
| 1182 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1183 | 1175 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1184 | 1176 | |
| 1185 | 1177 | 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" { |
| 145 | 145 | } |
| 146 | 146 | |
| 147 | 147 | test "fn returning empty error set can be passed as fn returning any error" { |
| 148 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 149 | ||
| 148 | 150 | entry(); |
| 149 | 151 | comptime entry(); |
| 150 | 152 | } |
| 151 | 153 | |
| 152 | 154 | test "fn returning empty error set can be passed as fn returning any error - pointer" { |
| 155 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 153 | 156 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 154 | 157 | |
| 155 | 158 | entryPtr(); |
| ... | ... | @@ -401,8 +404,8 @@ fn intLiteral(str: []const u8) !?i64 { |
| 401 | 404 | } |
| 402 | 405 | |
| 403 | 406 | test "nested error union function call in optional unwrap" { |
| 407 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 404 | 408 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 405 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 406 | 409 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 407 | 410 | |
| 408 | 411 | const S = struct { |
| ... | ... | @@ -448,7 +451,6 @@ test "nested error union function call in optional unwrap" { |
| 448 | 451 | } |
| 449 | 452 | |
| 450 | 453 | test "return function call to error set from error union function" { |
| 451 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 452 | 454 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 453 | 455 | |
| 454 | 456 | const S = struct { |
| ... | ... | @@ -465,7 +467,6 @@ test "return function call to error set from error union function" { |
| 465 | 467 | } |
| 466 | 468 | |
| 467 | 469 | test "optional error set is the same size as error set" { |
| 468 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 469 | 470 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 470 | 471 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 471 | 472 | |
| ... | ... | @@ -481,7 +482,7 @@ test "optional error set is the same size as error set" { |
| 481 | 482 | } |
| 482 | 483 | |
| 483 | 484 | test "nested catch" { |
| 484 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 485 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 485 | 486 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 486 | 487 | |
| 487 | 488 | const S = struct { |
| ... | ... | @@ -530,7 +531,7 @@ test "function pointer with return type that is error union with payload which i |
| 530 | 531 | } |
| 531 | 532 | |
| 532 | 533 | test "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; | |
| 534 | 535 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 535 | 536 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 536 | 537 | |
| ... | ... | @@ -562,7 +563,6 @@ test "return result loc as peer result loc in inferred error set function" { |
| 562 | 563 | |
| 563 | 564 | test "error payload type is correctly resolved" { |
| 564 | 565 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 565 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 566 | 566 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 567 | 567 | |
| 568 | 568 | const MyIntWrapper = struct { |
| ... | ... | @@ -590,8 +590,8 @@ test "error union comptime caching" { |
| 590 | 590 | } |
| 591 | 591 | |
| 592 | 592 | test "@errorName" { |
| 593 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 594 | 593 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 594 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 595 | 595 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 596 | 596 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 597 | 597 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -605,8 +605,8 @@ fn gimmeItBroke() anyerror { |
| 605 | 605 | } |
| 606 | 606 | |
| 607 | 607 | test "@errorName sentinel length matches slice length" { |
| 608 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 609 | 608 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 609 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 610 | 610 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 611 | 611 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 612 | 612 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -700,8 +700,8 @@ test "coerce error set to the current inferred error set" { |
| 700 | 700 | } |
| 701 | 701 | |
| 702 | 702 | test "error union payload is properly aligned" { |
| 703 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 703 | 704 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 704 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 705 | 705 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 706 | 706 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 707 | 707 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -719,7 +719,6 @@ test "error union payload is properly aligned" { |
| 719 | 719 | } |
| 720 | 720 | |
| 721 | 721 | test "ret_ptr doesn't cause own inferred error set to be resolved" { |
| 722 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 723 | 722 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 724 | 723 | |
| 725 | 724 | const S = struct { |
| ... | ... | @@ -760,7 +759,7 @@ test "simple else prong allowed even when all errors handled" { |
| 760 | 759 | } |
| 761 | 760 | |
| 762 | 761 | test "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; | |
| 764 | 763 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 765 | 764 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 766 | 765 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -794,7 +793,6 @@ const NoReturn = struct { |
| 794 | 793 | }; |
| 795 | 794 | |
| 796 | 795 | test "error union of noreturn used with if" { |
| 797 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 798 | 796 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 799 | 797 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 800 | 798 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -809,7 +807,6 @@ test "error union of noreturn used with if" { |
| 809 | 807 | } |
| 810 | 808 | |
| 811 | 809 | test "error union of noreturn used with try" { |
| 812 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 813 | 810 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 814 | 811 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 815 | 812 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -821,7 +818,6 @@ test "error union of noreturn used with try" { |
| 821 | 818 | } |
| 822 | 819 | |
| 823 | 820 | test "error union of noreturn used with catch" { |
| 824 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 825 | 821 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 826 | 822 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 827 | 823 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -833,7 +829,6 @@ test "error union of noreturn used with catch" { |
| 833 | 829 | } |
| 834 | 830 | |
| 835 | 831 | test "alignment of wrapping an error union payload" { |
| 836 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 837 | 832 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 838 | 833 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 839 | 834 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -852,6 +847,7 @@ test "alignment of wrapping an error union payload" { |
| 852 | 847 | } |
| 853 | 848 | |
| 854 | 849 | test "compare error union and error set" { |
| 850 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 855 | 851 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 856 | 852 | |
| 857 | 853 | var a: anyerror = error.Foo; |
| ... | ... | @@ -887,7 +883,7 @@ test "catch within a function that calls no errorable functions" { |
| 887 | 883 | } |
| 888 | 884 | |
| 889 | 885 | test "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; | |
| 891 | 887 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 892 | 888 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 893 | 889 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -913,7 +909,6 @@ test "field access of anyerror results in smaller error set" { |
| 913 | 909 | } |
| 914 | 910 | |
| 915 | 911 | test "optional error union return type" { |
| 916 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 917 | 912 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 918 | 913 | |
| 919 | 914 | const S = struct { |
| ... | ... | @@ -928,7 +923,6 @@ test "optional error union return type" { |
| 928 | 923 | |
| 929 | 924 | test "optional error set return type" { |
| 930 | 925 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 931 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 932 | 926 | |
| 933 | 927 | const E = error{ A, B }; |
| 934 | 928 | const S = struct { |
| ... | ... | @@ -952,8 +946,8 @@ test "optional error set function parameter" { |
| 952 | 946 | } |
| 953 | 947 | |
| 954 | 948 | test "returning an error union containing a type with no runtime bits" { |
| 949 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 955 | 950 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 956 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 957 | 951 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 958 | 952 | |
| 959 | 953 | const ZeroByteType = struct { |
| ... | ... | @@ -969,7 +963,7 @@ test "returning an error union containing a type with no runtime bits" { |
| 969 | 963 | } |
| 970 | 964 | |
| 971 | 965 | test "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; | |
| 973 | 967 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 974 | 968 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 975 | 969 | |
| ... | ... | @@ -1010,7 +1004,6 @@ test "generic inline function returns inferred error set" { |
| 1010 | 1004 | } |
| 1011 | 1005 | |
| 1012 | 1006 | test "function called at runtime is properly analyzed for inferred error set" { |
| 1013 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1014 | 1007 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1015 | 1008 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1016 | 1009 | |
| ... | ... | @@ -1045,6 +1038,8 @@ test "errorCast to adhoc inferred error set" { |
| 1045 | 1038 | } |
| 1046 | 1039 | |
| 1047 | 1040 | test "@errorCast from error set to error union" { |
| 1041 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1042 | ||
| 1048 | 1043 | const S = struct { |
| 1049 | 1044 | fn doTheTest(set: error{ A, B }) error{A}!i32 { |
| 1050 | 1045 | return @errorCast(set); |
| ... | ... | @@ -1055,6 +1050,8 @@ test "@errorCast from error set to error union" { |
| 1055 | 1050 | } |
| 1056 | 1051 | |
| 1057 | 1052 | test "@errorCast from error union to error union" { |
| 1053 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1054 | ||
| 1058 | 1055 | const S = struct { |
| 1059 | 1056 | fn doTheTest(set: error{ A, B }!i32) error{A}!i32 { |
| 1060 | 1057 | return @errorCast(set); |
| ... | ... | @@ -1065,8 +1062,8 @@ test "@errorCast from error union to error union" { |
| 1065 | 1062 | } |
| 1066 | 1063 | |
| 1067 | 1064 | test "result location initialization of error union with OPV payload" { |
| 1065 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1068 | 1066 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1069 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1070 | 1067 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1071 | 1068 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1072 | 1069 | 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 { |
| 18 | 18 | } |
| 19 | 19 | const should_be_1235 = unwrapAndAddOne(1234); |
| 20 | 20 | test "static add one" { |
| 21 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 22 | 21 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 23 | 22 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 24 | 23 | |
| ... | ... | @@ -71,7 +70,6 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 { |
| 71 | 70 | } |
| 72 | 71 | |
| 73 | 72 | test "constant expressions" { |
| 74 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 75 | 73 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 76 | 74 | |
| 77 | 75 | var array: [array_size]u8 = undefined; |
| ... | ... | @@ -93,7 +91,6 @@ fn letsTryToCompareBools(a: bool, b: bool) bool { |
| 93 | 91 | return max(bool, a, b); |
| 94 | 92 | } |
| 95 | 93 | test "inlined block and runtime block phi" { |
| 96 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 97 | 94 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 98 | 95 | |
| 99 | 96 | try expect(letsTryToCompareBools(true, true)); |
| ... | ... | @@ -140,7 +137,6 @@ test "pointer to type" { |
| 140 | 137 | } |
| 141 | 138 | |
| 142 | 139 | test "a type constructed in a global expression" { |
| 143 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 144 | 140 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 145 | 141 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 146 | 142 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -236,7 +232,6 @@ const vertices = [_]Vertex{ |
| 236 | 232 | }; |
| 237 | 233 | |
| 238 | 234 | test "statically initialized list" { |
| 239 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 240 | 235 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 241 | 236 | |
| 242 | 237 | try expect(static_point_list[0].x == 1); |
| ... | ... | @@ -342,7 +337,6 @@ fn doesAlotT(comptime T: type, value: usize) T { |
| 342 | 337 | } |
| 343 | 338 | |
| 344 | 339 | test "@setEvalBranchQuota at same scope as generic function call" { |
| 345 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 346 | 340 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 347 | 341 | |
| 348 | 342 | try expect(doesAlotT(u32, 2) == 2); |
| ... | ... | @@ -394,7 +388,6 @@ test "return 0 from function that has u0 return type" { |
| 394 | 388 | } |
| 395 | 389 | |
| 396 | 390 | test "statically initialized struct" { |
| 397 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 398 | 391 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 399 | 392 | |
| 400 | 393 | st_init_str_foo.x += 1; |
| ... | ... | @@ -444,7 +437,6 @@ fn copyWithPartialInline(s: []u32, b: []u8) void { |
| 444 | 437 | |
| 445 | 438 | test "binary math operator in partially inlined function" { |
| 446 | 439 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 447 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 448 | 440 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 449 | 441 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 450 | 442 | |
| ... | ... | @@ -462,7 +454,6 @@ test "binary math operator in partially inlined function" { |
| 462 | 454 | } |
| 463 | 455 | |
| 464 | 456 | test "comptime shl" { |
| 465 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 466 | 457 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 467 | 458 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 468 | 459 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -491,6 +482,7 @@ test "comptime bitwise operators" { |
| 491 | 482 | } |
| 492 | 483 | |
| 493 | 484 | test "comptime shlWithOverflow" { |
| 485 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 494 | 486 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 495 | 487 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 496 | 488 | |
| ... | ... | @@ -503,7 +495,6 @@ test "comptime shlWithOverflow" { |
| 503 | 495 | } |
| 504 | 496 | |
| 505 | 497 | test "const ptr to variable data changes at runtime" { |
| 506 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 507 | 498 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 508 | 499 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 509 | 500 | |
| ... | ... | @@ -521,7 +512,6 @@ const foo_ref = &foo_contents; |
| 521 | 512 | |
| 522 | 513 | test "runtime 128 bit integer division" { |
| 523 | 514 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 524 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 525 | 515 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 526 | 516 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 527 | 517 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -536,7 +526,6 @@ test "runtime 128 bit integer division" { |
| 536 | 526 | } |
| 537 | 527 | |
| 538 | 528 | test "@tagName of @typeInfo" { |
| 539 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 540 | 529 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 541 | 530 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 542 | 531 | |
| ... | ... | @@ -545,7 +534,6 @@ test "@tagName of @typeInfo" { |
| 545 | 534 | } |
| 546 | 535 | |
| 547 | 536 | test "static eval list init" { |
| 548 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 549 | 537 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 550 | 538 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 551 | 539 | |
| ... | ... | @@ -578,7 +566,6 @@ test "inlined loop has array literal with elided runtime scope on first iteratio |
| 578 | 566 | } |
| 579 | 567 | |
| 580 | 568 | test "ptr to local array argument at comptime" { |
| 581 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 582 | 569 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 583 | 570 | |
| 584 | 571 | comptime { |
| ... | ... | @@ -741,7 +728,6 @@ test "*align(1) u16 is the same as *align(1:0:2) u16" { |
| 741 | 728 | |
| 742 | 729 | test "array concatenation of function calls" { |
| 743 | 730 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 744 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 745 | 731 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 746 | 732 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 747 | 733 | |
| ... | ... | @@ -751,7 +737,6 @@ test "array concatenation of function calls" { |
| 751 | 737 | |
| 752 | 738 | test "array multiplication of function calls" { |
| 753 | 739 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 754 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 755 | 740 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 756 | 741 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 757 | 742 | |
| ... | ... | @@ -769,7 +754,6 @@ fn scalar(x: u32) u32 { |
| 769 | 754 | |
| 770 | 755 | test "array concatenation peer resolves element types - value" { |
| 771 | 756 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 772 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 773 | 757 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 774 | 758 | |
| 775 | 759 | var a = [2]u3{ 1, 7 }; |
| ... | ... | @@ -786,7 +770,6 @@ test "array concatenation peer resolves element types - value" { |
| 786 | 770 | |
| 787 | 771 | test "array concatenation peer resolves element types - pointer" { |
| 788 | 772 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 789 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 790 | 773 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 791 | 774 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 792 | 775 | |
| ... | ... | @@ -803,7 +786,6 @@ test "array concatenation peer resolves element types - pointer" { |
| 803 | 786 | |
| 804 | 787 | test "array concatenation sets the sentinel - value" { |
| 805 | 788 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 806 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 807 | 789 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 808 | 790 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 809 | 791 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -823,7 +805,6 @@ test "array concatenation sets the sentinel - value" { |
| 823 | 805 | } |
| 824 | 806 | |
| 825 | 807 | test "array concatenation sets the sentinel - pointer" { |
| 826 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 827 | 808 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 828 | 809 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 829 | 810 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -843,7 +824,6 @@ test "array concatenation sets the sentinel - pointer" { |
| 843 | 824 | |
| 844 | 825 | test "array multiplication sets the sentinel - value" { |
| 845 | 826 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 846 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 847 | 827 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 848 | 828 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 849 | 829 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -862,7 +842,6 @@ test "array multiplication sets the sentinel - value" { |
| 862 | 842 | |
| 863 | 843 | test "array multiplication sets the sentinel - pointer" { |
| 864 | 844 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 865 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 866 | 845 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 867 | 846 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 868 | 847 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -889,7 +868,6 @@ test "comptime assign int to optional int" { |
| 889 | 868 | |
| 890 | 869 | test "two comptime calls with array default initialized to undefined" { |
| 891 | 870 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 892 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 893 | 871 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 894 | 872 | |
| 895 | 873 | const S = struct { |
| ... | ... | @@ -976,7 +954,6 @@ test "const local with comptime init through array init" { |
| 976 | 954 | } |
| 977 | 955 | |
| 978 | 956 | test "closure capture type of runtime-known parameter" { |
| 979 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 980 | 957 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 981 | 958 | |
| 982 | 959 | const S = struct { |
| ... | ... | @@ -992,7 +969,6 @@ test "closure capture type of runtime-known parameter" { |
| 992 | 969 | } |
| 993 | 970 | |
| 994 | 971 | test "closure capture type of runtime-known var" { |
| 995 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 996 | 972 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 997 | 973 | |
| 998 | 974 | var x: u32 = 1234; |
| ... | ... | @@ -1035,7 +1011,6 @@ test "comptime break passing through runtime condition converted to runtime brea |
| 1035 | 1011 | } |
| 1036 | 1012 | |
| 1037 | 1013 | test "comptime break to outer loop passing through runtime condition converted to runtime break" { |
| 1038 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1039 | 1014 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1040 | 1015 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1041 | 1016 | |
| ... | ... | @@ -1088,7 +1063,6 @@ test "comptime break operand passing through runtime condition converted to runt |
| 1088 | 1063 | } |
| 1089 | 1064 | |
| 1090 | 1065 | test "comptime break operand passing through runtime switch converted to runtime break" { |
| 1091 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1092 | 1066 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1093 | 1067 | |
| 1094 | 1068 | const S = struct { |
| ... | ... | @@ -1108,7 +1082,6 @@ test "comptime break operand passing through runtime switch converted to runtime |
| 1108 | 1082 | } |
| 1109 | 1083 | |
| 1110 | 1084 | test "no dependency loop for alignment of self struct" { |
| 1111 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1112 | 1085 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1113 | 1086 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1114 | 1087 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1147,7 +1120,6 @@ test "no dependency loop for alignment of self struct" { |
| 1147 | 1120 | } |
| 1148 | 1121 | |
| 1149 | 1122 | test "no dependency loop for alignment of self bare union" { |
| 1150 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1151 | 1123 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1152 | 1124 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1153 | 1125 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1186,7 +1158,6 @@ test "no dependency loop for alignment of self bare union" { |
| 1186 | 1158 | } |
| 1187 | 1159 | |
| 1188 | 1160 | test "no dependency loop for alignment of self tagged union" { |
| 1189 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1190 | 1161 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1191 | 1162 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1192 | 1163 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1230,7 +1201,6 @@ test "equality of pointers to comptime const" { |
| 1230 | 1201 | } |
| 1231 | 1202 | |
| 1232 | 1203 | test "storing an array of type in a field" { |
| 1233 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1234 | 1204 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1235 | 1205 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1236 | 1206 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1260,7 +1230,6 @@ test "storing an array of type in a field" { |
| 1260 | 1230 | } |
| 1261 | 1231 | |
| 1262 | 1232 | test "pass pointer to field of comptime-only type as a runtime parameter" { |
| 1263 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1264 | 1233 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1265 | 1234 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1266 | 1235 | |
| ... | ... | @@ -1387,7 +1356,6 @@ test "lazy sizeof union tag size in compare" { |
| 1387 | 1356 | } |
| 1388 | 1357 | |
| 1389 | 1358 | test "lazy value is resolved as slice operand" { |
| 1390 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1391 | 1359 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1392 | 1360 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1393 | 1361 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1568,7 +1536,7 @@ test "x or true is comptime-known true" { |
| 1568 | 1536 | } |
| 1569 | 1537 | |
| 1570 | 1538 | test "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; | |
| 1572 | 1540 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1573 | 1541 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1574 | 1542 |
test/behavior/export_builtin.zig-4| ... | ... | @@ -4,7 +4,6 @@ const expect = std.testing.expect; |
| 4 | 4 | |
| 5 | 5 | test "exporting enum value" { |
| 6 | 6 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 7 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 8 | 7 | |
| 9 | 8 | if (builtin.cpu.arch.isWasm()) { |
| 10 | 9 | // https://github.com/ziglang/zig/issues/4866 |
| ... | ... | @@ -23,7 +22,6 @@ test "exporting enum value" { |
| 23 | 22 | |
| 24 | 23 | test "exporting with internal linkage" { |
| 25 | 24 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 26 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 27 | 25 | |
| 28 | 26 | const S = struct { |
| 29 | 27 | fn foo() callconv(.c) void {} |
| ... | ... | @@ -36,7 +34,6 @@ test "exporting with internal linkage" { |
| 36 | 34 | |
| 37 | 35 | test "exporting using namespace access" { |
| 38 | 36 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 39 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 40 | 37 | |
| 41 | 38 | if (builtin.cpu.arch.isWasm()) { |
| 42 | 39 | // https://github.com/ziglang/zig/issues/4866 |
| ... | ... | @@ -57,7 +54,6 @@ test "exporting using namespace access" { |
| 57 | 54 | |
| 58 | 55 | test "exporting comptime-known value" { |
| 59 | 56 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 60 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 61 | 57 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 62 | 58 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 63 | 59 |
test/behavior/field_parent_ptr.zig+5| ... | ... | @@ -2,6 +2,7 @@ const expect = @import("std").testing.expect; |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | 3 | |
| 4 | 4 | test "@fieldParentPtr struct" { |
| 5 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 5 | 6 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 6 | 7 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 7 | 8 | |
| ... | ... | @@ -586,6 +587,7 @@ test "@fieldParentPtr extern struct last zero-bit field" { |
| 586 | 587 | } |
| 587 | 588 | |
| 588 | 589 | test "@fieldParentPtr unaligned packed struct" { |
| 590 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 589 | 591 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 590 | 592 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; |
| 591 | 593 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -724,6 +726,7 @@ test "@fieldParentPtr unaligned packed struct" { |
| 724 | 726 | } |
| 725 | 727 | |
| 726 | 728 | test "@fieldParentPtr aligned packed struct" { |
| 729 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 727 | 730 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 728 | 731 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; |
| 729 | 732 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1339,6 +1342,7 @@ test "@fieldParentPtr packed struct last zero-bit field" { |
| 1339 | 1342 | } |
| 1340 | 1343 | |
| 1341 | 1344 | test "@fieldParentPtr tagged union" { |
| 1345 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1342 | 1346 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1343 | 1347 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1344 | 1348 | |
| ... | ... | @@ -1475,6 +1479,7 @@ test "@fieldParentPtr tagged union" { |
| 1475 | 1479 | } |
| 1476 | 1480 | |
| 1477 | 1481 | test "@fieldParentPtr untagged union" { |
| 1482 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1478 | 1483 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1479 | 1484 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1480 | 1485 |
test/behavior/floatop.zig+18-68| ... | ... | @@ -143,7 +143,6 @@ test "cmp f64" { |
| 143 | 143 | } |
| 144 | 144 | |
| 145 | 145 | test "cmp f128" { |
| 146 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 147 | 146 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 148 | 147 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| 149 | 148 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -154,7 +153,6 @@ test "cmp f128" { |
| 154 | 153 | } |
| 155 | 154 | |
| 156 | 155 | test "cmp f80/c_longdouble" { |
| 157 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 158 | 156 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 159 | 157 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| 160 | 158 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; |
| ... | ... | @@ -223,6 +221,7 @@ fn testCmp(comptime T: type) !void { |
| 223 | 221 | } |
| 224 | 222 | |
| 225 | 223 | test "vector cmp f16" { |
| 224 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 226 | 225 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 227 | 226 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 228 | 227 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| ... | ... | @@ -236,6 +235,7 @@ test "vector cmp f16" { |
| 236 | 235 | } |
| 237 | 236 | |
| 238 | 237 | test "vector cmp f32" { |
| 238 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 239 | 239 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 240 | 240 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 241 | 241 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -249,6 +249,7 @@ test "vector cmp f32" { |
| 249 | 249 | } |
| 250 | 250 | |
| 251 | 251 | test "vector cmp f64" { |
| 252 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 252 | 253 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 253 | 254 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 254 | 255 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -261,8 +262,8 @@ test "vector cmp f64" { |
| 261 | 262 | } |
| 262 | 263 | |
| 263 | 264 | test "vector cmp f128" { |
| 265 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 264 | 266 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 265 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 266 | 267 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 267 | 268 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| 268 | 269 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -276,6 +277,7 @@ test "vector cmp f128" { |
| 276 | 277 | } |
| 277 | 278 | |
| 278 | 279 | test "vector cmp f80/c_longdouble" { |
| 280 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 279 | 281 | if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest; |
| 280 | 282 | if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .powerpc64le) return error.SkipZigTest; |
| 281 | 283 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -324,7 +326,6 @@ fn testCmpVector(comptime T: type) !void { |
| 324 | 326 | |
| 325 | 327 | test "different sized float comparisons" { |
| 326 | 328 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 327 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 328 | 329 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 329 | 330 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 330 | 331 | |
| ... | ... | @@ -371,7 +372,6 @@ test "negative f128 intFromFloat at compile-time" { |
| 371 | 372 | |
| 372 | 373 | test "@sqrt f16" { |
| 373 | 374 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 374 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 375 | 375 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 376 | 376 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 377 | 377 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -382,7 +382,6 @@ test "@sqrt f16" { |
| 382 | 382 | |
| 383 | 383 | test "@sqrt f32/f64" { |
| 384 | 384 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 385 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 386 | 385 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 387 | 386 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 388 | 387 | |
| ... | ... | @@ -394,7 +393,6 @@ test "@sqrt f32/f64" { |
| 394 | 393 | |
| 395 | 394 | test "@sqrt f80/f128/c_longdouble" { |
| 396 | 395 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 397 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 398 | 396 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 399 | 397 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 400 | 398 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -481,9 +479,9 @@ fn testSqrt(comptime T: type) !void { |
| 481 | 479 | } |
| 482 | 480 | |
| 483 | 481 | test "@sqrt with vectors" { |
| 482 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 484 | 483 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 485 | 484 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 486 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 487 | 485 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 488 | 486 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 489 | 487 | |
| ... | ... | @@ -503,7 +501,6 @@ fn testSqrtWithVectors() !void { |
| 503 | 501 | |
| 504 | 502 | test "@sin f16" { |
| 505 | 503 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 506 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 507 | 504 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 508 | 505 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 509 | 506 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -514,7 +511,6 @@ test "@sin f16" { |
| 514 | 511 | |
| 515 | 512 | test "@sin f32/f64" { |
| 516 | 513 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 517 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 518 | 514 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 519 | 515 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 520 | 516 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -527,7 +523,6 @@ test "@sin f32/f64" { |
| 527 | 523 | |
| 528 | 524 | test "@sin f80/f128/c_longdouble" { |
| 529 | 525 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 530 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 531 | 526 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 532 | 527 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 533 | 528 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -554,9 +549,9 @@ fn testSin(comptime T: type) !void { |
| 554 | 549 | } |
| 555 | 550 | |
| 556 | 551 | test "@sin with vectors" { |
| 552 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 557 | 553 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 558 | 554 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 559 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 560 | 555 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 561 | 556 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 562 | 557 | |
| ... | ... | @@ -576,7 +571,6 @@ fn testSinWithVectors() !void { |
| 576 | 571 | |
| 577 | 572 | test "@cos f16" { |
| 578 | 573 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 579 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 580 | 574 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 581 | 575 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 582 | 576 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -587,7 +581,6 @@ test "@cos f16" { |
| 587 | 581 | |
| 588 | 582 | test "@cos f32/f64" { |
| 589 | 583 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 590 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 591 | 584 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 592 | 585 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 593 | 586 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -600,7 +593,6 @@ test "@cos f32/f64" { |
| 600 | 593 | |
| 601 | 594 | test "@cos f80/f128/c_longdouble" { |
| 602 | 595 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 603 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 604 | 596 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 605 | 597 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 606 | 598 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -627,9 +619,9 @@ fn testCos(comptime T: type) !void { |
| 627 | 619 | } |
| 628 | 620 | |
| 629 | 621 | test "@cos with vectors" { |
| 622 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 630 | 623 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 631 | 624 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 632 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 633 | 625 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 634 | 626 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 635 | 627 | |
| ... | ... | @@ -649,7 +641,6 @@ fn testCosWithVectors() !void { |
| 649 | 641 | |
| 650 | 642 | test "@tan f16" { |
| 651 | 643 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 652 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 653 | 644 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 654 | 645 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 655 | 646 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -660,7 +651,6 @@ test "@tan f16" { |
| 660 | 651 | |
| 661 | 652 | test "@tan f32/f64" { |
| 662 | 653 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 663 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 664 | 654 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 665 | 655 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 666 | 656 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -673,7 +663,6 @@ test "@tan f32/f64" { |
| 673 | 663 | |
| 674 | 664 | test "@tan f80/f128/c_longdouble" { |
| 675 | 665 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 676 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 677 | 666 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 678 | 667 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 679 | 668 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -700,9 +689,9 @@ fn testTan(comptime T: type) !void { |
| 700 | 689 | } |
| 701 | 690 | |
| 702 | 691 | test "@tan with vectors" { |
| 692 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 703 | 693 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 704 | 694 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 705 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 706 | 695 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 707 | 696 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 708 | 697 | |
| ... | ... | @@ -722,7 +711,6 @@ fn testTanWithVectors() !void { |
| 722 | 711 | |
| 723 | 712 | test "@exp f16" { |
| 724 | 713 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 725 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 726 | 714 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 727 | 715 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 728 | 716 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -733,7 +721,6 @@ test "@exp f16" { |
| 733 | 721 | |
| 734 | 722 | test "@exp f32/f64" { |
| 735 | 723 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 736 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 737 | 724 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 738 | 725 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 739 | 726 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -746,7 +733,6 @@ test "@exp f32/f64" { |
| 746 | 733 | |
| 747 | 734 | test "@exp f80/f128/c_longdouble" { |
| 748 | 735 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 749 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 750 | 736 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 751 | 737 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 752 | 738 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -777,9 +763,9 @@ fn testExp(comptime T: type) !void { |
| 777 | 763 | } |
| 778 | 764 | |
| 779 | 765 | test "@exp with vectors" { |
| 766 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 780 | 767 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 781 | 768 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 782 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 783 | 769 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 784 | 770 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 785 | 771 | |
| ... | ... | @@ -799,7 +785,6 @@ fn testExpWithVectors() !void { |
| 799 | 785 | |
| 800 | 786 | test "@exp2 f16" { |
| 801 | 787 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 802 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 803 | 788 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 804 | 789 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 805 | 790 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -810,7 +795,6 @@ test "@exp2 f16" { |
| 810 | 795 | |
| 811 | 796 | test "@exp2 f32/f64" { |
| 812 | 797 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 813 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 814 | 798 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 815 | 799 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 816 | 800 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -823,7 +807,6 @@ test "@exp2 f32/f64" { |
| 823 | 807 | |
| 824 | 808 | test "@exp2 f80/f128/c_longdouble" { |
| 825 | 809 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 826 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 827 | 810 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 828 | 811 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 829 | 812 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -849,9 +832,9 @@ fn testExp2(comptime T: type) !void { |
| 849 | 832 | } |
| 850 | 833 | |
| 851 | 834 | test "@exp2 with @vectors" { |
| 835 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 852 | 836 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 853 | 837 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 854 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 855 | 838 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 856 | 839 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 857 | 840 | |
| ... | ... | @@ -870,7 +853,6 @@ fn testExp2WithVectors() !void { |
| 870 | 853 | } |
| 871 | 854 | |
| 872 | 855 | test "@log f16" { |
| 873 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 874 | 856 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 875 | 857 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 876 | 858 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -881,7 +863,6 @@ test "@log f16" { |
| 881 | 863 | } |
| 882 | 864 | |
| 883 | 865 | test "@log f32/f64" { |
| 884 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 885 | 866 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 886 | 867 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 887 | 868 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -894,7 +875,6 @@ test "@log f32/f64" { |
| 894 | 875 | } |
| 895 | 876 | |
| 896 | 877 | test "@log f80/f128/c_longdouble" { |
| 897 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 898 | 878 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 899 | 879 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 900 | 880 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -921,8 +901,8 @@ fn testLog(comptime T: type) !void { |
| 921 | 901 | } |
| 922 | 902 | |
| 923 | 903 | test "@log with @vectors" { |
| 904 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 924 | 905 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 925 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 926 | 906 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 927 | 907 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 928 | 908 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -940,7 +920,6 @@ test "@log with @vectors" { |
| 940 | 920 | } |
| 941 | 921 | |
| 942 | 922 | test "@log2 f16" { |
| 943 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 944 | 923 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 945 | 924 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 946 | 925 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -951,7 +930,6 @@ test "@log2 f16" { |
| 951 | 930 | } |
| 952 | 931 | |
| 953 | 932 | test "@log2 f32/f64" { |
| 954 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 955 | 933 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 956 | 934 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 957 | 935 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -964,7 +942,6 @@ test "@log2 f32/f64" { |
| 964 | 942 | } |
| 965 | 943 | |
| 966 | 944 | test "@log2 f80/f128/c_longdouble" { |
| 967 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 968 | 945 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 969 | 946 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 970 | 947 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -991,8 +968,8 @@ fn testLog2(comptime T: type) !void { |
| 991 | 968 | } |
| 992 | 969 | |
| 993 | 970 | test "@log2 with vectors" { |
| 971 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 994 | 972 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 995 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 996 | 973 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 997 | 974 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 998 | 975 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1016,7 +993,6 @@ fn testLog2WithVectors() !void { |
| 1016 | 993 | } |
| 1017 | 994 | |
| 1018 | 995 | test "@log10 f16" { |
| 1019 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1020 | 996 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1021 | 997 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1022 | 998 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1027,7 +1003,6 @@ test "@log10 f16" { |
| 1027 | 1003 | } |
| 1028 | 1004 | |
| 1029 | 1005 | test "@log10 f32/f64" { |
| 1030 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1031 | 1006 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1032 | 1007 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1033 | 1008 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1040,7 +1015,6 @@ test "@log10 f32/f64" { |
| 1040 | 1015 | } |
| 1041 | 1016 | |
| 1042 | 1017 | test "@log10 f80/f128/c_longdouble" { |
| 1043 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1044 | 1018 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1045 | 1019 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1046 | 1020 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1067,8 +1041,8 @@ fn testLog10(comptime T: type) !void { |
| 1067 | 1041 | } |
| 1068 | 1042 | |
| 1069 | 1043 | test "@log10 with vectors" { |
| 1044 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1070 | 1045 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1071 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1072 | 1046 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1073 | 1047 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1074 | 1048 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1089,7 +1063,6 @@ fn testLog10WithVectors() !void { |
| 1089 | 1063 | |
| 1090 | 1064 | test "@abs f16" { |
| 1091 | 1065 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1092 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1093 | 1066 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1094 | 1067 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1095 | 1068 | |
| ... | ... | @@ -1099,7 +1072,6 @@ test "@abs f16" { |
| 1099 | 1072 | |
| 1100 | 1073 | test "@abs f32/f64" { |
| 1101 | 1074 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1102 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1103 | 1075 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1104 | 1076 | |
| 1105 | 1077 | try testFabs(f32); |
| ... | ... | @@ -1110,7 +1082,6 @@ test "@abs f32/f64" { |
| 1110 | 1082 | |
| 1111 | 1083 | test "@abs f80/f128/c_longdouble" { |
| 1112 | 1084 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1113 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1114 | 1085 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| 1115 | 1086 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1116 | 1087 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1190,7 +1161,7 @@ fn testFabs(comptime T: type) !void { |
| 1190 | 1161 | } |
| 1191 | 1162 | |
| 1192 | 1163 | test "@abs with vectors" { |
| 1193 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1164 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1194 | 1165 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1195 | 1166 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1196 | 1167 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1210,7 +1181,6 @@ fn testFabsWithVectors() !void { |
| 1210 | 1181 | } |
| 1211 | 1182 | |
| 1212 | 1183 | test "@floor f16" { |
| 1213 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1214 | 1184 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1215 | 1185 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1216 | 1186 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1220,7 +1190,6 @@ test "@floor f16" { |
| 1220 | 1190 | } |
| 1221 | 1191 | |
| 1222 | 1192 | test "@floor f32/f64" { |
| 1223 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1224 | 1193 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1225 | 1194 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1226 | 1195 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1232,7 +1201,6 @@ test "@floor f32/f64" { |
| 1232 | 1201 | } |
| 1233 | 1202 | |
| 1234 | 1203 | test "@floor f80/f128/c_longdouble" { |
| 1235 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1236 | 1204 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1237 | 1205 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| 1238 | 1206 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1284,7 +1252,7 @@ fn testFloor(comptime T: type) !void { |
| 1284 | 1252 | } |
| 1285 | 1253 | |
| 1286 | 1254 | test "@floor with vectors" { |
| 1287 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1255 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1288 | 1256 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1289 | 1257 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1290 | 1258 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1304,7 +1272,6 @@ fn testFloorWithVectors() !void { |
| 1304 | 1272 | } |
| 1305 | 1273 | |
| 1306 | 1274 | test "@ceil f16" { |
| 1307 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1308 | 1275 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1309 | 1276 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1310 | 1277 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1314,7 +1281,6 @@ test "@ceil f16" { |
| 1314 | 1281 | } |
| 1315 | 1282 | |
| 1316 | 1283 | test "@ceil f32/f64" { |
| 1317 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1318 | 1284 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1319 | 1285 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1320 | 1286 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1326,7 +1292,6 @@ test "@ceil f32/f64" { |
| 1326 | 1292 | } |
| 1327 | 1293 | |
| 1328 | 1294 | test "@ceil f80/f128/c_longdouble" { |
| 1329 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1330 | 1295 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1331 | 1296 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| 1332 | 1297 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1378,7 +1343,7 @@ fn testCeil(comptime T: type) !void { |
| 1378 | 1343 | } |
| 1379 | 1344 | |
| 1380 | 1345 | test "@ceil with vectors" { |
| 1381 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1346 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1382 | 1347 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1383 | 1348 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1384 | 1349 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1398,7 +1363,6 @@ fn testCeilWithVectors() !void { |
| 1398 | 1363 | } |
| 1399 | 1364 | |
| 1400 | 1365 | test "@trunc f16" { |
| 1401 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1402 | 1366 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1403 | 1367 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1404 | 1368 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1408,7 +1372,6 @@ test "@trunc f16" { |
| 1408 | 1372 | } |
| 1409 | 1373 | |
| 1410 | 1374 | test "@trunc f32/f64" { |
| 1411 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1412 | 1375 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1413 | 1376 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1414 | 1377 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1420,7 +1383,6 @@ test "@trunc f32/f64" { |
| 1420 | 1383 | } |
| 1421 | 1384 | |
| 1422 | 1385 | test "@trunc f80/f128/c_longdouble" { |
| 1423 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1424 | 1386 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1425 | 1387 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| 1426 | 1388 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1472,7 +1434,7 @@ fn testTrunc(comptime T: type) !void { |
| 1472 | 1434 | } |
| 1473 | 1435 | |
| 1474 | 1436 | test "@trunc with vectors" { |
| 1475 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1437 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1476 | 1438 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1477 | 1439 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1478 | 1440 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1492,7 +1454,6 @@ fn testTruncWithVectors() !void { |
| 1492 | 1454 | } |
| 1493 | 1455 | |
| 1494 | 1456 | test "neg f16" { |
| 1495 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1496 | 1457 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1497 | 1458 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1498 | 1459 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1508,7 +1469,6 @@ test "neg f16" { |
| 1508 | 1469 | } |
| 1509 | 1470 | |
| 1510 | 1471 | test "neg f32/f64" { |
| 1511 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1512 | 1472 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1513 | 1473 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1514 | 1474 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1520,7 +1480,6 @@ test "neg f32/f64" { |
| 1520 | 1480 | } |
| 1521 | 1481 | |
| 1522 | 1482 | test "neg f80/f128/c_longdouble" { |
| 1523 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1524 | 1483 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1525 | 1484 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1526 | 1485 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1606,7 +1565,6 @@ fn testNeg(comptime T: type) !void { |
| 1606 | 1565 | } |
| 1607 | 1566 | |
| 1608 | 1567 | test "eval @setFloatMode at compile-time" { |
| 1609 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1610 | 1568 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1611 | 1569 | |
| 1612 | 1570 | const result = comptime fnWithFloatMode(); |
| ... | ... | @@ -1629,7 +1587,6 @@ test "f128 at compile time is lossy" { |
| 1629 | 1587 | |
| 1630 | 1588 | test "comptime fixed-width float zero divided by zero produces NaN" { |
| 1631 | 1589 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1632 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1633 | 1590 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1634 | 1591 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1635 | 1592 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1641,7 +1598,6 @@ test "comptime fixed-width float zero divided by zero produces NaN" { |
| 1641 | 1598 | |
| 1642 | 1599 | test "comptime fixed-width float non-zero divided by zero produces signed Inf" { |
| 1643 | 1600 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1644 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1645 | 1601 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1646 | 1602 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1647 | 1603 | |
| ... | ... | @@ -1686,21 +1642,18 @@ test "comptime inf >= runtime 1" { |
| 1686 | 1642 | try std.testing.expect(f >= i); |
| 1687 | 1643 | } |
| 1688 | 1644 | test "comptime isNan(nan * 1)" { |
| 1689 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1690 | 1645 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1691 | 1646 | |
| 1692 | 1647 | const nan_times_one = comptime std.math.nan(f64) * 1; |
| 1693 | 1648 | try std.testing.expect(std.math.isNan(nan_times_one)); |
| 1694 | 1649 | } |
| 1695 | 1650 | test "runtime isNan(nan * 1)" { |
| 1696 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1697 | 1651 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1698 | 1652 | |
| 1699 | 1653 | const nan_times_one = std.math.nan(f64) * 1; |
| 1700 | 1654 | try std.testing.expect(std.math.isNan(nan_times_one)); |
| 1701 | 1655 | } |
| 1702 | 1656 | test "comptime isNan(nan * 0)" { |
| 1703 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1704 | 1657 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1705 | 1658 | |
| 1706 | 1659 | const nan_times_zero = comptime std.math.nan(f64) * 0; |
| ... | ... | @@ -1709,7 +1662,6 @@ test "comptime isNan(nan * 0)" { |
| 1709 | 1662 | try std.testing.expect(std.math.isNan(zero_times_nan)); |
| 1710 | 1663 | } |
| 1711 | 1664 | test "runtime isNan(nan * 0)" { |
| 1712 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1713 | 1665 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1714 | 1666 | |
| 1715 | 1667 | const nan_times_zero = std.math.nan(f64) * 0; |
| ... | ... | @@ -1718,7 +1670,6 @@ test "runtime isNan(nan * 0)" { |
| 1718 | 1670 | try std.testing.expect(std.math.isNan(zero_times_nan)); |
| 1719 | 1671 | } |
| 1720 | 1672 | test "comptime isNan(inf * 0)" { |
| 1721 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1722 | 1673 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1723 | 1674 | |
| 1724 | 1675 | const inf_times_zero = comptime std.math.inf(f64) * 0; |
| ... | ... | @@ -1727,7 +1678,6 @@ test "comptime isNan(inf * 0)" { |
| 1727 | 1678 | try std.testing.expect(std.math.isNan(zero_times_inf)); |
| 1728 | 1679 | } |
| 1729 | 1680 | test "runtime isNan(inf * 0)" { |
| 1730 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1731 | 1681 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1732 | 1682 | |
| 1733 | 1683 | 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 |
| 78 | 78 | |
| 79 | 79 | test "discard the result of a function that returns a struct" { |
| 80 | 80 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 81 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 82 | 81 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 83 | 82 | |
| 84 | 83 | const S = struct { |
| ... | ... | @@ -101,7 +100,6 @@ test "discard the result of a function that returns a struct" { |
| 101 | 100 | |
| 102 | 101 | test "inline function call that calls optional function pointer, return pointer at callsite interacts correctly with callsite return type" { |
| 103 | 102 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 104 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 105 | 103 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 106 | 104 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 107 | 105 | |
| ... | ... | @@ -179,7 +177,6 @@ fn fComplexCallconvRet(x: u32) callconv(blk: { |
| 179 | 177 | |
| 180 | 178 | test "function with complex callconv and return type expressions" { |
| 181 | 179 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 182 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 183 | 180 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 184 | 181 | |
| 185 | 182 | try expect(fComplexCallconvRet(3).x == 9); |
| ... | ... | @@ -255,7 +252,6 @@ test "pass by non-copying value as method, at comptime" { |
| 255 | 252 | |
| 256 | 253 | test "implicit cast fn call result to optional in field result" { |
| 257 | 254 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 258 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 259 | 255 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 260 | 256 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 261 | 257 | |
| ... | ... | @@ -283,7 +279,6 @@ test "implicit cast fn call result to optional in field result" { |
| 283 | 279 | |
| 284 | 280 | test "void parameters" { |
| 285 | 281 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 286 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 287 | 282 | |
| 288 | 283 | try voidFun(1, void{}, 2, {}); |
| 289 | 284 | } |
| ... | ... | @@ -306,7 +301,6 @@ fn acceptsString(foo: []u8) void { |
| 306 | 301 | } |
| 307 | 302 | |
| 308 | 303 | test "function pointers" { |
| 309 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 310 | 304 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 311 | 305 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 312 | 306 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -345,7 +339,6 @@ fn numberLiteralArg(a: anytype) !void { |
| 345 | 339 | |
| 346 | 340 | test "function call with anon list literal" { |
| 347 | 341 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 348 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 349 | 342 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 350 | 343 | |
| 351 | 344 | const S = struct { |
| ... | ... | @@ -365,7 +358,6 @@ test "function call with anon list literal" { |
| 365 | 358 | |
| 366 | 359 | test "function call with anon list literal - 2D" { |
| 367 | 360 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 368 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 369 | 361 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 370 | 362 | |
| 371 | 363 | const S = struct { |
| ... | ... | @@ -426,7 +418,6 @@ test "import passed byref to function in return type" { |
| 426 | 418 | |
| 427 | 419 | test "implicit cast function to function ptr" { |
| 428 | 420 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 429 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 430 | 421 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 431 | 422 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 432 | 423 | |
| ... | ... | @@ -485,7 +476,6 @@ test "method call with optional pointer first param" { |
| 485 | 476 | |
| 486 | 477 | test "using @ptrCast on function pointers" { |
| 487 | 478 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 488 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 489 | 479 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 490 | 480 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 491 | 481 | |
| ... | ... | @@ -524,8 +514,6 @@ test "function returns function returning type" { |
| 524 | 514 | } |
| 525 | 515 | |
| 526 | 516 | test "peer type resolution of inferred error set with non-void payload" { |
| 527 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 528 | ||
| 529 | 517 | const S = struct { |
| 530 | 518 | fn openDataFile(mode: enum { read, write }) !u32 { |
| 531 | 519 | return switch (mode) { |
| ... | ... | @@ -582,7 +570,6 @@ test "pass and return comptime-only types" { |
| 582 | 570 | |
| 583 | 571 | test "pointer to alias behaves same as pointer to function" { |
| 584 | 572 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 585 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 586 | 573 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 587 | 574 | |
| 588 | 575 | const S = struct { |
test/behavior/for.zig-20| ... | ... | @@ -5,7 +5,6 @@ const expectEqual = std.testing.expectEqual; |
| 5 | 5 | const mem = std.mem; |
| 6 | 6 | |
| 7 | 7 | test "continue in for loop" { |
| 8 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 9 | 8 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 10 | 9 | |
| 11 | 10 | const array = [_]i32{ 1, 2, 3, 4, 5 }; |
| ... | ... | @@ -67,7 +66,6 @@ test "ignore lval with underscore (for loop)" { |
| 67 | 66 | |
| 68 | 67 | test "basic for loop" { |
| 69 | 68 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 70 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 71 | 69 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 72 | 70 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 73 | 71 | |
| ... | ... | @@ -111,7 +109,6 @@ test "basic for loop" { |
| 111 | 109 | |
| 112 | 110 | test "for with null and T peer types and inferred result location type" { |
| 113 | 111 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 114 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 115 | 112 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 116 | 113 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 117 | 114 | |
| ... | ... | @@ -132,7 +129,6 @@ test "for with null and T peer types and inferred result location type" { |
| 132 | 129 | } |
| 133 | 130 | |
| 134 | 131 | test "2 break statements and an else" { |
| 135 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 136 | 132 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 137 | 133 | |
| 138 | 134 | const S = struct { |
| ... | ... | @@ -152,7 +148,6 @@ test "2 break statements and an else" { |
| 152 | 148 | } |
| 153 | 149 | |
| 154 | 150 | test "for loop with pointer elem var" { |
| 155 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 156 | 151 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 157 | 152 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 158 | 153 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -180,7 +175,6 @@ fn mangleString(s: []u8) void { |
| 180 | 175 | } |
| 181 | 176 | |
| 182 | 177 | test "for copies its payload" { |
| 183 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 184 | 178 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 185 | 179 | |
| 186 | 180 | const S = struct { |
| ... | ... | @@ -198,7 +192,6 @@ test "for copies its payload" { |
| 198 | 192 | } |
| 199 | 193 | |
| 200 | 194 | test "for on slice with allowzero ptr" { |
| 201 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 202 | 195 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 203 | 196 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 204 | 197 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -215,7 +208,6 @@ test "for on slice with allowzero ptr" { |
| 215 | 208 | } |
| 216 | 209 | |
| 217 | 210 | test "else continue outer for" { |
| 218 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 219 | 211 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 220 | 212 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 221 | 213 | |
| ... | ... | @@ -230,8 +222,6 @@ test "else continue outer for" { |
| 230 | 222 | } |
| 231 | 223 | |
| 232 | 224 | test "for loop with else branch" { |
| 233 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 234 | ||
| 235 | 225 | { |
| 236 | 226 | var x = [_]u32{ 1, 2 }; |
| 237 | 227 | _ = &x; |
| ... | ... | @@ -312,7 +302,6 @@ test "1-based counter and ptr to array" { |
| 312 | 302 | test "slice and two counters, one is offset and one is runtime" { |
| 313 | 303 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 314 | 304 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 315 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 316 | 305 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 317 | 306 | |
| 318 | 307 | const slice: []const u8 = "blah"; |
| ... | ... | @@ -342,7 +331,6 @@ test "slice and two counters, one is offset and one is runtime" { |
| 342 | 331 | test "two slices, one captured by-ref" { |
| 343 | 332 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 344 | 333 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 345 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 346 | 334 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 347 | 335 | |
| 348 | 336 | var buf: [10]u8 = undefined; |
| ... | ... | @@ -362,7 +350,6 @@ test "two slices, one captured by-ref" { |
| 362 | 350 | test "raw pointer and slice" { |
| 363 | 351 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 364 | 352 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 365 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 366 | 353 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 367 | 354 | |
| 368 | 355 | var buf: [10]u8 = undefined; |
| ... | ... | @@ -382,7 +369,6 @@ test "raw pointer and slice" { |
| 382 | 369 | test "raw pointer and counter" { |
| 383 | 370 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 384 | 371 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 385 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 386 | 372 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 387 | 373 | |
| 388 | 374 | var buf: [10]u8 = undefined; |
| ... | ... | @@ -401,7 +387,6 @@ test "raw pointer and counter" { |
| 401 | 387 | test "inline for with slice as the comptime-known" { |
| 402 | 388 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 403 | 389 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 404 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 405 | 390 | |
| 406 | 391 | const comptime_slice = "hello"; |
| 407 | 392 | var runtime_i: usize = 3; |
| ... | ... | @@ -432,7 +417,6 @@ test "inline for with slice as the comptime-known" { |
| 432 | 417 | test "inline for with counter as the comptime-known" { |
| 433 | 418 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 434 | 419 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 435 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 436 | 420 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 437 | 421 | |
| 438 | 422 | var runtime_slice = "hello"; |
| ... | ... | @@ -464,7 +448,6 @@ test "inline for with counter as the comptime-known" { |
| 464 | 448 | test "inline for on tuple pointer" { |
| 465 | 449 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 466 | 450 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 467 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 468 | 451 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 469 | 452 | |
| 470 | 453 | const S = struct { u32, u32, u32 }; |
| ... | ... | @@ -480,7 +463,6 @@ test "inline for on tuple pointer" { |
| 480 | 463 | test "ref counter that starts at zero" { |
| 481 | 464 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 482 | 465 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 483 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 484 | 466 | |
| 485 | 467 | for ([_]usize{ 0, 1, 2 }, 0..) |i, j| { |
| 486 | 468 | try expectEqual(i, j); |
| ... | ... | @@ -495,7 +477,6 @@ test "ref counter that starts at zero" { |
| 495 | 477 | test "inferred alloc ptr of for loop" { |
| 496 | 478 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 497 | 479 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 498 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 499 | 480 | |
| 500 | 481 | { |
| 501 | 482 | var cond = false; |
| ... | ... | @@ -516,7 +497,6 @@ test "inferred alloc ptr of for loop" { |
| 516 | 497 | } |
| 517 | 498 | |
| 518 | 499 | test "for loop results in a bool" { |
| 519 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 520 | 500 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 521 | 501 | |
| 522 | 502 | 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 { |
| 17 | 17 | } |
| 18 | 18 | |
| 19 | 19 | test "simple generic fn" { |
| 20 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 21 | 20 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 22 | 21 | |
| 23 | 22 | try expect(max(i32, 3, -1) == 3); |
| ... | ... | @@ -53,7 +52,6 @@ fn sameButWithFloats(a: f64, b: f64) f64 { |
| 53 | 52 | |
| 54 | 53 | test "fn with comptime args" { |
| 55 | 54 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 56 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 57 | 55 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 58 | 56 | |
| 59 | 57 | try expect(gimmeTheBigOne(1234, 5678) == 5678); |
| ... | ... | @@ -63,7 +61,6 @@ test "fn with comptime args" { |
| 63 | 61 | |
| 64 | 62 | test "anytype params" { |
| 65 | 63 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 66 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 67 | 64 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 68 | 65 | |
| 69 | 66 | try expect(max_i32(12, 34) == 34); |
| ... | ... | @@ -87,7 +84,6 @@ fn max_f64(a: f64, b: f64) f64 { |
| 87 | 84 | } |
| 88 | 85 | |
| 89 | 86 | test "type constructed by comptime function call" { |
| 90 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 91 | 87 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 92 | 88 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 93 | 89 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -113,7 +109,6 @@ fn SimpleList(comptime L: usize) type { |
| 113 | 109 | |
| 114 | 110 | test "function with return type type" { |
| 115 | 111 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 116 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 117 | 112 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 118 | 113 | |
| 119 | 114 | var list: List(i32) = undefined; |
| ... | ... | @@ -154,7 +149,6 @@ fn aGenericFn(comptime T: type, comptime a: T, b: T) T { |
| 154 | 149 | |
| 155 | 150 | test "generic fn with implicit cast" { |
| 156 | 151 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 157 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 158 | 152 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 159 | 153 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 160 | 154 | |
| ... | ... | @@ -173,7 +167,6 @@ fn getFirstByte(comptime T: type, mem: []const T) u8 { |
| 173 | 167 | |
| 174 | 168 | test "generic fn keeps non-generic parameter types" { |
| 175 | 169 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 176 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 177 | 170 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 178 | 171 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 179 | 172 | |
| ... | ... | @@ -249,7 +242,6 @@ test "function parameter is generic" { |
| 249 | 242 | } |
| 250 | 243 | |
| 251 | 244 | test "generic function instantiation turns into comptime call" { |
| 252 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 253 | 245 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 254 | 246 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 255 | 247 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -300,7 +292,6 @@ test "generic function with void and comptime parameter" { |
| 300 | 292 | } |
| 301 | 293 | |
| 302 | 294 | test "anonymous struct return type referencing comptime parameter" { |
| 303 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 304 | 295 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 305 | 296 | |
| 306 | 297 | const S = struct { |
| ... | ... | @@ -318,7 +309,6 @@ test "anonymous struct return type referencing comptime parameter" { |
| 318 | 309 | |
| 319 | 310 | test "generic function instantiation non-duplicates" { |
| 320 | 311 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 321 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 322 | 312 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 323 | 313 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 324 | 314 | |
| ... | ... | @@ -339,7 +329,6 @@ test "generic function instantiation non-duplicates" { |
| 339 | 329 | |
| 340 | 330 | test "generic instantiation of tagged union with only one field" { |
| 341 | 331 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 342 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 343 | 332 | |
| 344 | 333 | if (builtin.os.tag == .wasi) return error.SkipZigTest; |
| 345 | 334 | |
| ... | ... | @@ -439,8 +428,6 @@ test "null sentinel pointer passed as generic argument" { |
| 439 | 428 | } |
| 440 | 429 | |
| 441 | 430 | test "generic function passed as comptime argument" { |
| 442 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 443 | ||
| 444 | 431 | const S = struct { |
| 445 | 432 | fn doMath(comptime f: fn (comptime type, i32, i32) error{Overflow}!i32, a: i32, b: i32) !void { |
| 446 | 433 | const result = try f(i32, a, b); |
| ... | ... | @@ -451,7 +438,6 @@ test "generic function passed as comptime argument" { |
| 451 | 438 | } |
| 452 | 439 | |
| 453 | 440 | test "return type of generic function is function pointer" { |
| 454 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 455 | 441 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 456 | 442 | |
| 457 | 443 | const S = struct { |
| ... | ... | @@ -464,8 +450,6 @@ test "return type of generic function is function pointer" { |
| 464 | 450 | } |
| 465 | 451 | |
| 466 | 452 | test "coerced function body has inequal value with its uncoerced body" { |
| 467 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 468 | ||
| 469 | 453 | const S = struct { |
| 470 | 454 | const A = B(i32, c); |
| 471 | 455 | fn c() !i32 { |
| ... | ... | @@ -513,7 +497,6 @@ test "union in struct captures argument" { |
| 513 | 497 | |
| 514 | 498 | test "function argument tuple used as struct field" { |
| 515 | 499 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 516 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 517 | 500 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 518 | 501 | |
| 519 | 502 | const S = struct { |
| ... | ... | @@ -546,8 +529,8 @@ test "comptime callconv(.c) function ptr uses comptime type argument" { |
| 546 | 529 | } |
| 547 | 530 | |
| 548 | 531 | test "call generic function with from function called by the generic function" { |
| 549 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 550 | 532 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 533 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 551 | 534 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 552 | 535 | |
| 553 | 536 | const GET = struct { |
test/behavior/globals.zig+2-4| ... | ... | @@ -6,7 +6,6 @@ var pos = [2]f32{ 0.0, 0.0 }; |
| 6 | 6 | test "store to global array" { |
| 7 | 7 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 8 | 8 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 9 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 10 | 9 | |
| 11 | 10 | try expect(pos[1] == 0.0); |
| 12 | 11 | pos = [2]f32{ 0.0, 1.0 }; |
| ... | ... | @@ -15,9 +14,9 @@ test "store to global array" { |
| 15 | 14 | |
| 16 | 15 | var vpos = @Vector(2, f32){ 0.0, 0.0 }; |
| 17 | 16 | test "store to global vector" { |
| 17 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 18 | 18 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 19 | 19 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 20 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 21 | 20 | |
| 22 | 21 | try expect(vpos[1] == 0.0); |
| 23 | 22 | vpos = @Vector(2, f32){ 0.0, 1.0 }; |
| ... | ... | @@ -26,7 +25,6 @@ test "store to global vector" { |
| 26 | 25 | |
| 27 | 26 | test "slices pointing at the same address as global array." { |
| 28 | 27 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 29 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 30 | 28 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 31 | 29 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 32 | 30 | |
| ... | ... | @@ -47,7 +45,6 @@ test "slices pointing at the same address as global array." { |
| 47 | 45 | test "global loads can affect liveness" { |
| 48 | 46 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 49 | 47 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 50 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 51 | 48 | |
| 52 | 49 | const S = struct { |
| 53 | 50 | const ByRef = struct { |
| ... | ... | @@ -188,6 +185,7 @@ test "function pointer field call on global extern struct, conditional on global |
| 188 | 185 | } |
| 189 | 186 | |
| 190 | 187 | test "function pointer field call on global extern struct" { |
| 188 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 191 | 189 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 192 | 190 | |
| 193 | 191 | 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" { |
| 116 | 116 | |
| 117 | 117 | test "if peer expressions inferred optional type" { |
| 118 | 118 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 119 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 120 | 119 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 121 | 120 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 122 | 121 | |
| ... | ... | @@ -135,7 +134,6 @@ test "if peer expressions inferred optional type" { |
| 135 | 134 | |
| 136 | 135 | test "if-else expression with runtime condition result location is inferred optional" { |
| 137 | 136 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 138 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 139 | 137 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 140 | 138 | |
| 141 | 139 | const A = struct { b: u64, c: u64 }; |
| ... | ... | @@ -174,6 +172,8 @@ fn returnTrue() bool { |
| 174 | 172 | } |
| 175 | 173 | |
| 176 | 174 | test "if value shouldn't be load-elided if used later (structs)" { |
| 175 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 176 | ||
| 177 | 177 | const Foo = struct { x: i32 }; |
| 178 | 178 | |
| 179 | 179 | var a = Foo{ .x = 1 }; |
| ... | ... | @@ -191,6 +191,8 @@ test "if value shouldn't be load-elided if used later (structs)" { |
| 191 | 191 | } |
| 192 | 192 | |
| 193 | 193 | test "if value shouldn't be load-elided if used later (optionals)" { |
| 194 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 195 | ||
| 194 | 196 | var a: ?i32 = 1; |
| 195 | 197 | var b: ?i32 = 1; |
| 196 | 198 |
test/behavior/import_c_keywords.zig-1| ... | ... | @@ -27,7 +27,6 @@ extern fn @"break"() Id; |
| 27 | 27 | extern fn an_alias_of_some_non_c_keyword_function() Id; |
| 28 | 28 | |
| 29 | 29 | test "import c keywords" { |
| 30 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 31 | 30 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 32 | 31 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 33 | 32 | 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; |
| 3 | 3 | const builtin = @import("builtin"); |
| 4 | 4 | |
| 5 | 5 | test "inline scalar prongs" { |
| 6 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 7 | 6 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 8 | 7 | |
| 9 | 8 | var x: usize = 0; |
| ... | ... | @@ -18,7 +17,6 @@ test "inline scalar prongs" { |
| 18 | 17 | } |
| 19 | 18 | |
| 20 | 19 | test "inline prong ranges" { |
| 21 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 22 | 20 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 23 | 21 | |
| 24 | 22 | var x: usize = 0; |
| ... | ... | @@ -33,7 +31,6 @@ test "inline prong ranges" { |
| 33 | 31 | |
| 34 | 32 | const E = enum { a, b, c, d }; |
| 35 | 33 | test "inline switch enums" { |
| 36 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 37 | 34 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 38 | 35 | |
| 39 | 36 | var x: E = .a; |
| ... | ... | @@ -46,7 +43,7 @@ test "inline switch enums" { |
| 46 | 43 | |
| 47 | 44 | const U = union(E) { a: void, b: u2, c: u3, d: u4 }; |
| 48 | 45 | test "inline switch unions" { |
| 49 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 46 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 50 | 47 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 51 | 48 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 52 | 49 | |
| ... | ... | @@ -73,7 +70,6 @@ test "inline switch unions" { |
| 73 | 70 | } |
| 74 | 71 | |
| 75 | 72 | test "inline else bool" { |
| 76 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 77 | 73 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 78 | 74 | |
| 79 | 75 | var a = true; |
| ... | ... | @@ -85,7 +81,6 @@ test "inline else bool" { |
| 85 | 81 | } |
| 86 | 82 | |
| 87 | 83 | test "inline else error" { |
| 88 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 89 | 84 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 90 | 85 | |
| 91 | 86 | const Err = error{ a, b, c }; |
| ... | ... | @@ -98,7 +93,6 @@ test "inline else error" { |
| 98 | 93 | } |
| 99 | 94 | |
| 100 | 95 | test "inline else enum" { |
| 101 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 102 | 96 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 103 | 97 | |
| 104 | 98 | const E2 = enum(u8) { a = 2, b = 3, c = 4, d = 5 }; |
| ... | ... | @@ -111,7 +105,7 @@ test "inline else enum" { |
| 111 | 105 | } |
| 112 | 106 | |
| 113 | 107 | test "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; | |
| 115 | 109 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 116 | 110 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| 117 | 111 | |
| ... | ... | @@ -130,7 +124,6 @@ test "inline else int with gaps" { |
| 130 | 124 | } |
| 131 | 125 | |
| 132 | 126 | test "inline else int all values" { |
| 133 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 134 | 127 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 135 | 128 | |
| 136 | 129 | var a: u2 = 0; |
test/behavior/int128.zig-5| ... | ... | @@ -5,7 +5,6 @@ const minInt = std.math.minInt; |
| 5 | 5 | const builtin = @import("builtin"); |
| 6 | 6 | |
| 7 | 7 | test "uint128" { |
| 8 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 9 | 8 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 10 | 9 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 11 | 10 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -25,7 +24,6 @@ test "uint128" { |
| 25 | 24 | } |
| 26 | 25 | |
| 27 | 26 | test "undefined 128 bit int" { |
| 28 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 29 | 27 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 30 | 28 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 31 | 29 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -45,7 +43,6 @@ test "undefined 128 bit int" { |
| 45 | 43 | } |
| 46 | 44 | |
| 47 | 45 | test "int128" { |
| 48 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 49 | 46 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 50 | 47 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 51 | 48 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -68,7 +65,6 @@ test "int128" { |
| 68 | 65 | } |
| 69 | 66 | |
| 70 | 67 | test "truncate int128" { |
| 71 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 72 | 68 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 73 | 69 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 74 | 70 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -92,7 +88,6 @@ test "truncate int128" { |
| 92 | 88 | } |
| 93 | 89 | |
| 94 | 90 | test "shift int128" { |
| 95 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 96 | 91 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 97 | 92 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 98 | 93 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/int_comparison_elision.zig-1| ... | ... | @@ -15,7 +15,6 @@ test "int comparison elision" { |
| 15 | 15 | |
| 16 | 16 | // TODO: support int types > 128 bits wide in other backends |
| 17 | 17 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 18 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 19 | 18 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 20 | 19 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 21 | 20 |
test/behavior/ir_block_deps.zig-1| ... | ... | @@ -18,7 +18,6 @@ fn getErrInt() anyerror!i32 { |
| 18 | 18 | } |
| 19 | 19 | |
| 20 | 20 | test "ir block deps" { |
| 21 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 22 | 21 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 23 | 22 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 24 | 23 |
test/behavior/lower_strlit_to_vector.zig-1| ... | ... | @@ -3,7 +3,6 @@ const builtin = @import("builtin"); |
| 3 | 3 | |
| 4 | 4 | test "strlit to vector" { |
| 5 | 5 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 6 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 7 | 6 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 8 | 7 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 9 | 8 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/math.zig+23-49| ... | ... | @@ -62,11 +62,11 @@ fn assertFalse(b: bool) !void { |
| 62 | 62 | } |
| 63 | 63 | |
| 64 | 64 | test "@clz" { |
| 65 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 66 | 65 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 67 | 66 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 68 | 67 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 69 | 68 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 69 | ||
| 70 | 70 | try testClz(); |
| 71 | 71 | try comptime testClz(); |
| 72 | 72 | } |
| ... | ... | @@ -80,7 +80,6 @@ fn testClz() !void { |
| 80 | 80 | } |
| 81 | 81 | |
| 82 | 82 | test "@clz big ints" { |
| 83 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 84 | 83 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 85 | 84 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 86 | 85 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -100,8 +99,8 @@ fn testOneClz(comptime T: type, x: T) u32 { |
| 100 | 99 | } |
| 101 | 100 | |
| 102 | 101 | test "@clz vectors" { |
| 102 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 103 | 103 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 104 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 105 | 104 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 106 | 105 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 107 | 106 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -146,7 +145,6 @@ fn expectVectorsEqual(a: anytype, b: anytype) !void { |
| 146 | 145 | } |
| 147 | 146 | |
| 148 | 147 | test "@ctz" { |
| 149 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 150 | 148 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 151 | 149 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 152 | 150 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -170,7 +168,7 @@ fn testOneCtz(comptime T: type, x: T) u32 { |
| 170 | 168 | } |
| 171 | 169 | |
| 172 | 170 | test "@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; | |
| 174 | 172 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 175 | 173 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 176 | 174 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -188,8 +186,8 @@ fn testCtz128() !void { |
| 188 | 186 | } |
| 189 | 187 | |
| 190 | 188 | test "@ctz vectors" { |
| 189 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 191 | 190 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 192 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 193 | 191 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 194 | 192 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 195 | 193 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -227,7 +225,6 @@ test "const number literal" { |
| 227 | 225 | const ten = 10; |
| 228 | 226 | |
| 229 | 227 | test "float equality" { |
| 230 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 231 | 228 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 232 | 229 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 233 | 230 | |
| ... | ... | @@ -433,7 +430,6 @@ test "binary not" { |
| 433 | 430 | } |
| 434 | 431 | |
| 435 | 432 | test "binary not big int <= 128 bits" { |
| 436 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 437 | 433 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 438 | 434 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 439 | 435 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -467,7 +463,7 @@ test "binary not big int <= 128 bits" { |
| 467 | 463 | } |
| 468 | 464 | |
| 469 | 465 | test "division" { |
| 470 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 466 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 471 | 467 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 472 | 468 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 473 | 469 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -607,7 +603,6 @@ test "large integer division" { |
| 607 | 603 | } |
| 608 | 604 | |
| 609 | 605 | test "division half-precision floats" { |
| 610 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 611 | 606 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 612 | 607 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 613 | 608 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -694,7 +689,6 @@ fn testUnsignedNegationWrappingEval(x: u16) !void { |
| 694 | 689 | } |
| 695 | 690 | |
| 696 | 691 | test "negation wrapping" { |
| 697 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 698 | 692 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 699 | 693 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 700 | 694 | |
| ... | ... | @@ -747,7 +741,6 @@ fn testShrTrunc(x: u16) !void { |
| 747 | 741 | } |
| 748 | 742 | |
| 749 | 743 | test "f128" { |
| 750 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 751 | 744 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 752 | 745 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 753 | 746 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -776,6 +769,7 @@ fn should_not_be_zero(x: f128) !void { |
| 776 | 769 | } |
| 777 | 770 | |
| 778 | 771 | test "umax wrapped squaring" { |
| 772 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 779 | 773 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 780 | 774 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 781 | 775 | |
| ... | ... | @@ -832,7 +826,6 @@ test "umax wrapped squaring" { |
| 832 | 826 | } |
| 833 | 827 | |
| 834 | 828 | test "128-bit multiplication" { |
| 835 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 836 | 829 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 837 | 830 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 838 | 831 | 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 { |
| 867 | 860 | } |
| 868 | 861 | |
| 869 | 862 | test "@addWithOverflow" { |
| 870 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 871 | 863 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 872 | 864 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 873 | 865 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -886,7 +878,6 @@ test "@addWithOverflow" { |
| 886 | 878 | } |
| 887 | 879 | |
| 888 | 880 | test "@addWithOverflow > 64 bits" { |
| 889 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 890 | 881 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 891 | 882 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 892 | 883 | 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 { |
| 958 | 949 | } |
| 959 | 950 | |
| 960 | 951 | test "basic @mulWithOverflow" { |
| 961 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 952 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 962 | 953 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 963 | 954 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 964 | 955 | |
| ... | ... | @@ -970,7 +961,7 @@ test "basic @mulWithOverflow" { |
| 970 | 961 | } |
| 971 | 962 | |
| 972 | 963 | test "extensive @mulWithOverflow" { |
| 973 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 964 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 974 | 965 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 975 | 966 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 976 | 967 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1010,11 +1001,9 @@ test "extensive @mulWithOverflow" { |
| 1010 | 1001 | } |
| 1011 | 1002 | |
| 1012 | 1003 | test "@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; | |
| 1017 | 1005 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1006 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 1018 | 1007 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1019 | 1008 | |
| 1020 | 1009 | try testMulWithOverflow(u40, 3, 0x55_5555_5555, 0xff_ffff_ffff, 0); |
| ... | ... | @@ -1041,9 +1030,9 @@ test "@mulWithOverflow bitsize > 32" { |
| 1041 | 1030 | } |
| 1042 | 1031 | |
| 1043 | 1032 | test "@mulWithOverflow bitsize 128 bits" { |
| 1033 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1044 | 1034 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 1045 | 1035 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1046 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1047 | 1036 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1048 | 1037 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1049 | 1038 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1068,6 +1057,7 @@ test "@mulWithOverflow bitsize 128 bits" { |
| 1068 | 1057 | } |
| 1069 | 1058 | |
| 1070 | 1059 | test "@mulWithOverflow bitsize 256 bits" { |
| 1060 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1071 | 1061 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 1072 | 1062 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 1073 | 1063 | 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 { |
| 1114 | 1104 | } |
| 1115 | 1105 | |
| 1116 | 1106 | test "@subWithOverflow" { |
| 1117 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1118 | 1107 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1119 | 1108 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1120 | 1109 | |
| ... | ... | @@ -1131,7 +1120,6 @@ test "@subWithOverflow" { |
| 1131 | 1120 | } |
| 1132 | 1121 | |
| 1133 | 1122 | test "@subWithOverflow > 64 bits" { |
| 1134 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1135 | 1123 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1136 | 1124 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1137 | 1125 | 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: |
| 1179 | 1167 | } |
| 1180 | 1168 | |
| 1181 | 1169 | test "@shlWithOverflow" { |
| 1182 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1170 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1183 | 1171 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1184 | 1172 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1185 | 1173 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1198,7 +1186,7 @@ test "@shlWithOverflow" { |
| 1198 | 1186 | } |
| 1199 | 1187 | |
| 1200 | 1188 | test "@shlWithOverflow > 64 bits" { |
| 1201 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1189 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1202 | 1190 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1203 | 1191 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1204 | 1192 | 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 |
| 1267 | 1255 | } |
| 1268 | 1256 | |
| 1269 | 1257 | test "quad hex float literal parsing accurate" { |
| 1270 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1271 | 1258 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1272 | 1259 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1273 | 1260 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1425,8 +1412,8 @@ test "comptime float rem int" { |
| 1425 | 1412 | } |
| 1426 | 1413 | |
| 1427 | 1414 | test "remainder division" { |
| 1415 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1428 | 1416 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1429 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1430 | 1417 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1431 | 1418 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1432 | 1419 | 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 { |
| 1465 | 1452 | |
| 1466 | 1453 | test "float remainder division using @rem" { |
| 1467 | 1454 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1468 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1469 | 1455 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1470 | 1456 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1471 | 1457 | 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 { |
| 1506 | 1492 | } |
| 1507 | 1493 | |
| 1508 | 1494 | test "float modulo division using @mod" { |
| 1495 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1509 | 1496 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1510 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1511 | 1497 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1512 | 1498 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1513 | 1499 | 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 { |
| 1550 | 1536 | |
| 1551 | 1537 | test "@round f16" { |
| 1552 | 1538 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1553 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1554 | 1539 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1555 | 1540 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1556 | 1541 | |
| ... | ... | @@ -1560,7 +1545,6 @@ test "@round f16" { |
| 1560 | 1545 | |
| 1561 | 1546 | test "@round f32/f64" { |
| 1562 | 1547 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1563 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1564 | 1548 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1565 | 1549 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1566 | 1550 | |
| ... | ... | @@ -1577,7 +1561,6 @@ test "@round f32/f64" { |
| 1577 | 1561 | |
| 1578 | 1562 | test "@round f80" { |
| 1579 | 1563 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1580 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1581 | 1564 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1582 | 1565 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1583 | 1566 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| ... | ... | @@ -1589,7 +1572,6 @@ test "@round f80" { |
| 1589 | 1572 | |
| 1590 | 1573 | test "@round f128" { |
| 1591 | 1574 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1592 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1593 | 1575 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1594 | 1576 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1595 | 1577 | 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 { |
| 1606 | 1588 | } |
| 1607 | 1589 | |
| 1608 | 1590 | test "vector integer addition" { |
| 1591 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1609 | 1592 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1610 | 1593 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1611 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1612 | 1594 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1613 | 1595 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1614 | 1596 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1630,7 +1612,6 @@ test "vector integer addition" { |
| 1630 | 1612 | |
| 1631 | 1613 | test "NaN comparison" { |
| 1632 | 1614 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1633 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1634 | 1615 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1635 | 1616 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1636 | 1617 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1648,7 +1629,6 @@ test "NaN comparison" { |
| 1648 | 1629 | |
| 1649 | 1630 | test "NaN comparison f80" { |
| 1650 | 1631 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1651 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1652 | 1632 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1653 | 1633 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1654 | 1634 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1670,9 +1650,9 @@ fn testNanEqNan(comptime F: type) !void { |
| 1670 | 1650 | } |
| 1671 | 1651 | |
| 1672 | 1652 | test "vector comparison" { |
| 1653 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1673 | 1654 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1674 | 1655 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1675 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1676 | 1656 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1677 | 1657 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1678 | 1658 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1703,7 +1683,6 @@ test "compare undefined literal with comptime_int" { |
| 1703 | 1683 | |
| 1704 | 1684 | test "signed zeros are represented properly" { |
| 1705 | 1685 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1706 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1707 | 1686 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1708 | 1687 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1709 | 1688 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1735,7 +1714,6 @@ test "signed zeros are represented properly" { |
| 1735 | 1714 | |
| 1736 | 1715 | test "absFloat" { |
| 1737 | 1716 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1738 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1739 | 1717 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1740 | 1718 | |
| 1741 | 1719 | try testAbsFloat(); |
| ... | ... | @@ -1765,8 +1743,8 @@ test "mod lazy values" { |
| 1765 | 1743 | } |
| 1766 | 1744 | |
| 1767 | 1745 | test "@clz works on both vector and scalar inputs" { |
| 1746 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1768 | 1747 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1769 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1770 | 1748 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1771 | 1749 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1772 | 1750 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1784,7 +1762,6 @@ test "@clz works on both vector and scalar inputs" { |
| 1784 | 1762 | |
| 1785 | 1763 | test "runtime comparison to NaN is comptime-known" { |
| 1786 | 1764 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1787 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1788 | 1765 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1789 | 1766 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1790 | 1767 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1814,7 +1791,6 @@ test "runtime comparison to NaN is comptime-known" { |
| 1814 | 1791 | |
| 1815 | 1792 | test "runtime int comparison to inf is comptime-known" { |
| 1816 | 1793 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1817 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1818 | 1794 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1819 | 1795 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1820 | 1796 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1843,8 +1819,8 @@ test "runtime int comparison to inf is comptime-known" { |
| 1843 | 1819 | } |
| 1844 | 1820 | |
| 1845 | 1821 | test "float divide by zero" { |
| 1822 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1846 | 1823 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1847 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1848 | 1824 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1849 | 1825 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1850 | 1826 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1878,8 +1854,8 @@ test "float divide by zero" { |
| 1878 | 1854 | } |
| 1879 | 1855 | |
| 1880 | 1856 | test "partially-runtime integer vector division would be illegal if vector elements were reordered" { |
| 1857 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1881 | 1858 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1882 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1883 | 1859 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1884 | 1860 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1885 | 1861 | 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 |
| 1907 | 1883 | } |
| 1908 | 1884 | |
| 1909 | 1885 | test "float vector division of comptime zero by runtime nan is nan" { |
| 1886 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1910 | 1887 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1911 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1912 | 1888 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1913 | 1889 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1914 | 1890 | 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" { |
| 1925 | 1901 | } |
| 1926 | 1902 | |
| 1927 | 1903 | test "float vector multiplication of comptime zero by runtime nan is nan" { |
| 1904 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1928 | 1905 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1929 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1930 | 1906 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1931 | 1907 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1932 | 1908 | 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" { |
| 1943 | 1919 | |
| 1944 | 1920 | test "comptime float vector division of zero by nan is nan" { |
| 1945 | 1921 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1946 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1947 | 1922 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1948 | 1923 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1949 | 1924 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1959,7 +1934,6 @@ test "comptime float vector division of zero by nan is nan" { |
| 1959 | 1934 | |
| 1960 | 1935 | test "comptime float vector multiplication of zero by nan is nan" { |
| 1961 | 1936 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1962 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1963 | 1937 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1964 | 1938 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1965 | 1939 | 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; |
| 7 | 7 | |
| 8 | 8 | test "@max" { |
| 9 | 9 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 10 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 11 | 10 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 12 | 11 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 13 | 12 | |
| ... | ... | @@ -28,9 +27,9 @@ test "@max" { |
| 28 | 27 | } |
| 29 | 28 | |
| 30 | 29 | test "@max on vectors" { |
| 30 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 31 | 31 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 32 | 32 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 33 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 34 | 33 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 35 | 34 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 36 | 35 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -61,7 +60,6 @@ test "@max on vectors" { |
| 61 | 60 | } |
| 62 | 61 | |
| 63 | 62 | test "@min" { |
| 64 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 65 | 63 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 66 | 64 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 67 | 65 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -83,8 +81,8 @@ test "@min" { |
| 83 | 81 | } |
| 84 | 82 | |
| 85 | 83 | test "@min for vectors" { |
| 84 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 86 | 85 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 87 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 88 | 86 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 89 | 87 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 90 | 88 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -116,7 +114,6 @@ test "@min for vectors" { |
| 116 | 114 | } |
| 117 | 115 | |
| 118 | 116 | test "@min/max for floats" { |
| 119 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 120 | 117 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 121 | 118 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 122 | 119 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -167,8 +164,8 @@ test "@min/@max more than two arguments" { |
| 167 | 164 | } |
| 168 | 165 | |
| 169 | 166 | test "@min/@max more than two vector arguments" { |
| 167 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 170 | 168 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 171 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 172 | 169 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 173 | 170 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 174 | 171 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -181,7 +178,6 @@ test "@min/@max more than two vector arguments" { |
| 181 | 178 | } |
| 182 | 179 | |
| 183 | 180 | test "@min/@max notices bounds" { |
| 184 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 185 | 181 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 186 | 182 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 187 | 183 | |
| ... | ... | @@ -198,8 +194,8 @@ test "@min/@max notices bounds" { |
| 198 | 194 | } |
| 199 | 195 | |
| 200 | 196 | test "@min/@max notices vector bounds" { |
| 197 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 201 | 198 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 202 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 203 | 199 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 204 | 200 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 205 | 201 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -217,7 +213,6 @@ test "@min/@max notices vector bounds" { |
| 217 | 213 | } |
| 218 | 214 | |
| 219 | 215 | test "@min/@max on comptime_int" { |
| 220 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 221 | 216 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 222 | 217 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 223 | 218 | |
| ... | ... | @@ -231,7 +226,6 @@ test "@min/@max on comptime_int" { |
| 231 | 226 | } |
| 232 | 227 | |
| 233 | 228 | test "@min/@max notices bounds from types" { |
| 234 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 235 | 229 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 236 | 230 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 237 | 231 | |
| ... | ... | @@ -251,8 +245,8 @@ test "@min/@max notices bounds from types" { |
| 251 | 245 | } |
| 252 | 246 | |
| 253 | 247 | test "@min/@max notices bounds from vector types" { |
| 248 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 254 | 249 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 255 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 256 | 250 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 257 | 251 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 258 | 252 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -273,7 +267,6 @@ test "@min/@max notices bounds from vector types" { |
| 273 | 267 | } |
| 274 | 268 | |
| 275 | 269 | test "@min/@max notices bounds from types when comptime-known value is undef" { |
| 276 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 277 | 270 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 278 | 271 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 279 | 272 | 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" { |
| 293 | 286 | } |
| 294 | 287 | |
| 295 | 288 | test "@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; | |
| 296 | 290 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 297 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 298 | 291 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 299 | 292 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 300 | 293 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -333,7 +326,6 @@ test "@min/@max of signed and unsigned runtime integers" { |
| 333 | 326 | } |
| 334 | 327 | |
| 335 | 328 | test "@min resulting in u0" { |
| 336 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 337 | 329 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 338 | 330 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 339 | 331 | |
| ... | ... | @@ -364,8 +356,8 @@ test "@min/@max with runtime signed and unsigned integers of same size" { |
| 364 | 356 | } |
| 365 | 357 | |
| 366 | 358 | test "@min/@max with runtime vectors of signed and unsigned integers of same size" { |
| 359 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 367 | 360 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 368 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 369 | 361 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 370 | 362 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 371 | 363 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
test/behavior/member_func.zig-2| ... | ... | @@ -28,7 +28,6 @@ const HasFuncs = struct { |
| 28 | 28 | |
| 29 | 29 | test "standard field calls" { |
| 30 | 30 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 31 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 32 | 31 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 33 | 32 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 34 | 33 | |
| ... | ... | @@ -72,7 +71,6 @@ test "standard field calls" { |
| 72 | 71 | |
| 73 | 72 | test "@field field calls" { |
| 74 | 73 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 75 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 76 | 74 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 77 | 75 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 78 | 76 |
test/behavior/memcpy.zig+1-4| ... | ... | @@ -4,7 +4,6 @@ const expect = std.testing.expect; |
| 4 | 4 | const assert = std.debug.assert; |
| 5 | 5 | |
| 6 | 6 | test "memcpy and memset intrinsics" { |
| 7 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 8 | 7 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 9 | 8 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 10 | 9 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -26,7 +25,6 @@ fn testMemcpyMemset() !void { |
| 26 | 25 | } |
| 27 | 26 | |
| 28 | 27 | test "@memcpy with both operands single-ptr-to-array, one is null-terminated" { |
| 29 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 30 | 28 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 31 | 29 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 32 | 30 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -47,7 +45,6 @@ fn testMemcpyBothSinglePtrArrayOneIsNullTerminated() !void { |
| 47 | 45 | } |
| 48 | 46 | |
| 49 | 47 | test "@memcpy dest many pointer" { |
| 50 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 51 | 48 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 52 | 49 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 53 | 50 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -70,7 +67,6 @@ fn testMemcpyDestManyPtr() !void { |
| 70 | 67 | } |
| 71 | 68 | |
| 72 | 69 | test "@memcpy C pointer" { |
| 73 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 74 | 70 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 75 | 71 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 76 | 72 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -156,6 +152,7 @@ test "@memcpy zero-bit type with aliasing" { |
| 156 | 152 | } |
| 157 | 153 | |
| 158 | 154 | test "@memcpy with sentinel" { |
| 155 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 159 | 156 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 160 | 157 | |
| 161 | 158 | const S = struct { |
test/behavior/memmove.zig-3| ... | ... | @@ -3,7 +3,6 @@ const builtin = @import("builtin"); |
| 3 | 3 | const expect = std.testing.expect; |
| 4 | 4 | |
| 5 | 5 | test "memmove and memset intrinsics" { |
| 6 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 7 | 6 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 8 | 7 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 9 | 8 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -32,7 +31,6 @@ fn testMemmoveMemset() !void { |
| 32 | 31 | } |
| 33 | 32 | |
| 34 | 33 | test "@memmove with both operands single-ptr-to-array, one is null-terminated" { |
| 35 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 36 | 34 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 37 | 35 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 38 | 36 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -77,7 +75,6 @@ fn testMemmoveBothSinglePtrArrayOneIsNullTerminated() !void { |
| 77 | 75 | } |
| 78 | 76 | |
| 79 | 77 | test "@memmove dest many pointer" { |
| 80 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 81 | 78 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 82 | 79 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 83 | 80 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/memset.zig-7| ... | ... | @@ -3,7 +3,6 @@ const builtin = @import("builtin"); |
| 3 | 3 | const expect = std.testing.expect; |
| 4 | 4 | |
| 5 | 5 | test "@memset on array pointers" { |
| 6 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 7 | 6 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 8 | 7 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 9 | 8 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -32,7 +31,6 @@ fn testMemsetArray() !void { |
| 32 | 31 | } |
| 33 | 32 | |
| 34 | 33 | test "@memset on slices" { |
| 35 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 36 | 34 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 37 | 35 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 38 | 36 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -68,7 +66,6 @@ fn testMemsetSlice() !void { |
| 68 | 66 | } |
| 69 | 67 | |
| 70 | 68 | test "memset with bool element" { |
| 71 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 72 | 69 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 73 | 70 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 74 | 71 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -80,7 +77,6 @@ test "memset with bool element" { |
| 80 | 77 | } |
| 81 | 78 | |
| 82 | 79 | test "memset with 1-byte struct element" { |
| 83 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 84 | 80 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 85 | 81 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 86 | 82 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -94,7 +90,6 @@ test "memset with 1-byte struct element" { |
| 94 | 90 | } |
| 95 | 91 | |
| 96 | 92 | test "memset with 1-byte array element" { |
| 97 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 98 | 93 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 99 | 94 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 100 | 95 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -145,7 +140,6 @@ test "memset with large array element, comptime known" { |
| 145 | 140 | } |
| 146 | 141 | |
| 147 | 142 | test "@memset provides result type" { |
| 148 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 149 | 143 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 150 | 144 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 151 | 145 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -164,7 +158,6 @@ test "@memset provides result type" { |
| 164 | 158 | } |
| 165 | 159 | |
| 166 | 160 | test "zero keys with @memset" { |
| 167 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 168 | 161 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 169 | 162 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 170 | 163 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/muladd.zig+5-9| ... | ... | @@ -4,7 +4,6 @@ const expect = std.testing.expect; |
| 4 | 4 | |
| 5 | 5 | test "@mulAdd" { |
| 6 | 6 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 7 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 8 | 7 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 9 | 8 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 10 | 9 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -32,7 +31,6 @@ fn testMulAdd() !void { |
| 32 | 31 | |
| 33 | 32 | test "@mulAdd f16" { |
| 34 | 33 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 35 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 36 | 34 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 37 | 35 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 38 | 36 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -51,7 +49,6 @@ fn testMulAdd16() !void { |
| 51 | 49 | |
| 52 | 50 | test "@mulAdd f80" { |
| 53 | 51 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 54 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 55 | 52 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 56 | 53 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 57 | 54 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| ... | ... | @@ -71,7 +68,6 @@ fn testMulAdd80() !void { |
| 71 | 68 | |
| 72 | 69 | test "@mulAdd f128" { |
| 73 | 70 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 74 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 75 | 71 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 76 | 72 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 77 | 73 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| ... | ... | @@ -103,9 +99,9 @@ fn vector16() !void { |
| 103 | 99 | } |
| 104 | 100 | |
| 105 | 101 | test "vector f16" { |
| 102 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 106 | 103 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 107 | 104 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 108 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 109 | 105 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 110 | 106 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 111 | 107 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -128,9 +124,9 @@ fn vector32() !void { |
| 128 | 124 | } |
| 129 | 125 | |
| 130 | 126 | test "vector f32" { |
| 127 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 131 | 128 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 132 | 129 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 133 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 134 | 130 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 135 | 131 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 136 | 132 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -153,9 +149,9 @@ fn vector64() !void { |
| 153 | 149 | } |
| 154 | 150 | |
| 155 | 151 | test "vector f64" { |
| 152 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 156 | 153 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 157 | 154 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 158 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 159 | 155 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 160 | 156 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 161 | 157 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -177,9 +173,9 @@ fn vector80() !void { |
| 177 | 173 | } |
| 178 | 174 | |
| 179 | 175 | test "vector f80" { |
| 176 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 180 | 177 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 181 | 178 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 182 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 183 | 179 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 184 | 180 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 185 | 181 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| ... | ... | @@ -203,9 +199,9 @@ fn vector128() !void { |
| 203 | 199 | } |
| 204 | 200 | |
| 205 | 201 | test "vector f128" { |
| 202 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 206 | 203 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 207 | 204 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 208 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 209 | 205 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 210 | 206 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 211 | 207 | 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 { |
| 11 | 11 | const builtin = @import("builtin"); |
| 12 | 12 | |
| 13 | 13 | test "call extern function defined with conflicting type" { |
| 14 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 15 | 14 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 16 | 15 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 17 | 16 | 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); |
| 23 | 23 | |
| 24 | 24 | test "nan memory equality" { |
| 25 | 25 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 26 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 27 | 26 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 28 | 27 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 29 | 28 |
test/behavior/null.zig+2-4| ... | ... | @@ -29,8 +29,8 @@ test "optional type" { |
| 29 | 29 | } |
| 30 | 30 | |
| 31 | 31 | test "test maybe object and get a pointer to the inner value" { |
| 32 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 33 | 32 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 33 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 34 | 34 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 35 | 35 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 36 | 36 | |
| ... | ... | @@ -51,7 +51,6 @@ test "rhs maybe unwrap return" { |
| 51 | 51 | |
| 52 | 52 | test "maybe return" { |
| 53 | 53 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 54 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 55 | 54 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 56 | 55 | |
| 57 | 56 | try maybeReturnImpl(); |
| ... | ... | @@ -140,8 +139,8 @@ test "optional pointer to 0 bit type null value at runtime" { |
| 140 | 139 | } |
| 141 | 140 | |
| 142 | 141 | test "if var maybe pointer" { |
| 143 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 144 | 142 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 143 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 145 | 144 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 146 | 145 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 147 | 146 | |
| ... | ... | @@ -185,7 +184,6 @@ const here_is_a_null_literal = SillyStruct{ .context = null }; |
| 185 | 184 | |
| 186 | 185 | test "unwrap optional which is field of global var" { |
| 187 | 186 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 188 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 189 | 187 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 190 | 188 | |
| 191 | 189 | struct_with_optional.field = null; |
test/behavior/optional.zig+10-12| ... | ... | @@ -59,6 +59,7 @@ fn testNullPtrsEql() !void { |
| 59 | 59 | } |
| 60 | 60 | |
| 61 | 61 | test "optional with zero-bit type" { |
| 62 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 62 | 63 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 63 | 64 | |
| 64 | 65 | const S = struct { |
| ... | ... | @@ -109,7 +110,6 @@ test "optional with zero-bit type" { |
| 109 | 110 | } |
| 110 | 111 | |
| 111 | 112 | test "address of unwrap optional" { |
| 112 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 113 | 113 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 114 | 114 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 115 | 115 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -132,7 +132,6 @@ test "address of unwrap optional" { |
| 132 | 132 | } |
| 133 | 133 | |
| 134 | 134 | test "nested optional field in struct" { |
| 135 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 136 | 135 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 137 | 136 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 138 | 137 | |
| ... | ... | @@ -210,6 +209,7 @@ test "equality compare optionals and non-optionals" { |
| 210 | 209 | } |
| 211 | 210 | |
| 212 | 211 | test "compare optionals with modified payloads" { |
| 212 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 213 | 213 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 214 | 214 | |
| 215 | 215 | var lhs: ?bool = false; |
| ... | ... | @@ -319,7 +319,7 @@ test "assigning to an unwrapped optional field in an inline loop" { |
| 319 | 319 | } |
| 320 | 320 | |
| 321 | 321 | test "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; | |
| 323 | 323 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 324 | 324 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 325 | 325 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -339,7 +339,6 @@ test "coerce an anon struct literal to optional struct" { |
| 339 | 339 | } |
| 340 | 340 | |
| 341 | 341 | test "0-bit child type coerced to optional return ptr result location" { |
| 342 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 343 | 342 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 344 | 343 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 345 | 344 | |
| ... | ... | @@ -365,6 +364,7 @@ test "0-bit child type coerced to optional return ptr result location" { |
| 365 | 364 | } |
| 366 | 365 | |
| 367 | 366 | test "0-bit child type coerced to optional" { |
| 367 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 368 | 368 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 369 | 369 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 370 | 370 | |
| ... | ... | @@ -391,7 +391,7 @@ test "0-bit child type coerced to optional" { |
| 391 | 391 | } |
| 392 | 392 | |
| 393 | 393 | test "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; | |
| 395 | 395 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 396 | 396 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 397 | 397 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -428,8 +428,8 @@ test "array of optional unaligned types" { |
| 428 | 428 | } |
| 429 | 429 | |
| 430 | 430 | test "optional pointer to zero bit optional payload" { |
| 431 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 431 | 432 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 432 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 433 | 433 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 434 | 434 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 435 | 435 | |
| ... | ... | @@ -447,8 +447,8 @@ test "optional pointer to zero bit optional payload" { |
| 447 | 447 | } |
| 448 | 448 | |
| 449 | 449 | test "optional pointer to zero bit error union payload" { |
| 450 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 450 | 451 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 451 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 452 | 452 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 453 | 453 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 454 | 454 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -543,7 +543,6 @@ test "alignment of wrapping an optional payload" { |
| 543 | 543 | } |
| 544 | 544 | |
| 545 | 545 | test "Optional slice size is optimized" { |
| 546 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 547 | 546 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 548 | 547 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 549 | 548 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -556,7 +555,7 @@ test "Optional slice size is optimized" { |
| 556 | 555 | } |
| 557 | 556 | |
| 558 | 557 | test "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; | |
| 560 | 559 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 561 | 560 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 562 | 561 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -574,7 +573,6 @@ test "Optional slice passed to function" { |
| 574 | 573 | } |
| 575 | 574 | |
| 576 | 575 | test "peer type resolution in nested if expressions" { |
| 577 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 578 | 576 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 579 | 577 | |
| 580 | 578 | const Thing = struct { n: i32 }; |
| ... | ... | @@ -623,8 +621,8 @@ test "variable of optional of noreturn" { |
| 623 | 621 | } |
| 624 | 622 | |
| 625 | 623 | test "copied optional doesn't alias source" { |
| 624 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 626 | 625 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 627 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 628 | 626 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 629 | 627 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 630 | 628 | |
| ... | ... | @@ -637,8 +635,8 @@ test "copied optional doesn't alias source" { |
| 637 | 635 | } |
| 638 | 636 | |
| 639 | 637 | test "result location initialization of optional with OPV payload" { |
| 638 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 640 | 639 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 641 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 642 | 640 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 643 | 641 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 644 | 642 | 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" { |
| 120 | 120 | } |
| 121 | 121 | |
| 122 | 122 | test "correct sizeOf and offsets in packed structs" { |
| 123 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 124 | 123 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 125 | 124 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 126 | 125 | |
| ... | ... | @@ -187,7 +186,6 @@ test "correct sizeOf and offsets in packed structs" { |
| 187 | 186 | } |
| 188 | 187 | |
| 189 | 188 | test "nested packed structs" { |
| 190 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 191 | 189 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 192 | 190 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 193 | 191 | |
| ... | ... | @@ -484,7 +482,6 @@ test "load pointer from packed struct" { |
| 484 | 482 | } |
| 485 | 483 | |
| 486 | 484 | test "@intFromPtr on a packed struct field" { |
| 487 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 488 | 485 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 489 | 486 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 490 | 487 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -507,7 +504,6 @@ test "@intFromPtr on a packed struct field" { |
| 507 | 504 | } |
| 508 | 505 | |
| 509 | 506 | test "@intFromPtr on a packed struct field unaligned and nested" { |
| 510 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 511 | 507 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 512 | 508 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 513 | 509 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -617,6 +613,7 @@ test "@intFromPtr on a packed struct field unaligned and nested" { |
| 617 | 613 | } |
| 618 | 614 | |
| 619 | 615 | test "packed struct fields modification" { |
| 616 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 620 | 617 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 621 | 618 | |
| 622 | 619 | // Originally reported at https://github.com/ziglang/zig/issues/16615 |
| ... | ... | @@ -656,9 +653,9 @@ test "optional pointer in packed struct" { |
| 656 | 653 | } |
| 657 | 654 | |
| 658 | 655 | test "nested packed struct field access test" { |
| 656 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 659 | 657 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 660 | 658 | 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 | |
| 662 | 659 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 663 | 660 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 664 | 661 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -777,6 +774,7 @@ test "nested packed struct field access test" { |
| 777 | 774 | } |
| 778 | 775 | |
| 779 | 776 | test "nested packed struct at non-zero offset" { |
| 777 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 780 | 778 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 781 | 779 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 782 | 780 | |
| ... | ... | @@ -915,7 +913,6 @@ test "packed struct passed to callconv(.c) function" { |
| 915 | 913 | } |
| 916 | 914 | |
| 917 | 915 | test "overaligned pointer to packed struct" { |
| 918 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 919 | 916 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 920 | 917 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 921 | 918 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -937,7 +934,7 @@ test "overaligned pointer to packed struct" { |
| 937 | 934 | } |
| 938 | 935 | |
| 939 | 936 | test "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; | |
| 941 | 938 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 942 | 939 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 943 | 940 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -986,8 +983,8 @@ test "store undefined to packed result location" { |
| 986 | 983 | try expectEqual(x, s.x); |
| 987 | 984 | } |
| 988 | 985 | |
| 986 | // Originally reported at https://github.com/ziglang/zig/issues/9914 | |
| 989 | 987 | test "bitcast back and forth" { |
| 990 | // Originally reported at https://github.com/ziglang/zig/issues/9914 | |
| 991 | 988 | const S = packed struct { one: u6, two: u1 }; |
| 992 | 989 | const s = S{ .one = 0b110101, .two = 0b1 }; |
| 993 | 990 | const u: u7 = @bitCast(s); |
| ... | ... | @@ -996,8 +993,9 @@ test "bitcast back and forth" { |
| 996 | 993 | try expect(s.two == s2.two); |
| 997 | 994 | } |
| 998 | 995 | |
| 996 | // Originally reported at https://github.com/ziglang/zig/issues/14200 | |
| 999 | 997 | test "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; | |
| 1001 | 999 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1002 | 1000 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 1003 | 1001 | |
| ... | ... | @@ -1015,8 +1013,8 @@ test "field access of packed struct smaller than its abi size inside struct init |
| 1015 | 1013 | try expect(@as(i2, 1) == s.ps.y); |
| 1016 | 1014 | } |
| 1017 | 1015 | |
| 1016 | // Originally reported at https://github.com/ziglang/zig/issues/14632 | |
| 1018 | 1017 | test "modify nested packed struct aligned field" { |
| 1019 | // Originally reported at https://github.com/ziglang/zig/issues/14632 | |
| 1020 | 1018 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1021 | 1019 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 1022 | 1020 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| ... | ... | @@ -1045,10 +1043,10 @@ test "modify nested packed struct aligned field" { |
| 1045 | 1043 | try std.testing.expect(!opts.baz); |
| 1046 | 1044 | } |
| 1047 | 1045 | |
| 1046 | // Originally reported at https://github.com/ziglang/zig/issues/9674 | |
| 1048 | 1047 | test "assigning packed struct inside another packed struct" { |
| 1048 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1049 | 1049 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1050 | ||
| 1051 | // Originally reported at https://github.com/ziglang/zig/issues/9674 | |
| 1052 | 1050 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1053 | 1051 | |
| 1054 | 1052 | const S = struct { |
| ... | ... | @@ -1078,7 +1076,6 @@ test "assigning packed struct inside another packed struct" { |
| 1078 | 1076 | } |
| 1079 | 1077 | |
| 1080 | 1078 | test "packed struct used as part of anon decl name" { |
| 1081 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1082 | 1079 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1083 | 1080 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1084 | 1081 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1107,7 +1104,13 @@ test "packed struct acts as a namespace" { |
| 1107 | 1104 | } |
| 1108 | 1105 | |
| 1109 | 1106 | test "pointer loaded correctly from packed struct" { |
| 1107 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1108 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1110 | 1109 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1110 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; | |
| 1111 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 1112 | ||
| 1113 | if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // crashes MSVC | |
| 1111 | 1114 | |
| 1112 | 1115 | const RAM = struct { |
| 1113 | 1116 | data: [0xFFFF + 1]u8, |
| ... | ... | @@ -1135,12 +1138,6 @@ test "pointer loaded correctly from packed struct" { |
| 1135 | 1138 | } |
| 1136 | 1139 | } |
| 1137 | 1140 | }; |
| 1138 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1139 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1140 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; | |
| 1141 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 1142 | ||
| 1143 | if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // crashes MSVC | |
| 1144 | 1141 | |
| 1145 | 1142 | var ram = try RAM.new(); |
| 1146 | 1143 | var cpu = try CPU.new(&ram); |
| ... | ... | @@ -1149,7 +1146,7 @@ test "pointer loaded correctly from packed struct" { |
| 1149 | 1146 | } |
| 1150 | 1147 | |
| 1151 | 1148 | test "assignment to non-byte-aligned field in packed struct" { |
| 1152 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1149 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1153 | 1150 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1154 | 1151 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1155 | 1152 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1170,7 +1167,6 @@ test "assignment to non-byte-aligned field in packed struct" { |
| 1170 | 1167 | } |
| 1171 | 1168 | |
| 1172 | 1169 | test "packed struct field pointer aligned properly" { |
| 1173 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1174 | 1170 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1175 | 1171 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1176 | 1172 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1189,7 +1185,7 @@ test "packed struct field pointer aligned properly" { |
| 1189 | 1185 | } |
| 1190 | 1186 | |
| 1191 | 1187 | test "load flag from packed struct in union" { |
| 1192 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1188 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1193 | 1189 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1194 | 1190 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1195 | 1191 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1314,6 +1310,7 @@ test "packed struct equality" { |
| 1314 | 1310 | } |
| 1315 | 1311 | |
| 1316 | 1312 | test "packed struct equality ignores padding bits" { |
| 1313 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1317 | 1314 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 1318 | 1315 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1319 | 1316 | |
| ... | ... | @@ -1325,6 +1322,8 @@ test "packed struct equality ignores padding bits" { |
| 1325 | 1322 | } |
| 1326 | 1323 | |
| 1327 | 1324 | test "packed struct with signed field" { |
| 1325 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1326 | ||
| 1328 | 1327 | var s: packed struct { |
| 1329 | 1328 | a: i2, |
| 1330 | 1329 | b: u6, |
| ... | ... | @@ -1335,6 +1334,7 @@ test "packed struct with signed field" { |
| 1335 | 1334 | } |
| 1336 | 1335 | |
| 1337 | 1336 | test "assign packed struct initialized with RLS to packed struct literal field" { |
| 1337 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1338 | 1338 | if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isWasm()) return error.SkipZigTest; |
| 1339 | 1339 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1340 | 1340 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1352,6 +1352,7 @@ test "assign packed struct initialized with RLS to packed struct literal field" |
| 1352 | 1352 | } |
| 1353 | 1353 | |
| 1354 | 1354 | test "byte-aligned packed relocation" { |
| 1355 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1355 | 1356 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 1356 | 1357 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; |
| 1357 | 1358 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1366,6 +1367,7 @@ test "byte-aligned packed relocation" { |
| 1366 | 1367 | } |
| 1367 | 1368 | |
| 1368 | 1369 | test "packed struct store of comparison result" { |
| 1370 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1369 | 1371 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1370 | 1372 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 1371 | 1373 |
test/behavior/packed-union.zig+3-3| ... | ... | @@ -99,10 +99,10 @@ fn testFlagsInPackedUnionAtOffset() !void { |
| 99 | 99 | try expectEqual(false, test_bits.adv_flags.adv.flags.enable_2); |
| 100 | 100 | } |
| 101 | 101 | |
| 102 | // Originally reported at https://github.com/ziglang/zig/issues/16581 | |
| 102 | 103 | test "packed union in packed struct" { |
| 104 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 103 | 105 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 104 | ||
| 105 | // Originally reported at https://github.com/ziglang/zig/issues/16581 | |
| 106 | 106 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 107 | 107 | |
| 108 | 108 | try testPackedUnionInPackedStruct(); |
| ... | ... | @@ -136,7 +136,7 @@ fn testPackedUnionInPackedStruct() !void { |
| 136 | 136 | } |
| 137 | 137 | |
| 138 | 138 | test "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; | |
| 140 | 140 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 141 | 141 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 142 | 142 | 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; |
| 5 | 5 | const native_endian = builtin.cpu.arch.endian(); |
| 6 | 6 | |
| 7 | 7 | test "packed struct explicit backing integer" { |
| 8 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 9 | 8 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 10 | 9 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 11 | 10 |
test/behavior/pointers.zig+1-12| ... | ... | @@ -18,7 +18,6 @@ fn testDerefPtr() !void { |
| 18 | 18 | } |
| 19 | 19 | |
| 20 | 20 | test "pointer-integer arithmetic" { |
| 21 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 22 | 21 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 23 | 22 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 24 | 23 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -232,7 +231,6 @@ test "peer type resolution with C pointer and const pointer" { |
| 232 | 231 | |
| 233 | 232 | test "implicit casting between C pointer and optional non-C pointer" { |
| 234 | 233 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 235 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 236 | 234 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 237 | 235 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 238 | 236 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -248,8 +246,8 @@ test "implicit casting between C pointer and optional non-C pointer" { |
| 248 | 246 | } |
| 249 | 247 | |
| 250 | 248 | test "implicit cast error unions with non-optional to optional pointer" { |
| 249 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 251 | 250 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 252 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 253 | 251 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 254 | 252 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 255 | 253 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -298,7 +296,6 @@ test "allowzero pointer and slice" { |
| 298 | 296 | |
| 299 | 297 | test "assign null directly to C pointer and test null equality" { |
| 300 | 298 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 301 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 302 | 299 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 303 | 300 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 304 | 301 | |
| ... | ... | @@ -366,7 +363,6 @@ test "array initialization types" { |
| 366 | 363 | } |
| 367 | 364 | |
| 368 | 365 | test "null terminated pointer" { |
| 369 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 370 | 366 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 371 | 367 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 372 | 368 | |
| ... | ... | @@ -384,7 +380,6 @@ test "null terminated pointer" { |
| 384 | 380 | } |
| 385 | 381 | |
| 386 | 382 | test "allow any sentinel" { |
| 387 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 388 | 383 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 389 | 384 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 390 | 385 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -401,7 +396,6 @@ test "allow any sentinel" { |
| 401 | 396 | } |
| 402 | 397 | |
| 403 | 398 | test "pointer sentinel with enums" { |
| 404 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 405 | 399 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 406 | 400 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 407 | 401 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -515,7 +509,6 @@ test "@intFromPtr on null optional at comptime" { |
| 515 | 509 | } |
| 516 | 510 | |
| 517 | 511 | test "indexing array with sentinel returns correct type" { |
| 518 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 519 | 512 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 520 | 513 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 521 | 514 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -525,7 +518,6 @@ test "indexing array with sentinel returns correct type" { |
| 525 | 518 | } |
| 526 | 519 | |
| 527 | 520 | test "element pointer to slice" { |
| 528 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 529 | 521 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 530 | 522 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 531 | 523 | |
| ... | ... | @@ -548,7 +540,6 @@ test "element pointer to slice" { |
| 548 | 540 | } |
| 549 | 541 | |
| 550 | 542 | test "element pointer arithmetic to slice" { |
| 551 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 552 | 543 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 553 | 544 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 554 | 545 | |
| ... | ... | @@ -604,7 +595,6 @@ test "pointer to constant decl preserves alignment" { |
| 604 | 595 | |
| 605 | 596 | test "ptrCast comptime known slice to C pointer" { |
| 606 | 597 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 607 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 608 | 598 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 609 | 599 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 610 | 600 | |
| ... | ... | @@ -625,7 +615,6 @@ test "pointer alignment and element type include call expression" { |
| 625 | 615 | } |
| 626 | 616 | |
| 627 | 617 | test "pointer to array has explicit alignment" { |
| 628 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 629 | 618 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 630 | 619 | |
| 631 | 620 | const S = struct { |
test/behavior/popcount.zig+2-3| ... | ... | @@ -4,7 +4,6 @@ const expect = std.testing.expect; |
| 4 | 4 | const expectEqual = std.testing.expectEqual; |
| 5 | 5 | |
| 6 | 6 | test "@popCount integers" { |
| 7 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 8 | 7 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 9 | 8 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 10 | 9 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -15,7 +14,7 @@ test "@popCount integers" { |
| 15 | 14 | } |
| 16 | 15 | |
| 17 | 16 | test "@popCount 128bit integer" { |
| 18 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 17 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 19 | 18 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 20 | 19 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 21 | 20 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -77,8 +76,8 @@ fn testPopCountIntegers() !void { |
| 77 | 76 | } |
| 78 | 77 | |
| 79 | 78 | test "@popCount vectors" { |
| 79 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 80 | 80 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 81 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 82 | 81 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 83 | 82 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 84 | 83 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/ptrcast.zig-19| ... | ... | @@ -22,7 +22,6 @@ fn testReinterpretBytesAsInteger() !void { |
| 22 | 22 | |
| 23 | 23 | test "reinterpret an array over multiple elements, with no well-defined layout" { |
| 24 | 24 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 25 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 26 | 25 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 27 | 26 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 28 | 27 | |
| ... | ... | @@ -56,7 +55,6 @@ fn testReinterpretStructWrappedBytesAsInteger() !void { |
| 56 | 55 | } |
| 57 | 56 | |
| 58 | 57 | test "reinterpret bytes of an array into an extern struct" { |
| 59 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 60 | 58 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 61 | 59 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 62 | 60 | |
| ... | ... | @@ -130,7 +128,6 @@ fn testReinterpretOverAlignedExternStructAsExternStruct() !void { |
| 130 | 128 | |
| 131 | 129 | test "lower reinterpreted comptime field ptr (with under-aligned fields)" { |
| 132 | 130 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 133 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 134 | 131 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 135 | 132 | |
| 136 | 133 | // Test lowering a field ptr |
| ... | ... | @@ -152,7 +149,6 @@ test "lower reinterpreted comptime field ptr (with under-aligned fields)" { |
| 152 | 149 | |
| 153 | 150 | test "lower reinterpreted comptime field ptr" { |
| 154 | 151 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 155 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 156 | 152 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 157 | 153 | |
| 158 | 154 | // Test lowering a field ptr |
| ... | ... | @@ -174,7 +170,6 @@ test "lower reinterpreted comptime field ptr" { |
| 174 | 170 | |
| 175 | 171 | test "reinterpret struct field at comptime" { |
| 176 | 172 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 177 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 178 | 173 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 179 | 174 | |
| 180 | 175 | const numNative = comptime Bytes.init(0x12345678); |
| ... | ... | @@ -232,7 +227,6 @@ test "ptrcast of const integer has the correct object size" { |
| 232 | 227 | test "implicit optional pointer to optional anyopaque pointer" { |
| 233 | 228 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 234 | 229 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 235 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 236 | 230 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 237 | 231 | |
| 238 | 232 | var buf: [4]u8 = "aoeu".*; |
| ... | ... | @@ -244,7 +238,6 @@ test "implicit optional pointer to optional anyopaque pointer" { |
| 244 | 238 | |
| 245 | 239 | test "@ptrCast slice to slice" { |
| 246 | 240 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 247 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 248 | 241 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 249 | 242 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 250 | 243 | |
| ... | ... | @@ -262,7 +255,6 @@ test "@ptrCast slice to slice" { |
| 262 | 255 | |
| 263 | 256 | test "comptime @ptrCast a subset of an array, then write through it" { |
| 264 | 257 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 265 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 266 | 258 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 267 | 259 | |
| 268 | 260 | comptime { |
| ... | ... | @@ -354,7 +346,6 @@ test "@ptrCast restructures sliced comptime-only array" { |
| 354 | 346 | |
| 355 | 347 | test "@ptrCast slice multiplying length" { |
| 356 | 348 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 357 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 358 | 349 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 359 | 350 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 360 | 351 | |
| ... | ... | @@ -372,7 +363,6 @@ test "@ptrCast slice multiplying length" { |
| 372 | 363 | |
| 373 | 364 | test "@ptrCast array pointer to slice multiplying length" { |
| 374 | 365 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 375 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 376 | 366 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 377 | 367 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 378 | 368 | |
| ... | ... | @@ -390,7 +380,6 @@ test "@ptrCast array pointer to slice multiplying length" { |
| 390 | 380 | |
| 391 | 381 | test "@ptrCast slice dividing length" { |
| 392 | 382 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 393 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 394 | 383 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 395 | 384 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 396 | 385 | |
| ... | ... | @@ -408,7 +397,6 @@ test "@ptrCast slice dividing length" { |
| 408 | 397 | |
| 409 | 398 | test "@ptrCast array pointer to slice dividing length" { |
| 410 | 399 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 411 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 412 | 400 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 413 | 401 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 414 | 402 | |
| ... | ... | @@ -426,7 +414,6 @@ test "@ptrCast array pointer to slice dividing length" { |
| 426 | 414 | |
| 427 | 415 | test "@ptrCast slice with complex length increase" { |
| 428 | 416 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 429 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 430 | 417 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 431 | 418 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 432 | 419 | |
| ... | ... | @@ -447,7 +434,6 @@ test "@ptrCast slice with complex length increase" { |
| 447 | 434 | |
| 448 | 435 | test "@ptrCast array pointer to slice with complex length increase" { |
| 449 | 436 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 450 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 451 | 437 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 452 | 438 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 453 | 439 | |
| ... | ... | @@ -468,7 +454,6 @@ test "@ptrCast array pointer to slice with complex length increase" { |
| 468 | 454 | |
| 469 | 455 | test "@ptrCast slice with complex length decrease" { |
| 470 | 456 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 471 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 472 | 457 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 473 | 458 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 474 | 459 | |
| ... | ... | @@ -489,7 +474,6 @@ test "@ptrCast slice with complex length decrease" { |
| 489 | 474 | |
| 490 | 475 | test "@ptrCast array pointer to slice with complex length decrease" { |
| 491 | 476 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 492 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 493 | 477 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 494 | 478 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 495 | 479 | |
| ... | ... | @@ -510,7 +494,6 @@ test "@ptrCast array pointer to slice with complex length decrease" { |
| 510 | 494 | |
| 511 | 495 | test "@ptrCast slice of zero-bit type to different slice" { |
| 512 | 496 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 513 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 514 | 497 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 515 | 498 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 516 | 499 | |
| ... | ... | @@ -530,7 +513,6 @@ test "@ptrCast slice of zero-bit type to different slice" { |
| 530 | 513 | |
| 531 | 514 | test "@ptrCast single-item pointer to slice with length 1" { |
| 532 | 515 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 533 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 534 | 516 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 535 | 517 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 536 | 518 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -552,7 +534,6 @@ test "@ptrCast single-item pointer to slice with length 1" { |
| 552 | 534 | |
| 553 | 535 | test "@ptrCast single-item pointer to slice of bytes" { |
| 554 | 536 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 555 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 556 | 537 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 557 | 538 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 558 | 539 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
test/behavior/ptrfromint.zig-3| ... | ... | @@ -17,7 +17,6 @@ fn addressToFunction() void { |
| 17 | 17 | |
| 18 | 18 | test "mutate through ptr initialized with constant ptrFromInt value" { |
| 19 | 19 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 20 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 21 | 20 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 22 | 21 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 23 | 22 | |
| ... | ... | @@ -35,7 +34,6 @@ fn forceCompilerAnalyzeBranchHardCodedPtrDereference(x: bool) void { |
| 35 | 34 | |
| 36 | 35 | test "@ptrFromInt creates null pointer" { |
| 37 | 36 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 38 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 39 | 37 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 40 | 38 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 41 | 39 | |
| ... | ... | @@ -45,7 +43,6 @@ test "@ptrFromInt creates null pointer" { |
| 45 | 43 | |
| 46 | 44 | test "@ptrFromInt creates allowzero zero pointer" { |
| 47 | 45 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 48 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 49 | 46 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 50 | 47 | |
| 51 | 48 | 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; |
| 6 | 6 | var ok: bool = false; |
| 7 | 7 | test "reference a variable in an if after an if in the 2nd switch prong" { |
| 8 | 8 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 9 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 10 | 9 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 11 | 10 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 12 | 11 |
test/behavior/reflection.zig-1| ... | ... | @@ -26,7 +26,6 @@ fn dummy(a: bool, b: i32, c: f32) i32 { |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | 28 | test "reflection: @field" { |
| 29 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 30 | 29 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 31 | 30 | |
| 32 | 31 | var f = Foo{ |
test/behavior/return_address.zig+1-1| ... | ... | @@ -6,7 +6,7 @@ fn retAddr() usize { |
| 6 | 6 | } |
| 7 | 7 | |
| 8 | 8 | test "return address" { |
| 9 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 9 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 10 | 10 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 11 | 11 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 12 | 12 | 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; |
| 5 | 5 | const expect = std.testing.expect; |
| 6 | 6 | |
| 7 | 7 | test "saturating add" { |
| 8 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 8 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 9 | 9 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 10 | 10 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 11 | 11 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -52,8 +52,8 @@ test "saturating add" { |
| 52 | 52 | } |
| 53 | 53 | |
| 54 | 54 | test "saturating add 128bit" { |
| 55 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 55 | 56 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 56 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 57 | 57 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 58 | 58 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 59 | 59 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -79,7 +79,7 @@ test "saturating add 128bit" { |
| 79 | 79 | } |
| 80 | 80 | |
| 81 | 81 | test "saturating subtraction" { |
| 82 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 82 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 83 | 83 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 84 | 84 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 85 | 85 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -125,8 +125,8 @@ test "saturating subtraction" { |
| 125 | 125 | } |
| 126 | 126 | |
| 127 | 127 | test "saturating subtraction 128bit" { |
| 128 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 128 | 129 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 129 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 130 | 130 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 131 | 131 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 132 | 132 | 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 { |
| 158 | 158 | } |
| 159 | 159 | |
| 160 | 160 | test "saturating multiplication <= 32 bits" { |
| 161 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 162 | 161 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 163 | 162 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 164 | 163 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -229,6 +228,7 @@ test "saturating multiplication <= 32 bits" { |
| 229 | 228 | } |
| 230 | 229 | |
| 231 | 230 | test "saturating mul i64, i128" { |
| 231 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 232 | 232 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 233 | 233 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 234 | 234 | |
| ... | ... | @@ -256,8 +256,8 @@ test "saturating mul i64, i128" { |
| 256 | 256 | } |
| 257 | 257 | |
| 258 | 258 | test "saturating multiplication" { |
| 259 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 259 | 260 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 260 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 261 | 261 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 262 | 262 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 263 | 263 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -295,7 +295,7 @@ test "saturating multiplication" { |
| 295 | 295 | } |
| 296 | 296 | |
| 297 | 297 | test "saturating shift-left" { |
| 298 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 298 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 299 | 299 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 300 | 300 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 301 | 301 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -340,6 +340,7 @@ test "saturating shift-left" { |
| 340 | 340 | } |
| 341 | 341 | |
| 342 | 342 | test "saturating shift-left large rhs" { |
| 343 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 343 | 344 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 344 | 345 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 345 | 346 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -357,7 +358,7 @@ test "saturating shift-left large rhs" { |
| 357 | 358 | } |
| 358 | 359 | |
| 359 | 360 | test "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; | |
| 361 | 362 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 362 | 363 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 363 | 364 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/select.zig+3-2| ... | ... | @@ -4,9 +4,9 @@ const mem = std.mem; |
| 4 | 4 | const expect = std.testing.expect; |
| 5 | 5 | |
| 6 | 6 | test "@select vectors" { |
| 7 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 7 | 8 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 8 | 9 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 9 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 10 | 10 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 11 | 11 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 12 | 12 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -35,9 +35,9 @@ fn selectVectors() !void { |
| 35 | 35 | } |
| 36 | 36 | |
| 37 | 37 | test "@select arrays" { |
| 38 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 38 | 39 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 39 | 40 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 40 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 41 | 41 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 42 | 42 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 43 | 43 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -66,6 +66,7 @@ fn selectArrays() !void { |
| 66 | 66 | } |
| 67 | 67 | |
| 68 | 68 | test "@select compare result" { |
| 69 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 69 | 70 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 70 | 71 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 71 | 72 | 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; |
| 5 | 5 | const expectEqual = std.testing.expectEqual; |
| 6 | 6 | |
| 7 | 7 | test "@shuffle int" { |
| 8 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 8 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 9 | 9 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 10 | 10 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 11 | 11 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -50,8 +50,8 @@ test "@shuffle int" { |
| 50 | 50 | } |
| 51 | 51 | |
| 52 | 52 | test "@shuffle int strange sizes" { |
| 53 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 53 | 54 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 54 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 55 | 55 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 56 | 56 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 57 | 57 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -132,8 +132,8 @@ fn testShuffle( |
| 132 | 132 | } |
| 133 | 133 | |
| 134 | 134 | test "@shuffle bool 1" { |
| 135 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 135 | 136 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 136 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 137 | 137 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 138 | 138 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 139 | 139 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -155,8 +155,8 @@ test "@shuffle bool 1" { |
| 155 | 155 | } |
| 156 | 156 | |
| 157 | 157 | test "@shuffle bool 2" { |
| 158 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 158 | 159 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 159 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 160 | 160 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 161 | 161 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 162 | 162 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
test/behavior/sizeof_and_typeof.zig-3| ... | ... | @@ -270,7 +270,6 @@ test "bitSizeOf comptime_int" { |
| 270 | 270 | } |
| 271 | 271 | |
| 272 | 272 | test "runtime instructions inside typeof in comptime only scope" { |
| 273 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 274 | 273 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 275 | 274 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 276 | 275 | |
| ... | ... | @@ -326,7 +325,6 @@ test "lazy abi size used in comparison" { |
| 326 | 325 | } |
| 327 | 326 | |
| 328 | 327 | test "peer type resolution with @TypeOf doesn't trigger dependency loop check" { |
| 329 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 330 | 328 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 331 | 329 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 332 | 330 | |
| ... | ... | @@ -437,7 +435,6 @@ test "Peer resolution of extern function calls in @TypeOf" { |
| 437 | 435 | } |
| 438 | 436 | |
| 439 | 437 | test "Extern function calls, dereferences and field access in @TypeOf" { |
| 440 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 441 | 438 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 442 | 439 | |
| 443 | 440 | const Test = struct { |
test/behavior/slice.zig+2-22| ... | ... | @@ -211,7 +211,6 @@ test "comptime pointer cast array and then slice" { |
| 211 | 211 | } |
| 212 | 212 | |
| 213 | 213 | test "slicing zero length array" { |
| 214 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 215 | 214 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 216 | 215 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 217 | 216 | |
| ... | ... | @@ -273,7 +272,6 @@ test "result location zero sized array inside struct field implicit cast to slic |
| 273 | 272 | } |
| 274 | 273 | |
| 275 | 274 | test "runtime safety lets us slice from len..len" { |
| 276 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 277 | 275 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 278 | 276 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 279 | 277 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -287,7 +285,6 @@ fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 { |
| 287 | 285 | } |
| 288 | 286 | |
| 289 | 287 | test "C pointer" { |
| 290 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 291 | 288 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 292 | 289 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 293 | 290 | |
| ... | ... | @@ -299,7 +296,6 @@ test "C pointer" { |
| 299 | 296 | } |
| 300 | 297 | |
| 301 | 298 | test "C pointer slice access" { |
| 302 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 303 | 299 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 304 | 300 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 305 | 301 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -331,7 +327,6 @@ fn sliceSum(comptime q: []const u8) i32 { |
| 331 | 327 | } |
| 332 | 328 | |
| 333 | 329 | test "slice type with custom alignment" { |
| 334 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 335 | 330 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 336 | 331 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 337 | 332 | |
| ... | ... | @@ -390,7 +385,6 @@ test "empty array to slice" { |
| 390 | 385 | } |
| 391 | 386 | |
| 392 | 387 | test "@ptrCast slice to pointer" { |
| 393 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 394 | 388 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 395 | 389 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 396 | 390 | |
| ... | ... | @@ -445,7 +439,6 @@ test "slice multi-pointer without end" { |
| 445 | 439 | } |
| 446 | 440 | |
| 447 | 441 | test "slice syntax resulting in pointer-to-array" { |
| 448 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 449 | 442 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 450 | 443 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 451 | 444 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -665,7 +658,6 @@ test "slice syntax resulting in pointer-to-array" { |
| 665 | 658 | } |
| 666 | 659 | |
| 667 | 660 | test "slice pointer-to-array null terminated" { |
| 668 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 669 | 661 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 670 | 662 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 671 | 663 | |
| ... | ... | @@ -718,7 +710,7 @@ test "slice pointer-to-array zero length" { |
| 718 | 710 | } |
| 719 | 711 | |
| 720 | 712 | test "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; | |
| 722 | 714 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 723 | 715 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 724 | 716 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -812,7 +804,6 @@ test "slice sentinel access at comptime" { |
| 812 | 804 | } |
| 813 | 805 | |
| 814 | 806 | test "slicing array with sentinel as end index" { |
| 815 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 816 | 807 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 817 | 808 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 818 | 809 | |
| ... | ... | @@ -831,7 +822,6 @@ test "slicing array with sentinel as end index" { |
| 831 | 822 | } |
| 832 | 823 | |
| 833 | 824 | test "slicing slice with sentinel as end index" { |
| 834 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 835 | 825 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 836 | 826 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 837 | 827 | |
| ... | ... | @@ -888,7 +878,7 @@ test "slice field ptr var" { |
| 888 | 878 | } |
| 889 | 879 | |
| 890 | 880 | test "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; | |
| 892 | 882 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 893 | 883 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 894 | 884 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -929,7 +919,6 @@ test "slice with dereferenced value" { |
| 929 | 919 | } |
| 930 | 920 | |
| 931 | 921 | test "empty slice ptr is non null" { |
| 932 | if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest; // TODO | |
| 933 | 922 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // Test assumes `undefined` is non-zero |
| 934 | 923 | |
| 935 | 924 | { |
| ... | ... | @@ -947,7 +936,6 @@ test "empty slice ptr is non null" { |
| 947 | 936 | } |
| 948 | 937 | |
| 949 | 938 | test "slice decays to many pointer" { |
| 950 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 951 | 939 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 952 | 940 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 953 | 941 | |
| ... | ... | @@ -957,7 +945,6 @@ test "slice decays to many pointer" { |
| 957 | 945 | } |
| 958 | 946 | |
| 959 | 947 | test "write through pointer to optional slice arg" { |
| 960 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 961 | 948 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 962 | 949 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 963 | 950 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -977,7 +964,6 @@ test "write through pointer to optional slice arg" { |
| 977 | 964 | } |
| 978 | 965 | |
| 979 | 966 | test "modify slice length at comptime" { |
| 980 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 981 | 967 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 982 | 968 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 983 | 969 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -994,7 +980,6 @@ test "modify slice length at comptime" { |
| 994 | 980 | } |
| 995 | 981 | |
| 996 | 982 | test "slicing zero length array field of struct" { |
| 997 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 998 | 983 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 999 | 984 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1000 | 985 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1010,7 +995,6 @@ test "slicing zero length array field of struct" { |
| 1010 | 995 | } |
| 1011 | 996 | |
| 1012 | 997 | test "slicing slices gives correct result" { |
| 1013 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1014 | 998 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1015 | 999 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1016 | 1000 | |
| ... | ... | @@ -1024,7 +1008,6 @@ test "slicing slices gives correct result" { |
| 1024 | 1008 | } |
| 1025 | 1009 | |
| 1026 | 1010 | test "get address of element of zero-sized slice" { |
| 1027 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1028 | 1011 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1029 | 1012 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1030 | 1013 | |
| ... | ... | @@ -1037,7 +1020,6 @@ test "get address of element of zero-sized slice" { |
| 1037 | 1020 | } |
| 1038 | 1021 | |
| 1039 | 1022 | test "sentinel-terminated 0-length slices" { |
| 1040 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1041 | 1023 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1042 | 1024 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1043 | 1025 | |
| ... | ... | @@ -1058,8 +1040,6 @@ test "sentinel-terminated 0-length slices" { |
| 1058 | 1040 | } |
| 1059 | 1041 | |
| 1060 | 1042 | test "peer slices keep abi alignment with empty struct" { |
| 1061 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 1062 | ||
| 1063 | 1043 | var cond: bool = undefined; |
| 1064 | 1044 | cond = false; |
| 1065 | 1045 | const slice = if (cond) &[1]u32{42} else &.{}; |
test/behavior/src.zig-1| ... | ... | @@ -16,7 +16,6 @@ const expect = std.testing.expect; |
| 16 | 16 | const expectEqualStrings = std.testing.expectEqualStrings; |
| 17 | 17 | |
| 18 | 18 | test "@src" { |
| 19 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 20 | 19 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 21 | 20 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 22 | 21 | 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); |
| 6 | 6 | const ptr_tag_name: [*:0]const u8 = tag_name; |
| 7 | 7 | |
| 8 | 8 | test "@tagName() returns a string literal" { |
| 9 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 10 | 9 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 11 | 10 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 12 | 11 | |
| ... | ... | @@ -20,7 +19,6 @@ const error_name = @errorName(TestError.TestErrorCode); |
| 20 | 19 | const ptr_error_name: [*:0]const u8 = error_name; |
| 21 | 20 | |
| 22 | 21 | test "@errorName() returns a string literal" { |
| 23 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 24 | 22 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 25 | 23 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 26 | 24 | |
| ... | ... | @@ -34,7 +32,6 @@ const type_name = @typeName(TestType); |
| 34 | 32 | const ptr_type_name: [*:0]const u8 = type_name; |
| 35 | 33 | |
| 36 | 34 | test "@typeName() returns a string literal" { |
| 37 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 38 | 35 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 39 | 36 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 40 | 37 | |
| ... | ... | @@ -48,7 +45,6 @@ const ptr_actual_contents: [*:0]const u8 = actual_contents; |
| 48 | 45 | const expected_contents = "hello zig\n"; |
| 49 | 46 | |
| 50 | 47 | test "@embedFile() returns a string literal" { |
| 51 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 52 | 48 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 53 | 49 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 54 | 50 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -64,7 +60,7 @@ fn testFnForSrc() std.builtin.SourceLocation { |
| 64 | 60 | } |
| 65 | 61 | |
| 66 | 62 | test "@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; | |
| 68 | 64 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 69 | 65 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 70 | 66 |
test/behavior/struct.zig+17-45| ... | ... | @@ -10,7 +10,6 @@ const maxInt = std.math.maxInt; |
| 10 | 10 | top_level_field: i32, |
| 11 | 11 | |
| 12 | 12 | test "top level fields" { |
| 13 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 14 | 13 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 15 | 14 | |
| 16 | 15 | var instance = @This(){ |
| ... | ... | @@ -87,7 +86,6 @@ const StructFoo = struct { |
| 87 | 86 | }; |
| 88 | 87 | |
| 89 | 88 | test "structs" { |
| 90 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 91 | 89 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 92 | 90 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 93 | 91 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -200,7 +198,6 @@ const MemberFnRand = struct { |
| 200 | 198 | }; |
| 201 | 199 | |
| 202 | 200 | test "return struct byval from function" { |
| 203 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 204 | 201 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 205 | 202 | |
| 206 | 203 | const Bar = struct { |
| ... | ... | @@ -237,7 +234,6 @@ test "call method with mutable reference to struct with no fields" { |
| 237 | 234 | } |
| 238 | 235 | |
| 239 | 236 | test "struct field init with catch" { |
| 240 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 241 | 237 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 242 | 238 | |
| 243 | 239 | const S = struct { |
| ... | ... | @@ -280,7 +276,6 @@ const Val = struct { |
| 280 | 276 | }; |
| 281 | 277 | |
| 282 | 278 | test "struct point to self" { |
| 283 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 284 | 279 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 285 | 280 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 286 | 281 | |
| ... | ... | @@ -297,7 +292,6 @@ test "struct point to self" { |
| 297 | 292 | } |
| 298 | 293 | |
| 299 | 294 | test "void struct fields" { |
| 300 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 301 | 295 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 302 | 296 | |
| 303 | 297 | const foo = VoidStructFieldsFoo{ |
| ... | ... | @@ -335,7 +329,6 @@ fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize { |
| 335 | 329 | } |
| 336 | 330 | |
| 337 | 331 | test "self-referencing struct via array member" { |
| 338 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 339 | 332 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 340 | 333 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 341 | 334 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -492,7 +485,7 @@ const Bitfields = packed struct { |
| 492 | 485 | }; |
| 493 | 486 | |
| 494 | 487 | test "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; | |
| 496 | 489 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 497 | 490 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 498 | 491 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -610,7 +603,6 @@ fn getC(data: *const BitField1) u2 { |
| 610 | 603 | } |
| 611 | 604 | |
| 612 | 605 | test "default struct initialization fields" { |
| 613 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 614 | 606 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 615 | 607 | |
| 616 | 608 | const S = struct { |
| ... | ... | @@ -634,8 +626,8 @@ test "default struct initialization fields" { |
| 634 | 626 | } |
| 635 | 627 | |
| 636 | 628 | test "packed array 24bits" { |
| 637 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 638 | 629 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 630 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 639 | 631 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 640 | 632 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 641 | 633 | |
| ... | ... | @@ -701,8 +693,8 @@ const FooArrayOfAligned = packed struct { |
| 701 | 693 | }; |
| 702 | 694 | |
| 703 | 695 | test "pointer to packed struct member in a stack variable" { |
| 696 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 704 | 697 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 705 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 706 | 698 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 707 | 699 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 708 | 700 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -731,7 +723,6 @@ test "packed struct with u0 field access" { |
| 731 | 723 | } |
| 732 | 724 | |
| 733 | 725 | test "access to global struct fields" { |
| 734 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 735 | 726 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 736 | 727 | |
| 737 | 728 | g_foo.bar.value = 42; |
| ... | ... | @@ -753,8 +744,8 @@ const S0 = struct { |
| 753 | 744 | var g_foo: S0 = S0.init(); |
| 754 | 745 | |
| 755 | 746 | test "packed struct with fp fields" { |
| 747 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 756 | 748 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 757 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 758 | 749 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 759 | 750 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 760 | 751 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -783,7 +774,6 @@ test "packed struct with fp fields" { |
| 783 | 774 | |
| 784 | 775 | test "fn with C calling convention returns struct by value" { |
| 785 | 776 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 786 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 787 | 777 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 788 | 778 | |
| 789 | 779 | const S = struct { |
| ... | ... | @@ -807,7 +797,7 @@ test "fn with C calling convention returns struct by value" { |
| 807 | 797 | } |
| 808 | 798 | |
| 809 | 799 | test "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; | |
| 811 | 801 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 812 | 802 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 813 | 803 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -834,8 +824,8 @@ test "non-packed struct with u128 entry in union" { |
| 834 | 824 | } |
| 835 | 825 | |
| 836 | 826 | test "packed struct field passed to generic function" { |
| 827 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 837 | 828 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 838 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 839 | 829 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 840 | 830 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 841 | 831 | |
| ... | ... | @@ -859,7 +849,6 @@ test "packed struct field passed to generic function" { |
| 859 | 849 | } |
| 860 | 850 | |
| 861 | 851 | test "anonymous struct literal syntax" { |
| 862 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 863 | 852 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 864 | 853 | |
| 865 | 854 | const S = struct { |
| ... | ... | @@ -951,7 +940,6 @@ test "comptime struct field" { |
| 951 | 940 | test "tuple element initialized with fn call" { |
| 952 | 941 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 953 | 942 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 954 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 955 | 943 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 956 | 944 | |
| 957 | 945 | const S = struct { |
| ... | ... | @@ -968,8 +956,8 @@ test "tuple element initialized with fn call" { |
| 968 | 956 | } |
| 969 | 957 | |
| 970 | 958 | test "struct with union field" { |
| 959 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 971 | 960 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 972 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 973 | 961 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 974 | 962 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 975 | 963 | |
| ... | ... | @@ -990,7 +978,6 @@ test "struct with union field" { |
| 990 | 978 | } |
| 991 | 979 | |
| 992 | 980 | test "struct with 0-length union array field" { |
| 993 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 994 | 981 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 995 | 982 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 996 | 983 | |
| ... | ... | @@ -1039,6 +1026,7 @@ test "packed struct with undefined initializers" { |
| 1039 | 1026 | } |
| 1040 | 1027 | |
| 1041 | 1028 | test "for loop over pointers to struct, getting field from struct pointer" { |
| 1029 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1042 | 1030 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1043 | 1031 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1044 | 1032 | 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" { |
| 1078 | 1066 | } |
| 1079 | 1067 | |
| 1080 | 1068 | test "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; | |
| 1082 | 1070 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1083 | 1071 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1084 | 1072 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1105,7 +1093,7 @@ test "anon init through error unions and optionals" { |
| 1105 | 1093 | } |
| 1106 | 1094 | |
| 1107 | 1095 | test "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; | |
| 1109 | 1097 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1110 | 1098 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1111 | 1099 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1125,7 +1113,7 @@ test "anon init through optional" { |
| 1125 | 1113 | } |
| 1126 | 1114 | |
| 1127 | 1115 | test "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; | |
| 1129 | 1117 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1130 | 1118 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1131 | 1119 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1145,7 +1133,7 @@ test "anon init through error union" { |
| 1145 | 1133 | } |
| 1146 | 1134 | |
| 1147 | 1135 | test "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; | |
| 1149 | 1137 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1150 | 1138 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1151 | 1139 | |
| ... | ... | @@ -1171,7 +1159,6 @@ test "typed init through error unions and optionals" { |
| 1171 | 1159 | } |
| 1172 | 1160 | |
| 1173 | 1161 | test "initialize struct with empty literal" { |
| 1174 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1175 | 1162 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1176 | 1163 | |
| 1177 | 1164 | const S = struct { x: i32 = 1234 }; |
| ... | ... | @@ -1206,7 +1193,7 @@ test "loading a struct pointer perfoms a copy" { |
| 1206 | 1193 | } |
| 1207 | 1194 | |
| 1208 | 1195 | test "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; | |
| 1210 | 1197 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1211 | 1198 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1212 | 1199 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1226,7 +1213,7 @@ test "packed struct aggregate init" { |
| 1226 | 1213 | } |
| 1227 | 1214 | |
| 1228 | 1215 | test "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; | |
| 1230 | 1217 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1231 | 1218 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1232 | 1219 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1267,7 +1254,6 @@ test "store to comptime field" { |
| 1267 | 1254 | } |
| 1268 | 1255 | |
| 1269 | 1256 | test "struct field init value is size of the struct" { |
| 1270 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1271 | 1257 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1272 | 1258 | |
| 1273 | 1259 | const namespace = struct { |
| ... | ... | @@ -1282,7 +1268,6 @@ test "struct field init value is size of the struct" { |
| 1282 | 1268 | } |
| 1283 | 1269 | |
| 1284 | 1270 | test "under-aligned struct field" { |
| 1285 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1286 | 1271 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1287 | 1272 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1288 | 1273 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1306,7 +1291,6 @@ test "under-aligned struct field" { |
| 1306 | 1291 | } |
| 1307 | 1292 | |
| 1308 | 1293 | test "fieldParentPtr of a zero-bit field" { |
| 1309 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1310 | 1294 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1311 | 1295 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1312 | 1296 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1357,7 +1341,6 @@ test "fieldParentPtr of a zero-bit field" { |
| 1357 | 1341 | |
| 1358 | 1342 | test "struct field has a pointer to an aligned version of itself" { |
| 1359 | 1343 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1360 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1361 | 1344 | |
| 1362 | 1345 | const E = struct { |
| 1363 | 1346 | next: *align(1) @This(), |
| ... | ... | @@ -1437,7 +1420,6 @@ test "discarded struct initialization works as expected" { |
| 1437 | 1420 | } |
| 1438 | 1421 | |
| 1439 | 1422 | test "function pointer in struct returns the struct" { |
| 1440 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1441 | 1423 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1442 | 1424 | |
| 1443 | 1425 | const A = struct { |
| ... | ... | @@ -1455,7 +1437,6 @@ test "function pointer in struct returns the struct" { |
| 1455 | 1437 | |
| 1456 | 1438 | test "no dependency loop on optional field wrapped in generic function" { |
| 1457 | 1439 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1458 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1459 | 1440 | |
| 1460 | 1441 | const S = struct { |
| 1461 | 1442 | fn Atomic(comptime T: type) type { |
| ... | ... | @@ -1473,7 +1454,6 @@ test "no dependency loop on optional field wrapped in generic function" { |
| 1473 | 1454 | } |
| 1474 | 1455 | |
| 1475 | 1456 | test "optional field init with tuple" { |
| 1476 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1477 | 1457 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1478 | 1458 | |
| 1479 | 1459 | const S = struct { |
| ... | ... | @@ -1488,8 +1468,6 @@ test "optional field init with tuple" { |
| 1488 | 1468 | } |
| 1489 | 1469 | |
| 1490 | 1470 | test "if inside struct init inside if" { |
| 1491 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1492 | ||
| 1493 | 1471 | const MyStruct = struct { x: u32 }; |
| 1494 | 1472 | const b: u32 = 5; |
| 1495 | 1473 | var i: u32 = 1; |
| ... | ... | @@ -1580,7 +1558,6 @@ test "instantiate struct with comptime field" { |
| 1580 | 1558 | test "struct field pointer has correct alignment" { |
| 1581 | 1559 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 1582 | 1560 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1583 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1584 | 1561 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1585 | 1562 | |
| 1586 | 1563 | const S = struct { |
| ... | ... | @@ -1610,7 +1587,6 @@ test "struct field pointer has correct alignment" { |
| 1610 | 1587 | test "extern struct field pointer has correct alignment" { |
| 1611 | 1588 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 1612 | 1589 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1613 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1614 | 1590 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1615 | 1591 | |
| 1616 | 1592 | const S = struct { |
| ... | ... | @@ -1828,7 +1804,6 @@ test "tuple with comptime-only field" { |
| 1828 | 1804 | } |
| 1829 | 1805 | |
| 1830 | 1806 | test "extern struct fields are aligned to 1" { |
| 1831 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1832 | 1807 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1833 | 1808 | |
| 1834 | 1809 | const Foo = extern struct { |
| ... | ... | @@ -1845,7 +1820,7 @@ test "extern struct fields are aligned to 1" { |
| 1845 | 1820 | } |
| 1846 | 1821 | |
| 1847 | 1822 | test "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; | |
| 1849 | 1824 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1850 | 1825 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1851 | 1826 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1897,7 +1872,6 @@ test "array of structs inside struct initialized with undefined" { |
| 1897 | 1872 | } |
| 1898 | 1873 | |
| 1899 | 1874 | test "runtime call in nested initializer" { |
| 1900 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1901 | 1875 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1902 | 1876 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1903 | 1877 | |
| ... | ... | @@ -1929,7 +1903,6 @@ test "runtime call in nested initializer" { |
| 1929 | 1903 | } |
| 1930 | 1904 | |
| 1931 | 1905 | test "runtime value in nested initializer passed as pointer to function" { |
| 1932 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1933 | 1906 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1934 | 1907 | |
| 1935 | 1908 | const Bar = struct { |
| ... | ... | @@ -1953,7 +1926,7 @@ test "runtime value in nested initializer passed as pointer to function" { |
| 1953 | 1926 | } |
| 1954 | 1927 | |
| 1955 | 1928 | test "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; | |
| 1957 | 1930 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1958 | 1931 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1959 | 1932 | |
| ... | ... | @@ -2001,7 +1974,6 @@ test "aggregate initializers should allow initializing comptime fields, verifyin |
| 2001 | 1974 | |
| 2002 | 1975 | test "assignment of field with padding" { |
| 2003 | 1976 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 2004 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2005 | 1977 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2006 | 1978 | |
| 2007 | 1979 | const Mesh = extern struct { |
| ... | ... | @@ -2031,7 +2003,6 @@ test "assignment of field with padding" { |
| 2031 | 2003 | |
| 2032 | 2004 | test "initiate global variable with runtime value" { |
| 2033 | 2005 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 2034 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2035 | 2006 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2036 | 2007 | |
| 2037 | 2008 | const S = struct { |
| ... | ... | @@ -2126,6 +2097,7 @@ test "anonymous struct equivalence" { |
| 2126 | 2097 | } |
| 2127 | 2098 | |
| 2128 | 2099 | test "field access through mem ptr arg" { |
| 2100 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2129 | 2101 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 2130 | 2102 | |
| 2131 | 2103 | const S = struct { |
test/behavior/struct_contains_null_ptr_itself.zig-1| ... | ... | @@ -3,7 +3,6 @@ const expect = std.testing.expect; |
| 3 | 3 | const builtin = @import("builtin"); |
| 4 | 4 | |
| 5 | 5 | test "struct contains null pointer which contains original struct" { |
| 6 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 7 | 6 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 8 | 7 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 9 | 8 |
test/behavior/struct_contains_slice_of_itself.zig+2-1| ... | ... | @@ -12,6 +12,7 @@ const NodeAligned = struct { |
| 12 | 12 | }; |
| 13 | 13 | |
| 14 | 14 | test "struct contains slice of itself" { |
| 15 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 15 | 16 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 16 | 17 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 17 | 18 | |
| ... | ... | @@ -52,7 +53,7 @@ test "struct contains slice of itself" { |
| 52 | 53 | } |
| 53 | 54 | |
| 54 | 55 | test "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; | |
| 56 | 57 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 57 | 58 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 58 | 59 |
test/behavior/switch.zig+20-13| ... | ... | @@ -8,6 +8,7 @@ const minInt = std.math.minInt; |
| 8 | 8 | const maxInt = std.math.maxInt; |
| 9 | 9 | |
| 10 | 10 | test "switch with numbers" { |
| 11 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 11 | 12 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 12 | 13 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 13 | 14 | |
| ... | ... | @@ -43,7 +44,7 @@ fn testSwitchWithAllRanges(x: u32, y: u32) u32 { |
| 43 | 44 | } |
| 44 | 45 | |
| 45 | 46 | test "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; | |
| 47 | 48 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 48 | 49 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 49 | 50 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -274,8 +275,8 @@ const SwitchProngWithVarEnum = union(enum) { |
| 274 | 275 | }; |
| 275 | 276 | |
| 276 | 277 | test "switch prong with variable" { |
| 278 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 277 | 279 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 278 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 279 | 280 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 280 | 281 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 281 | 282 | |
| ... | ... | @@ -299,8 +300,8 @@ fn switchProngWithVarFn(a: SwitchProngWithVarEnum) !void { |
| 299 | 300 | } |
| 300 | 301 | |
| 301 | 302 | test "switch on enum using pointer capture" { |
| 303 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 302 | 304 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 303 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 304 | 305 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 305 | 306 | |
| 306 | 307 | try testSwitchEnumPtrCapture(); |
| ... | ... | @@ -360,8 +361,8 @@ fn testSwitchHandleAllCasesRange(x: u8) u8 { |
| 360 | 361 | } |
| 361 | 362 | |
| 362 | 363 | test "switch on union with some prongs capturing" { |
| 364 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 363 | 365 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 364 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 365 | 366 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 366 | 367 | |
| 367 | 368 | const X = union(enum) { |
| ... | ... | @@ -398,7 +399,6 @@ test "switch on const enum with var" { |
| 398 | 399 | } |
| 399 | 400 | |
| 400 | 401 | test "anon enum literal used in switch on union enum" { |
| 401 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 402 | 402 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 403 | 403 | |
| 404 | 404 | const Foo = union(enum) { |
| ... | ... | @@ -469,8 +469,8 @@ test "switch on integer with else capturing expr" { |
| 469 | 469 | } |
| 470 | 470 | |
| 471 | 471 | test "else prong of switch on error set excludes other cases" { |
| 472 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 472 | 473 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 473 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 474 | 474 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 475 | 475 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 476 | 476 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -505,8 +505,8 @@ test "else prong of switch on error set excludes other cases" { |
| 505 | 505 | } |
| 506 | 506 | |
| 507 | 507 | test "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; | |
| 508 | 509 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 509 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 510 | 510 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 511 | 511 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 512 | 512 | 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 |
| 563 | 563 | |
| 564 | 564 | test "switch with null and T peer types and inferred result location type" { |
| 565 | 565 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 566 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 567 | 566 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 568 | 567 | |
| 569 | 568 | const S = struct { |
| ... | ... | @@ -582,7 +581,7 @@ test "switch with null and T peer types and inferred result location type" { |
| 582 | 581 | } |
| 583 | 582 | |
| 584 | 583 | test "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; | |
| 586 | 585 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 587 | 586 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 588 | 587 | |
| ... | ... | @@ -689,7 +688,7 @@ test "switch prong pointer capture alignment" { |
| 689 | 688 | } |
| 690 | 689 | |
| 691 | 690 | test "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; | |
| 693 | 692 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 694 | 693 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 695 | 694 | |
| ... | ... | @@ -737,8 +736,8 @@ test "switch on error set with single else" { |
| 737 | 736 | } |
| 738 | 737 | |
| 739 | 738 | test "switch capture copies its payload" { |
| 739 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 740 | 740 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 741 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 742 | 741 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 743 | 742 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 744 | 743 | |
| ... | ... | @@ -831,6 +830,7 @@ test "comptime inline switch" { |
| 831 | 830 | } |
| 832 | 831 | |
| 833 | 832 | test "switch capture peer type resolution" { |
| 833 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 834 | 834 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 835 | 835 | |
| 836 | 836 | const U = union(enum) { |
| ... | ... | @@ -848,6 +848,8 @@ test "switch capture peer type resolution" { |
| 848 | 848 | } |
| 849 | 849 | |
| 850 | 850 | test "switch capture peer type resolution for in-memory coercible payloads" { |
| 851 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 852 | ||
| 851 | 853 | const T1 = c_int; |
| 852 | 854 | const T2 = @Type(@typeInfo(T1)); |
| 853 | 855 | |
| ... | ... | @@ -868,6 +870,8 @@ test "switch capture peer type resolution for in-memory coercible payloads" { |
| 868 | 870 | } |
| 869 | 871 | |
| 870 | 872 | test "switch pointer capture peer type resolution" { |
| 873 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 874 | ||
| 871 | 875 | const T1 = c_int; |
| 872 | 876 | const T2 = @Type(@typeInfo(T1)); |
| 873 | 877 | |
| ... | ... | @@ -904,6 +908,7 @@ test "inline switch range that includes the maximum value of the switched type" |
| 904 | 908 | } |
| 905 | 909 | |
| 906 | 910 | test "nested break ignores switch conditions and breaks instead" { |
| 911 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 907 | 912 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 908 | 913 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 909 | 914 | |
| ... | ... | @@ -926,6 +931,7 @@ test "nested break ignores switch conditions and breaks instead" { |
| 926 | 931 | } |
| 927 | 932 | |
| 928 | 933 | test "peer type resolution on switch captures ignores unused payload bits" { |
| 934 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 929 | 935 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 930 | 936 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 931 | 937 | |
| ... | ... | @@ -951,7 +957,6 @@ test "peer type resolution on switch captures ignores unused payload bits" { |
| 951 | 957 | } |
| 952 | 958 | |
| 953 | 959 | test "switch prong captures range" { |
| 954 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 955 | 960 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 956 | 961 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| 957 | 962 | |
| ... | ... | @@ -971,6 +976,8 @@ test "switch prong captures range" { |
| 971 | 976 | } |
| 972 | 977 | |
| 973 | 978 | test "prong with inline call to unreachable" { |
| 979 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 980 | ||
| 974 | 981 | const U = union(enum) { |
| 975 | 982 | void: void, |
| 976 | 983 | bool: bool, |
| ... | ... | @@ -1042,7 +1049,7 @@ test "labeled switch with break" { |
| 1042 | 1049 | } |
| 1043 | 1050 | |
| 1044 | 1051 | test "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; | |
| 1046 | 1053 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1047 | 1054 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1048 | 1055 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
test/behavior/switch_loop.zig+32-9| ... | ... | @@ -3,7 +3,7 @@ const std = @import("std"); |
| 3 | 3 | const expect = std.testing.expect; |
| 4 | 4 | |
| 5 | 5 | test "simple switch loop" { |
| 6 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 6 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 7 | 7 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 8 | 8 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 9 | 9 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -27,7 +27,7 @@ test "simple switch loop" { |
| 27 | 27 | } |
| 28 | 28 | |
| 29 | 29 | test "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; | |
| 31 | 31 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 32 | 32 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 33 | 33 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -48,7 +48,7 @@ test "switch loop with ranges" { |
| 48 | 48 | } |
| 49 | 49 | |
| 50 | 50 | test "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; | |
| 52 | 52 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 53 | 53 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 54 | 54 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -72,7 +72,7 @@ test "switch loop on enum" { |
| 72 | 72 | } |
| 73 | 73 | |
| 74 | 74 | test "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; | |
| 76 | 76 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 77 | 77 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 78 | 78 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -96,7 +96,7 @@ test "switch loop with error set" { |
| 96 | 96 | } |
| 97 | 97 | |
| 98 | 98 | test "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; | |
| 100 | 100 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 101 | 101 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 102 | 102 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -129,7 +129,7 @@ test "switch loop on tagged union" { |
| 129 | 129 | } |
| 130 | 130 | |
| 131 | 131 | test "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; | |
| 133 | 133 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 134 | 134 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 135 | 135 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -179,7 +179,7 @@ test "switch loop dispatching instructions" { |
| 179 | 179 | } |
| 180 | 180 | |
| 181 | 181 | test "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; | |
| 183 | 183 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 184 | 184 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 185 | 185 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -218,11 +218,34 @@ test "switch loop with pointer capture" { |
| 218 | 218 | } |
| 219 | 219 | |
| 220 | 220 | test "unanalyzed continue with operand" { |
| 221 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 222 | ||
| 223 | 221 | @setRuntimeSafety(false); |
| 224 | 222 | label: switch (false) { |
| 225 | 223 | false => if (false) continue :label true, |
| 226 | 224 | true => {}, |
| 227 | 225 | } |
| 228 | 226 | } |
| 227 | ||
| 228 | test "switch loop on larger than pointer integer" { | |
| 229 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 230 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; | |
| 231 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 232 | ||
| 233 | var entry: @Type(.{ .int = .{ | |
| 234 | .signedness = .unsigned, | |
| 235 | .bits = @bitSizeOf(usize) + 1, | |
| 236 | } }) = undefined; | |
| 237 | entry = 0; | |
| 238 | loop: switch (entry) { | |
| 239 | 0 => { | |
| 240 | entry += 1; | |
| 241 | continue :loop 1; | |
| 242 | }, | |
| 243 | 1 => |x| { | |
| 244 | entry += 1; | |
| 245 | continue :loop x + 1; | |
| 246 | }, | |
| 247 | 2 => entry += 1, | |
| 248 | else => unreachable, | |
| 249 | } | |
| 250 | try expect(entry == 3); | |
| 251 | } |
test/behavior/switch_on_captured_error.zig+2| ... | ... | @@ -6,6 +6,7 @@ const expectEqual = std.testing.expectEqual; |
| 6 | 6 | const builtin = @import("builtin"); |
| 7 | 7 | |
| 8 | 8 | test "switch on error union catch capture" { |
| 9 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 9 | 10 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 10 | 11 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 11 | 12 | |
| ... | ... | @@ -300,6 +301,7 @@ test "switch on error union catch capture" { |
| 300 | 301 | } |
| 301 | 302 | |
| 302 | 303 | test "switch on error union if else capture" { |
| 304 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 303 | 305 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 304 | 306 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 305 | 307 |
test/behavior/switch_prong_err_enum.zig+1-1| ... | ... | @@ -21,8 +21,8 @@ fn doThing(form_id: u64) anyerror!FormValue { |
| 21 | 21 | } |
| 22 | 22 | |
| 23 | 23 | test "switch prong returns error enum" { |
| 24 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 25 | 24 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 25 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 26 | 26 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 27 | 27 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 28 | 28 |
test/behavior/switch_prong_implicit_cast.zig+1-1| ... | ... | @@ -15,8 +15,8 @@ fn foo(id: u64) !FormValue { |
| 15 | 15 | } |
| 16 | 16 | |
| 17 | 17 | test "switch prong implicit cast" { |
| 18 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 19 | 18 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 19 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 20 | 20 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 21 | 21 | |
| 22 | 22 | const result = switch (foo(2) catch unreachable) { |
test/behavior/this.zig-2| ... | ... | @@ -26,7 +26,6 @@ test "this refer to module call private fn" { |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | 28 | test "this refer to container" { |
| 29 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 30 | 29 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 31 | 30 | |
| 32 | 31 | var pt: Point(i32) = undefined; |
| ... | ... | @@ -47,7 +46,6 @@ fn prev(p: ?State) void { |
| 47 | 46 | } |
| 48 | 47 | |
| 49 | 48 | test "this used as optional function parameter" { |
| 50 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 51 | 49 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 52 | 50 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 53 | 51 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/threadlocal.zig-3| ... | ... | @@ -4,7 +4,6 @@ const expect = std.testing.expect; |
| 4 | 4 | |
| 5 | 5 | test "thread local variable" { |
| 6 | 6 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 7 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 8 | 7 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 9 | 8 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 10 | 9 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -25,7 +24,6 @@ test "thread local variable" { |
| 25 | 24 | |
| 26 | 25 | test "pointer to thread local array" { |
| 27 | 26 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 28 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 29 | 27 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 30 | 28 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 31 | 29 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -40,7 +38,6 @@ threadlocal var buffer: [11]u8 = undefined; |
| 40 | 38 | |
| 41 | 39 | test "reference a global threadlocal variable" { |
| 42 | 40 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 43 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 44 | 41 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 45 | 42 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 46 | 43 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/truncate.zig+1-1| ... | ... | @@ -65,8 +65,8 @@ test "truncate on comptime integer" { |
| 65 | 65 | } |
| 66 | 66 | |
| 67 | 67 | test "truncate on vectors" { |
| 68 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 69 | 68 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 69 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 70 | 70 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 71 | 71 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 72 | 72 | 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" { |
| 47 | 47 | } |
| 48 | 48 | |
| 49 | 49 | test "`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; | |
| 51 | 51 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 52 | 52 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 53 | 53 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -68,7 +68,6 @@ test "`try`ing an if/else expression" { |
| 68 | 68 | } |
| 69 | 69 | |
| 70 | 70 | test "'return try' of empty error set in function returning non-error" { |
| 71 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 72 | 71 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 73 | 72 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 74 | 73 |
test/behavior/tuple.zig+2-20| ... | ... | @@ -8,7 +8,6 @@ const expectEqual = std.testing.expectEqual; |
| 8 | 8 | |
| 9 | 9 | test "tuple concatenation" { |
| 10 | 10 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 11 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 12 | 11 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 13 | 12 | |
| 14 | 13 | const S = struct { |
| ... | ... | @@ -51,7 +50,6 @@ test "tuple multiplication" { |
| 51 | 50 | } |
| 52 | 51 | |
| 53 | 52 | test "more tuple concatenation" { |
| 54 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 55 | 53 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 56 | 54 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 57 | 55 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -129,7 +127,6 @@ test "tuple initializer for var" { |
| 129 | 127 | } |
| 130 | 128 | |
| 131 | 129 | test "array-like initializer for tuple types" { |
| 132 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 133 | 130 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 134 | 131 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 135 | 132 | |
| ... | ... | @@ -216,7 +213,6 @@ test "initializing anon struct with explicit type" { |
| 216 | 213 | } |
| 217 | 214 | |
| 218 | 215 | test "fieldParentPtr of tuple" { |
| 219 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 220 | 216 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 221 | 217 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 222 | 218 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -229,7 +225,6 @@ test "fieldParentPtr of tuple" { |
| 229 | 225 | } |
| 230 | 226 | |
| 231 | 227 | test "fieldParentPtr of anon struct" { |
| 232 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 233 | 228 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 234 | 229 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 235 | 230 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -256,7 +251,6 @@ test "offsetOf anon struct" { |
| 256 | 251 | } |
| 257 | 252 | |
| 258 | 253 | test "initializing tuple with mixed comptime-runtime fields" { |
| 259 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 260 | 254 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 261 | 255 | |
| 262 | 256 | var x: u32 = 15; |
| ... | ... | @@ -268,7 +262,6 @@ test "initializing tuple with mixed comptime-runtime fields" { |
| 268 | 262 | } |
| 269 | 263 | |
| 270 | 264 | test "initializing anon struct with mixed comptime-runtime fields" { |
| 271 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 272 | 265 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 273 | 266 | |
| 274 | 267 | var x: u32 = 15; |
| ... | ... | @@ -280,7 +273,6 @@ test "initializing anon struct with mixed comptime-runtime fields" { |
| 280 | 273 | } |
| 281 | 274 | |
| 282 | 275 | test "tuple in tuple passed to generic function" { |
| 283 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 284 | 276 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 285 | 277 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 286 | 278 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -300,7 +292,6 @@ test "tuple in tuple passed to generic function" { |
| 300 | 292 | } |
| 301 | 293 | |
| 302 | 294 | test "coerce tuple to tuple" { |
| 303 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 304 | 295 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 305 | 296 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 306 | 297 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -315,7 +306,6 @@ test "coerce tuple to tuple" { |
| 315 | 306 | } |
| 316 | 307 | |
| 317 | 308 | test "tuple type with void field" { |
| 318 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 319 | 309 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 320 | 310 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 321 | 311 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -353,7 +343,6 @@ test "zero sized struct in tuple handled correctly" { |
| 353 | 343 | } |
| 354 | 344 | |
| 355 | 345 | test "tuple type with void field and a runtime field" { |
| 356 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 357 | 346 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 358 | 347 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 359 | 348 | |
| ... | ... | @@ -364,7 +353,6 @@ test "tuple type with void field and a runtime field" { |
| 364 | 353 | } |
| 365 | 354 | |
| 366 | 355 | test "branching inside tuple literal" { |
| 367 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 368 | 356 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 369 | 357 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 370 | 358 | |
| ... | ... | @@ -410,7 +398,6 @@ test "tuple of struct concatenation and coercion to array" { |
| 410 | 398 | } |
| 411 | 399 | |
| 412 | 400 | test "nested runtime conditionals in tuple initializer" { |
| 413 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 414 | 401 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 415 | 402 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 416 | 403 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -446,7 +433,6 @@ test "sentinel slice in tuple" { |
| 446 | 433 | } |
| 447 | 434 | |
| 448 | 435 | test "tuple pointer is indexable" { |
| 449 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 450 | 436 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 451 | 437 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 452 | 438 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -470,7 +456,6 @@ test "tuple pointer is indexable" { |
| 470 | 456 | } |
| 471 | 457 | |
| 472 | 458 | test "coerce anon tuple to tuple" { |
| 473 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 474 | 459 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 475 | 460 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 476 | 461 | |
| ... | ... | @@ -496,14 +481,12 @@ test "empty tuple type" { |
| 496 | 481 | } |
| 497 | 482 | |
| 498 | 483 | test "tuple with comptime fields with non empty initializer" { |
| 499 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 500 | ||
| 501 | 484 | const a: struct { comptime comptime_int = 0 } = .{0}; |
| 502 | 485 | _ = a; |
| 503 | 486 | } |
| 504 | 487 | |
| 505 | 488 | test "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; | |
| 507 | 490 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 508 | 491 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 509 | 492 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -578,7 +561,6 @@ test "comptime fields in tuple can be initialized" { |
| 578 | 561 | |
| 579 | 562 | test "empty struct in tuple" { |
| 580 | 563 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 581 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 582 | 564 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 583 | 565 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 584 | 566 | |
| ... | ... | @@ -591,7 +573,6 @@ test "empty struct in tuple" { |
| 591 | 573 | |
| 592 | 574 | test "empty union in tuple" { |
| 593 | 575 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 594 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 595 | 576 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 596 | 577 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 597 | 578 | |
| ... | ... | @@ -604,6 +585,7 @@ test "empty union in tuple" { |
| 604 | 585 | |
| 605 | 586 | test "field pointer of underaligned tuple" { |
| 606 | 587 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 588 | ||
| 607 | 589 | const S = struct { |
| 608 | 590 | fn doTheTest() !void { |
| 609 | 591 | const T = struct { u8, u32 }; |
test/behavior/tuple_declarations.zig-2| ... | ... | @@ -5,7 +5,6 @@ const expect = testing.expect; |
| 5 | 5 | const expectEqualStrings = testing.expectEqualStrings; |
| 6 | 6 | |
| 7 | 7 | test "tuple declaration type info" { |
| 8 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 9 | 8 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 10 | 9 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 11 | 10 | |
| ... | ... | @@ -34,7 +33,6 @@ test "tuple declaration type info" { |
| 34 | 33 | } |
| 35 | 34 | |
| 36 | 35 | test "tuple declaration usage" { |
| 37 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 38 | 36 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 39 | 37 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 40 | 38 |
test/behavior/type.zig+3-6| ... | ... | @@ -200,8 +200,8 @@ test "Type.ErrorUnion" { |
| 200 | 200 | } |
| 201 | 201 | |
| 202 | 202 | test "Type.Opaque" { |
| 203 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 203 | 204 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 204 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 205 | 205 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 206 | 206 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 207 | 207 | |
| ... | ... | @@ -258,8 +258,8 @@ test "Type.ErrorSet" { |
| 258 | 258 | } |
| 259 | 259 | |
| 260 | 260 | test "Type.Struct" { |
| 261 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 261 | 262 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 262 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 263 | 263 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 264 | 264 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 265 | 265 | |
| ... | ... | @@ -348,7 +348,6 @@ test "Type.Struct" { |
| 348 | 348 | |
| 349 | 349 | test "Type.Enum" { |
| 350 | 350 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 351 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 352 | 351 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 353 | 352 | |
| 354 | 353 | const Foo = @Type(.{ |
| ... | ... | @@ -409,8 +408,8 @@ test "Type.Enum" { |
| 409 | 408 | } |
| 410 | 409 | |
| 411 | 410 | test "Type.Union" { |
| 411 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 412 | 412 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 413 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 414 | 413 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 415 | 414 | |
| 416 | 415 | const Untagged = @Type(.{ |
| ... | ... | @@ -547,7 +546,6 @@ test "Type.Union from empty Type.Enum" { |
| 547 | 546 | |
| 548 | 547 | test "Type.Fn" { |
| 549 | 548 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 550 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 551 | 549 | |
| 552 | 550 | const some_opaque = opaque {}; |
| 553 | 551 | const some_ptr = *some_opaque; |
| ... | ... | @@ -724,7 +722,6 @@ test "@Type should resolve its children types" { |
| 724 | 722 | } |
| 725 | 723 | |
| 726 | 724 | test "struct field names sliced at comptime from larger string" { |
| 727 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 728 | 725 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 729 | 726 | |
| 730 | 727 | const text = |
test/behavior/type_info.zig+2-4| ... | ... | @@ -158,7 +158,6 @@ fn testArray() !void { |
| 158 | 158 | } |
| 159 | 159 | |
| 160 | 160 | test "type info: error set, error union info, anyerror" { |
| 161 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 162 | 161 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 163 | 162 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 164 | 163 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -190,7 +189,6 @@ fn testErrorSet() !void { |
| 190 | 189 | } |
| 191 | 190 | |
| 192 | 191 | test "type info: error set single value" { |
| 193 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 194 | 192 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 195 | 193 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 196 | 194 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -204,7 +202,6 @@ test "type info: error set single value" { |
| 204 | 202 | } |
| 205 | 203 | |
| 206 | 204 | test "type info: error set merged" { |
| 207 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 208 | 205 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 209 | 206 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 210 | 207 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -221,7 +218,6 @@ test "type info: error set merged" { |
| 221 | 218 | |
| 222 | 219 | test "type info: enum info" { |
| 223 | 220 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 224 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 225 | 221 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 226 | 222 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 227 | 223 | |
| ... | ... | @@ -362,6 +358,8 @@ test "type info: function type info" { |
| 362 | 358 | } |
| 363 | 359 | |
| 364 | 360 | fn testFunction() !void { |
| 361 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 362 | ||
| 365 | 363 | const S = struct { |
| 366 | 364 | export fn typeInfoFoo() callconv(.c) usize { |
| 367 | 365 | unreachable; |
test/behavior/typename.zig-8| ... | ... | @@ -12,7 +12,6 @@ const expectStringStartsWith = std.testing.expectStringStartsWith; |
| 12 | 12 | // failures. |
| 13 | 13 | |
| 14 | 14 | test "anon fn param" { |
| 15 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 16 | 15 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 17 | 16 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 18 | 17 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -38,7 +37,6 @@ test "anon fn param" { |
| 38 | 37 | } |
| 39 | 38 | |
| 40 | 39 | test "anon field init" { |
| 41 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 42 | 40 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 43 | 41 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 44 | 42 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -64,7 +62,6 @@ test "anon field init" { |
| 64 | 62 | } |
| 65 | 63 | |
| 66 | 64 | test "basic" { |
| 67 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 68 | 65 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 69 | 66 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 70 | 67 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -86,7 +83,6 @@ test "basic" { |
| 86 | 83 | } |
| 87 | 84 | |
| 88 | 85 | test "top level decl" { |
| 89 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 90 | 86 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 91 | 87 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 92 | 88 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -136,7 +132,6 @@ const B = struct { |
| 136 | 132 | }; |
| 137 | 133 | |
| 138 | 134 | test "fn param" { |
| 139 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 140 | 135 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 141 | 136 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 142 | 137 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -216,7 +211,6 @@ pub fn expectEqualStringsIgnoreDigits(expected: []const u8, actual: []const u8) |
| 216 | 211 | } |
| 217 | 212 | |
| 218 | 213 | test "local variable" { |
| 219 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 220 | 214 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 221 | 215 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 222 | 216 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -235,7 +229,6 @@ test "local variable" { |
| 235 | 229 | } |
| 236 | 230 | |
| 237 | 231 | test "comptime parameters not converted to anytype in function type" { |
| 238 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 239 | 232 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 240 | 233 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 241 | 234 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -245,7 +238,6 @@ test "comptime parameters not converted to anytype in function type" { |
| 245 | 238 | } |
| 246 | 239 | |
| 247 | 240 | test "anon name strategy used in sub expression" { |
| 248 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 249 | 241 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 250 | 242 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 251 | 243 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/undefined.zig-4| ... | ... | @@ -46,7 +46,6 @@ fn setFooX(foo: *Foo) void { |
| 46 | 46 | |
| 47 | 47 | test "assign undefined to struct" { |
| 48 | 48 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 49 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 50 | 49 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 51 | 50 | |
| 52 | 51 | comptime { |
| ... | ... | @@ -63,7 +62,6 @@ test "assign undefined to struct" { |
| 63 | 62 | |
| 64 | 63 | test "assign undefined to struct with method" { |
| 65 | 64 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 66 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 67 | 65 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 68 | 66 | |
| 69 | 67 | comptime { |
| ... | ... | @@ -89,7 +87,6 @@ test "type name of undefined" { |
| 89 | 87 | var buf: []u8 = undefined; |
| 90 | 88 | |
| 91 | 89 | test "reslice of undefined global var slice" { |
| 92 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 93 | 90 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 94 | 91 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 95 | 92 | |
| ... | ... | @@ -100,7 +97,6 @@ test "reslice of undefined global var slice" { |
| 100 | 97 | } |
| 101 | 98 | |
| 102 | 99 | test "returned undef is 0xaa bytes when runtime safety is enabled" { |
| 103 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 104 | 100 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 105 | 101 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 106 | 102 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
test/behavior/union.zig+60-60| ... | ... | @@ -12,8 +12,8 @@ const FooWithFloats = union { |
| 12 | 12 | }; |
| 13 | 13 | |
| 14 | 14 | test "basic unions with floats" { |
| 15 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 16 | 15 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 16 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 17 | 17 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 18 | 18 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 19 | 19 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -29,8 +29,8 @@ fn setFloat(foo: *FooWithFloats, x: f64) void { |
| 29 | 29 | } |
| 30 | 30 | |
| 31 | 31 | test "init union with runtime value - floats" { |
| 32 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 33 | 32 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 33 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 34 | 34 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 35 | 35 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 36 | 36 | |
| ... | ... | @@ -60,8 +60,8 @@ const Foo = union { |
| 60 | 60 | }; |
| 61 | 61 | |
| 62 | 62 | test "init union with runtime value" { |
| 63 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 64 | 63 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 64 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 65 | 65 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 66 | 66 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 67 | 67 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -160,8 +160,8 @@ test "unions embedded in aggregate types" { |
| 160 | 160 | } |
| 161 | 161 | |
| 162 | 162 | test "constant tagged union with payload" { |
| 163 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 164 | 163 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 164 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 165 | 165 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 166 | 166 | |
| 167 | 167 | var empty = TaggedUnionWithPayload{ .Empty = {} }; |
| ... | ... | @@ -210,8 +210,8 @@ const Payload = union(Letter) { |
| 210 | 210 | }; |
| 211 | 211 | |
| 212 | 212 | test "union with specified enum tag" { |
| 213 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 214 | 213 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 214 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 215 | 215 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 216 | 216 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 217 | 217 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -221,8 +221,8 @@ test "union with specified enum tag" { |
| 221 | 221 | } |
| 222 | 222 | |
| 223 | 223 | test "packed union generates correctly aligned type" { |
| 224 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 225 | 224 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 225 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 226 | 226 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 227 | 227 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 228 | 228 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -263,8 +263,8 @@ fn testComparison() !void { |
| 263 | 263 | } |
| 264 | 264 | |
| 265 | 265 | test "comparison between union and enum literal" { |
| 266 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 267 | 266 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 267 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 268 | 268 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 269 | 269 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 270 | 270 | |
| ... | ... | @@ -279,8 +279,8 @@ const TheUnion = union(TheTag) { |
| 279 | 279 | C: i32, |
| 280 | 280 | }; |
| 281 | 281 | test "cast union to tag type of union" { |
| 282 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 283 | 282 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 283 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 284 | 284 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 285 | 285 | |
| 286 | 286 | try testCastUnionToTag(); |
| ... | ... | @@ -300,8 +300,8 @@ test "union field access gives the enum values" { |
| 300 | 300 | } |
| 301 | 301 | |
| 302 | 302 | test "cast tag type of union to union" { |
| 303 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 304 | 303 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 304 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 305 | 305 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 306 | 306 | |
| 307 | 307 | var x: Value2 = Letter2.B; |
| ... | ... | @@ -316,8 +316,8 @@ const Value2 = union(Letter2) { |
| 316 | 316 | }; |
| 317 | 317 | |
| 318 | 318 | test "implicit cast union to its tag type" { |
| 319 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 320 | 319 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 320 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 321 | 321 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 322 | 322 | |
| 323 | 323 | var x: Value2 = Letter2.B; |
| ... | ... | @@ -337,8 +337,8 @@ pub const PackThis = union(enum) { |
| 337 | 337 | }; |
| 338 | 338 | |
| 339 | 339 | test "constant packed union" { |
| 340 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 341 | 340 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 341 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 342 | 342 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 343 | 343 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 344 | 344 | |
| ... | ... | @@ -357,7 +357,6 @@ const MultipleChoice = union(enum(u32)) { |
| 357 | 357 | }; |
| 358 | 358 | test "simple union(enum(u32))" { |
| 359 | 359 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 360 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 361 | 360 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 362 | 361 | |
| 363 | 362 | var x = MultipleChoice.C; |
| ... | ... | @@ -403,7 +402,6 @@ test "assigning to union with zero size field" { |
| 403 | 402 | |
| 404 | 403 | test "tagged union initialization with runtime void" { |
| 405 | 404 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 406 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 407 | 405 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 408 | 406 | |
| 409 | 407 | try expect(testTaggedUnionInit({})); |
| ... | ... | @@ -423,7 +421,6 @@ pub const UnionEnumNoPayloads = union(enum) { A, B }; |
| 423 | 421 | |
| 424 | 422 | test "tagged union with no payloads" { |
| 425 | 423 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 426 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 427 | 424 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 428 | 425 | |
| 429 | 426 | const a = UnionEnumNoPayloads{ .B = {} }; |
| ... | ... | @@ -470,7 +467,6 @@ var glbl: Foo1 = undefined; |
| 470 | 467 | |
| 471 | 468 | test "global union with single field is correctly initialized" { |
| 472 | 469 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 473 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 474 | 470 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 475 | 471 | |
| 476 | 472 | glbl = Foo1{ |
| ... | ... | @@ -487,8 +483,8 @@ pub const FooUnion = union(enum) { |
| 487 | 483 | var glbl_array: [2]FooUnion = undefined; |
| 488 | 484 | |
| 489 | 485 | test "initialize global array of union" { |
| 490 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 491 | 486 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 487 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 492 | 488 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 493 | 489 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 494 | 490 | |
| ... | ... | @@ -499,8 +495,8 @@ test "initialize global array of union" { |
| 499 | 495 | } |
| 500 | 496 | |
| 501 | 497 | test "update the tag value for zero-sized unions" { |
| 502 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 503 | 498 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 499 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 504 | 500 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 505 | 501 | |
| 506 | 502 | const S = union(enum) { |
| ... | ... | @@ -515,7 +511,6 @@ test "update the tag value for zero-sized unions" { |
| 515 | 511 | |
| 516 | 512 | test "union initializer generates padding only if needed" { |
| 517 | 513 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 518 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 519 | 514 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 520 | 515 | |
| 521 | 516 | const U = union(enum) { |
| ... | ... | @@ -528,7 +523,6 @@ test "union initializer generates padding only if needed" { |
| 528 | 523 | } |
| 529 | 524 | |
| 530 | 525 | test "runtime tag name with single field" { |
| 531 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 532 | 526 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 533 | 527 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 534 | 528 | |
| ... | ... | @@ -543,7 +537,6 @@ test "runtime tag name with single field" { |
| 543 | 537 | |
| 544 | 538 | test "method call on an empty union" { |
| 545 | 539 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 546 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 547 | 540 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 548 | 541 | |
| 549 | 542 | const S = struct { |
| ... | ... | @@ -604,8 +597,8 @@ test "tagged union type" { |
| 604 | 597 | } |
| 605 | 598 | |
| 606 | 599 | test "tagged union as return value" { |
| 607 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 608 | 600 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 601 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 609 | 602 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 610 | 603 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 611 | 604 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -621,8 +614,8 @@ fn returnAnInt(x: i32) TaggedFoo { |
| 621 | 614 | } |
| 622 | 615 | |
| 623 | 616 | test "tagged union with all void fields but a meaningful tag" { |
| 624 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 625 | 617 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 618 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 626 | 619 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 627 | 620 | |
| 628 | 621 | const S = struct { |
| ... | ... | @@ -649,8 +642,8 @@ test "tagged union with all void fields but a meaningful tag" { |
| 649 | 642 | } |
| 650 | 643 | |
| 651 | 644 | test "union(enum(u32)) with specified and unspecified tag values" { |
| 652 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 653 | 645 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 646 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 654 | 647 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 655 | 648 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 656 | 649 | |
| ... | ... | @@ -687,7 +680,6 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void { |
| 687 | 680 | } |
| 688 | 681 | |
| 689 | 682 | test "switch on union with only 1 field" { |
| 690 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 691 | 683 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 692 | 684 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 693 | 685 | |
| ... | ... | @@ -742,8 +734,8 @@ test "union with only 1 field casted to its enum type which has enum value speci |
| 742 | 734 | } |
| 743 | 735 | |
| 744 | 736 | test "@intFromEnum works on unions" { |
| 737 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 745 | 738 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 746 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 747 | 739 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 748 | 740 | |
| 749 | 741 | const Bar = union(enum) { |
| ... | ... | @@ -801,8 +793,8 @@ fn Setter(comptime attr: Attribute) type { |
| 801 | 793 | } |
| 802 | 794 | |
| 803 | 795 | test "return union init with void payload" { |
| 804 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 805 | 796 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 797 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 806 | 798 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 807 | 799 | |
| 808 | 800 | const S = struct { |
| ... | ... | @@ -825,7 +817,7 @@ test "return union init with void payload" { |
| 825 | 817 | } |
| 826 | 818 | |
| 827 | 819 | test "@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; | |
| 829 | 821 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 830 | 822 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 831 | 823 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -856,7 +848,7 @@ test "@unionInit stored to a const" { |
| 856 | 848 | } |
| 857 | 849 | |
| 858 | 850 | test "@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; | |
| 860 | 852 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 861 | 853 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 862 | 854 | |
| ... | ... | @@ -879,7 +871,7 @@ test "@unionInit can modify a union type" { |
| 879 | 871 | } |
| 880 | 872 | |
| 881 | 873 | test "@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; | |
| 883 | 875 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 884 | 876 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 885 | 877 | |
| ... | ... | @@ -899,7 +891,6 @@ test "@unionInit can modify a pointer value" { |
| 899 | 891 | } |
| 900 | 892 | |
| 901 | 893 | test "union no tag with struct member" { |
| 902 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 903 | 894 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 904 | 895 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 905 | 896 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -935,8 +926,8 @@ test "extern union doesn't trigger field check at comptime" { |
| 935 | 926 | } |
| 936 | 927 | |
| 937 | 928 | test "anonymous union literal syntax" { |
| 929 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 938 | 930 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 939 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 940 | 931 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 941 | 932 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 942 | 933 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -964,8 +955,8 @@ test "anonymous union literal syntax" { |
| 964 | 955 | } |
| 965 | 956 | |
| 966 | 957 | test "function call result coerces from tagged union to the tag" { |
| 958 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 967 | 959 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 968 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 969 | 960 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 970 | 961 | |
| 971 | 962 | const S = struct { |
| ... | ... | @@ -999,8 +990,8 @@ test "function call result coerces from tagged union to the tag" { |
| 999 | 990 | } |
| 1000 | 991 | |
| 1001 | 992 | test "switching on non exhaustive union" { |
| 993 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1002 | 994 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1003 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1004 | 995 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1005 | 996 | |
| 1006 | 997 | const S = struct { |
| ... | ... | @@ -1028,7 +1019,6 @@ test "switching on non exhaustive union" { |
| 1028 | 1019 | |
| 1029 | 1020 | test "containers with single-field enums" { |
| 1030 | 1021 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1031 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1032 | 1022 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1033 | 1023 | |
| 1034 | 1024 | const S = struct { |
| ... | ... | @@ -1057,8 +1047,8 @@ test "containers with single-field enums" { |
| 1057 | 1047 | } |
| 1058 | 1048 | |
| 1059 | 1049 | test "@unionInit on union with tag but no fields" { |
| 1050 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1060 | 1051 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1061 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1062 | 1052 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1063 | 1053 | |
| 1064 | 1054 | const S = struct { |
| ... | ... | @@ -1106,7 +1096,7 @@ test "union enum type gets a separate scope" { |
| 1106 | 1096 | } |
| 1107 | 1097 | |
| 1108 | 1098 | test "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; | |
| 1110 | 1100 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1111 | 1101 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1112 | 1102 | 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 |
| 1133 | 1123 | } |
| 1134 | 1124 | |
| 1135 | 1125 | test "union with no result loc initiated with a runtime value" { |
| 1126 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1136 | 1127 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1137 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1138 | 1128 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1139 | 1129 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1140 | 1130 | |
| ... | ... | @@ -1151,8 +1141,8 @@ test "union with no result loc initiated with a runtime value" { |
| 1151 | 1141 | } |
| 1152 | 1142 | |
| 1153 | 1143 | test "union with a large struct field" { |
| 1144 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1154 | 1145 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1155 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1156 | 1146 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1157 | 1147 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1158 | 1148 | |
| ... | ... | @@ -1186,8 +1176,8 @@ test "comptime equality of extern unions with same tag" { |
| 1186 | 1176 | } |
| 1187 | 1177 | |
| 1188 | 1178 | test "union tag is set when initiated as a temporary value at runtime" { |
| 1179 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1189 | 1180 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1190 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1191 | 1181 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1192 | 1182 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1193 | 1183 | |
| ... | ... | @@ -1206,8 +1196,8 @@ test "union tag is set when initiated as a temporary value at runtime" { |
| 1206 | 1196 | } |
| 1207 | 1197 | |
| 1208 | 1198 | test "extern union most-aligned field is smaller" { |
| 1199 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1209 | 1200 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1210 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1211 | 1201 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1212 | 1202 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1213 | 1203 | |
| ... | ... | @@ -1226,8 +1216,8 @@ test "extern union most-aligned field is smaller" { |
| 1226 | 1216 | } |
| 1227 | 1217 | |
| 1228 | 1218 | test "return an extern union from C calling convention" { |
| 1219 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1229 | 1220 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1230 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1231 | 1221 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1232 | 1222 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1233 | 1223 | |
| ... | ... | @@ -1258,7 +1248,7 @@ test "return an extern union from C calling convention" { |
| 1258 | 1248 | } |
| 1259 | 1249 | |
| 1260 | 1250 | test "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; | |
| 1262 | 1252 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1263 | 1253 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1264 | 1254 | |
| ... | ... | @@ -1309,7 +1299,7 @@ test "noreturn field in union" { |
| 1309 | 1299 | } |
| 1310 | 1300 | |
| 1311 | 1301 | test "@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; | |
| 1313 | 1303 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1314 | 1304 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1315 | 1305 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1339,7 +1329,6 @@ test "@unionInit uses tag value instead of field index" { |
| 1339 | 1329 | } |
| 1340 | 1330 | |
| 1341 | 1331 | test "union field ptr - zero sized payload" { |
| 1342 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1343 | 1332 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1344 | 1333 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1345 | 1334 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1354,7 +1343,6 @@ test "union field ptr - zero sized payload" { |
| 1354 | 1343 | } |
| 1355 | 1344 | |
| 1356 | 1345 | test "union field ptr - zero sized field" { |
| 1357 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1358 | 1346 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1359 | 1347 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1360 | 1348 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1369,7 +1357,7 @@ test "union field ptr - zero sized field" { |
| 1369 | 1357 | } |
| 1370 | 1358 | |
| 1371 | 1359 | test "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; | |
| 1373 | 1361 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1374 | 1362 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1375 | 1363 | |
| ... | ... | @@ -1420,8 +1408,8 @@ test "union int tag type is properly managed" { |
| 1420 | 1408 | } |
| 1421 | 1409 | |
| 1422 | 1410 | test "no dependency loop when function pointer in union returns the union" { |
| 1411 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1423 | 1412 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1424 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1425 | 1413 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1426 | 1414 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1427 | 1415 | |
| ... | ... | @@ -1442,7 +1430,7 @@ test "no dependency loop when function pointer in union returns the union" { |
| 1442 | 1430 | } |
| 1443 | 1431 | |
| 1444 | 1432 | test "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; | |
| 1446 | 1434 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1447 | 1435 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1448 | 1436 | |
| ... | ... | @@ -1456,7 +1444,7 @@ test "union reassignment can use previous value" { |
| 1456 | 1444 | } |
| 1457 | 1445 | |
| 1458 | 1446 | test "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; | |
| 1460 | 1448 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1461 | 1449 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1462 | 1450 | |
| ... | ... | @@ -1475,7 +1463,7 @@ test "packed union with zero-bit field" { |
| 1475 | 1463 | } |
| 1476 | 1464 | |
| 1477 | 1465 | test "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; | |
| 1479 | 1467 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1480 | 1468 | |
| 1481 | 1469 | const U = packed union { |
| ... | ... | @@ -1493,7 +1481,7 @@ test "reinterpreting enum value inside packed union" { |
| 1493 | 1481 | } |
| 1494 | 1482 | |
| 1495 | 1483 | test "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; | |
| 1497 | 1485 | |
| 1498 | 1486 | const U = union(enum) { |
| 1499 | 1487 | a, |
| ... | ... | @@ -1504,7 +1492,7 @@ test "access the tag of a global tagged union" { |
| 1504 | 1492 | } |
| 1505 | 1493 | |
| 1506 | 1494 | test "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; | |
| 1508 | 1496 | |
| 1509 | 1497 | const U = union(enum) { |
| 1510 | 1498 | a, |
| ... | ... | @@ -1522,7 +1510,6 @@ test "coerce enum literal to union in result loc" { |
| 1522 | 1510 | test "defined-layout union field pointer has correct alignment" { |
| 1523 | 1511 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 1524 | 1512 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1525 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1526 | 1513 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1527 | 1514 | |
| 1528 | 1515 | const S = struct { |
| ... | ... | @@ -1557,7 +1544,6 @@ test "defined-layout union field pointer has correct alignment" { |
| 1557 | 1544 | test "undefined-layout union field pointer has correct alignment" { |
| 1558 | 1545 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 1559 | 1546 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1560 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1561 | 1547 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1562 | 1548 | |
| 1563 | 1549 | const S = struct { |
| ... | ... | @@ -1590,8 +1576,8 @@ test "undefined-layout union field pointer has correct alignment" { |
| 1590 | 1576 | } |
| 1591 | 1577 | |
| 1592 | 1578 | test "packed union field pointer has correct alignment" { |
| 1579 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1593 | 1580 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1594 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1595 | 1581 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1596 | 1582 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| 1597 | 1583 | |
| ... | ... | @@ -1624,6 +1610,7 @@ test "packed union field pointer has correct alignment" { |
| 1624 | 1610 | } |
| 1625 | 1611 | |
| 1626 | 1612 | test "union with 128 bit integer" { |
| 1613 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1627 | 1614 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1628 | 1615 | |
| 1629 | 1616 | const ValueTag = enum { int, other }; |
| ... | ... | @@ -1647,6 +1634,7 @@ test "union with 128 bit integer" { |
| 1647 | 1634 | } |
| 1648 | 1635 | |
| 1649 | 1636 | test "memset extern union" { |
| 1637 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1650 | 1638 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1651 | 1639 | |
| 1652 | 1640 | const U = extern union { |
| ... | ... | @@ -1668,6 +1656,7 @@ test "memset extern union" { |
| 1668 | 1656 | } |
| 1669 | 1657 | |
| 1670 | 1658 | test "memset packed union" { |
| 1659 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1671 | 1660 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1672 | 1661 | |
| 1673 | 1662 | const U = packed union { |
| ... | ... | @@ -1768,6 +1757,7 @@ test "reinterpret extern union" { |
| 1768 | 1757 | } |
| 1769 | 1758 | |
| 1770 | 1759 | test "reinterpret packed union" { |
| 1760 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1771 | 1761 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1772 | 1762 | |
| 1773 | 1763 | const U = packed union { |
| ... | ... | @@ -1840,6 +1830,7 @@ test "reinterpret packed union" { |
| 1840 | 1830 | } |
| 1841 | 1831 | |
| 1842 | 1832 | test "reinterpret packed union inside packed struct" { |
| 1833 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1843 | 1834 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1844 | 1835 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 1845 | 1836 | |
| ... | ... | @@ -1945,6 +1936,8 @@ test "extern union initialized via reintepreted struct field initializer" { |
| 1945 | 1936 | } |
| 1946 | 1937 | |
| 1947 | 1938 | test "packed union initialized via reintepreted struct field initializer" { |
| 1939 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1940 | ||
| 1948 | 1941 | const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; |
| 1949 | 1942 | |
| 1950 | 1943 | const U = packed union { |
| ... | ... | @@ -1963,6 +1956,7 @@ test "packed union initialized via reintepreted struct field initializer" { |
| 1963 | 1956 | } |
| 1964 | 1957 | |
| 1965 | 1958 | test "store of comptime reinterpreted memory to extern union" { |
| 1959 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1966 | 1960 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1967 | 1961 | |
| 1968 | 1962 | const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; |
| ... | ... | @@ -1985,6 +1979,8 @@ test "store of comptime reinterpreted memory to extern union" { |
| 1985 | 1979 | } |
| 1986 | 1980 | |
| 1987 | 1981 | test "store of comptime reinterpreted memory to packed union" { |
| 1982 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1983 | ||
| 1988 | 1984 | const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; |
| 1989 | 1985 | |
| 1990 | 1986 | const U = packed union { |
| ... | ... | @@ -2005,7 +2001,6 @@ test "store of comptime reinterpreted memory to packed union" { |
| 2005 | 2001 | } |
| 2006 | 2002 | |
| 2007 | 2003 | test "union field is a pointer to an aligned version of itself" { |
| 2008 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2009 | 2004 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 2010 | 2005 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 2011 | 2006 | |
| ... | ... | @@ -2019,6 +2014,7 @@ test "union field is a pointer to an aligned version of itself" { |
| 2019 | 2014 | } |
| 2020 | 2015 | |
| 2021 | 2016 | test "pass register-sized field as non-register-sized union" { |
| 2017 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2022 | 2018 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 2023 | 2019 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 2024 | 2020 | |
| ... | ... | @@ -2067,6 +2063,7 @@ test "circular dependency through pointer field of a union" { |
| 2067 | 2063 | } |
| 2068 | 2064 | |
| 2069 | 2065 | test "pass nested union with rls" { |
| 2066 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2070 | 2067 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 2071 | 2068 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 2072 | 2069 | |
| ... | ... | @@ -2088,8 +2085,8 @@ test "pass nested union with rls" { |
| 2088 | 2085 | } |
| 2089 | 2086 | |
| 2090 | 2087 | test "runtime union init, most-aligned field != largest" { |
| 2088 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2091 | 2089 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2092 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2093 | 2090 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2094 | 2091 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 2095 | 2092 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -2114,8 +2111,8 @@ test "runtime union init, most-aligned field != largest" { |
| 2114 | 2111 | } |
| 2115 | 2112 | |
| 2116 | 2113 | test "copied union field doesn't alias source" { |
| 2114 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2117 | 2115 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2118 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2119 | 2116 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2120 | 2117 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 2121 | 2118 | |
| ... | ... | @@ -2134,7 +2131,7 @@ test "copied union field doesn't alias source" { |
| 2134 | 2131 | } |
| 2135 | 2132 | |
| 2136 | 2133 | test "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; | |
| 2138 | 2135 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2139 | 2136 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 2140 | 2137 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -2258,7 +2255,7 @@ test "matching captures causes union equivalence" { |
| 2258 | 2255 | } |
| 2259 | 2256 | |
| 2260 | 2257 | test "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; | |
| 2262 | 2259 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2263 | 2260 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 2264 | 2261 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -2315,6 +2312,7 @@ test "extern union @FieldType" { |
| 2315 | 2312 | } |
| 2316 | 2313 | |
| 2317 | 2314 | test "assign global tagged union" { |
| 2315 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2318 | 2316 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 2319 | 2317 | |
| 2320 | 2318 | const U = union(enum) { |
| ... | ... | @@ -2336,6 +2334,8 @@ test "assign global tagged union" { |
| 2336 | 2334 | } |
| 2337 | 2335 | |
| 2338 | 2336 | test "set mutable union by switching on same union" { |
| 2337 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2338 | ||
| 2339 | 2339 | const U = union(enum) { |
| 2340 | 2340 | foo, |
| 2341 | 2341 | bar: usize, |
test/behavior/union_with_members.zig+1-1| ... | ... | @@ -17,8 +17,8 @@ const ET = union(enum) { |
| 17 | 17 | }; |
| 18 | 18 | |
| 19 | 19 | test "enum with members" { |
| 20 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 20 | 21 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 21 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 22 | 22 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 23 | 23 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 24 | 24 |
test/behavior/var_args.zig+10-12| ... | ... | @@ -28,7 +28,6 @@ test "send void arg to var args" { |
| 28 | 28 | } |
| 29 | 29 | |
| 30 | 30 | test "pass args directly" { |
| 31 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 32 | 31 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 33 | 32 | |
| 34 | 33 | 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 { |
| 41 | 40 | } |
| 42 | 41 | |
| 43 | 42 | test "runtime parameter before var args" { |
| 44 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 45 | 43 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 46 | 44 | |
| 47 | 45 | try expect((try extraFn(10, .{})) == 0); |
| ... | ... | @@ -94,13 +92,13 @@ fn doNothingWithFirstArg(args: anytype) void { |
| 94 | 92 | } |
| 95 | 93 | |
| 96 | 94 | test "simple variadic function" { |
| 97 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 95 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 98 | 96 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 99 | 97 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 100 | 98 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 101 | 99 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 102 | 100 | 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()) { | |
| 104 | 102 | // https://github.com/ziglang/zig/issues/14096 |
| 105 | 103 | return error.SkipZigTest; |
| 106 | 104 | } |
| ... | ... | @@ -156,13 +154,13 @@ test "simple variadic function" { |
| 156 | 154 | } |
| 157 | 155 | |
| 158 | 156 | test "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; | |
| 160 | 158 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 161 | 159 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 162 | 160 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 163 | 161 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 164 | 162 | 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()) { | |
| 166 | 164 | // https://github.com/ziglang/zig/issues/14096 |
| 167 | 165 | return error.SkipZigTest; |
| 168 | 166 | } |
| ... | ... | @@ -189,13 +187,13 @@ test "coerce reference to var arg" { |
| 189 | 187 | } |
| 190 | 188 | |
| 191 | 189 | test "variadic functions" { |
| 192 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 190 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 193 | 191 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 194 | 192 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 195 | 193 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 196 | 194 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 197 | 195 | 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()) { | |
| 199 | 197 | // https://github.com/ziglang/zig/issues/14096 |
| 200 | 198 | return error.SkipZigTest; |
| 201 | 199 | } |
| ... | ... | @@ -236,12 +234,12 @@ test "variadic functions" { |
| 236 | 234 | } |
| 237 | 235 | |
| 238 | 236 | test "copy VaList" { |
| 239 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 237 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 240 | 238 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 241 | 239 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 242 | 240 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 243 | 241 | 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()) { | |
| 245 | 243 | // https://github.com/ziglang/zig/issues/14096 |
| 246 | 244 | return error.SkipZigTest; |
| 247 | 245 | } |
| ... | ... | @@ -271,12 +269,12 @@ test "copy VaList" { |
| 271 | 269 | } |
| 272 | 270 | |
| 273 | 271 | test "unused VaList arg" { |
| 274 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 272 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 275 | 273 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 276 | 274 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 277 | 275 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 278 | 276 | 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()) { | |
| 280 | 278 | // https://github.com/ziglang/zig/issues/14096 |
| 281 | 279 | return error.SkipZigTest; |
| 282 | 280 | } |
test/behavior/vector.zig+43-55| ... | ... | @@ -8,7 +8,6 @@ const expectEqual = std.testing.expectEqual; |
| 8 | 8 | |
| 9 | 9 | test "implicit cast vector to array - bool" { |
| 10 | 10 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 11 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 12 | 11 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 13 | 12 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 14 | 13 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -25,8 +24,8 @@ test "implicit cast vector to array - bool" { |
| 25 | 24 | } |
| 26 | 25 | |
| 27 | 26 | test "vector wrap operators" { |
| 27 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 28 | 28 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 29 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 30 | 29 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 31 | 30 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 32 | 31 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -49,8 +48,8 @@ test "vector wrap operators" { |
| 49 | 48 | } |
| 50 | 49 | |
| 51 | 50 | test "vector bin compares with mem.eql" { |
| 51 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 52 | 52 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 53 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 54 | 53 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 55 | 54 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 56 | 55 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -74,8 +73,8 @@ test "vector bin compares with mem.eql" { |
| 74 | 73 | } |
| 75 | 74 | |
| 76 | 75 | test "vector int operators" { |
| 76 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 77 | 77 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 78 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 79 | 78 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 80 | 79 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 81 | 80 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -97,8 +96,8 @@ test "vector int operators" { |
| 97 | 96 | } |
| 98 | 97 | |
| 99 | 98 | test "vector float operators" { |
| 99 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 100 | 100 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 101 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 102 | 101 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 103 | 102 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 104 | 103 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -141,8 +140,8 @@ test "vector float operators" { |
| 141 | 140 | } |
| 142 | 141 | |
| 143 | 142 | test "vector bit operators" { |
| 143 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 144 | 144 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 145 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 146 | 145 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 147 | 146 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 148 | 147 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -173,7 +172,7 @@ test "vector bit operators" { |
| 173 | 172 | } |
| 174 | 173 | |
| 175 | 174 | test "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; | |
| 177 | 176 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 178 | 177 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 179 | 178 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -193,7 +192,7 @@ test "implicit cast vector to array" { |
| 193 | 192 | } |
| 194 | 193 | |
| 195 | 194 | test "array to vector" { |
| 196 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 195 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 197 | 196 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 198 | 197 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 199 | 198 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -212,7 +211,7 @@ test "array to vector" { |
| 212 | 211 | } |
| 213 | 212 | |
| 214 | 213 | test "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; | |
| 216 | 215 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 217 | 216 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 218 | 217 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| ... | ... | @@ -251,7 +250,7 @@ test "array vector coercion - odd sizes" { |
| 251 | 250 | } |
| 252 | 251 | |
| 253 | 252 | test "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; | |
| 255 | 254 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 256 | 255 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 257 | 256 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -273,7 +272,6 @@ test "array to vector with element type coercion" { |
| 273 | 272 | |
| 274 | 273 | test "peer type resolution with coercible element types" { |
| 275 | 274 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 276 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 277 | 275 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 278 | 276 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 279 | 277 | |
| ... | ... | @@ -291,8 +289,8 @@ test "peer type resolution with coercible element types" { |
| 291 | 289 | } |
| 292 | 290 | |
| 293 | 291 | test "tuple to vector" { |
| 292 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 294 | 293 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 295 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 296 | 294 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 297 | 295 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 298 | 296 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -314,8 +312,8 @@ test "tuple to vector" { |
| 314 | 312 | } |
| 315 | 313 | |
| 316 | 314 | test "vector casts of sizes not divisible by 8" { |
| 315 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 317 | 316 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 318 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 319 | 317 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 320 | 318 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 321 | 319 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -354,7 +352,7 @@ test "vector casts of sizes not divisible by 8" { |
| 354 | 352 | } |
| 355 | 353 | |
| 356 | 354 | test "vector @splat" { |
| 357 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 355 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 358 | 356 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 359 | 357 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 360 | 358 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -395,7 +393,7 @@ test "vector @splat" { |
| 395 | 393 | } |
| 396 | 394 | |
| 397 | 395 | test "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; | |
| 399 | 397 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 400 | 398 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 401 | 399 | |
| ... | ... | @@ -416,7 +414,7 @@ test "load vector elements via comptime index" { |
| 416 | 414 | } |
| 417 | 415 | |
| 418 | 416 | test "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; | |
| 420 | 418 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 421 | 419 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 422 | 420 | |
| ... | ... | @@ -443,7 +441,6 @@ test "store vector elements via comptime index" { |
| 443 | 441 | } |
| 444 | 442 | |
| 445 | 443 | test "load vector elements via runtime index" { |
| 446 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 447 | 444 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 448 | 445 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 449 | 446 | |
| ... | ... | @@ -465,7 +462,7 @@ test "load vector elements via runtime index" { |
| 465 | 462 | } |
| 466 | 463 | |
| 467 | 464 | test "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; | |
| 469 | 466 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 470 | 467 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 471 | 468 | |
| ... | ... | @@ -487,7 +484,6 @@ test "store vector elements via runtime index" { |
| 487 | 484 | } |
| 488 | 485 | |
| 489 | 486 | test "initialize vector which is a struct field" { |
| 490 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 491 | 487 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 492 | 488 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 493 | 489 | |
| ... | ... | @@ -508,8 +504,8 @@ test "initialize vector which is a struct field" { |
| 508 | 504 | } |
| 509 | 505 | |
| 510 | 506 | test "vector comparison operators" { |
| 507 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 511 | 508 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 512 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 513 | 509 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 514 | 510 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 515 | 511 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -554,8 +550,8 @@ test "vector comparison operators" { |
| 554 | 550 | } |
| 555 | 551 | |
| 556 | 552 | test "vector division operators" { |
| 553 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 557 | 554 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 558 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 559 | 555 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 560 | 556 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 561 | 557 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -647,9 +643,9 @@ test "vector division operators" { |
| 647 | 643 | } |
| 648 | 644 | |
| 649 | 645 | test "vector bitwise not operator" { |
| 646 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 650 | 647 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 651 | 648 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 652 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 653 | 649 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 654 | 650 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 655 | 651 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -681,9 +677,9 @@ test "vector bitwise not operator" { |
| 681 | 677 | } |
| 682 | 678 | |
| 683 | 679 | test "vector boolean not operator" { |
| 680 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 684 | 681 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 685 | 682 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 686 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 687 | 683 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 688 | 684 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 689 | 685 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -705,8 +701,8 @@ test "vector boolean not operator" { |
| 705 | 701 | } |
| 706 | 702 | |
| 707 | 703 | test "vector shift operators" { |
| 704 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 708 | 705 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 709 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 710 | 706 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 711 | 707 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 712 | 708 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -776,8 +772,8 @@ test "vector shift operators" { |
| 776 | 772 | } |
| 777 | 773 | |
| 778 | 774 | test "vector reduce operation" { |
| 775 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 779 | 776 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 780 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 781 | 777 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 782 | 778 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 783 | 779 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -908,7 +904,6 @@ test "vector reduce operation" { |
| 908 | 904 | |
| 909 | 905 | test "vector @reduce comptime" { |
| 910 | 906 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 911 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 912 | 907 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 913 | 908 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 914 | 909 | |
| ... | ... | @@ -924,7 +919,7 @@ test "vector @reduce comptime" { |
| 924 | 919 | } |
| 925 | 920 | |
| 926 | 921 | test "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; | |
| 928 | 923 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 929 | 924 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 930 | 925 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -946,8 +941,8 @@ test "mask parameter of @shuffle is comptime scope" { |
| 946 | 941 | } |
| 947 | 942 | |
| 948 | 943 | test "saturating add" { |
| 944 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 949 | 945 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 950 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 951 | 946 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 952 | 947 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 953 | 948 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -980,8 +975,8 @@ test "saturating add" { |
| 980 | 975 | } |
| 981 | 976 | |
| 982 | 977 | test "saturating subtraction" { |
| 978 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 983 | 979 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 984 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 985 | 980 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 986 | 981 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 987 | 982 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1004,8 +999,8 @@ test "saturating subtraction" { |
| 1004 | 999 | } |
| 1005 | 1000 | |
| 1006 | 1001 | test "saturating multiplication" { |
| 1002 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1007 | 1003 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1008 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1009 | 1004 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1010 | 1005 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1011 | 1006 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1032,8 +1027,8 @@ test "saturating multiplication" { |
| 1032 | 1027 | } |
| 1033 | 1028 | |
| 1034 | 1029 | test "saturating shift-left" { |
| 1030 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1035 | 1031 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1036 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1037 | 1032 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1038 | 1033 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1039 | 1034 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1056,8 +1051,8 @@ test "saturating shift-left" { |
| 1056 | 1051 | } |
| 1057 | 1052 | |
| 1058 | 1053 | test "multiplication-assignment operator with an array operand" { |
| 1054 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1059 | 1055 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1060 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1061 | 1056 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1062 | 1057 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1063 | 1058 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1077,8 +1072,8 @@ test "multiplication-assignment operator with an array operand" { |
| 1077 | 1072 | } |
| 1078 | 1073 | |
| 1079 | 1074 | test "@addWithOverflow" { |
| 1075 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1080 | 1076 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1081 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1082 | 1077 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1083 | 1078 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1084 | 1079 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1127,8 +1122,8 @@ test "@addWithOverflow" { |
| 1127 | 1122 | } |
| 1128 | 1123 | |
| 1129 | 1124 | test "@subWithOverflow" { |
| 1125 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1130 | 1126 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1131 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1132 | 1127 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1133 | 1128 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1134 | 1129 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1161,8 +1156,8 @@ test "@subWithOverflow" { |
| 1161 | 1156 | } |
| 1162 | 1157 | |
| 1163 | 1158 | test "@mulWithOverflow" { |
| 1159 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1164 | 1160 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1165 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1166 | 1161 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1167 | 1162 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1168 | 1163 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1184,8 +1179,8 @@ test "@mulWithOverflow" { |
| 1184 | 1179 | } |
| 1185 | 1180 | |
| 1186 | 1181 | test "@shlWithOverflow" { |
| 1182 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1187 | 1183 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1188 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1189 | 1184 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1190 | 1185 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1191 | 1186 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1229,8 +1224,8 @@ test "alignment of vectors" { |
| 1229 | 1224 | } |
| 1230 | 1225 | |
| 1231 | 1226 | test "loading the second vector from a slice of vectors" { |
| 1227 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1232 | 1228 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1233 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1234 | 1229 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1235 | 1230 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1236 | 1231 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1246,8 +1241,8 @@ test "loading the second vector from a slice of vectors" { |
| 1246 | 1241 | } |
| 1247 | 1242 | |
| 1248 | 1243 | test "array of vectors is copied" { |
| 1244 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1249 | 1245 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1250 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1251 | 1246 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1252 | 1247 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1253 | 1248 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1270,8 +1265,8 @@ test "array of vectors is copied" { |
| 1270 | 1265 | } |
| 1271 | 1266 | |
| 1272 | 1267 | test "byte vector initialized in inline function" { |
| 1268 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1273 | 1269 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1274 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1275 | 1270 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1276 | 1271 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1277 | 1272 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1297,7 +1292,6 @@ test "byte vector initialized in inline function" { |
| 1297 | 1292 | |
| 1298 | 1293 | test "zero divisor" { |
| 1299 | 1294 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1300 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1301 | 1295 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1302 | 1296 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1303 | 1297 | |
| ... | ... | @@ -1317,7 +1311,6 @@ test "zero divisor" { |
| 1317 | 1311 | |
| 1318 | 1312 | test "zero multiplicand" { |
| 1319 | 1313 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1320 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1321 | 1314 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1322 | 1315 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1323 | 1316 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1341,7 +1334,6 @@ test "zero multiplicand" { |
| 1341 | 1334 | |
| 1342 | 1335 | test "@intCast to u0" { |
| 1343 | 1336 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1344 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1345 | 1337 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1346 | 1338 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1347 | 1339 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1364,8 +1356,8 @@ test "modRem with zero divisor" { |
| 1364 | 1356 | } |
| 1365 | 1357 | |
| 1366 | 1358 | test "array operands to shuffle are coerced to vectors" { |
| 1359 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1367 | 1360 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1368 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1369 | 1361 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1370 | 1362 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1371 | 1363 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1379,7 +1371,7 @@ test "array operands to shuffle are coerced to vectors" { |
| 1379 | 1371 | } |
| 1380 | 1372 | |
| 1381 | 1373 | test "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; | |
| 1383 | 1375 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1384 | 1376 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1385 | 1377 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1391,7 +1383,7 @@ test "load packed vector element" { |
| 1391 | 1383 | } |
| 1392 | 1384 | |
| 1393 | 1385 | test "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; | |
| 1395 | 1387 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1396 | 1388 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1397 | 1389 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1408,7 +1400,7 @@ test "store packed vector element" { |
| 1408 | 1400 | } |
| 1409 | 1401 | |
| 1410 | 1402 | test "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; | |
| 1412 | 1404 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1413 | 1405 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1414 | 1406 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1426,7 +1418,7 @@ test "store to vector in slice" { |
| 1426 | 1418 | } |
| 1427 | 1419 | |
| 1428 | 1420 | test "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; | |
| 1430 | 1422 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1431 | 1423 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1432 | 1424 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1459,7 +1451,7 @@ test "store vector with memset" { |
| 1459 | 1451 | } |
| 1460 | 1452 | |
| 1461 | 1453 | test "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; | |
| 1463 | 1455 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1464 | 1456 | |
| 1465 | 1457 | const V = @Vector(3, u8); |
| ... | ... | @@ -1469,7 +1461,7 @@ test "addition of vectors represented as strings" { |
| 1469 | 1461 | } |
| 1470 | 1462 | |
| 1471 | 1463 | test "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; | |
| 1473 | 1465 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1474 | 1466 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1475 | 1467 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1482,7 +1474,6 @@ test "compare vectors with different element types" { |
| 1482 | 1474 | } |
| 1483 | 1475 | |
| 1484 | 1476 | test "vector pointer is indexable" { |
| 1485 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1486 | 1477 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1487 | 1478 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1488 | 1479 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1506,7 +1497,6 @@ test "vector pointer is indexable" { |
| 1506 | 1497 | } |
| 1507 | 1498 | |
| 1508 | 1499 | test "boolean vector with 2 or more booleans" { |
| 1509 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1510 | 1500 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1511 | 1501 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1512 | 1502 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1519,7 +1509,7 @@ test "boolean vector with 2 or more booleans" { |
| 1519 | 1509 | } |
| 1520 | 1510 | |
| 1521 | 1511 | test "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; | |
| 1523 | 1513 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1524 | 1514 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1525 | 1515 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1551,7 +1541,6 @@ test "index into comptime-known vector is comptime-known" { |
| 1551 | 1541 | |
| 1552 | 1542 | test "arithmetic on zero-length vectors" { |
| 1553 | 1543 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1554 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1555 | 1544 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1556 | 1545 | |
| 1557 | 1546 | { |
| ... | ... | @@ -1568,7 +1557,6 @@ test "arithmetic on zero-length vectors" { |
| 1568 | 1557 | |
| 1569 | 1558 | test "@reduce on bool vector" { |
| 1570 | 1559 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1571 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1572 | 1560 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1573 | 1561 | |
| 1574 | 1562 | const a = @Vector(2, bool){ true, true }; |
| ... | ... | @@ -1578,7 +1566,7 @@ test "@reduce on bool vector" { |
| 1578 | 1566 | } |
| 1579 | 1567 | |
| 1580 | 1568 | test "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; | |
| 1582 | 1570 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1583 | 1571 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1584 | 1572 |
test/behavior/void.zig-1| ... | ... | @@ -36,7 +36,6 @@ fn times(n: usize) []const void { |
| 36 | 36 | |
| 37 | 37 | test "void optional" { |
| 38 | 38 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 39 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 40 | 39 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 41 | 40 | |
| 42 | 41 | var x: ?void = {}; |
test/behavior/while.zig+3-9| ... | ... | @@ -124,8 +124,6 @@ test "while copies its payload" { |
| 124 | 124 | } |
| 125 | 125 | |
| 126 | 126 | test "continue and break" { |
| 127 | if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest; | |
| 128 | ||
| 129 | 127 | try runContinueAndBreakTest(); |
| 130 | 128 | try expect(continue_and_break_counter == 8); |
| 131 | 129 | } |
| ... | ... | @@ -176,6 +174,7 @@ test "while with optional as condition with else" { |
| 176 | 174 | } |
| 177 | 175 | |
| 178 | 176 | test "while with error union condition" { |
| 177 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 179 | 178 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 180 | 179 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 181 | 180 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -209,7 +208,6 @@ test "while on bool with else result follow break prong" { |
| 209 | 208 | |
| 210 | 209 | test "while on optional with else result follow else prong" { |
| 211 | 210 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 212 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 213 | 211 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 214 | 212 | |
| 215 | 213 | const result = while (returnNull()) |value| { |
| ... | ... | @@ -220,7 +218,6 @@ test "while on optional with else result follow else prong" { |
| 220 | 218 | |
| 221 | 219 | test "while on optional with else result follow break prong" { |
| 222 | 220 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 223 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 224 | 221 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 225 | 222 | |
| 226 | 223 | const result = while (returnOptional(10)) |value| { |
| ... | ... | @@ -292,7 +289,6 @@ test "while bool 2 break statements and an else" { |
| 292 | 289 | |
| 293 | 290 | test "while optional 2 break statements and an else" { |
| 294 | 291 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 295 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 296 | 292 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 297 | 293 | |
| 298 | 294 | const S = struct { |
| ... | ... | @@ -310,8 +306,8 @@ test "while optional 2 break statements and an else" { |
| 310 | 306 | } |
| 311 | 307 | |
| 312 | 308 | test "while error 2 break statements and an else" { |
| 309 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 313 | 310 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 314 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 315 | 311 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 316 | 312 | |
| 317 | 313 | const S = struct { |
| ... | ... | @@ -348,8 +344,8 @@ test "else continue outer while" { |
| 348 | 344 | } |
| 349 | 345 | |
| 350 | 346 | test "try terminating an infinite loop" { |
| 347 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 351 | 348 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 352 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 353 | 349 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 354 | 350 | |
| 355 | 351 | // 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 |
| 376 | 372 | } |
| 377 | 373 | |
| 378 | 374 | test "int returned from switch in while" { |
| 379 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 380 | 375 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 381 | 376 | |
| 382 | 377 | var x: u32 = 3; |
| ... | ... | @@ -389,7 +384,6 @@ test "int returned from switch in while" { |
| 389 | 384 | |
| 390 | 385 | test "breaking from a loop in an if statement" { |
| 391 | 386 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 392 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 393 | 387 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 394 | 388 | |
| 395 | 389 | const S = struct { |
test/behavior/widening.zig-5| ... | ... | @@ -4,7 +4,6 @@ const mem = std.mem; |
| 4 | 4 | const builtin = @import("builtin"); |
| 5 | 5 | |
| 6 | 6 | test "integer widening" { |
| 7 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 8 | 7 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 9 | 8 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 10 | 9 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -29,7 +28,6 @@ test "integer widening u0 to u8" { |
| 29 | 28 | } |
| 30 | 29 | |
| 31 | 30 | test "implicit unsigned integer to signed integer" { |
| 32 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 33 | 31 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 34 | 32 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 35 | 33 | |
| ... | ... | @@ -40,7 +38,6 @@ test "implicit unsigned integer to signed integer" { |
| 40 | 38 | } |
| 41 | 39 | |
| 42 | 40 | test "float widening" { |
| 43 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 44 | 41 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 45 | 42 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 46 | 43 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -60,7 +57,6 @@ test "float widening" { |
| 60 | 57 | } |
| 61 | 58 | |
| 62 | 59 | test "float widening f16 to f128" { |
| 63 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 64 | 60 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 65 | 61 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 66 | 62 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -73,7 +69,6 @@ test "float widening f16 to f128" { |
| 73 | 69 | } |
| 74 | 70 | |
| 75 | 71 | test "cast small unsigned to larger signed" { |
| 76 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 77 | 72 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 78 | 73 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 79 | 74 | 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" { |
| 25 | 25 | |
| 26 | 26 | test "initializer list expression" { |
| 27 | 27 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 28 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 29 | 28 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 30 | 29 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 31 | 30 | |
| ... | ... | @@ -38,7 +37,6 @@ test "initializer list expression" { |
| 38 | 37 | } |
| 39 | 38 | |
| 40 | 39 | test "sizeof in macros" { |
| 41 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 42 | 40 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 43 | 41 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 44 | 42 | |
| ... | ... | @@ -55,7 +53,6 @@ test "reference to a struct type" { |
| 55 | 53 | |
| 56 | 54 | test "cast negative integer to pointer" { |
| 57 | 55 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 58 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 59 | 56 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 60 | 57 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 61 | 58 | |
| ... | ... | @@ -64,7 +61,6 @@ test "cast negative integer to pointer" { |
| 64 | 61 | |
| 65 | 62 | test "casting to union with a macro" { |
| 66 | 63 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 67 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 68 | 64 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 69 | 65 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 70 | 66 | |
| ... | ... | @@ -80,7 +76,6 @@ test "casting to union with a macro" { |
| 80 | 76 | |
| 81 | 77 | test "casting or calling a value with a paren-surrounded macro" { |
| 82 | 78 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 83 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 84 | 79 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 85 | 80 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 86 | 81 | |
| ... | ... | @@ -99,7 +94,6 @@ test "casting or calling a value with a paren-surrounded macro" { |
| 99 | 94 | |
| 100 | 95 | test "nested comma operator" { |
| 101 | 96 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 102 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 103 | 97 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 104 | 98 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 105 | 99 | |
| ... | ... | @@ -109,7 +103,6 @@ test "nested comma operator" { |
| 109 | 103 | |
| 110 | 104 | test "cast functions" { |
| 111 | 105 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 112 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 113 | 106 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 114 | 107 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 115 | 108 | |
| ... | ... | @@ -123,7 +116,6 @@ test "cast functions" { |
| 123 | 116 | test "large integer macro" { |
| 124 | 117 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 125 | 118 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 126 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 127 | 119 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 128 | 120 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 129 | 121 | |
| ... | ... | @@ -132,7 +124,6 @@ test "large integer macro" { |
| 132 | 124 | |
| 133 | 125 | test "string literal macro with embedded tab character" { |
| 134 | 126 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 135 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 136 | 127 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 137 | 128 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 138 | 129 | |
| ... | ... | @@ -141,7 +132,6 @@ test "string literal macro with embedded tab character" { |
| 141 | 132 | |
| 142 | 133 | test "string and char literals that are not UTF-8 encoded. Issue #12784" { |
| 143 | 134 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 144 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 145 | 135 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 146 | 136 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 147 | 137 | |
| ... | ... | @@ -152,7 +142,6 @@ test "string and char literals that are not UTF-8 encoded. Issue #12784" { |
| 152 | 142 | test "Macro that uses division operator. Issue #13162" { |
| 153 | 143 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 154 | 144 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 155 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 156 | 145 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 157 | 146 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 158 | 147 | 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" { |
| 196 | 185 | test "Macro that uses remainder operator. Issue #13346" { |
| 197 | 186 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 198 | 187 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 199 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 200 | 188 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 201 | 189 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 202 | 190 |
test/tests.zig+37-3| ... | ... | @@ -116,8 +116,6 @@ const test_targets = blk: { |
| 116 | 116 | .abi = .eabihf, |
| 117 | 117 | }, |
| 118 | 118 | .link_libc = true, |
| 119 | // https://github.com/ziglang/zig/issues/23949 | |
| 120 | .skip_modules = &.{"std"}, | |
| 121 | 119 | }, |
| 122 | 120 | |
| 123 | 121 | .{ |
| ... | ... | @@ -191,6 +189,30 @@ const test_targets = blk: { |
| 191 | 189 | .link_libc = true, |
| 192 | 190 | }, |
| 193 | 191 | |
| 192 | .{ | |
| 193 | .target = .{ | |
| 194 | .cpu_arch = .aarch64, | |
| 195 | .os_tag = .linux, | |
| 196 | .abi = .none, | |
| 197 | }, | |
| 198 | .use_llvm = false, | |
| 199 | .use_lld = false, | |
| 200 | .optimize_mode = .ReleaseFast, | |
| 201 | .strip = true, | |
| 202 | }, | |
| 203 | .{ | |
| 204 | .target = .{ | |
| 205 | .cpu_arch = .aarch64, | |
| 206 | .cpu_model = .{ .explicit = &std.Target.aarch64.cpu.neoverse_n1 }, | |
| 207 | .os_tag = .linux, | |
| 208 | .abi = .none, | |
| 209 | }, | |
| 210 | .use_llvm = false, | |
| 211 | .use_lld = false, | |
| 212 | .optimize_mode = .ReleaseFast, | |
| 213 | .strip = true, | |
| 214 | }, | |
| 215 | ||
| 194 | 216 | .{ |
| 195 | 217 | .target = .{ |
| 196 | 218 | .cpu_arch = .aarch64_be, |
| ... | ... | @@ -1182,6 +1204,18 @@ const test_targets = blk: { |
| 1182 | 1204 | }, |
| 1183 | 1205 | }, |
| 1184 | 1206 | |
| 1207 | .{ | |
| 1208 | .target = .{ | |
| 1209 | .cpu_arch = .aarch64, | |
| 1210 | .os_tag = .macos, | |
| 1211 | .abi = .none, | |
| 1212 | }, | |
| 1213 | .use_llvm = false, | |
| 1214 | .use_lld = false, | |
| 1215 | .optimize_mode = .ReleaseFast, | |
| 1216 | .strip = true, | |
| 1217 | }, | |
| 1218 | ||
| 1185 | 1219 | .{ |
| 1186 | 1220 | .target = .{ |
| 1187 | 1221 | .cpu_arch = .x86_64, |
| ... | ... | @@ -2260,7 +2294,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { |
| 2260 | 2294 | continue; |
| 2261 | 2295 | |
| 2262 | 2296 | // TODO get compiler-rt tests passing for self-hosted backends. |
| 2263 | if ((target.cpu.arch != .x86_64 or target.ofmt != .elf) and | |
| 2297 | if (((target.cpu.arch != .x86_64 and target.cpu.arch != .aarch64) or target.ofmt == .coff) and | |
| 2264 | 2298 | test_target.use_llvm == false and mem.eql(u8, options.name, "compiler-rt")) |
| 2265 | 2299 | continue; |
| 2266 | 2300 |