authorgravatar for 78876133+IOKG04@users.noreply.github.comRue <78876133+IOKG04@users.noreply.github.com> 2025-07-28 14:54:52+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-07-28 14:54:52+02:00
log5381e7891dcdd7b6a9e74250cdcce221fe464cdc
tree4c74744ed84120dccae6dc9811ce945911108a17
parent84ae54fbe64a15301317716e7f901d81585332d5
parentdea3ed7f59347e87a1b8fa237202873988084ae8
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge branch 'ziglang:master' into some-documentation-updates-0


358 files changed, 35966 insertions(+), 11528 deletions(-)

CMakeLists.txt+8-9
...@@ -390,15 +390,6 @@ set(ZIG_STAGE2_SOURCES...@@ -390,15 +390,6 @@ set(ZIG_STAGE2_SOURCES
390 lib/std/Io.zig390 lib/std/Io.zig
391 lib/std/Io/Reader.zig391 lib/std/Io/Reader.zig
392 lib/std/Io/Writer.zig392 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 lib/std/Progress.zig393 lib/std/Progress.zig
403 lib/std/Random.zig394 lib/std/Random.zig
404 lib/std/Target.zig395 lib/std/Target.zig
...@@ -550,6 +541,14 @@ set(ZIG_STAGE2_SOURCES...@@ -550,6 +541,14 @@ set(ZIG_STAGE2_SOURCES
550 src/clang_options.zig541 src/clang_options.zig
551 src/clang_options_data.zig542 src/clang_options_data.zig
552 src/codegen.zig543 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 src/codegen/c.zig552 src/codegen/c.zig
554 src/codegen/c/Type.zig553 src/codegen/c/Type.zig
555 src/codegen/llvm.zig554 src/codegen/llvm.zig
doc/langref/build.zig+4-2
...@@ -4,8 +4,10 @@ pub fn build(b: *std.Build) void {...@@ -4,8 +4,10 @@ pub fn build(b: *std.Build) void {
4 const optimize = b.standardOptimizeOption(.{});4 const optimize = b.standardOptimizeOption(.{});
5 const exe = b.addExecutable(.{5 const exe = b.addExecutable(.{
6 .name = "example",6 .name = "example",
7 .root_source_file = b.path("example.zig"),7 .root_module = b.createModule(.{
8 .optimize = optimize,8 .root_source_file = b.path("example.zig"),
9 .optimize = optimize,
10 }),
9 });11 });
10 b.default_step.dependOn(&exe.step);12 b.default_step.dependOn(&exe.step);
11}13}
doc/langref/build_c.zig+8-4
...@@ -4,15 +4,19 @@ pub fn build(b: *std.Build) void {...@@ -4,15 +4,19 @@ pub fn build(b: *std.Build) void {
4 const lib = b.addLibrary(.{4 const lib = b.addLibrary(.{
5 .linkage = .dynamic,5 .linkage = .dynamic,
6 .name = "mathtest",6 .name = "mathtest",
7 .root_source_file = b.path("mathtest.zig"),7 .root_module = b.createModule(.{
8 .root_source_file = b.path("mathtest.zig"),
9 }),
8 .version = .{ .major = 1, .minor = 0, .patch = 0 },10 .version = .{ .major = 1, .minor = 0, .patch = 0 },
9 });11 });
10 const exe = b.addExecutable(.{12 const exe = b.addExecutable(.{
11 .name = "test",13 .name = "test",
14 .root_module = b.createModule(.{
15 .link_libc = true,
16 }),
12 });17 });
13 exe.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });18 exe.root_module.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });
14 exe.linkLibrary(lib);19 exe.root_module.linkLibrary(lib);
15 exe.linkSystemLibrary("c");
1620
17 b.default_step.dependOn(&exe.step);21 b.default_step.dependOn(&exe.step);
1822
doc/langref/build_object.zig+8-4
...@@ -3,15 +3,19 @@ const std = @import("std");...@@ -3,15 +3,19 @@ const std = @import("std");
3pub fn build(b: *std.Build) void {3pub fn build(b: *std.Build) void {
4 const obj = b.addObject(.{4 const obj = b.addObject(.{
5 .name = "base64",5 .name = "base64",
6 .root_source_file = b.path("base64.zig"),6 .root_module = b.createModule(.{
7 .root_source_file = b.path("base64.zig"),
8 }),
7 });9 });
810
9 const exe = b.addExecutable(.{11 const exe = b.addExecutable(.{
10 .name = "test",12 .name = "test",
13 .root_module = b.createModule(.{
14 .link_libc = true,
15 }),
11 });16 });
12 exe.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });17 exe.root_module.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} });
13 exe.addObject(obj);18 exe.root_module.addObject(obj);
14 exe.linkSystemLibrary("c");
15 b.installArtifact(exe);19 b.installArtifact(exe);
16}20}
1721
lib/compiler/build_runner.zig+7-3
...@@ -696,8 +696,11 @@ fn runStepNames(...@@ -696,8 +696,11 @@ fn runStepNames(
696 .failures, .none => true,696 .failures, .none => true,
697 else => false,697 else => false,
698 };698 };
699 if (failure_count == 0 and failures_only) {699 if (failure_count == 0) {
700 return run.cleanExit();700 std.Progress.setStatus(.success);
701 if (failures_only) return run.cleanExit();
702 } else {
703 std.Progress.setStatus(.failure);
701 }704 }
702705
703 const ttyconf = run.ttyconf;706 const ttyconf = run.ttyconf;
...@@ -708,7 +711,7 @@ fn runStepNames(...@@ -708,7 +711,7 @@ fn runStepNames(
708711
709 const total_count = success_count + failure_count + pending_count + skipped_count;712 const total_count = success_count + failure_count + pending_count + skipped_count;
710 ttyconf.setColor(w, .cyan) catch {};713 ttyconf.setColor(w, .cyan) catch {};
711 w.writeAll("Build Summary:") catch {};714 w.writeAll("\nBuild Summary:") catch {};
712 ttyconf.setColor(w, .reset) catch {};715 ttyconf.setColor(w, .reset) catch {};
713 w.print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {};716 w.print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {};
714 if (skipped_count > 0) w.print("; {d} skipped", .{skipped_count}) catch {};717 if (skipped_count > 0) w.print("; {d} skipped", .{skipped_count}) catch {};
...@@ -1149,6 +1152,7 @@ fn workerMakeOneStep(...@@ -1149,6 +1152,7 @@ fn workerMakeOneStep(
1149 } else |err| switch (err) {1152 } else |err| switch (err) {
1150 error.MakeFailed => {1153 error.MakeFailed => {
1151 @atomicStore(Step.State, &s.state, .failure, .seq_cst);1154 @atomicStore(Step.State, &s.state, .failure, .seq_cst);
1155 std.Progress.setStatus(.failure_working);
1152 break :handle_result;1156 break :handle_result;
1153 },1157 },
1154 error.MakeSkipped => @atomicStore(Step.State, &s.state, .skipped, .seq_cst),1158 error.MakeSkipped => @atomicStore(Step.State, &s.state, .skipped, .seq_cst),
lib/compiler/objcopy.zig+62-907
...@@ -13,6 +13,9 @@ const Server = std.zig.Server;...@@ -13,6 +13,9 @@ const Server = std.zig.Server;
13var stdin_buffer: [1024]u8 = undefined;13var stdin_buffer: [1024]u8 = undefined;
14var stdout_buffer: [1024]u8 = undefined;14var stdout_buffer: [1024]u8 = undefined;
1515
16var input_buffer: [1024]u8 = undefined;
17var output_buffer: [1024]u8 = undefined;
18
16pub fn main() !void {19pub fn main() !void {
17 var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator);20 var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator);
18 defer arena_instance.deinit();21 defer arena_instance.deinit();
...@@ -145,13 +148,16 @@ fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void...@@ -145,13 +148,16 @@ fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
145 const input = opt_input orelse fatal("expected input parameter", .{});148 const input = opt_input orelse fatal("expected input parameter", .{});
146 const output = opt_output orelse fatal("expected output parameter", .{});149 const output = opt_output orelse fatal("expected output parameter", .{});
147150
148 var in_file = fs.cwd().openFile(input, .{}) catch |err|151 const input_file = fs.cwd().openFile(input, .{}) catch |err| fatal("failed to open {s}: {t}", .{ input, err });
149 fatal("unable to open '{s}': {s}", .{ input, @errorName(err) });152 defer input_file.close();
150 defer in_file.close();153
154 const stat = input_file.stat() catch |err| fatal("failed to stat {s}: {t}", .{ input, err });
151155
152 const elf_hdr = std.elf.Header.read(in_file) catch |err| switch (err) {156 var in: File.Reader = .initSize(input_file, &input_buffer, stat.size);
153 error.InvalidElfMagic => fatal("not an ELF file: '{s}'", .{input}),157
154 else => fatal("unable to read '{s}': {s}", .{ input, @errorName(err) }),158 const elf_hdr = std.elf.Header.read(&in.interface) catch |err| switch (err) {
159 error.ReadFailed => fatal("unable to read {s}: {t}", .{ input, in.err.? }),
160 else => |e| fatal("invalid elf file: {t}", .{e}),
155 };161 };
156162
157 const in_ofmt = .elf;163 const in_ofmt = .elf;
...@@ -168,16 +174,12 @@ fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void...@@ -168,16 +174,12 @@ fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
168 }174 }
169 };175 };
170176
171 const mode = mode: {177 const mode = if (out_fmt != .elf or only_keep_debug) fs.File.default_mode else stat.mode;
172 if (out_fmt != .elf or only_keep_debug)178
173 break :mode fs.File.default_mode;179 var output_file = try fs.cwd().createFile(output, .{ .mode = mode });
174 if (in_file.stat()) |stat|180 defer output_file.close();
175 break :mode stat.mode181
176 else |_|182 var out = output_file.writer(&output_buffer);
177 break :mode fs.File.default_mode;
178 };
179 var out_file = try fs.cwd().createFile(output, .{ .mode = mode });
180 defer out_file.close();
181183
182 switch (out_fmt) {184 switch (out_fmt) {
183 .hex, .raw => {185 .hex, .raw => {
...@@ -192,7 +194,7 @@ fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void...@@ -192,7 +194,7 @@ fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
192 if (set_section_flags != null)194 if (set_section_flags != null)
193 fatal("zig objcopy: ELF to RAW or HEX copying does not support --set_section_flags", .{});195 fatal("zig objcopy: ELF to RAW or HEX copying does not support --set_section_flags", .{});
194196
195 try emitElf(arena, in_file, out_file, elf_hdr, .{197 try emitElf(arena, &in, &out, elf_hdr, .{
196 .ofmt = out_fmt,198 .ofmt = out_fmt,
197 .only_section = only_section,199 .only_section = only_section,
198 .pad_to = pad_to,200 .pad_to = pad_to,
...@@ -208,22 +210,13 @@ fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void...@@ -208,22 +210,13 @@ fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
208 if (pad_to) |_|210 if (pad_to) |_|
209 fatal("zig objcopy: ELF to ELF copying does not support --pad-to", .{});211 fatal("zig objcopy: ELF to ELF copying does not support --pad-to", .{});
210212
211 try stripElf(arena, in_file, out_file, elf_hdr, .{213 fatal("unimplemented", .{});
212 .strip_debug = strip_debug,
213 .strip_all = strip_all,
214 .only_keep_debug = only_keep_debug,
215 .add_debuglink = opt_add_debuglink,
216 .extract_to = opt_extract,
217 .compress_debug = compress_debug_sections,
218 .add_section = add_section,
219 .set_section_alignment = set_section_alignment,
220 .set_section_flags = set_section_flags,
221 });
222 return std.process.cleanExit();
223 },214 },
224 else => fatal("unsupported output object format: {s}", .{@tagName(out_fmt)}),215 else => fatal("unsupported output object format: {s}", .{@tagName(out_fmt)}),
225 }216 }
226217
218 try out.end();
219
227 if (listen) {220 if (listen) {
228 var stdin_reader = fs.File.stdin().reader(&stdin_buffer);221 var stdin_reader = fs.File.stdin().reader(&stdin_buffer);
229 var stdout_writer = fs.File.stdout().writer(&stdout_buffer);222 var stdout_writer = fs.File.stdout().writer(&stdout_buffer);
...@@ -304,12 +297,12 @@ const SetSectionFlags = struct {...@@ -304,12 +297,12 @@ const SetSectionFlags = struct {
304297
305fn emitElf(298fn emitElf(
306 arena: Allocator,299 arena: Allocator,
307 in_file: File,300 in: *File.Reader,
308 out_file: File,301 out: *File.Writer,
309 elf_hdr: elf.Header,302 elf_hdr: elf.Header,
310 options: EmitRawElfOptions,303 options: EmitRawElfOptions,
311) !void {304) !void {
312 var binary_elf_output = try BinaryElfOutput.parse(arena, in_file, elf_hdr);305 var binary_elf_output = try BinaryElfOutput.parse(arena, in, elf_hdr);
313 defer binary_elf_output.deinit();306 defer binary_elf_output.deinit();
314307
315 if (options.ofmt == .elf) {308 if (options.ofmt == .elf) {
...@@ -328,8 +321,8 @@ fn emitElf(...@@ -328,8 +321,8 @@ fn emitElf(
328 continue;321 continue;
329 }322 }
330323
331 try writeBinaryElfSection(in_file, out_file, section);324 try writeBinaryElfSection(in, out, section);
332 try padFile(out_file, options.pad_to);325 try padFile(out, options.pad_to);
333 return;326 return;
334 }327 }
335 },328 },
...@@ -342,10 +335,10 @@ fn emitElf(...@@ -342,10 +335,10 @@ fn emitElf(
342 switch (options.ofmt) {335 switch (options.ofmt) {
343 .raw => {336 .raw => {
344 for (binary_elf_output.sections.items) |section| {337 for (binary_elf_output.sections.items) |section| {
345 try out_file.seekTo(section.binaryOffset);338 try out.seekTo(section.binaryOffset);
346 try writeBinaryElfSection(in_file, out_file, section);339 try writeBinaryElfSection(in, out, section);
347 }340 }
348 try padFile(out_file, options.pad_to);341 try padFile(out, options.pad_to);
349 },342 },
350 .hex => {343 .hex => {
351 if (binary_elf_output.segments.items.len == 0) return;344 if (binary_elf_output.segments.items.len == 0) return;
...@@ -353,15 +346,15 @@ fn emitElf(...@@ -353,15 +346,15 @@ fn emitElf(
353 return error.InvalidHexfileAddressRange;346 return error.InvalidHexfileAddressRange;
354 }347 }
355348
356 var hex_writer = HexWriter{ .out_file = out_file };349 var hex_writer = HexWriter{ .out = out };
357 for (binary_elf_output.segments.items) |segment| {350 for (binary_elf_output.segments.items) |segment| {
358 try hex_writer.writeSegment(segment, in_file);351 try hex_writer.writeSegment(segment, in);
359 }352 }
360 if (options.pad_to) |_| {353 if (options.pad_to) |_| {
361 // Padding to a size in hex files isn't applicable354 // Padding to a size in hex files isn't applicable
362 return error.InvalidArgument;355 return error.InvalidArgument;
363 }356 }
364 try hex_writer.writeEOF();357 try hex_writer.writeEof();
365 },358 },
366 else => unreachable,359 else => unreachable,
367 }360 }
...@@ -399,7 +392,7 @@ const BinaryElfOutput = struct {...@@ -399,7 +392,7 @@ const BinaryElfOutput = struct {
399 self.segments.deinit(self.allocator);392 self.segments.deinit(self.allocator);
400 }393 }
401394
402 pub fn parse(allocator: Allocator, elf_file: File, elf_hdr: elf.Header) !Self {395 pub fn parse(allocator: Allocator, in: *File.Reader, elf_hdr: elf.Header) !Self {
403 var self: Self = .{396 var self: Self = .{
404 .segments = .{},397 .segments = .{},
405 .sections = .{},398 .sections = .{},
...@@ -412,7 +405,7 @@ const BinaryElfOutput = struct {...@@ -412,7 +405,7 @@ const BinaryElfOutput = struct {
412 self.shstrtab = blk: {405 self.shstrtab = blk: {
413 if (elf_hdr.shstrndx >= elf_hdr.shnum) break :blk null;406 if (elf_hdr.shstrndx >= elf_hdr.shnum) break :blk null;
414407
415 var section_headers = elf_hdr.section_header_iterator(&elf_file);408 var section_headers = elf_hdr.iterateSectionHeaders(in);
416409
417 var section_counter: usize = 0;410 var section_counter: usize = 0;
418 while (section_counter < elf_hdr.shstrndx) : (section_counter += 1) {411 while (section_counter < elf_hdr.shstrndx) : (section_counter += 1) {
...@@ -421,18 +414,13 @@ const BinaryElfOutput = struct {...@@ -421,18 +414,13 @@ const BinaryElfOutput = struct {
421414
422 const shstrtab_shdr = (try section_headers.next()).?;415 const shstrtab_shdr = (try section_headers.next()).?;
423416
424 const buffer = try allocator.alloc(u8, @intCast(shstrtab_shdr.sh_size));417 try in.seekTo(shstrtab_shdr.sh_offset);
425 errdefer allocator.free(buffer);418 break :blk try in.interface.readAlloc(allocator, shstrtab_shdr.sh_size);
426
427 const num_read = try elf_file.preadAll(buffer, shstrtab_shdr.sh_offset);
428 if (num_read != buffer.len) return error.EndOfStream;
429
430 break :blk buffer;
431 };419 };
432420
433 errdefer if (self.shstrtab) |shstrtab| allocator.free(shstrtab);421 errdefer if (self.shstrtab) |shstrtab| allocator.free(shstrtab);
434422
435 var section_headers = elf_hdr.section_header_iterator(&elf_file);423 var section_headers = elf_hdr.iterateSectionHeaders(in);
436 while (try section_headers.next()) |section| {424 while (try section_headers.next()) |section| {
437 if (sectionValidForOutput(section)) {425 if (sectionValidForOutput(section)) {
438 const newSection = try allocator.create(BinaryElfSection);426 const newSection = try allocator.create(BinaryElfSection);
...@@ -451,7 +439,7 @@ const BinaryElfOutput = struct {...@@ -451,7 +439,7 @@ const BinaryElfOutput = struct {
451 }439 }
452 }440 }
453441
454 var program_headers = elf_hdr.program_header_iterator(&elf_file);442 var program_headers = elf_hdr.iterateProgramHeaders(in);
455 while (try program_headers.next()) |phdr| {443 while (try program_headers.next()) |phdr| {
456 if (phdr.p_type == elf.PT_LOAD) {444 if (phdr.p_type == elf.PT_LOAD) {
457 const newSegment = try allocator.create(BinaryElfSegment);445 const newSegment = try allocator.create(BinaryElfSegment);
...@@ -539,19 +527,17 @@ const BinaryElfOutput = struct {...@@ -539,19 +527,17 @@ const BinaryElfOutput = struct {
539 }527 }
540};528};
541529
542fn writeBinaryElfSection(elf_file: File, out_file: File, section: *BinaryElfSection) !void {530fn writeBinaryElfSection(in: *File.Reader, out: *File.Writer, section: *BinaryElfSection) !void {
543 try out_file.writeFileAll(elf_file, .{531 try in.seekTo(section.elfOffset);
544 .in_offset = section.elfOffset,532 _ = try out.interface.sendFileAll(in, .limited(section.fileSize));
545 .in_len = section.fileSize,
546 });
547}533}
548534
549const HexWriter = struct {535const HexWriter = struct {
550 prev_addr: ?u32 = null,536 prev_addr: ?u32 = null,
551 out_file: File,537 out: *File.Writer,
552538
553 /// Max data bytes per line of output539 /// Max data bytes per line of output
554 const MAX_PAYLOAD_LEN: u8 = 16;540 const max_payload_len: u8 = 16;
555541
556 fn addressParts(address: u16) [2]u8 {542 fn addressParts(address: u16) [2]u8 {
557 const msb: u8 = @truncate(address >> 8);543 const msb: u8 = @truncate(address >> 8);
...@@ -627,13 +613,13 @@ const HexWriter = struct {...@@ -627,13 +613,13 @@ const HexWriter = struct {
627 return (sum ^ 0xFF) +% 1;613 return (sum ^ 0xFF) +% 1;
628 }614 }
629615
630 fn write(self: Record, file: File) File.WriteError!void {616 fn write(self: Record, out: *File.Writer) !void {
631 const linesep = "\r\n";617 const linesep = "\r\n";
632 // colon, (length, address, type, payload, checksum) as hex, CRLF618 // colon, (length, address, type, payload, checksum) as hex, CRLF
633 const BUFSIZE = 1 + (1 + 2 + 1 + MAX_PAYLOAD_LEN + 1) * 2 + linesep.len;619 const BUFSIZE = 1 + (1 + 2 + 1 + max_payload_len + 1) * 2 + linesep.len;
634 var outbuf: [BUFSIZE]u8 = undefined;620 var outbuf: [BUFSIZE]u8 = undefined;
635 const payload_bytes = self.getPayloadBytes();621 const payload_bytes = self.getPayloadBytes();
636 assert(payload_bytes.len <= MAX_PAYLOAD_LEN);622 assert(payload_bytes.len <= max_payload_len);
637623
638 const line = try std.fmt.bufPrint(&outbuf, ":{0X:0>2}{1X:0>4}{2X:0>2}{3X}{4X:0>2}" ++ linesep, .{624 const line = try std.fmt.bufPrint(&outbuf, ":{0X:0>2}{1X:0>4}{2X:0>2}{3X}{4X:0>2}" ++ linesep, .{
639 @as(u8, @intCast(payload_bytes.len)),625 @as(u8, @intCast(payload_bytes.len)),
...@@ -642,38 +628,37 @@ const HexWriter = struct {...@@ -642,38 +628,37 @@ const HexWriter = struct {
642 payload_bytes,628 payload_bytes,
643 self.checksum(),629 self.checksum(),
644 });630 });
645 try file.writeAll(line);631 try out.interface.writeAll(line);
646 }632 }
647 };633 };
648634
649 pub fn writeSegment(self: *HexWriter, segment: *const BinaryElfSegment, elf_file: File) !void {635 pub fn writeSegment(self: *HexWriter, segment: *const BinaryElfSegment, in: *File.Reader) !void {
650 var buf: [MAX_PAYLOAD_LEN]u8 = undefined;636 var buf: [max_payload_len]u8 = undefined;
651 var bytes_read: usize = 0;637 var bytes_read: usize = 0;
652 while (bytes_read < segment.fileSize) {638 while (bytes_read < segment.fileSize) {
653 const row_address: u32 = @intCast(segment.physicalAddress + bytes_read);639 const row_address: u32 = @intCast(segment.physicalAddress + bytes_read);
654640
655 const remaining = segment.fileSize - bytes_read;641 const remaining = segment.fileSize - bytes_read;
656 const to_read: usize = @intCast(@min(remaining, MAX_PAYLOAD_LEN));642 const dest = buf[0..@min(remaining, max_payload_len)];
657 const did_read = try elf_file.preadAll(buf[0..to_read], segment.elfOffset + bytes_read);643 try in.seekTo(segment.elfOffset + bytes_read);
658 if (did_read < to_read) return error.UnexpectedEOF;644 try in.interface.readSliceAll(dest);
645 try self.writeDataRow(row_address, dest);
659646
660 try self.writeDataRow(row_address, buf[0..did_read]);647 bytes_read += dest.len;
661
662 bytes_read += did_read;
663 }648 }
664 }649 }
665650
666 fn writeDataRow(self: *HexWriter, address: u32, data: []const u8) File.WriteError!void {651 fn writeDataRow(self: *HexWriter, address: u32, data: []const u8) !void {
667 const record = Record.Data(address, data);652 const record = Record.Data(address, data);
668 if (address > 0xFFFF and (self.prev_addr == null or record.address != self.prev_addr.?)) {653 if (address > 0xFFFF and (self.prev_addr == null or record.address != self.prev_addr.?)) {
669 try Record.Address(address).write(self.out_file);654 try Record.Address(address).write(self.out);
670 }655 }
671 try record.write(self.out_file);656 try record.write(self.out);
672 self.prev_addr = @intCast(record.address + data.len);657 self.prev_addr = @intCast(record.address + data.len);
673 }658 }
674659
675 fn writeEOF(self: HexWriter) File.WriteError!void {660 fn writeEof(self: HexWriter) !void {
676 try Record.EOF().write(self.out_file);661 try Record.EOF().write(self.out);
677 }662 }
678};663};
679664
...@@ -686,9 +671,9 @@ fn containsValidAddressRange(segments: []*BinaryElfSegment) bool {...@@ -686,9 +671,9 @@ fn containsValidAddressRange(segments: []*BinaryElfSegment) bool {
686 return true;671 return true;
687}672}
688673
689fn padFile(f: File, opt_size: ?u64) !void {674fn padFile(out: *File.Writer, opt_size: ?u64) !void {
690 const size = opt_size orelse return;675 const size = opt_size orelse return;
691 try f.setEndPos(size);676 try out.file.setEndPos(size);
692}677}
693678
694test "HexWriter.Record.Address has correct payload and checksum" {679test "HexWriter.Record.Address has correct payload and checksum" {
...@@ -732,836 +717,6 @@ test "containsValidAddressRange" {...@@ -732,836 +717,6 @@ test "containsValidAddressRange" {
732 try std.testing.expect(containsValidAddressRange(&buf));717 try std.testing.expect(containsValidAddressRange(&buf));
733}718}
734719
735// -------------
736// ELF to ELF stripping
737
738const StripElfOptions = struct {
739 extract_to: ?[]const u8 = null,
740 add_debuglink: ?[]const u8 = null,
741 strip_all: bool = false,
742 strip_debug: bool = false,
743 only_keep_debug: bool = false,
744 compress_debug: bool = false,
745 add_section: ?AddSection,
746 set_section_alignment: ?SetSectionAlignment,
747 set_section_flags: ?SetSectionFlags,
748};
749
750fn stripElf(
751 allocator: Allocator,
752 in_file: File,
753 out_file: File,
754 elf_hdr: elf.Header,
755 options: StripElfOptions,
756) !void {
757 const Filter = ElfFileHelper.Filter;
758 const DebugLink = ElfFileHelper.DebugLink;
759
760 const filter: Filter = filter: {
761 if (options.only_keep_debug) break :filter .debug;
762 if (options.strip_all) break :filter .program;
763 if (options.strip_debug) break :filter .program_and_symbols;
764 break :filter .all;
765 };
766
767 const filter_complement: ?Filter = blk: {
768 if (options.extract_to) |_| {
769 break :blk switch (filter) {
770 .program => .debug_and_symbols,
771 .debug => .program_and_symbols,
772 .program_and_symbols => .debug,
773 .debug_and_symbols => .program,
774 .all => fatal("zig objcopy: nothing to extract", .{}),
775 };
776 } else {
777 break :blk null;
778 }
779 };
780 const debuglink_path = path: {
781 if (options.add_debuglink) |path| break :path path;
782 if (options.extract_to) |path| break :path path;
783 break :path null;
784 };
785
786 switch (elf_hdr.is_64) {
787 inline else => |is_64| {
788 var elf_file = try ElfFile(is_64).parse(allocator, in_file, elf_hdr);
789 defer elf_file.deinit();
790
791 if (options.add_section) |user_section| {
792 for (elf_file.sections) |section| {
793 if (std.mem.eql(u8, section.name, user_section.section_name)) {
794 fatal("zig objcopy: unable to add section '{s}'. Section already exists in input", .{user_section.section_name});
795 }
796 }
797 }
798
799 if (filter_complement) |flt| {
800 // write the .dbg file and close it, so it can be read back to compute the debuglink checksum.
801 const path = options.extract_to.?;
802 const dbg_file = std.fs.cwd().createFile(path, .{}) catch |err| {
803 fatal("zig objcopy: unable to create '{s}': {s}", .{ path, @errorName(err) });
804 };
805 defer dbg_file.close();
806
807 try elf_file.emit(allocator, dbg_file, in_file, .{ .section_filter = flt, .compress_debug = options.compress_debug });
808 }
809
810 const debuglink: ?DebugLink = if (debuglink_path) |path| ElfFileHelper.createDebugLink(path) else null;
811 try elf_file.emit(allocator, out_file, in_file, .{
812 .section_filter = filter,
813 .debuglink = debuglink,
814 .compress_debug = options.compress_debug,
815 .add_section = options.add_section,
816 .set_section_alignment = options.set_section_alignment,
817 .set_section_flags = options.set_section_flags,
818 });
819 },
820 }
821}
822
823// note: this is "a minimal effort implementation"
824// It doesn't support all possibile elf files: some sections type may need fixups, the program header may need fix up, ...
825// It was written for a specific use case (strip debug info to a sperate file, for linux 64-bits executables built with `zig` or `zig c++` )
826// It moves and reoders the sections as little as possible to avoid having to do fixups.
827// TODO: support non-native endianess
828
829fn ElfFile(comptime is_64: bool) type {
830 const Elf_Ehdr = if (is_64) elf.Elf64_Ehdr else elf.Elf32_Ehdr;
831 const Elf_Phdr = if (is_64) elf.Elf64_Phdr else elf.Elf32_Phdr;
832 const Elf_Shdr = if (is_64) elf.Elf64_Shdr else elf.Elf32_Shdr;
833 const Elf_Chdr = if (is_64) elf.Elf64_Chdr else elf.Elf32_Chdr;
834 const Elf_Sym = if (is_64) elf.Elf64_Sym else elf.Elf32_Sym;
835 const Elf_OffSize = if (is_64) elf.Elf64_Off else elf.Elf32_Off;
836
837 return struct {
838 raw_elf_header: Elf_Ehdr,
839 program_segments: []const Elf_Phdr,
840 sections: []const Section,
841 arena: std.heap.ArenaAllocator,
842
843 const SectionCategory = ElfFileHelper.SectionCategory;
844 const section_memory_align: std.mem.Alignment = .of(Elf_Sym); // most restrictive of what we may load in memory
845 const Section = struct {
846 section: Elf_Shdr,
847 name: []const u8 = "",
848 segment: ?*const Elf_Phdr = null, // if the section is used by a program segment (there can be more than one)
849 payload: ?[]align(section_memory_align.toByteUnits()) const u8 = null, // if we need the data in memory
850 category: SectionCategory = .none, // should the section be kept in the exe or stripped to the debug database, or both.
851 };
852
853 const Self = @This();
854
855 pub fn parse(gpa: Allocator, in_file: File, header: elf.Header) !Self {
856 var arena = std.heap.ArenaAllocator.init(gpa);
857 errdefer arena.deinit();
858 const allocator = arena.allocator();
859
860 var raw_header: Elf_Ehdr = undefined;
861 {
862 const bytes_read = try in_file.preadAll(std.mem.asBytes(&raw_header), 0);
863 if (bytes_read < @sizeOf(Elf_Ehdr))
864 return error.TRUNCATED_ELF;
865 }
866
867 // program header: list of segments
868 const program_segments = blk: {
869 if (@sizeOf(Elf_Phdr) != header.phentsize)
870 fatal("zig objcopy: unsupported ELF file, unexpected phentsize ({d})", .{header.phentsize});
871
872 const program_header = try allocator.alloc(Elf_Phdr, header.phnum);
873 const bytes_read = try in_file.preadAll(std.mem.sliceAsBytes(program_header), header.phoff);
874 if (bytes_read < @sizeOf(Elf_Phdr) * header.phnum)
875 return error.TRUNCATED_ELF;
876 break :blk program_header;
877 };
878
879 // section header
880 const sections = blk: {
881 if (@sizeOf(Elf_Shdr) != header.shentsize)
882 fatal("zig objcopy: unsupported ELF file, unexpected shentsize ({d})", .{header.shentsize});
883
884 const section_header = try allocator.alloc(Section, header.shnum);
885
886 const raw_section_header = try allocator.alloc(Elf_Shdr, header.shnum);
887 defer allocator.free(raw_section_header);
888 const bytes_read = try in_file.preadAll(std.mem.sliceAsBytes(raw_section_header), header.shoff);
889 if (bytes_read < @sizeOf(Elf_Phdr) * header.shnum)
890 return error.TRUNCATED_ELF;
891
892 for (section_header, raw_section_header) |*section, hdr| {
893 section.* = .{ .section = hdr };
894 }
895 break :blk section_header;
896 };
897
898 // load data to memory for some sections:
899 // string tables for access
900 // sections than need modifications when other sections move.
901 for (sections, 0..) |*section, idx| {
902 const need_data = switch (section.section.sh_type) {
903 elf.DT_VERSYM => true,
904 elf.SHT_SYMTAB, elf.SHT_DYNSYM => true,
905 else => false,
906 };
907 const need_strings = (idx == header.shstrndx);
908
909 if (need_data or need_strings) {
910 const buffer = try allocator.alignedAlloc(u8, section_memory_align, @intCast(section.section.sh_size));
911 const bytes_read = try in_file.preadAll(buffer, section.section.sh_offset);
912 if (bytes_read != section.section.sh_size) return error.TRUNCATED_ELF;
913 section.payload = buffer;
914 }
915 }
916
917 // fill-in sections info:
918 // resolve the name
919 // find if a program segment uses the section
920 // categorize sections usage (used by program segments, debug datadase, common metadata, symbol table)
921 for (sections) |*section| {
922 section.segment = for (program_segments) |*seg| {
923 if (sectionWithinSegment(section.section, seg.*)) break seg;
924 } else null;
925
926 if (section.section.sh_name != 0 and header.shstrndx != elf.SHN_UNDEF)
927 section.name = std.mem.span(@as([*:0]const u8, @ptrCast(&sections[header.shstrndx].payload.?[section.section.sh_name])));
928
929 const category_from_program: SectionCategory = if (section.segment != null) .exe else .debug;
930 section.category = switch (section.section.sh_type) {
931 elf.SHT_NOTE => .common,
932 elf.SHT_SYMTAB => .symbols, // "strip all" vs "strip only debug"
933 elf.SHT_DYNSYM => .exe,
934 elf.SHT_PROGBITS => cat: {
935 if (std.mem.eql(u8, section.name, ".comment")) break :cat .exe;
936 if (std.mem.eql(u8, section.name, ".gnu_debuglink")) break :cat .none;
937 break :cat category_from_program;
938 },
939 elf.SHT_LOPROC...elf.SHT_HIPROC => .common, // don't strip unknown sections
940 elf.SHT_LOUSER...elf.SHT_HIUSER => .common, // don't strip unknown sections
941 else => category_from_program,
942 };
943 }
944
945 sections[0].category = .common; // mandatory null section
946 if (header.shstrndx != elf.SHN_UNDEF)
947 sections[header.shstrndx].category = .common; // string table for the headers
948
949 // recursively propagate section categories to their linked sections, so that they are kept together
950 var dirty: u1 = 1;
951 while (dirty != 0) {
952 dirty = 0;
953
954 for (sections) |*section| {
955 if (section.section.sh_link != elf.SHN_UNDEF)
956 dirty |= ElfFileHelper.propagateCategory(&sections[section.section.sh_link].category, section.category);
957 if ((section.section.sh_flags & elf.SHF_INFO_LINK) != 0 and section.section.sh_info != elf.SHN_UNDEF)
958 dirty |= ElfFileHelper.propagateCategory(&sections[section.section.sh_info].category, section.category);
959 }
960 }
961
962 return Self{
963 .arena = arena,
964 .raw_elf_header = raw_header,
965 .program_segments = program_segments,
966 .sections = sections,
967 };
968 }
969
970 pub fn deinit(self: *Self) void {
971 self.arena.deinit();
972 }
973
974 const Filter = ElfFileHelper.Filter;
975 const DebugLink = ElfFileHelper.DebugLink;
976 const EmitElfOptions = struct {
977 section_filter: Filter = .all,
978 debuglink: ?DebugLink = null,
979 compress_debug: bool = false,
980 add_section: ?AddSection = null,
981 set_section_alignment: ?SetSectionAlignment = null,
982 set_section_flags: ?SetSectionFlags = null,
983 };
984 fn emit(self: *const Self, gpa: Allocator, out_file: File, in_file: File, options: EmitElfOptions) !void {
985 var arena = std.heap.ArenaAllocator.init(gpa);
986 defer arena.deinit();
987 const allocator = arena.allocator();
988
989 // when emitting the stripped exe:
990 // - unused sections are removed
991 // when emitting the debug file:
992 // - all sections are kept, but some are emptied and their types is changed to SHT_NOBITS
993 // the program header is kept unchanged. (`strip` does update it, but `eu-strip` does not, and it still works)
994
995 const Update = struct {
996 action: ElfFileHelper.Action,
997
998 // remap the indexs after omitting the filtered sections
999 remap_idx: u16,
1000
1001 // optionally overrides the payload from the source file
1002 payload: ?[]align(section_memory_align.toByteUnits()) const u8 = null,
1003 section: ?Elf_Shdr = null,
1004 };
1005 const sections_update = try allocator.alloc(Update, self.sections.len);
1006 const new_shnum = blk: {
1007 var next_idx: u16 = 0;
1008 for (self.sections, sections_update) |section, *update| {
1009 const action = ElfFileHelper.selectAction(section.category, options.section_filter);
1010 const remap_idx = idx: {
1011 if (action == .strip) break :idx elf.SHN_UNDEF;
1012 next_idx += 1;
1013 break :idx next_idx - 1;
1014 };
1015 update.* = Update{ .action = action, .remap_idx = remap_idx };
1016 }
1017
1018 if (options.debuglink != null)
1019 next_idx += 1;
1020
1021 if (options.add_section != null) {
1022 next_idx += 1;
1023 }
1024
1025 break :blk next_idx;
1026 };
1027
1028 // add a ".gnu_debuglink" to the string table if needed
1029 const debuglink_name: u32 = blk: {
1030 if (options.debuglink == null) break :blk elf.SHN_UNDEF;
1031 if (self.raw_elf_header.e_shstrndx == elf.SHN_UNDEF)
1032 fatal("zig objcopy: no strtab, cannot add the debuglink section", .{}); // TODO add the section if needed?
1033
1034 const strtab = &self.sections[self.raw_elf_header.e_shstrndx];
1035 const update = &sections_update[self.raw_elf_header.e_shstrndx];
1036
1037 const name: []const u8 = ".gnu_debuglink";
1038 const new_offset: u32 = @intCast(strtab.payload.?.len);
1039 const buf = try allocator.alignedAlloc(u8, section_memory_align, new_offset + name.len + 1);
1040 @memcpy(buf[0..new_offset], strtab.payload.?);
1041 @memcpy(buf[new_offset..][0..name.len], name);
1042 buf[new_offset + name.len] = 0;
1043
1044 assert(update.action == .keep);
1045 update.payload = buf;
1046
1047 break :blk new_offset;
1048 };
1049
1050 // add user section to the string table if needed
1051 const user_section_name: u32 = blk: {
1052 if (options.add_section == null) break :blk elf.SHN_UNDEF;
1053 if (self.raw_elf_header.e_shstrndx == elf.SHN_UNDEF)
1054 fatal("zig objcopy: no strtab, cannot add the user section", .{}); // TODO add the section if needed?
1055
1056 const strtab = &self.sections[self.raw_elf_header.e_shstrndx];
1057 const update = &sections_update[self.raw_elf_header.e_shstrndx];
1058
1059 const name = options.add_section.?.section_name;
1060 const new_offset: u32 = @intCast(strtab.payload.?.len);
1061 const buf = try allocator.alignedAlloc(u8, section_memory_align, new_offset + name.len + 1);
1062 @memcpy(buf[0..new_offset], strtab.payload.?);
1063 @memcpy(buf[new_offset..][0..name.len], name);
1064 buf[new_offset + name.len] = 0;
1065
1066 assert(update.action == .keep);
1067 update.payload = buf;
1068
1069 break :blk new_offset;
1070 };
1071
1072 // maybe compress .debug sections
1073 if (options.compress_debug) {
1074 for (self.sections[1..], sections_update[1..]) |section, *update| {
1075 if (update.action != .keep) continue;
1076 if (!std.mem.startsWith(u8, section.name, ".debug_")) continue;
1077 if ((section.section.sh_flags & elf.SHF_COMPRESSED) != 0) continue; // already compressed
1078
1079 const chdr = Elf_Chdr{
1080 .ch_type = elf.COMPRESS.ZLIB,
1081 .ch_size = section.section.sh_size,
1082 .ch_addralign = section.section.sh_addralign,
1083 };
1084
1085 const compressed_payload = try ElfFileHelper.tryCompressSection(allocator, in_file, section.section.sh_offset, section.section.sh_size, std.mem.asBytes(&chdr));
1086 if (compressed_payload) |payload| {
1087 update.payload = payload;
1088 update.section = section.section;
1089 update.section.?.sh_addralign = @alignOf(Elf_Chdr);
1090 update.section.?.sh_size = @intCast(payload.len);
1091 update.section.?.sh_flags |= elf.SHF_COMPRESSED;
1092 }
1093 }
1094 }
1095
1096 var cmdbuf = std.ArrayList(ElfFileHelper.WriteCmd).init(allocator);
1097 defer cmdbuf.deinit();
1098 try cmdbuf.ensureUnusedCapacity(3 + new_shnum);
1099 var eof_offset: Elf_OffSize = 0; // track the end of the data written so far.
1100
1101 // build the updated headers
1102 // nb: updated_elf_header will be updated before the actual write
1103 var updated_elf_header = self.raw_elf_header;
1104 if (updated_elf_header.e_shstrndx != elf.SHN_UNDEF)
1105 updated_elf_header.e_shstrndx = sections_update[updated_elf_header.e_shstrndx].remap_idx;
1106 cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = std.mem.asBytes(&updated_elf_header), .out_offset = 0 } });
1107 eof_offset = @sizeOf(Elf_Ehdr);
1108
1109 // program header as-is.
1110 // nb: for only-debug files, removing it appears to work, but is invalid by ELF specifcation.
1111 {
1112 assert(updated_elf_header.e_phoff == @sizeOf(Elf_Ehdr));
1113 const data = std.mem.sliceAsBytes(self.program_segments);
1114 assert(data.len == @as(usize, updated_elf_header.e_phentsize) * updated_elf_header.e_phnum);
1115 cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = data, .out_offset = updated_elf_header.e_phoff } });
1116 eof_offset = updated_elf_header.e_phoff + @as(Elf_OffSize, @intCast(data.len));
1117 }
1118
1119 // update sections and queue payload writes
1120 const updated_section_header = blk: {
1121 const dest_sections = try allocator.alloc(Elf_Shdr, new_shnum);
1122
1123 {
1124 // the ELF format doesn't specify the order for all sections.
1125 // this code only supports when they are in increasing file order.
1126 var offset: u64 = eof_offset;
1127 for (self.sections[1..]) |section| {
1128 if (section.section.sh_type == elf.SHT_NOBITS)
1129 continue;
1130 if (section.section.sh_offset < offset) {
1131 fatal("zig objcopy: unsupported ELF file", .{});
1132 }
1133 offset = section.section.sh_offset;
1134 }
1135 }
1136
1137 dest_sections[0] = self.sections[0].section;
1138
1139 var dest_section_idx: u32 = 1;
1140 for (self.sections[1..], sections_update[1..]) |section, update| {
1141 if (update.action == .strip) continue;
1142 assert(update.remap_idx == dest_section_idx);
1143
1144 const src = if (update.section) |*s| s else &section.section;
1145 const dest = &dest_sections[dest_section_idx];
1146 const payload = if (update.payload) |data| data else section.payload;
1147 dest_section_idx += 1;
1148
1149 dest.* = src.*;
1150
1151 if (src.sh_link != elf.SHN_UNDEF)
1152 dest.sh_link = sections_update[src.sh_link].remap_idx;
1153 if ((src.sh_flags & elf.SHF_INFO_LINK) != 0 and src.sh_info != elf.SHN_UNDEF)
1154 dest.sh_info = sections_update[src.sh_info].remap_idx;
1155
1156 if (payload) |data|
1157 dest.sh_size = @intCast(data.len);
1158
1159 const addralign = if (src.sh_addralign == 0 or dest.sh_type == elf.SHT_NOBITS) 1 else src.sh_addralign;
1160 dest.sh_offset = std.mem.alignForward(Elf_OffSize, eof_offset, addralign);
1161 if (src.sh_offset != dest.sh_offset and section.segment != null and update.action != .empty and dest.sh_type != elf.SHT_NOTE and dest.sh_type != elf.SHT_NOBITS) {
1162 if (src.sh_offset > dest.sh_offset) {
1163 dest.sh_offset = src.sh_offset; // add padding to avoid modifing the program segments
1164 } else {
1165 fatal("zig objcopy: cannot adjust program segments", .{});
1166 }
1167 }
1168 assert(dest.sh_addr % addralign == dest.sh_offset % addralign);
1169
1170 if (update.action == .empty)
1171 dest.sh_type = elf.SHT_NOBITS;
1172
1173 if (dest.sh_type != elf.SHT_NOBITS) {
1174 if (payload) |src_data| {
1175 // update sections payload and write
1176 const dest_data = switch (src.sh_type) {
1177 elf.DT_VERSYM => dst_data: {
1178 const data = try allocator.alignedAlloc(u8, section_memory_align, src_data.len);
1179 @memcpy(data, src_data);
1180
1181 const defs = @as([*]elf.Verdef, @ptrCast(data))[0 .. @as(usize, @intCast(src.sh_size)) / @sizeOf(elf.Verdef)];
1182 for (defs) |*def| switch (def.ndx) {
1183 .LOCAL, .GLOBAL => {},
1184 else => def.ndx = @enumFromInt(sections_update[src.sh_info].remap_idx),
1185 };
1186
1187 break :dst_data data;
1188 },
1189 elf.SHT_SYMTAB, elf.SHT_DYNSYM => dst_data: {
1190 const data = try allocator.alignedAlloc(u8, section_memory_align, src_data.len);
1191 @memcpy(data, src_data);
1192
1193 const syms = @as([*]Elf_Sym, @ptrCast(data))[0 .. @as(usize, @intCast(src.sh_size)) / @sizeOf(Elf_Sym)];
1194 for (syms) |*sym| {
1195 if (sym.st_shndx != elf.SHN_UNDEF and sym.st_shndx < elf.SHN_LORESERVE)
1196 sym.st_shndx = sections_update[sym.st_shndx].remap_idx;
1197 }
1198
1199 break :dst_data data;
1200 },
1201 else => src_data,
1202 };
1203
1204 assert(dest_data.len == dest.sh_size);
1205 cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = dest_data, .out_offset = dest.sh_offset } });
1206 eof_offset = dest.sh_offset + dest.sh_size;
1207 } else {
1208 // direct contents copy
1209 cmdbuf.appendAssumeCapacity(.{ .copy_range = .{ .in_offset = src.sh_offset, .len = dest.sh_size, .out_offset = dest.sh_offset } });
1210 eof_offset = dest.sh_offset + dest.sh_size;
1211 }
1212 } else {
1213 // account for alignment padding even in empty sections to keep logical section order
1214 eof_offset = dest.sh_offset;
1215 }
1216 }
1217
1218 // add a ".gnu_debuglink" section
1219 if (options.debuglink) |link| {
1220 const payload = payload: {
1221 const crc_offset = std.mem.alignForward(usize, link.name.len + 1, 4);
1222 const buf = try allocator.alignedAlloc(u8, .@"4", crc_offset + 4);
1223 @memcpy(buf[0..link.name.len], link.name);
1224 @memset(buf[link.name.len..crc_offset], 0);
1225 @memcpy(buf[crc_offset..], std.mem.asBytes(&link.crc32));
1226 break :payload buf;
1227 };
1228
1229 dest_sections[dest_section_idx] = Elf_Shdr{
1230 .sh_name = debuglink_name,
1231 .sh_type = elf.SHT_PROGBITS,
1232 .sh_flags = 0,
1233 .sh_addr = 0,
1234 .sh_offset = eof_offset,
1235 .sh_size = @intCast(payload.len),
1236 .sh_link = elf.SHN_UNDEF,
1237 .sh_info = elf.SHN_UNDEF,
1238 .sh_addralign = 4,
1239 .sh_entsize = 0,
1240 };
1241 dest_section_idx += 1;
1242
1243 cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = payload, .out_offset = eof_offset } });
1244 eof_offset += @as(Elf_OffSize, @intCast(payload.len));
1245 }
1246
1247 // --add-section
1248 if (options.add_section) |add_section| {
1249 var section_file = fs.cwd().openFile(add_section.file_path, .{}) catch |err|
1250 fatal("unable to open '{s}': {s}", .{ add_section.file_path, @errorName(err) });
1251 defer section_file.close();
1252
1253 const payload = try section_file.readToEndAlloc(arena.allocator(), std.math.maxInt(usize));
1254
1255 dest_sections[dest_section_idx] = Elf_Shdr{
1256 .sh_name = user_section_name,
1257 .sh_type = elf.SHT_PROGBITS,
1258 .sh_flags = 0,
1259 .sh_addr = 0,
1260 .sh_offset = eof_offset,
1261 .sh_size = @intCast(payload.len),
1262 .sh_link = elf.SHN_UNDEF,
1263 .sh_info = elf.SHN_UNDEF,
1264 .sh_addralign = 4,
1265 .sh_entsize = 0,
1266 };
1267 dest_section_idx += 1;
1268
1269 cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = payload, .out_offset = eof_offset } });
1270 eof_offset += @as(Elf_OffSize, @intCast(payload.len));
1271 }
1272
1273 assert(dest_section_idx == new_shnum);
1274 break :blk dest_sections;
1275 };
1276
1277 // --set-section-alignment: overwrite alignment
1278 if (options.set_section_alignment) |set_align| {
1279 if (self.raw_elf_header.e_shstrndx == elf.SHN_UNDEF)
1280 fatal("zig objcopy: no strtab, cannot add the user section", .{}); // TODO add the section if needed?
1281
1282 const strtab = &sections_update[self.raw_elf_header.e_shstrndx];
1283 for (updated_section_header) |*section| {
1284 const section_name = std.mem.span(@as([*:0]const u8, @ptrCast(&strtab.payload.?[section.sh_name])));
1285 if (std.mem.eql(u8, section_name, set_align.section_name)) {
1286 section.sh_addralign = set_align.alignment;
1287 break;
1288 }
1289 } else std.log.warn("Skipping --set-section-alignment. Section '{s}' not found", .{set_align.section_name});
1290 }
1291
1292 // --set-section-flags: overwrite flags
1293 if (options.set_section_flags) |set_flags| {
1294 if (self.raw_elf_header.e_shstrndx == elf.SHN_UNDEF)
1295 fatal("zig objcopy: no strtab, cannot add the user section", .{}); // TODO add the section if needed?
1296
1297 const strtab = &sections_update[self.raw_elf_header.e_shstrndx];
1298 for (updated_section_header) |*section| {
1299 const section_name = std.mem.span(@as([*:0]const u8, @ptrCast(&strtab.payload.?[section.sh_name])));
1300 if (std.mem.eql(u8, section_name, set_flags.section_name)) {
1301 section.sh_flags = std.elf.SHF_WRITE; // default is writable cleared by "readonly"
1302 const f = set_flags.flags;
1303
1304 // Supporting a subset of GNU and LLVM objcopy for ELF only
1305 // GNU:
1306 // alloc: add SHF_ALLOC
1307 // contents: if section is SHT_NOBITS, set SHT_PROGBITS, otherwise do nothing
1308 // load: if section is SHT_NOBITS, set SHT_PROGBITS, otherwise do nothing (same as contents)
1309 // noload: not ELF relevant
1310 // readonly: clear default SHF_WRITE flag
1311 // code: add SHF_EXECINSTR
1312 // data: not ELF relevant
1313 // rom: ignored
1314 // exclude: add SHF_EXCLUDE
1315 // share: not ELF relevant
1316 // debug: not ELF relevant
1317 // large: add SHF_X86_64_LARGE. Fatal error if target is not x86_64
1318 if (f.alloc) section.sh_flags |= std.elf.SHF_ALLOC;
1319 if (f.contents or f.load) {
1320 if (section.sh_type == std.elf.SHT_NOBITS) section.sh_type = std.elf.SHT_PROGBITS;
1321 }
1322 if (f.readonly) section.sh_flags &= ~@as(@TypeOf(section.sh_type), std.elf.SHF_WRITE);
1323 if (f.code) section.sh_flags |= std.elf.SHF_EXECINSTR;
1324 if (f.exclude) section.sh_flags |= std.elf.SHF_EXCLUDE;
1325 if (f.large) {
1326 if (updated_elf_header.e_machine != std.elf.EM.X86_64)
1327 fatal("zig objcopy: 'large' section flag is only supported on x86_64 targets", .{});
1328 section.sh_flags |= std.elf.SHF_X86_64_LARGE;
1329 }
1330
1331 // LLVM:
1332 // merge: add SHF_MERGE
1333 // strings: add SHF_STRINGS
1334 if (f.merge) section.sh_flags |= std.elf.SHF_MERGE;
1335 if (f.strings) section.sh_flags |= std.elf.SHF_STRINGS;
1336 break;
1337 }
1338 } else std.log.warn("Skipping --set-section-flags. Section '{s}' not found", .{set_flags.section_name});
1339 }
1340
1341 // write the section header at the tail
1342 {
1343 const offset = std.mem.alignForward(Elf_OffSize, eof_offset, @alignOf(Elf_Shdr));
1344
1345 const data = std.mem.sliceAsBytes(updated_section_header);
1346 assert(data.len == @as(usize, updated_elf_header.e_shentsize) * new_shnum);
1347 updated_elf_header.e_shoff = offset;
1348 updated_elf_header.e_shnum = new_shnum;
1349
1350 cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = data, .out_offset = updated_elf_header.e_shoff } });
1351 }
1352
1353 try ElfFileHelper.write(allocator, out_file, in_file, cmdbuf.items);
1354 }
1355
1356 fn sectionWithinSegment(section: Elf_Shdr, segment: Elf_Phdr) bool {
1357 const file_size = if (section.sh_type == elf.SHT_NOBITS) 0 else section.sh_size;
1358 return segment.p_offset <= section.sh_offset and (segment.p_offset + segment.p_filesz) >= (section.sh_offset + file_size);
1359 }
1360 };
1361}
1362
1363const ElfFileHelper = struct {
1364 const DebugLink = struct { name: []const u8, crc32: u32 };
1365 const Filter = enum { all, program, debug, program_and_symbols, debug_and_symbols };
1366
1367 const SectionCategory = enum { common, exe, debug, symbols, none };
1368 fn propagateCategory(cur: *SectionCategory, new: SectionCategory) u1 {
1369 const cat: SectionCategory = switch (cur.*) {
1370 .none => new,
1371 .common => .common,
1372 .debug => switch (new) {
1373 .none, .debug => .debug,
1374 else => new,
1375 },
1376 .exe => switch (new) {
1377 .common => .common,
1378 .none, .debug, .exe => .exe,
1379 .symbols => .exe,
1380 },
1381 .symbols => switch (new) {
1382 .none, .common, .debug, .exe => unreachable,
1383 .symbols => .symbols,
1384 },
1385 };
1386
1387 if (cur.* != cat) {
1388 cur.* = cat;
1389 return 1;
1390 } else {
1391 return 0;
1392 }
1393 }
1394
1395 const Action = enum { keep, strip, empty };
1396 fn selectAction(category: SectionCategory, filter: Filter) Action {
1397 if (category == .none) return .strip;
1398 return switch (filter) {
1399 .all => switch (category) {
1400 .none => .strip,
1401 else => .keep,
1402 },
1403 .program => switch (category) {
1404 .common, .exe => .keep,
1405 else => .strip,
1406 },
1407 .program_and_symbols => switch (category) {
1408 .common, .exe, .symbols => .keep,
1409 else => .strip,
1410 },
1411 .debug => switch (category) {
1412 .exe, .symbols => .empty,
1413 .none => .strip,
1414 else => .keep,
1415 },
1416 .debug_and_symbols => switch (category) {
1417 .exe => .empty,
1418 .none => .strip,
1419 else => .keep,
1420 },
1421 };
1422 }
1423
1424 const WriteCmd = union(enum) {
1425 copy_range: struct { in_offset: u64, len: u64, out_offset: u64 },
1426 write_data: struct { data: []const u8, out_offset: u64 },
1427 };
1428 fn write(allocator: Allocator, out_file: File, in_file: File, cmds: []const WriteCmd) !void {
1429 // consolidate holes between writes:
1430 // by coping original padding data from in_file (by fusing contiguous ranges)
1431 // by writing zeroes otherwise
1432 const zeroes = [1]u8{0} ** 4096;
1433 var consolidated = std.ArrayList(WriteCmd).init(allocator);
1434 defer consolidated.deinit();
1435 try consolidated.ensureUnusedCapacity(cmds.len * 2);
1436 var offset: u64 = 0;
1437 var fused_cmd: ?WriteCmd = null;
1438 for (cmds) |cmd| {
1439 switch (cmd) {
1440 .write_data => |data| {
1441 assert(data.out_offset >= offset);
1442 if (fused_cmd) |prev| {
1443 consolidated.appendAssumeCapacity(prev);
1444 fused_cmd = null;
1445 }
1446 if (data.out_offset > offset) {
1447 consolidated.appendAssumeCapacity(.{ .write_data = .{ .data = zeroes[0..@intCast(data.out_offset - offset)], .out_offset = offset } });
1448 }
1449 consolidated.appendAssumeCapacity(cmd);
1450 offset = data.out_offset + data.data.len;
1451 },
1452 .copy_range => |range| {
1453 assert(range.out_offset >= offset);
1454 if (fused_cmd) |prev| {
1455 if (range.in_offset >= prev.copy_range.in_offset + prev.copy_range.len and (range.out_offset - prev.copy_range.out_offset == range.in_offset - prev.copy_range.in_offset)) {
1456 fused_cmd = .{ .copy_range = .{
1457 .in_offset = prev.copy_range.in_offset,
1458 .out_offset = prev.copy_range.out_offset,
1459 .len = (range.out_offset + range.len) - prev.copy_range.out_offset,
1460 } };
1461 } else {
1462 consolidated.appendAssumeCapacity(prev);
1463 if (range.out_offset > offset) {
1464 consolidated.appendAssumeCapacity(.{ .write_data = .{ .data = zeroes[0..@intCast(range.out_offset - offset)], .out_offset = offset } });
1465 }
1466 fused_cmd = cmd;
1467 }
1468 } else {
1469 fused_cmd = cmd;
1470 }
1471 offset = range.out_offset + range.len;
1472 },
1473 }
1474 }
1475 if (fused_cmd) |cmd| {
1476 consolidated.appendAssumeCapacity(cmd);
1477 }
1478
1479 // write the output file
1480 for (consolidated.items) |cmd| {
1481 switch (cmd) {
1482 .write_data => |data| {
1483 var iovec = [_]std.posix.iovec_const{.{ .base = data.data.ptr, .len = data.data.len }};
1484 try out_file.pwritevAll(&iovec, data.out_offset);
1485 },
1486 .copy_range => |range| {
1487 const copied_bytes = try in_file.copyRangeAll(range.in_offset, out_file, range.out_offset, range.len);
1488 if (copied_bytes < range.len) return error.TRUNCATED_ELF;
1489 },
1490 }
1491 }
1492 }
1493
1494 fn tryCompressSection(allocator: Allocator, in_file: File, offset: u64, size: u64, prefix: []const u8) !?[]align(8) const u8 {
1495 if (size < prefix.len) return null;
1496
1497 try in_file.seekTo(offset);
1498 var section_reader = std.io.limitedReader(in_file.deprecatedReader(), size);
1499
1500 // allocate as large as decompressed data. if the compression doesn't fit, keep the data uncompressed.
1501 const compressed_data = try allocator.alignedAlloc(u8, .@"8", @intCast(size));
1502 var compressed_stream = std.io.fixedBufferStream(compressed_data);
1503
1504 try compressed_stream.writer().writeAll(prefix);
1505
1506 {
1507 var compressor = try std.compress.zlib.compressor(compressed_stream.writer(), .{});
1508
1509 var buf: [8000]u8 = undefined;
1510 while (true) {
1511 const bytes_read = try section_reader.read(&buf);
1512 if (bytes_read == 0) break;
1513 const bytes_written = compressor.write(buf[0..bytes_read]) catch |err| switch (err) {
1514 error.NoSpaceLeft => {
1515 allocator.free(compressed_data);
1516 return null;
1517 },
1518 else => return err,
1519 };
1520 std.debug.assert(bytes_written == bytes_read);
1521 }
1522 compressor.finish() catch |err| switch (err) {
1523 error.NoSpaceLeft => {
1524 allocator.free(compressed_data);
1525 return null;
1526 },
1527 else => return err,
1528 };
1529 }
1530
1531 const compressed_len: usize = @intCast(compressed_stream.getPos() catch unreachable);
1532 const data = allocator.realloc(compressed_data, compressed_len) catch compressed_data;
1533 return data[0..compressed_len];
1534 }
1535
1536 fn createDebugLink(path: []const u8) DebugLink {
1537 const file = std.fs.cwd().openFile(path, .{}) catch |err| {
1538 fatal("zig objcopy: could not open `{s}`: {s}\n", .{ path, @errorName(err) });
1539 };
1540 defer file.close();
1541
1542 const crc = ElfFileHelper.computeFileCrc(file) catch |err| {
1543 fatal("zig objcopy: could not read `{s}`: {s}\n", .{ path, @errorName(err) });
1544 };
1545 return .{
1546 .name = std.fs.path.basename(path),
1547 .crc32 = crc,
1548 };
1549 }
1550
1551 fn computeFileCrc(file: File) !u32 {
1552 var buf: [8000]u8 = undefined;
1553
1554 try file.seekTo(0);
1555 var hasher = std.hash.Crc32.init();
1556 while (true) {
1557 const bytes_read = try file.read(&buf);
1558 if (bytes_read == 0) break;
1559 hasher.update(buf[0..bytes_read]);
1560 }
1561 return hasher.final();
1562 }
1563};
1564
1565const SectionFlags = packed struct {720const SectionFlags = packed struct {
1566 alloc: bool = false,721 alloc: bool = false,
1567 contents: bool = false,722 contents: bool = false,
lib/compiler/std-docs.zig+25-20
...@@ -60,7 +60,9 @@ pub fn main() !void {...@@ -60,7 +60,9 @@ pub fn main() !void {
60 const should_open_browser = force_open_browser orelse (listen_port == 0);60 const should_open_browser = force_open_browser orelse (listen_port == 0);
6161
62 const address = std.net.Address.parseIp("127.0.0.1", listen_port) catch unreachable;62 const address = std.net.Address.parseIp("127.0.0.1", listen_port) catch unreachable;
63 var http_server = try address.listen(.{});63 var http_server = try address.listen(.{
64 .reuse_address = true,
65 });
64 const port = http_server.listen_address.in.getPort();66 const port = http_server.listen_address.in.getPort();
65 const url_with_newline = try std.fmt.allocPrint(arena, "http://127.0.0.1:{d}/\n", .{port});67 const url_with_newline = try std.fmt.allocPrint(arena, "http://127.0.0.1:{d}/\n", .{port});
66 std.fs.File.stdout().writeAll(url_with_newline) catch {};68 std.fs.File.stdout().writeAll(url_with_newline) catch {};
...@@ -189,7 +191,11 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {...@@ -189,7 +191,11 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {
189 var walker = try std_dir.walk(gpa);191 var walker = try std_dir.walk(gpa);
190 defer walker.deinit();192 defer walker.deinit();
191193
192 var archiver = std.tar.writer(response.writer());194 var adapter_buffer: [500]u8 = undefined;
195 var response_writer = response.writer().adaptToNewApi();
196 response_writer.new_interface.buffer = &adapter_buffer;
197
198 var archiver: std.tar.Writer = .{ .underlying_writer = &response_writer.new_interface };
193 archiver.prefix = "std";199 archiver.prefix = "std";
194200
195 while (try walker.next()) |entry| {201 while (try walker.next()) |entry| {
...@@ -204,7 +210,13 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {...@@ -204,7 +210,13 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {
204 }210 }
205 var file = try entry.dir.openFile(entry.basename, .{});211 var file = try entry.dir.openFile(entry.basename, .{});
206 defer file.close();212 defer file.close();
207 try archiver.writeFile(entry.path, file);213 const stat = try file.stat();
214 var file_reader: std.fs.File.Reader = .{
215 .file = file,
216 .interface = std.fs.File.Reader.initInterface(&.{}),
217 .size = stat.size,
218 };
219 try archiver.writeFile(entry.path, &file_reader, stat.mtime);
208 }220 }
209221
210 {222 {
...@@ -217,6 +229,7 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {...@@ -217,6 +229,7 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void {
217229
218 // intentionally omitting the pointless trailer230 // intentionally omitting the pointless trailer
219 //try archiver.finish();231 //try archiver.finish();
232 try response_writer.new_interface.flush();
220 try response.end();233 try response.end();
221}234}
222235
...@@ -307,21 +320,17 @@ fn buildWasmBinary(...@@ -307,21 +320,17 @@ fn buildWasmBinary(
307 try sendMessage(child.stdin.?, .update);320 try sendMessage(child.stdin.?, .update);
308 try sendMessage(child.stdin.?, .exit);321 try sendMessage(child.stdin.?, .exit);
309322
310 const Header = std.zig.Server.Message.Header;
311 var result: ?Cache.Path = null;323 var result: ?Cache.Path = null;
312 var result_error_bundle = std.zig.ErrorBundle.empty;324 var result_error_bundle = std.zig.ErrorBundle.empty;
313325
314 const stdout = poller.fifo(.stdout);326 const stdout = poller.reader(.stdout);
315327
316 poll: while (true) {328 poll: while (true) {
317 while (stdout.readableLength() < @sizeOf(Header)) {329 const Header = std.zig.Server.Message.Header;
318 if (!(try poller.poll())) break :poll;330 while (stdout.buffered().len < @sizeOf(Header)) if (!try poller.poll()) break :poll;
319 }331 const header = stdout.takeStruct(Header, .little) catch unreachable;
320 const header = stdout.reader().readStruct(Header) catch unreachable;332 while (stdout.buffered().len < header.bytes_len) if (!try poller.poll()) break :poll;
321 while (stdout.readableLength() < header.bytes_len) {333 const body = stdout.take(header.bytes_len) catch unreachable;
322 if (!(try poller.poll())) break :poll;
323 }
324 const body = stdout.readableSliceOfLen(header.bytes_len);
325334
326 switch (header.tag) {335 switch (header.tag) {
327 .zig_version => {336 .zig_version => {
...@@ -361,15 +370,11 @@ fn buildWasmBinary(...@@ -361,15 +370,11 @@ fn buildWasmBinary(
361 },370 },
362 else => {}, // ignore other messages371 else => {}, // ignore other messages
363 }372 }
364
365 stdout.discard(body.len);
366 }373 }
367374
368 const stderr = poller.fifo(.stderr);375 const stderr = poller.reader(.stderr);
369 if (stderr.readableLength() > 0) {376 if (stderr.bufferedLen() > 0) {
370 const owned_stderr = try stderr.toOwnedSlice();377 std.debug.print("{s}", .{stderr.buffered()});
371 defer gpa.free(owned_stderr);
372 std.debug.print("{s}", .{owned_stderr});
373 }378 }
374379
375 // Send EOF to stdin.380 // Send EOF to stdin.
lib/compiler/test_runner.zig+19-20
...@@ -16,6 +16,7 @@ var stdin_buffer: [4096]u8 = undefined;...@@ -16,6 +16,7 @@ var stdin_buffer: [4096]u8 = undefined;
16var stdout_buffer: [4096]u8 = undefined;16var stdout_buffer: [4096]u8 = undefined;
1717
18const crippled = switch (builtin.zig_backend) {18const crippled = switch (builtin.zig_backend) {
19 .stage2_aarch64,
19 .stage2_powerpc,20 .stage2_powerpc,
20 .stage2_riscv64,21 .stage2_riscv64,
21 => true,22 => true,
...@@ -287,13 +288,14 @@ pub fn log(...@@ -287,13 +288,14 @@ pub fn log(
287/// work-in-progress backends can handle it.288/// work-in-progress backends can handle it.
288pub fn mainSimple() anyerror!void {289pub fn mainSimple() anyerror!void {
289 @disableInstrumentation();290 @disableInstrumentation();
290 // is the backend capable of printing to stderr?291 // is the backend capable of calling `std.fs.File.writeAll`?
291 const enable_print = switch (builtin.zig_backend) {292 const enable_write = switch (builtin.zig_backend) {
293 .stage2_aarch64, .stage2_riscv64 => true,
292 else => false,294 else => false,
293 };295 };
294 // is the backend capable of using std.fmt.format to print a summary at the end?296 // is the backend capable of calling `std.Io.Writer.print`?
295 const print_summary = switch (builtin.zig_backend) {297 const enable_print = switch (builtin.zig_backend) {
296 .stage2_riscv64 => true,298 .stage2_aarch64, .stage2_riscv64 => true,
297 else => false,299 else => false,
298 };300 };
299301
...@@ -302,34 +304,31 @@ pub fn mainSimple() anyerror!void {...@@ -302,34 +304,31 @@ pub fn mainSimple() anyerror!void {
302 var failed: u64 = 0;304 var failed: u64 = 0;
303305
304 // we don't want to bring in File and Writer if the backend doesn't support it306 // we don't want to bring in File and Writer if the backend doesn't support it
305 const stderr = if (comptime enable_print) std.fs.File.stderr() else {};307 const stdout = if (enable_write) std.fs.File.stdout() else {};
306308
307 for (builtin.test_functions) |test_fn| {309 for (builtin.test_functions) |test_fn| {
310 if (enable_write) {
311 stdout.writeAll(test_fn.name) catch {};
312 stdout.writeAll("... ") catch {};
313 }
308 if (test_fn.func()) |_| {314 if (test_fn.func()) |_| {
309 if (enable_print) {315 if (enable_write) stdout.writeAll("PASS\n") catch {};
310 stderr.writeAll(test_fn.name) catch {};
311 stderr.writeAll("... ") catch {};
312 stderr.writeAll("PASS\n") catch {};
313 }
314 } else |err| {316 } else |err| {
315 if (enable_print) {
316 stderr.writeAll(test_fn.name) catch {};
317 stderr.writeAll("... ") catch {};
318 }
319 if (err != error.SkipZigTest) {317 if (err != error.SkipZigTest) {
320 if (enable_print) stderr.writeAll("FAIL\n") catch {};318 if (enable_write) stdout.writeAll("FAIL\n") catch {};
321 failed += 1;319 failed += 1;
322 if (!enable_print) return err;320 if (!enable_write) return err;
323 continue;321 continue;
324 }322 }
325 if (enable_print) stderr.writeAll("SKIP\n") catch {};323 if (enable_write) stdout.writeAll("SKIP\n") catch {};
326 skipped += 1;324 skipped += 1;
327 continue;325 continue;
328 }326 }
329 passed += 1;327 passed += 1;
330 }328 }
331 if (enable_print and print_summary) {329 if (enable_print) {
332 stderr.deprecatedWriter().print("{} passed, {} skipped, {} failed\n", .{ passed, skipped, failed }) catch {};330 var stdout_writer = stdout.writer(&.{});
331 stdout_writer.interface.print("{} passed, {} skipped, {} failed\n", .{ passed, skipped, failed }) catch {};
333 }332 }
334 if (failed != 0) std.process.exit(1);333 if (failed != 0) std.process.exit(1);
335}334}
lib/compiler_rt.zig+2-2
...@@ -249,12 +249,12 @@ comptime {...@@ -249,12 +249,12 @@ comptime {
249 _ = @import("compiler_rt/hexagon.zig");249 _ = @import("compiler_rt/hexagon.zig");
250250
251 if (@import("builtin").object_format != .c) {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 _ = @import("compiler_rt/stack_probe.zig");253 _ = @import("compiler_rt/stack_probe.zig");
254254
255 // macOS has these functions inside libSystem.255 // macOS has these functions inside libSystem.
256 if (builtin.cpu.arch.isAARCH64() and !builtin.os.tag.isDarwin()) {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 }
259259
260 _ = @import("compiler_rt/memcpy.zig");260 _ = @import("compiler_rt/memcpy.zig");
lib/compiler_rt/addo.zig+1-3
...@@ -1,6 +1,4 @@...@@ -1,6 +1,4 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");
3const is_test = builtin.is_test;
4const common = @import("./common.zig");2const common = @import("./common.zig");
5pub const panic = @import("common.zig").panic;3pub const panic = @import("common.zig").panic;
64
...@@ -16,7 +14,7 @@ comptime {...@@ -16,7 +14,7 @@ comptime {
16// - addoXi4_generic as default14// - addoXi4_generic as default
1715
18inline fn addoXi4_generic(comptime ST: type, a: ST, b: ST, overflow: *c_int) ST {16inline 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 overflow.* = 0;18 overflow.* = 0;
21 const sum: ST = a +% b;19 const sum: ST = a +% b;
22 // Hackers Delight: section Overflow Detection, subsection Signed Add/Subtract20 // Hackers Delight: section Overflow Detection, subsection Signed Add/Subtract
lib/compiler_rt/addoti4_test.zig+3
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const addv = @import("addo.zig");1const addv = @import("addo.zig");
2const builtin = @import("builtin");
2const std = @import("std");3const std = @import("std");
3const testing = std.testing;4const testing = std.testing;
4const math = std.math;5const math = std.math;
...@@ -23,6 +24,8 @@ fn simple_addoti4(a: i128, b: i128, overflow: *c_int) i128 {...@@ -23,6 +24,8 @@ fn simple_addoti4(a: i128, b: i128, overflow: *c_int) i128 {
23}24}
2425
25test "addoti4" {26test "addoti4" {
27 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
28
26 const min: i128 = math.minInt(i128);29 const min: i128 = math.minInt(i128);
27 const max: i128 = math.maxInt(i128);30 const max: i128 = math.maxInt(i128);
28 var i: i128 = 1;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,8 +97,7 @@ fn clear_cache(start: usize, end: usize) callconv(.c) void {
97 .nbytes = end - start,97 .nbytes = end - start,
98 .whichcache = 3, // ICACHE | DCACHE98 .whichcache = 3, // ICACHE | DCACHE
99 };99 };
100 asm volatile (100 asm volatile ("syscall"
101 \\ syscall
102 :101 :
103 : [_] "{$2}" (165), // nr = SYS_sysarch102 : [_] "{$2}" (165), // nr = SYS_sysarch
104 [_] "{$4}" (0), // op = MIPS_CACHEFLUSH103 [_] "{$4}" (0), // op = MIPS_CACHEFLUSH
...@@ -116,11 +115,8 @@ fn clear_cache(start: usize, end: usize) callconv(.c) void {...@@ -116,11 +115,8 @@ fn clear_cache(start: usize, end: usize) callconv(.c) void {
116 } else if (arm64 and !apple) {115 } else if (arm64 and !apple) {
117 // Get Cache Type Info.116 // Get Cache Type Info.
118 // TODO memoize this?117 // TODO memoize this?
119 var ctr_el0: u64 = 0;118 const ctr_el0 = asm volatile ("mrs %[ctr_el0], ctr_el0"
120 asm volatile (119 : [ctr_el0] "=r" (-> u64),
121 \\mrs %[x], ctr_el0
122 \\
123 : [x] "=r" (ctr_el0),
124 );120 );
125 // The DC and IC instructions must use 64-bit registers so we don't use121 // The DC and IC instructions must use 64-bit registers so we don't use
126 // uintptr_t in case this runs in an IPL32 environment.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,9 +183,7 @@ fn clear_cache(start: usize, end: usize) callconv(.c) void {
187 exportIt();183 exportIt();
188 } else if (os == .linux and loongarch) {184 } else if (os == .linux and loongarch) {
189 // See: https://github.com/llvm/llvm-project/blob/cf54cae26b65fc3201eff7200ffb9b0c9e8f9a13/compiler-rt/lib/builtins/clear_cache.c#L94-L95185 // See: https://github.com/llvm/llvm-project/blob/cf54cae26b65fc3201eff7200ffb9b0c9e8f9a13/compiler-rt/lib/builtins/clear_cache.c#L94-L95
190 asm volatile (186 asm volatile ("ibar 0");
191 \\ ibar 0
192 );
193 exportIt();187 exportIt();
194 }188 }
195189
lib/compiler_rt/cmp.zig-1
...@@ -1,6 +1,5 @@...@@ -1,6 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const is_test = builtin.is_test;
4const common = @import("common.zig");3const common = @import("common.zig");
54
6pub const panic = common.panic;5pub 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,9 +102,14 @@ pub const gnu_f16_abi = switch (builtin.cpu.arch) {
102102
103pub const want_sparc_abi = builtin.cpu.arch.isSPARC();103pub const want_sparc_abi = builtin.cpu.arch.isSPARC();
104104
105pub const test_safety = switch (builtin.zig_backend) {
106 .stage2_aarch64 => false,
107 else => builtin.is_test,
108};
109
105// Avoid dragging in the runtime safety mechanisms into this .o file, unless110// Avoid dragging in the runtime safety mechanisms into this .o file, unless
106// we're trying to test compiler-rt.111// we're trying to test compiler-rt.
107pub const panic = if (builtin.is_test) std.debug.FullPanic(std.debug.defaultPanic) else std.debug.no_panic;112pub const panic = if (test_safety) std.debug.FullPanic(std.debug.defaultPanic) else std.debug.no_panic;
108113
109/// This seems to mostly correspond to `clang::TargetInfo::HasFloat16`.114/// This seems to mostly correspond to `clang::TargetInfo::HasFloat16`.
110pub fn F16T(comptime OtherType: type) type {115pub fn F16T(comptime OtherType: type) type {
lib/compiler_rt/comparedf2_test.zig-1
...@@ -4,7 +4,6 @@...@@ -4,7 +4,6 @@
44
5const std = @import("std");5const std = @import("std");
6const builtin = @import("builtin");6const builtin = @import("builtin");
7const is_test = builtin.is_test;
87
9const __eqdf2 = @import("./cmpdf2.zig").__eqdf2;8const __eqdf2 = @import("./cmpdf2.zig").__eqdf2;
10const __ledf2 = @import("./cmpdf2.zig").__ledf2;9const __ledf2 = @import("./cmpdf2.zig").__ledf2;
lib/compiler_rt/comparesf2_test.zig-1
...@@ -4,7 +4,6 @@...@@ -4,7 +4,6 @@
44
5const std = @import("std");5const std = @import("std");
6const builtin = @import("builtin");6const builtin = @import("builtin");
7const is_test = builtin.is_test;
87
9const __eqsf2 = @import("./cmpsf2.zig").__eqsf2;8const __eqsf2 = @import("./cmpsf2.zig").__eqsf2;
10const __lesf2 = @import("./cmpsf2.zig").__lesf2;9const __lesf2 = @import("./cmpsf2.zig").__lesf2;
lib/compiler_rt/count0bits.zig-1
...@@ -1,6 +1,5 @@...@@ -1,6 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const is_test = builtin.is_test;
4const common = @import("common.zig");3const common = @import("common.zig");
54
6pub const panic = common.panic;5pub const panic = common.panic;
lib/compiler_rt/divdf3.zig-1
...@@ -5,7 +5,6 @@...@@ -5,7 +5,6 @@
5const std = @import("std");5const std = @import("std");
6const builtin = @import("builtin");6const builtin = @import("builtin");
7const arch = builtin.cpu.arch;7const arch = builtin.cpu.arch;
8const is_test = builtin.is_test;
9const common = @import("common.zig");8const common = @import("common.zig");
109
11const normalize = common.normalize;10const 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,7 +34,7 @@ fn divmod(q: ?[]u32, r: ?[]u32, u: []u32, v: []u32) !void {
34}34}
3535
36pub fn __divei4(q_p: [*]u8, u_p: [*]u8, v_p: [*]u8, bits: usize) callconv(.c) void {36pub 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 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));38 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
39 const q: []u32 = @ptrCast(@alignCast(q_p[0..byte_size]));39 const q: []u32 = @ptrCast(@alignCast(q_p[0..byte_size]));
40 const u: []u32 = @ptrCast(@alignCast(u_p[0..byte_size]));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,7 +43,7 @@ pub fn __divei4(q_p: [*]u8, u_p: [*]u8, v_p: [*]u8, bits: usize) callconv(.c) vo
43}43}
4444
45pub fn __modei4(r_p: [*]u8, u_p: [*]u8, v_p: [*]u8, bits: usize) callconv(.c) void {45pub 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 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));47 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
48 const r: []u32 = @ptrCast(@alignCast(r_p[0..byte_size]));48 const r: []u32 = @ptrCast(@alignCast(r_p[0..byte_size]));
49 const u: []u32 = @ptrCast(@alignCast(u_p[0..byte_size]));49 const u: []u32 = @ptrCast(@alignCast(u_p[0..byte_size]));
lib/compiler_rt/fixint_test.zig-1
...@@ -1,4 +1,3 @@...@@ -1,4 +1,3 @@
1const is_test = @import("builtin").is_test;
2const std = @import("std");1const std = @import("std");
3const math = std.math;2const math = std.math;
4const testing = std.testing;3const testing = std.testing;
lib/compiler_rt/int.zig-1
...@@ -6,7 +6,6 @@ const testing = std.testing;...@@ -6,7 +6,6 @@ const testing = std.testing;
6const maxInt = std.math.maxInt;6const maxInt = std.math.maxInt;
7const minInt = std.math.minInt;7const minInt = std.math.minInt;
8const arch = builtin.cpu.arch;8const arch = builtin.cpu.arch;
9const is_test = builtin.is_test;
10const common = @import("common.zig");9const common = @import("common.zig");
11const udivmod = @import("udivmod.zig").udivmod;10const udivmod = @import("udivmod.zig").udivmod;
12const __divti3 = @import("divti3.zig").__divti3;11const __divti3 = @import("divti3.zig").__divti3;
lib/compiler_rt/memcpy.zig+3-1
...@@ -11,7 +11,7 @@ comptime {...@@ -11,7 +11,7 @@ comptime {
11 .visibility = common.visibility,11 .visibility = common.visibility,
12 };12 };
1313
14 if (builtin.mode == .ReleaseSmall)14 if (builtin.mode == .ReleaseSmall or builtin.zig_backend == .stage2_aarch64)
15 @export(&memcpySmall, export_options)15 @export(&memcpySmall, export_options)
16 else16 else
17 @export(&memcpyFast, export_options);17 @export(&memcpyFast, export_options);
...@@ -195,6 +195,8 @@ inline fn copyRange4(...@@ -195,6 +195,8 @@ inline fn copyRange4(
195}195}
196196
197test "memcpy" {197test "memcpy" {
198 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
199
198 const S = struct {200 const S = struct {
199 fn testFunc(comptime copy_func: anytype) !void {201 fn testFunc(comptime copy_func: anytype) !void {
200 const max_len = 1024;202 const max_len = 1024;
lib/compiler_rt/memmove.zig+9-7
...@@ -14,7 +14,7 @@ comptime {...@@ -14,7 +14,7 @@ comptime {
14 .visibility = common.visibility,14 .visibility = common.visibility,
15 };15 };
1616
17 if (builtin.mode == .ReleaseSmall)17 if (builtin.mode == .ReleaseSmall or builtin.zig_backend == .stage2_aarch64)
18 @export(&memmoveSmall, export_options)18 @export(&memmoveSmall, export_options)
19 else19 else
20 @export(&memmoveFast, export_options);20 @export(&memmoveFast, export_options);
...@@ -39,7 +39,7 @@ fn memmoveSmall(opt_dest: ?[*]u8, opt_src: ?[*]const u8, len: usize) callconv(.c...@@ -39,7 +39,7 @@ fn memmoveSmall(opt_dest: ?[*]u8, opt_src: ?[*]const u8, len: usize) callconv(.c
39}39}
4040
41fn memmoveFast(dest: ?[*]u8, src: ?[*]u8, len: usize) callconv(.c) ?[*]u8 {41fn memmoveFast(dest: ?[*]u8, src: ?[*]u8, len: usize) callconv(.c) ?[*]u8 {
42 @setRuntimeSafety(builtin.is_test);42 @setRuntimeSafety(common.test_safety);
43 const small_limit = @max(2 * @sizeOf(Element), @sizeOf(Element));43 const small_limit = @max(2 * @sizeOf(Element), @sizeOf(Element));
4444
45 if (copySmallLength(small_limit, dest.?, src.?, len)) return dest;45 if (copySmallLength(small_limit, dest.?, src.?, len)) return dest;
...@@ -79,7 +79,7 @@ inline fn copyLessThan16(...@@ -79,7 +79,7 @@ inline fn copyLessThan16(
79 src: [*]const u8,79 src: [*]const u8,
80 len: usize,80 len: usize,
81) void {81) void {
82 @setRuntimeSafety(builtin.is_test);82 @setRuntimeSafety(common.test_safety);
83 if (len < 4) {83 if (len < 4) {
84 if (len == 0) return;84 if (len == 0) return;
85 const b = len / 2;85 const b = len / 2;
...@@ -100,7 +100,7 @@ inline fn copy16ToSmallLimit(...@@ -100,7 +100,7 @@ inline fn copy16ToSmallLimit(
100 src: [*]const u8,100 src: [*]const u8,
101 len: usize,101 len: usize,
102) bool {102) bool {
103 @setRuntimeSafety(builtin.is_test);103 @setRuntimeSafety(common.test_safety);
104 inline for (2..(std.math.log2(small_limit) + 1) / 2 + 1) |p| {104 inline for (2..(std.math.log2(small_limit) + 1) / 2 + 1) |p| {
105 const limit = 1 << (2 * p);105 const limit = 1 << (2 * p);
106 if (len < limit) {106 if (len < limit) {
...@@ -119,7 +119,7 @@ inline fn copyRange4(...@@ -119,7 +119,7 @@ inline fn copyRange4(
119 src: [*]const u8,119 src: [*]const u8,
120 len: usize,120 len: usize,
121) void {121) void {
122 @setRuntimeSafety(builtin.is_test);122 @setRuntimeSafety(common.test_safety);
123 comptime assert(std.math.isPowerOfTwo(copy_len));123 comptime assert(std.math.isPowerOfTwo(copy_len));
124 assert(len >= copy_len);124 assert(len >= copy_len);
125 assert(len < 4 * copy_len);125 assert(len < 4 * copy_len);
...@@ -147,7 +147,7 @@ inline fn copyForwards(...@@ -147,7 +147,7 @@ inline fn copyForwards(
147 src: [*]const u8,147 src: [*]const u8,
148 len: usize,148 len: usize,
149) void {149) void {
150 @setRuntimeSafety(builtin.is_test);150 @setRuntimeSafety(common.test_safety);
151 assert(len >= 2 * @sizeOf(Element));151 assert(len >= 2 * @sizeOf(Element));
152152
153 const head = src[0..@sizeOf(Element)].*;153 const head = src[0..@sizeOf(Element)].*;
...@@ -181,7 +181,7 @@ inline fn copyBlocks(...@@ -181,7 +181,7 @@ inline fn copyBlocks(
181 src: anytype,181 src: anytype,
182 max_bytes: usize,182 max_bytes: usize,
183) void {183) void {
184 @setRuntimeSafety(builtin.is_test);184 @setRuntimeSafety(common.test_safety);
185185
186 const T = @typeInfo(@TypeOf(dest)).pointer.child;186 const T = @typeInfo(@TypeOf(dest)).pointer.child;
187 comptime assert(T == @typeInfo(@TypeOf(src)).pointer.child);187 comptime assert(T == @typeInfo(@TypeOf(src)).pointer.child);
...@@ -217,6 +217,8 @@ inline fn copyBackwards(...@@ -217,6 +217,8 @@ inline fn copyBackwards(
217}217}
218218
219test memmoveFast {219test memmoveFast {
220 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
221
220 const max_len = 1024;222 const max_len = 1024;
221 var buffer: [max_len + @alignOf(Element) - 1]u8 = undefined;223 var buffer: [max_len + @alignOf(Element) - 1]u8 = undefined;
222 for (&buffer, 0..) |*b, i| {224 for (&buffer, 0..) |*b, i| {
lib/compiler_rt/mulf3.zig+2-2
...@@ -6,7 +6,7 @@ const common = @import("./common.zig");...@@ -6,7 +6,7 @@ const common = @import("./common.zig");
6/// Ported from:6/// Ported from:
7/// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/lib/builtins/fp_mul_impl.inc7/// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/lib/builtins/fp_mul_impl.inc
8pub inline fn mulf3(comptime T: type, a: T, b: T) T {8pub inline fn mulf3(comptime T: type, a: T, b: T) T {
9 @setRuntimeSafety(builtin.is_test);9 @setRuntimeSafety(common.test_safety);
10 const typeWidth = @typeInfo(T).float.bits;10 const typeWidth = @typeInfo(T).float.bits;
11 const significandBits = math.floatMantissaBits(T);11 const significandBits = math.floatMantissaBits(T);
12 const fractionalBits = math.floatFractionalBits(T);12 const fractionalBits = math.floatFractionalBits(T);
...@@ -163,7 +163,7 @@ pub inline fn mulf3(comptime T: type, a: T, b: T) T {...@@ -163,7 +163,7 @@ pub inline fn mulf3(comptime T: type, a: T, b: T) T {
163///163///
164/// This is analogous to an shr version of `@shlWithOverflow`164/// This is analogous to an shr version of `@shlWithOverflow`
165fn wideShrWithTruncation(comptime Z: type, hi: *Z, lo: *Z, count: u32) bool {165fn wideShrWithTruncation(comptime Z: type, hi: *Z, lo: *Z, count: u32) bool {
166 @setRuntimeSafety(builtin.is_test);166 @setRuntimeSafety(common.test_safety);
167 const typeWidth = @typeInfo(Z).int.bits;167 const typeWidth = @typeInfo(Z).int.bits;
168 var inexact = false;168 var inexact = false;
169 if (count < typeWidth) {169 if (count < typeWidth) {
lib/compiler_rt/rem_pio2_large.zig+1-1
...@@ -251,7 +251,7 @@ const PIo2 = [_]f64{...@@ -251,7 +251,7 @@ const PIo2 = [_]f64{
251/// compiler will convert from decimal to binary accurately enough251/// compiler will convert from decimal to binary accurately enough
252/// to produce the hexadecimal values shown.252/// to produce the hexadecimal values shown.
253///253///
254pub fn rem_pio2_large(x: []f64, y: []f64, e0: i32, nx: i32, prec: usize) i32 {254pub fn rem_pio2_large(x: []const f64, y: []f64, e0: i32, nx: i32, prec: usize) i32 {
255 var jz: i32 = undefined;255 var jz: i32 = undefined;
256 var jx: i32 = undefined;256 var jx: i32 = undefined;
257 var jv: i32 = undefined;257 var jv: i32 = undefined;
lib/compiler_rt/stack_probe.zig-1
...@@ -4,7 +4,6 @@ const common = @import("common.zig");...@@ -4,7 +4,6 @@ const common = @import("common.zig");
4const os_tag = builtin.os.tag;4const os_tag = builtin.os.tag;
5const arch = builtin.cpu.arch;5const arch = builtin.cpu.arch;
6const abi = builtin.abi;6const abi = builtin.abi;
7const is_test = builtin.is_test;
87
9pub const panic = common.panic;8pub const panic = common.panic;
109
lib/compiler_rt/suboti4_test.zig+3
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const subo = @import("subo.zig");1const subo = @import("subo.zig");
2const builtin = @import("builtin");
2const std = @import("std");3const std = @import("std");
3const testing = std.testing;4const testing = std.testing;
4const math = std.math;5const math = std.math;
...@@ -27,6 +28,8 @@ pub fn simple_suboti4(a: i128, b: i128, overflow: *c_int) i128 {...@@ -27,6 +28,8 @@ pub fn simple_suboti4(a: i128, b: i128, overflow: *c_int) i128 {
27}28}
2829
29test "suboti3" {30test "suboti3" {
31 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
32
30 const min: i128 = math.minInt(i128);33 const min: i128 = math.minInt(i128);
31 const max: i128 = math.maxInt(i128);34 const max: i128 = math.maxInt(i128);
32 var i: i128 = 1;35 var i: i128 = 1;
lib/compiler_rt/udivmod.zig+5-5
...@@ -1,8 +1,8 @@...@@ -1,8 +1,8 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const is_test = builtin.is_test;
4const Log2Int = std.math.Log2Int;3const Log2Int = std.math.Log2Int;
5const HalveInt = @import("common.zig").HalveInt;4const common = @import("common.zig");
5const HalveInt = common.HalveInt;
66
7const lo = switch (builtin.cpu.arch.endian()) {7const lo = switch (builtin.cpu.arch.endian()) {
8 .big => 1,8 .big => 1,
...@@ -14,7 +14,7 @@ const hi = 1 - lo;...@@ -14,7 +14,7 @@ const hi = 1 - lo;
14// Returns U / v_ and sets r = U % v_.14// Returns U / v_ and sets r = U % v_.
15fn divwide_generic(comptime T: type, _u1: T, _u0: T, v_: T, r: *T) T {15fn divwide_generic(comptime T: type, _u1: T, _u0: T, v_: T, r: *T) T {
16 const HalfT = HalveInt(T, false).HalfT;16 const HalfT = HalveInt(T, false).HalfT;
17 @setRuntimeSafety(is_test);17 @setRuntimeSafety(common.test_safety);
18 var v = v_;18 var v = v_;
1919
20 const b = @as(T, 1) << (@bitSizeOf(T) / 2);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,7 +70,7 @@ fn divwide_generic(comptime T: type, _u1: T, _u0: T, v_: T, r: *T) T {
70}70}
7171
72fn divwide(comptime T: type, _u1: T, _u0: T, v: T, r: *T) T {72fn divwide(comptime T: type, _u1: T, _u0: T, v: T, r: *T) T {
73 @setRuntimeSafety(is_test);73 @setRuntimeSafety(common.test_safety);
74 if (T == u64 and builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag != .windows) {74 if (T == u64 and builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag != .windows) {
75 var rem: T = undefined;75 var rem: T = undefined;
76 const quo = asm (76 const quo = asm (
...@@ -90,7 +90,7 @@ fn divwide(comptime T: type, _u1: T, _u0: T, v: T, r: *T) T {...@@ -90,7 +90,7 @@ fn divwide(comptime T: type, _u1: T, _u0: T, v: T, r: *T) T {
9090
91// Returns a_ / b_ and sets maybe_rem = a_ % b.91// Returns a_ / b_ and sets maybe_rem = a_ % b.
92pub fn udivmod(comptime T: type, a_: T, b_: T, maybe_rem: ?*T) T {92pub fn udivmod(comptime T: type, a_: T, b_: T, maybe_rem: ?*T) T {
93 @setRuntimeSafety(is_test);93 @setRuntimeSafety(common.test_safety);
94 const HalfT = HalveInt(T, false).HalfT;94 const HalfT = HalveInt(T, false).HalfT;
95 const SignedT = std.meta.Int(.signed, @bitSizeOf(T));95 const SignedT = std.meta.Int(.signed, @bitSizeOf(T));
9696
lib/compiler_rt/udivmodei4.zig+3-2
...@@ -113,7 +113,7 @@ pub fn divmod(q: ?[]u32, r: ?[]u32, u: []const u32, v: []const u32) !void {...@@ -113,7 +113,7 @@ pub fn divmod(q: ?[]u32, r: ?[]u32, u: []const u32, v: []const u32) !void {
113}113}
114114
115pub fn __udivei4(q_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, bits: usize) callconv(.c) void {115pub 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 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));117 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
118 const q: []u32 = @ptrCast(@alignCast(q_p[0..byte_size]));118 const q: []u32 = @ptrCast(@alignCast(q_p[0..byte_size]));
119 const u: []const u32 = @ptrCast(@alignCast(u_p[0..byte_size]));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,7 +122,7 @@ pub fn __udivei4(q_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, bits: usize) ca
122}122}
123123
124pub fn __umodei4(r_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, bits: usize) callconv(.c) void {124pub 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 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));126 const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits));
127 const r: []u32 = @ptrCast(@alignCast(r_p[0..byte_size]));127 const r: []u32 = @ptrCast(@alignCast(r_p[0..byte_size]));
128 const u: []const u32 = @ptrCast(@alignCast(u_p[0..byte_size]));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,6 +131,7 @@ pub fn __umodei4(r_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, bits: usize) ca
131}131}
132132
133test "__udivei4/__umodei4" {133test "__udivei4/__umodei4" {
134 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
134 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;135 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
135 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;136 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
136137
lib/docs/wasm/main.zig+3-3
...@@ -772,10 +772,10 @@ export fn decl_type_html(decl_index: Decl.Index) String {...@@ -772,10 +772,10 @@ export fn decl_type_html(decl_index: Decl.Index) String {
772const Oom = error{OutOfMemory};772const Oom = error{OutOfMemory};
773773
774fn unpackInner(tar_bytes: []u8) !void {774fn unpackInner(tar_bytes: []u8) !void {
775 var fbs = std.io.fixedBufferStream(tar_bytes);775 var reader: std.Io.Reader = .fixed(tar_bytes);
776 var file_name_buffer: [1024]u8 = undefined;776 var file_name_buffer: [1024]u8 = undefined;
777 var link_name_buffer: [1024]u8 = undefined;777 var link_name_buffer: [1024]u8 = undefined;
778 var it = std.tar.iterator(fbs.reader(), .{778 var it: std.tar.Iterator = .init(&reader, .{
779 .file_name_buffer = &file_name_buffer,779 .file_name_buffer = &file_name_buffer,
780 .link_name_buffer = &link_name_buffer,780 .link_name_buffer = &link_name_buffer,
781 });781 });
...@@ -796,7 +796,7 @@ fn unpackInner(tar_bytes: []u8) !void {...@@ -796,7 +796,7 @@ fn unpackInner(tar_bytes: []u8) !void {
796 {796 {
797 gop.value_ptr.* = file;797 gop.value_ptr.* = file;
798 }798 }
799 const file_bytes = tar_bytes[fbs.pos..][0..@intCast(tar_file.size)];799 const file_bytes = tar_bytes[reader.seek..][0..@intCast(tar_file.size)];
800 assert(file == try Walk.add_file(file_name, file_bytes));800 assert(file == try Walk.add_file(file_name, file_bytes));
801 }801 }
802 } else {802 } else {
lib/init/build.zig-1
...@@ -1,4 +1,3 @@...@@ -1,4 +1,3 @@
1//! Use `zig init --strip` next time to generate a project without comments.
2const std = @import("std");1const std = @import("std");
32
4// Although this function looks imperative, it does not perform the build3// Although this function looks imperative, it does not perform the build
lib/std/Build.zig+151-76
...@@ -408,104 +408,179 @@ fn createChildOnly(...@@ -408,104 +408,179 @@ fn createChildOnly(
408 return child;408 return child;
409}409}
410410
411fn userInputOptionsFromArgs(allocator: Allocator, args: anytype) UserInputOptionsMap {411fn userInputOptionsFromArgs(arena: Allocator, args: anytype) UserInputOptionsMap {
412 var user_input_options = UserInputOptionsMap.init(allocator);412 var map = UserInputOptionsMap.init(arena);
413 inline for (@typeInfo(@TypeOf(args)).@"struct".fields) |field| {413 inline for (@typeInfo(@TypeOf(args)).@"struct".fields) |field| {
414 const v = @field(args, field.name);414 if (field.type == @Type(.null)) continue;
415 const T = @TypeOf(v);415 addUserInputOptionFromArg(arena, &map, field, field.type, @field(args, field.name));
416 switch (T) {416 }
417 Target.Query => {417 return map;
418 user_input_options.put(field.name, .{418}
419 .name = field.name,419
420 .value = .{ .scalar = v.zigTriple(allocator) catch @panic("OOM") },420fn addUserInputOptionFromArg(
421 .used = false,421 arena: Allocator,
422 }) catch @panic("OOM");422 map: *UserInputOptionsMap,
423 user_input_options.put("cpu", .{423 field: std.builtin.Type.StructField,
424 .name = "cpu",424 comptime T: type,
425 .value = .{ .scalar = v.serializeCpuAlloc(allocator) catch @panic("OOM") },425 /// If null, the value won't be added, but `T` will still be type-checked.
426 .used = false,426 maybe_value: ?T,
427 }) catch @panic("OOM");427) void {
428 },428 switch (T) {
429 ResolvedTarget => {429 Target.Query => return if (maybe_value) |v| {
430 user_input_options.put(field.name, .{430 map.put(field.name, .{
431 .name = field.name,431 .name = field.name,
432 .value = .{ .scalar = v.query.zigTriple(allocator) catch @panic("OOM") },432 .value = .{ .scalar = v.zigTriple(arena) catch @panic("OOM") },
433 .used = false,433 .used = false,
434 }) catch @panic("OOM");434 }) catch @panic("OOM");
435 user_input_options.put("cpu", .{435 map.put("cpu", .{
436 .name = "cpu",436 .name = "cpu",
437 .value = .{ .scalar = v.query.serializeCpuAlloc(allocator) catch @panic("OOM") },437 .value = .{ .scalar = v.serializeCpuAlloc(arena) catch @panic("OOM") },
438 .used = false,438 .used = false,
439 }) catch @panic("OOM");439 }) catch @panic("OOM");
440 },440 },
441 LazyPath => {441 ResolvedTarget => return if (maybe_value) |v| {
442 user_input_options.put(field.name, .{442 map.put(field.name, .{
443 .name = field.name,
444 .value = .{ .scalar = v.query.zigTriple(arena) catch @panic("OOM") },
445 .used = false,
446 }) catch @panic("OOM");
447 map.put("cpu", .{
448 .name = "cpu",
449 .value = .{ .scalar = v.query.serializeCpuAlloc(arena) catch @panic("OOM") },
450 .used = false,
451 }) catch @panic("OOM");
452 },
453 std.zig.BuildId => return if (maybe_value) |v| {
454 map.put(field.name, .{
455 .name = field.name,
456 .value = .{ .scalar = std.fmt.allocPrint(arena, "{f}", .{v}) catch @panic("OOM") },
457 .used = false,
458 }) catch @panic("OOM");
459 },
460 LazyPath => return if (maybe_value) |v| {
461 map.put(field.name, .{
462 .name = field.name,
463 .value = .{ .lazy_path = v.dupeInner(arena) },
464 .used = false,
465 }) catch @panic("OOM");
466 },
467 []const LazyPath => return if (maybe_value) |v| {
468 var list = ArrayList(LazyPath).initCapacity(arena, v.len) catch @panic("OOM");
469 for (v) |lp| list.appendAssumeCapacity(lp.dupeInner(arena));
470 map.put(field.name, .{
471 .name = field.name,
472 .value = .{ .lazy_path_list = list },
473 .used = false,
474 }) catch @panic("OOM");
475 },
476 []const u8 => return if (maybe_value) |v| {
477 map.put(field.name, .{
478 .name = field.name,
479 .value = .{ .scalar = arena.dupe(u8, v) catch @panic("OOM") },
480 .used = false,
481 }) catch @panic("OOM");
482 },
483 []const []const u8 => return if (maybe_value) |v| {
484 var list = ArrayList([]const u8).initCapacity(arena, v.len) catch @panic("OOM");
485 for (v) |s| list.appendAssumeCapacity(arena.dupe(u8, s) catch @panic("OOM"));
486 map.put(field.name, .{
487 .name = field.name,
488 .value = .{ .list = list },
489 .used = false,
490 }) catch @panic("OOM");
491 },
492 else => switch (@typeInfo(T)) {
493 .bool => return if (maybe_value) |v| {
494 map.put(field.name, .{
443 .name = field.name,495 .name = field.name,
444 .value = .{ .lazy_path = v.dupeInner(allocator) },496 .value = .{ .scalar = if (v) "true" else "false" },
445 .used = false,497 .used = false,
446 }) catch @panic("OOM");498 }) catch @panic("OOM");
447 },499 },
448 []const LazyPath => {500 .@"enum", .enum_literal => return if (maybe_value) |v| {
449 var list = ArrayList(LazyPath).initCapacity(allocator, v.len) catch @panic("OOM");501 map.put(field.name, .{
450 for (v) |lp| list.appendAssumeCapacity(lp.dupeInner(allocator));
451 user_input_options.put(field.name, .{
452 .name = field.name,502 .name = field.name,
453 .value = .{ .lazy_path_list = list },503 .value = .{ .scalar = @tagName(v) },
454 .used = false,504 .used = false,
455 }) catch @panic("OOM");505 }) catch @panic("OOM");
456 },506 },
457 []const u8 => {507 .comptime_int, .int => return if (maybe_value) |v| {
458 user_input_options.put(field.name, .{508 map.put(field.name, .{
459 .name = field.name,509 .name = field.name,
460 .value = .{ .scalar = v },510 .value = .{ .scalar = std.fmt.allocPrint(arena, "{d}", .{v}) catch @panic("OOM") },
461 .used = false,511 .used = false,
462 }) catch @panic("OOM");512 }) catch @panic("OOM");
463 },513 },
464 []const []const u8 => {514 .comptime_float, .float => return if (maybe_value) |v| {
465 var list = ArrayList([]const u8).initCapacity(allocator, v.len) catch @panic("OOM");515 map.put(field.name, .{
466 list.appendSliceAssumeCapacity(v);
467
468 user_input_options.put(field.name, .{
469 .name = field.name,516 .name = field.name,
470 .value = .{ .list = list },517 .value = .{ .scalar = std.fmt.allocPrint(arena, "{x}", .{v}) catch @panic("OOM") },
471 .used = false,518 .used = false,
472 }) catch @panic("OOM");519 }) catch @panic("OOM");
473 },520 },
474 else => switch (@typeInfo(T)) {521 .pointer => |ptr_info| switch (ptr_info.size) {
475 .bool => {522 .one => switch (@typeInfo(ptr_info.child)) {
476 user_input_options.put(field.name, .{523 .array => |array_info| {
477 .name = field.name,524 comptime var slice_info = ptr_info;
478 .value = .{ .scalar = if (v) "true" else "false" },525 slice_info.size = .slice;
479 .used = false,526 slice_info.is_const = true;
480 }) catch @panic("OOM");527 slice_info.child = array_info.child;
481 },528 slice_info.sentinel_ptr = null;
482 .@"enum", .enum_literal => {529 addUserInputOptionFromArg(
483 user_input_options.put(field.name, .{530 arena,
484 .name = field.name,531 map,
485 .value = .{ .scalar = @tagName(v) },532 field,
486 .used = false,533 @Type(.{ .pointer = slice_info }),
487 }) catch @panic("OOM");534 maybe_value orelse null,
535 );
536 return;
537 },
538 else => {},
488 },539 },
489 .comptime_int, .int => {540 .slice => switch (@typeInfo(ptr_info.child)) {
490 user_input_options.put(field.name, .{541 .@"enum" => return if (maybe_value) |v| {
491 .name = field.name,542 var list = ArrayList([]const u8).initCapacity(arena, v.len) catch @panic("OOM");
492 .value = .{ .scalar = std.fmt.allocPrint(allocator, "{d}", .{v}) catch @panic("OOM") },543 for (v) |tag| list.appendAssumeCapacity(@tagName(tag));
493 .used = false,544 map.put(field.name, .{
494 }) catch @panic("OOM");545 .name = field.name,
546 .value = .{ .list = list },
547 .used = false,
548 }) catch @panic("OOM");
549 },
550 else => {
551 comptime var slice_info = ptr_info;
552 slice_info.is_const = true;
553 slice_info.sentinel_ptr = null;
554 addUserInputOptionFromArg(
555 arena,
556 map,
557 field,
558 @Type(.{ .pointer = slice_info }),
559 maybe_value orelse null,
560 );
561 return;
562 },
495 },563 },
496 .comptime_float, .float => {564 else => {},
497 user_input_options.put(field.name, .{565 },
498 .name = field.name,566 .null => unreachable,
499 .value = .{ .scalar = std.fmt.allocPrint(allocator, "{e}", .{v}) catch @panic("OOM") },567 .optional => |info| switch (@typeInfo(info.child)) {
500 .used = false,568 .optional => {},
501 }) catch @panic("OOM");569 else => {
570 addUserInputOptionFromArg(
571 arena,
572 map,
573 field,
574 info.child,
575 maybe_value orelse null,
576 );
577 return;
502 },578 },
503 else => @compileError("option '" ++ field.name ++ "' has unsupported type: " ++ @typeName(T)),
504 },579 },
505 }580 else => {},
581 },
506 }582 }
507583 @compileError("option '" ++ field.name ++ "' has unsupported type: " ++ @typeName(field.type));
508 return user_input_options;
509}584}
510585
511const OrderedUserValue = union(enum) {586const OrderedUserValue = union(enum) {
lib/std/Build/Fuzz/WebServer.zig+17-22
...@@ -273,21 +273,17 @@ fn buildWasmBinary(...@@ -273,21 +273,17 @@ fn buildWasmBinary(
273 try sendMessage(child.stdin.?, .update);273 try sendMessage(child.stdin.?, .update);
274 try sendMessage(child.stdin.?, .exit);274 try sendMessage(child.stdin.?, .exit);
275275
276 const Header = std.zig.Server.Message.Header;
277 var result: ?Path = null;276 var result: ?Path = null;
278 var result_error_bundle = std.zig.ErrorBundle.empty;277 var result_error_bundle = std.zig.ErrorBundle.empty;
279278
280 const stdout = poller.fifo(.stdout);279 const stdout = poller.reader(.stdout);
281280
282 poll: while (true) {281 poll: while (true) {
283 while (stdout.readableLength() < @sizeOf(Header)) {282 const Header = std.zig.Server.Message.Header;
284 if (!(try poller.poll())) break :poll;283 while (stdout.buffered().len < @sizeOf(Header)) if (!try poller.poll()) break :poll;
285 }284 const header = stdout.takeStruct(Header, .little) catch unreachable;
286 const header = stdout.reader().readStruct(Header) catch unreachable;285 while (stdout.buffered().len < header.bytes_len) if (!try poller.poll()) break :poll;
287 while (stdout.readableLength() < header.bytes_len) {286 const body = stdout.take(header.bytes_len) catch unreachable;
288 if (!(try poller.poll())) break :poll;
289 }
290 const body = stdout.readableSliceOfLen(header.bytes_len);
291287
292 switch (header.tag) {288 switch (header.tag) {
293 .zig_version => {289 .zig_version => {
...@@ -325,15 +321,11 @@ fn buildWasmBinary(...@@ -325,15 +321,11 @@ fn buildWasmBinary(
325 },321 },
326 else => {}, // ignore other messages322 else => {}, // ignore other messages
327 }323 }
328
329 stdout.discard(body.len);
330 }324 }
331325
332 const stderr = poller.fifo(.stderr);326 const stderr_contents = try poller.toOwnedSlice(.stderr);
333 if (stderr.readableLength() > 0) {327 if (stderr_contents.len > 0) {
334 const owned_stderr = try stderr.toOwnedSlice();328 std.debug.print("{s}", .{stderr_contents});
335 defer gpa.free(owned_stderr);
336 std.debug.print("{s}", .{owned_stderr});
337 }329 }
338330
339 // Send EOF to stdin.331 // Send EOF to stdin.
...@@ -522,7 +514,9 @@ fn serveSourcesTar(ws: *WebServer, request: *std.http.Server.Request) !void {...@@ -522,7 +514,9 @@ fn serveSourcesTar(ws: *WebServer, request: *std.http.Server.Request) !void {
522514
523 var cwd_cache: ?[]const u8 = null;515 var cwd_cache: ?[]const u8 = null;
524516
525 var archiver = std.tar.writer(response.writer());517 var adapter = response.writer().adaptToNewApi();
518 var archiver: std.tar.Writer = .{ .underlying_writer = &adapter.new_interface };
519 var read_buffer: [1024]u8 = undefined;
526520
527 for (deduped_paths) |joined_path| {521 for (deduped_paths) |joined_path| {
528 var file = joined_path.root_dir.handle.openFile(joined_path.sub_path, .{}) catch |err| {522 var file = joined_path.root_dir.handle.openFile(joined_path.sub_path, .{}) catch |err| {
...@@ -530,13 +524,14 @@ fn serveSourcesTar(ws: *WebServer, request: *std.http.Server.Request) !void {...@@ -530,13 +524,14 @@ fn serveSourcesTar(ws: *WebServer, request: *std.http.Server.Request) !void {
530 continue;524 continue;
531 };525 };
532 defer file.close();526 defer file.close();
533527 const stat = try file.stat();
528 var file_reader: std.fs.File.Reader = .initSize(file, &read_buffer, stat.size);
534 archiver.prefix = joined_path.root_dir.path orelse try memoizedCwd(arena, &cwd_cache);529 archiver.prefix = joined_path.root_dir.path orelse try memoizedCwd(arena, &cwd_cache);
535 try archiver.writeFile(joined_path.sub_path, file);530 try archiver.writeFile(joined_path.sub_path, &file_reader, stat.mtime);
536 }531 }
537532
538 // intentionally omitting the pointless trailer533 // intentionally not calling `archiver.finishPedantically`
539 //try archiver.finish();534 try adapter.new_interface.flush();
540 try response.end();535 try response.end();
541}536}
542537
lib/std/Build/Step.zig+25-34
...@@ -286,7 +286,7 @@ pub fn cast(step: *Step, comptime T: type) ?*T {...@@ -286,7 +286,7 @@ pub fn cast(step: *Step, comptime T: type) ?*T {
286}286}
287287
288/// For debugging purposes, prints identifying information about this Step.288/// For debugging purposes, prints identifying information about this Step.
289pub fn dump(step: *Step, w: *std.io.Writer, tty_config: std.io.tty.Config) void {289pub fn dump(step: *Step, w: *std.Io.Writer, tty_config: std.Io.tty.Config) void {
290 const debug_info = std.debug.getSelfDebugInfo() catch |err| {290 const debug_info = std.debug.getSelfDebugInfo() catch |err| {
291 w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{291 w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{
292 @errorName(err),292 @errorName(err),
...@@ -359,7 +359,7 @@ pub fn addError(step: *Step, comptime fmt: []const u8, args: anytype) error{OutO...@@ -359,7 +359,7 @@ pub fn addError(step: *Step, comptime fmt: []const u8, args: anytype) error{OutO
359359
360pub const ZigProcess = struct {360pub const ZigProcess = struct {
361 child: std.process.Child,361 child: std.process.Child,
362 poller: std.io.Poller(StreamEnum),362 poller: std.Io.Poller(StreamEnum),
363 progress_ipc_fd: if (std.Progress.have_ipc) ?std.posix.fd_t else void,363 progress_ipc_fd: if (std.Progress.have_ipc) ?std.posix.fd_t else void,
364364
365 pub const StreamEnum = enum { stdout, stderr };365 pub const StreamEnum = enum { stdout, stderr };
...@@ -428,7 +428,7 @@ pub fn evalZigProcess(...@@ -428,7 +428,7 @@ pub fn evalZigProcess(
428 const zp = try gpa.create(ZigProcess);428 const zp = try gpa.create(ZigProcess);
429 zp.* = .{429 zp.* = .{
430 .child = child,430 .child = child,
431 .poller = std.io.poll(gpa, ZigProcess.StreamEnum, .{431 .poller = std.Io.poll(gpa, ZigProcess.StreamEnum, .{
432 .stdout = child.stdout.?,432 .stdout = child.stdout.?,
433 .stderr = child.stderr.?,433 .stderr = child.stderr.?,
434 }),434 }),
...@@ -508,20 +508,16 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?Path {...@@ -508,20 +508,16 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?Path {
508 try sendMessage(zp.child.stdin.?, .update);508 try sendMessage(zp.child.stdin.?, .update);
509 if (!watch) try sendMessage(zp.child.stdin.?, .exit);509 if (!watch) try sendMessage(zp.child.stdin.?, .exit);
510510
511 const Header = std.zig.Server.Message.Header;
512 var result: ?Path = null;511 var result: ?Path = null;
513512
514 const stdout = zp.poller.fifo(.stdout);513 const stdout = zp.poller.reader(.stdout);
515514
516 poll: while (true) {515 poll: while (true) {
517 while (stdout.readableLength() < @sizeOf(Header)) {516 const Header = std.zig.Server.Message.Header;
518 if (!(try zp.poller.poll())) break :poll;517 while (stdout.buffered().len < @sizeOf(Header)) if (!try zp.poller.poll()) break :poll;
519 }518 const header = stdout.takeStruct(Header, .little) catch unreachable;
520 const header = stdout.reader().readStruct(Header) catch unreachable;519 while (stdout.buffered().len < header.bytes_len) if (!try zp.poller.poll()) break :poll;
521 while (stdout.readableLength() < header.bytes_len) {520 const body = stdout.take(header.bytes_len) catch unreachable;
522 if (!(try zp.poller.poll())) break :poll;
523 }
524 const body = stdout.readableSliceOfLen(header.bytes_len);
525521
526 switch (header.tag) {522 switch (header.tag) {
527 .zig_version => {523 .zig_version => {
...@@ -547,11 +543,8 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?Path {...@@ -547,11 +543,8 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?Path {
547 .string_bytes = try arena.dupe(u8, string_bytes),543 .string_bytes = try arena.dupe(u8, string_bytes),
548 .extra = extra_array,544 .extra = extra_array,
549 };545 };
550 if (watch) {546 // This message indicates the end of the update.
551 // This message indicates the end of the update.547 if (watch) break :poll;
552 stdout.discard(body.len);
553 break;
554 }
555 },548 },
556 .emit_digest => {549 .emit_digest => {
557 const EmitDigest = std.zig.Server.Message.EmitDigest;550 const EmitDigest = std.zig.Server.Message.EmitDigest;
...@@ -611,15 +604,13 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?Path {...@@ -611,15 +604,13 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?Path {
611 },604 },
612 else => {}, // ignore other messages605 else => {}, // ignore other messages
613 }606 }
614
615 stdout.discard(body.len);
616 }607 }
617608
618 s.result_duration_ns = timer.read();609 s.result_duration_ns = timer.read();
619610
620 const stderr = zp.poller.fifo(.stderr);611 const stderr_contents = try zp.poller.toOwnedSlice(.stderr);
621 if (stderr.readableLength() > 0) {612 if (stderr_contents.len > 0) {
622 try s.result_error_msgs.append(arena, try stderr.toOwnedSlice());613 try s.result_error_msgs.append(arena, try arena.dupe(u8, stderr_contents));
623 }614 }
624615
625 return result;616 return result;
...@@ -736,7 +727,7 @@ pub fn allocPrintCmd2(...@@ -736,7 +727,7 @@ pub fn allocPrintCmd2(
736 argv: []const []const u8,727 argv: []const []const u8,
737) Allocator.Error![]u8 {728) Allocator.Error![]u8 {
738 const shell = struct {729 const shell = struct {
739 fn escape(writer: anytype, string: []const u8, is_argv0: bool) !void {730 fn escape(writer: *std.Io.Writer, string: []const u8, is_argv0: bool) !void {
740 for (string) |c| {731 for (string) |c| {
741 if (switch (c) {732 if (switch (c) {
742 else => true,733 else => true,
...@@ -770,9 +761,9 @@ pub fn allocPrintCmd2(...@@ -770,9 +761,9 @@ pub fn allocPrintCmd2(
770 }761 }
771 };762 };
772763
773 var buf: std.ArrayListUnmanaged(u8) = .empty;764 var aw: std.Io.Writer.Allocating = .init(arena);
774 const writer = buf.writer(arena);765 const writer = &aw.writer;
775 if (opt_cwd) |cwd| try writer.print("cd {s} && ", .{cwd});766 if (opt_cwd) |cwd| writer.print("cd {s} && ", .{cwd}) catch return error.OutOfMemory;
776 if (opt_env) |env| {767 if (opt_env) |env| {
777 const process_env_map = std.process.getEnvMap(arena) catch std.process.EnvMap.init(arena);768 const process_env_map = std.process.getEnvMap(arena) catch std.process.EnvMap.init(arena);
778 var it = env.iterator();769 var it = env.iterator();
...@@ -782,17 +773,17 @@ pub fn allocPrintCmd2(...@@ -782,17 +773,17 @@ pub fn allocPrintCmd2(
782 if (process_env_map.get(key)) |process_value| {773 if (process_env_map.get(key)) |process_value| {
783 if (std.mem.eql(u8, value, process_value)) continue;774 if (std.mem.eql(u8, value, process_value)) continue;
784 }775 }
785 try writer.print("{s}=", .{key});776 writer.print("{s}=", .{key}) catch return error.OutOfMemory;
786 try shell.escape(writer, value, false);777 shell.escape(writer, value, false) catch return error.OutOfMemory;
787 try writer.writeByte(' ');778 writer.writeByte(' ') catch return error.OutOfMemory;
788 }779 }
789 }780 }
790 try shell.escape(writer, argv[0], true);781 shell.escape(writer, argv[0], true) catch return error.OutOfMemory;
791 for (argv[1..]) |arg| {782 for (argv[1..]) |arg| {
792 try writer.writeByte(' ');783 writer.writeByte(' ') catch return error.OutOfMemory;
793 try shell.escape(writer, arg, false);784 shell.escape(writer, arg, false) catch return error.OutOfMemory;
794 }785 }
795 return buf.toOwnedSlice(arena);786 return aw.toOwnedSlice();
796}787}
797788
798/// Prefer `cacheHitAndWatch` unless you already added watch inputs789/// Prefer `cacheHitAndWatch` unless you already added watch inputs
lib/std/Build/Step/Compile.zig+42-4
...@@ -681,10 +681,14 @@ pub fn producesImplib(compile: *Compile) bool {...@@ -681,10 +681,14 @@ pub fn producesImplib(compile: *Compile) bool {
681 return compile.isDll();681 return compile.isDll();
682}682}
683683
684/// Deprecated; use `compile.root_module.link_libc = true` instead.
685/// To be removed after 0.15.0 is tagged.
684pub fn linkLibC(compile: *Compile) void {686pub fn linkLibC(compile: *Compile) void {
685 compile.root_module.link_libc = true;687 compile.root_module.link_libc = true;
686}688}
687689
690/// Deprecated; use `compile.root_module.link_libcpp = true` instead.
691/// To be removed after 0.15.0 is tagged.
688pub fn linkLibCpp(compile: *Compile) void {692pub fn linkLibCpp(compile: *Compile) void {
689 compile.root_module.link_libcpp = true;693 compile.root_module.link_libcpp = true;
690}694}
...@@ -802,10 +806,14 @@ fn runPkgConfig(compile: *Compile, lib_name: []const u8) !PkgConfigResult {...@@ -802,10 +806,14 @@ fn runPkgConfig(compile: *Compile, lib_name: []const u8) !PkgConfigResult {
802 };806 };
803}807}
804808
809/// Deprecated; use `compile.root_module.linkSystemLibrary(name, .{})` instead.
810/// To be removed after 0.15.0 is tagged.
805pub fn linkSystemLibrary(compile: *Compile, name: []const u8) void {811pub fn linkSystemLibrary(compile: *Compile, name: []const u8) void {
806 return compile.root_module.linkSystemLibrary(name, .{});812 return compile.root_module.linkSystemLibrary(name, .{});
807}813}
808814
815/// Deprecated; use `compile.root_module.linkSystemLibrary(name, options)` instead.
816/// To be removed after 0.15.0 is tagged.
809pub fn linkSystemLibrary2(817pub fn linkSystemLibrary2(
810 compile: *Compile,818 compile: *Compile,
811 name: []const u8,819 name: []const u8,
...@@ -814,22 +822,26 @@ pub fn linkSystemLibrary2(...@@ -814,22 +822,26 @@ pub fn linkSystemLibrary2(
814 return compile.root_module.linkSystemLibrary(name, options);822 return compile.root_module.linkSystemLibrary(name, options);
815}823}
816824
825/// Deprecated; use `c.root_module.linkFramework(name, .{})` instead.
826/// To be removed after 0.15.0 is tagged.
817pub fn linkFramework(c: *Compile, name: []const u8) void {827pub fn linkFramework(c: *Compile, name: []const u8) void {
818 c.root_module.linkFramework(name, .{});828 c.root_module.linkFramework(name, .{});
819}829}
820830
821/// Handy when you have many C/C++ source files and want them all to have the same flags.831/// Deprecated; use `compile.root_module.addCSourceFiles(options)` instead.
832/// To be removed after 0.15.0 is tagged.
822pub fn addCSourceFiles(compile: *Compile, options: Module.AddCSourceFilesOptions) void {833pub fn addCSourceFiles(compile: *Compile, options: Module.AddCSourceFilesOptions) void {
823 compile.root_module.addCSourceFiles(options);834 compile.root_module.addCSourceFiles(options);
824}835}
825836
837/// Deprecated; use `compile.root_module.addCSourceFile(source)` instead.
838/// To be removed after 0.15.0 is tagged.
826pub fn addCSourceFile(compile: *Compile, source: Module.CSourceFile) void {839pub fn addCSourceFile(compile: *Compile, source: Module.CSourceFile) void {
827 compile.root_module.addCSourceFile(source);840 compile.root_module.addCSourceFile(source);
828}841}
829842
830/// Resource files must have the extension `.rc`.843/// Deprecated; use `compile.root_module.addWin32ResourceFile(source)` instead.
831/// Can be called regardless of target. The .rc file will be ignored844/// To be removed after 0.15.0 is tagged.
832/// if the target object format does not support embedded resources.
833pub fn addWin32ResourceFile(compile: *Compile, source: Module.RcSourceFile) void {845pub fn addWin32ResourceFile(compile: *Compile, source: Module.RcSourceFile) void {
834 compile.root_module.addWin32ResourceFile(source);846 compile.root_module.addWin32ResourceFile(source);
835}847}
...@@ -915,54 +927,80 @@ pub fn getEmittedLlvmBc(compile: *Compile) LazyPath {...@@ -915,54 +927,80 @@ pub fn getEmittedLlvmBc(compile: *Compile) LazyPath {
915 return compile.getEmittedFileGeneric(&compile.generated_llvm_bc);927 return compile.getEmittedFileGeneric(&compile.generated_llvm_bc);
916}928}
917929
930/// Deprecated; use `compile.root_module.addAssemblyFile(source)` instead.
931/// To be removed after 0.15.0 is tagged.
918pub fn addAssemblyFile(compile: *Compile, source: LazyPath) void {932pub fn addAssemblyFile(compile: *Compile, source: LazyPath) void {
919 compile.root_module.addAssemblyFile(source);933 compile.root_module.addAssemblyFile(source);
920}934}
921935
936/// Deprecated; use `compile.root_module.addObjectFile(source)` instead.
937/// To be removed after 0.15.0 is tagged.
922pub fn addObjectFile(compile: *Compile, source: LazyPath) void {938pub fn addObjectFile(compile: *Compile, source: LazyPath) void {
923 compile.root_module.addObjectFile(source);939 compile.root_module.addObjectFile(source);
924}940}
925941
942/// Deprecated; use `compile.root_module.addObject(object)` instead.
943/// To be removed after 0.15.0 is tagged.
926pub fn addObject(compile: *Compile, object: *Compile) void {944pub fn addObject(compile: *Compile, object: *Compile) void {
927 compile.root_module.addObject(object);945 compile.root_module.addObject(object);
928}946}
929947
948/// Deprecated; use `compile.root_module.linkLibrary(library)` instead.
949/// To be removed after 0.15.0 is tagged.
930pub fn linkLibrary(compile: *Compile, library: *Compile) void {950pub fn linkLibrary(compile: *Compile, library: *Compile) void {
931 compile.root_module.linkLibrary(library);951 compile.root_module.linkLibrary(library);
932}952}
933953
954/// Deprecated; use `compile.root_module.addAfterIncludePath(lazy_path)` instead.
955/// To be removed after 0.15.0 is tagged.
934pub fn addAfterIncludePath(compile: *Compile, lazy_path: LazyPath) void {956pub fn addAfterIncludePath(compile: *Compile, lazy_path: LazyPath) void {
935 compile.root_module.addAfterIncludePath(lazy_path);957 compile.root_module.addAfterIncludePath(lazy_path);
936}958}
937959
960/// Deprecated; use `compile.root_module.addSystemIncludePath(lazy_path)` instead.
961/// To be removed after 0.15.0 is tagged.
938pub fn addSystemIncludePath(compile: *Compile, lazy_path: LazyPath) void {962pub fn addSystemIncludePath(compile: *Compile, lazy_path: LazyPath) void {
939 compile.root_module.addSystemIncludePath(lazy_path);963 compile.root_module.addSystemIncludePath(lazy_path);
940}964}
941965
966/// Deprecated; use `compile.root_module.addIncludePath(lazy_path)` instead.
967/// To be removed after 0.15.0 is tagged.
942pub fn addIncludePath(compile: *Compile, lazy_path: LazyPath) void {968pub fn addIncludePath(compile: *Compile, lazy_path: LazyPath) void {
943 compile.root_module.addIncludePath(lazy_path);969 compile.root_module.addIncludePath(lazy_path);
944}970}
945971
972/// Deprecated; use `compile.root_module.addConfigHeader(config_header)` instead.
973/// To be removed after 0.15.0 is tagged.
946pub fn addConfigHeader(compile: *Compile, config_header: *Step.ConfigHeader) void {974pub fn addConfigHeader(compile: *Compile, config_header: *Step.ConfigHeader) void {
947 compile.root_module.addConfigHeader(config_header);975 compile.root_module.addConfigHeader(config_header);
948}976}
949977
978/// Deprecated; use `compile.root_module.addEmbedPath(lazy_path)` instead.
979/// To be removed after 0.15.0 is tagged.
950pub fn addEmbedPath(compile: *Compile, lazy_path: LazyPath) void {980pub fn addEmbedPath(compile: *Compile, lazy_path: LazyPath) void {
951 compile.root_module.addEmbedPath(lazy_path);981 compile.root_module.addEmbedPath(lazy_path);
952}982}
953983
984/// Deprecated; use `compile.root_module.addLibraryPath(directory_path)` instead.
985/// To be removed after 0.15.0 is tagged.
954pub fn addLibraryPath(compile: *Compile, directory_path: LazyPath) void {986pub fn addLibraryPath(compile: *Compile, directory_path: LazyPath) void {
955 compile.root_module.addLibraryPath(directory_path);987 compile.root_module.addLibraryPath(directory_path);
956}988}
957989
990/// Deprecated; use `compile.root_module.addRPath(directory_path)` instead.
991/// To be removed after 0.15.0 is tagged.
958pub fn addRPath(compile: *Compile, directory_path: LazyPath) void {992pub fn addRPath(compile: *Compile, directory_path: LazyPath) void {
959 compile.root_module.addRPath(directory_path);993 compile.root_module.addRPath(directory_path);
960}994}
961995
996/// Deprecated; use `compile.root_module.addSystemFrameworkPath(directory_path)` instead.
997/// To be removed after 0.15.0 is tagged.
962pub fn addSystemFrameworkPath(compile: *Compile, directory_path: LazyPath) void {998pub fn addSystemFrameworkPath(compile: *Compile, directory_path: LazyPath) void {
963 compile.root_module.addSystemFrameworkPath(directory_path);999 compile.root_module.addSystemFrameworkPath(directory_path);
964}1000}
9651001
1002/// Deprecated; use `compile.root_module.addFrameworkPath(directory_path)` instead.
1003/// To be removed after 0.15.0 is tagged.
966pub fn addFrameworkPath(compile: *Compile, directory_path: LazyPath) void {1004pub fn addFrameworkPath(compile: *Compile, directory_path: LazyPath) void {
967 compile.root_module.addFrameworkPath(directory_path);1005 compile.root_module.addFrameworkPath(directory_path);
968}1006}
lib/std/Build/Step/Run.zig+58-39
...@@ -73,9 +73,12 @@ skip_foreign_checks: bool,...@@ -73,9 +73,12 @@ skip_foreign_checks: bool,
73/// external executor (such as qemu) but not fail if the executor is unavailable.73/// external executor (such as qemu) but not fail if the executor is unavailable.
74failing_to_execute_foreign_is_an_error: bool,74failing_to_execute_foreign_is_an_error: bool,
7575
76/// Deprecated in favor of `stdio_limit`.
77max_stdio_size: usize,
78
76/// If stderr or stdout exceeds this amount, the child process is killed and79/// If stderr or stdout exceeds this amount, the child process is killed and
77/// the step fails.80/// the step fails.
78max_stdio_size: usize,81stdio_limit: std.Io.Limit,
7982
80captured_stdout: ?*Output,83captured_stdout: ?*Output,
81captured_stderr: ?*Output,84captured_stderr: ?*Output,
...@@ -169,7 +172,7 @@ pub const Output = struct {...@@ -169,7 +172,7 @@ pub const Output = struct {
169pub fn create(owner: *std.Build, name: []const u8) *Run {172pub fn create(owner: *std.Build, name: []const u8) *Run {
170 const run = owner.allocator.create(Run) catch @panic("OOM");173 const run = owner.allocator.create(Run) catch @panic("OOM");
171 run.* = .{174 run.* = .{
172 .step = Step.init(.{175 .step = .init(.{
173 .id = base_id,176 .id = base_id,
174 .name = name,177 .name = name,
175 .owner = owner,178 .owner = owner,
...@@ -186,6 +189,7 @@ pub fn create(owner: *std.Build, name: []const u8) *Run {...@@ -186,6 +189,7 @@ pub fn create(owner: *std.Build, name: []const u8) *Run {
186 .skip_foreign_checks = false,189 .skip_foreign_checks = false,
187 .failing_to_execute_foreign_is_an_error = true,190 .failing_to_execute_foreign_is_an_error = true,
188 .max_stdio_size = 10 * 1024 * 1024,191 .max_stdio_size = 10 * 1024 * 1024,
192 .stdio_limit = .unlimited,
189 .captured_stdout = null,193 .captured_stdout = null,
190 .captured_stderr = null,194 .captured_stderr = null,
191 .dep_output_file = null,195 .dep_output_file = null,
...@@ -1011,7 +1015,7 @@ fn populateGeneratedPaths(...@@ -1011,7 +1015,7 @@ fn populateGeneratedPaths(
1011 }1015 }
1012}1016}
10131017
1014fn formatTerm(term: ?std.process.Child.Term, w: *std.io.Writer) std.io.Writer.Error!void {1018fn formatTerm(term: ?std.process.Child.Term, w: *std.Io.Writer) std.Io.Writer.Error!void {
1015 if (term) |t| switch (t) {1019 if (term) |t| switch (t) {
1016 .Exited => |code| try w.print("exited with code {d}", .{code}),1020 .Exited => |code| try w.print("exited with code {d}", .{code}),
1017 .Signal => |sig| try w.print("terminated with signal {d}", .{sig}),1021 .Signal => |sig| try w.print("terminated with signal {d}", .{sig}),
...@@ -1500,7 +1504,7 @@ fn evalZigTest(...@@ -1500,7 +1504,7 @@ fn evalZigTest(
1500 const gpa = run.step.owner.allocator;1504 const gpa = run.step.owner.allocator;
1501 const arena = run.step.owner.allocator;1505 const arena = run.step.owner.allocator;
15021506
1503 var poller = std.io.poll(gpa, enum { stdout, stderr }, .{1507 var poller = std.Io.poll(gpa, enum { stdout, stderr }, .{
1504 .stdout = child.stdout.?,1508 .stdout = child.stdout.?,
1505 .stderr = child.stderr.?,1509 .stderr = child.stderr.?,
1506 });1510 });
...@@ -1524,11 +1528,6 @@ fn evalZigTest(...@@ -1524,11 +1528,6 @@ fn evalZigTest(
1524 break :failed false;1528 break :failed false;
1525 };1529 };
15261530
1527 const Header = std.zig.Server.Message.Header;
1528
1529 const stdout = poller.fifo(.stdout);
1530 const stderr = poller.fifo(.stderr);
1531
1532 var fail_count: u32 = 0;1531 var fail_count: u32 = 0;
1533 var skip_count: u32 = 0;1532 var skip_count: u32 = 0;
1534 var leak_count: u32 = 0;1533 var leak_count: u32 = 0;
...@@ -1541,16 +1540,14 @@ fn evalZigTest(...@@ -1541,16 +1540,14 @@ fn evalZigTest(
1541 var sub_prog_node: ?std.Progress.Node = null;1540 var sub_prog_node: ?std.Progress.Node = null;
1542 defer if (sub_prog_node) |n| n.end();1541 defer if (sub_prog_node) |n| n.end();
15431542
1543 const stdout = poller.reader(.stdout);
1544 const stderr = poller.reader(.stderr);
1544 const any_write_failed = first_write_failed or poll: while (true) {1545 const any_write_failed = first_write_failed or poll: while (true) {
1545 while (stdout.readableLength() < @sizeOf(Header)) {1546 const Header = std.zig.Server.Message.Header;
1546 if (!(try poller.poll())) break :poll false;1547 while (stdout.buffered().len < @sizeOf(Header)) if (!try poller.poll()) break :poll false;
1547 }1548 const header = stdout.takeStruct(Header, .little) catch unreachable;
1548 const header = stdout.reader().readStruct(Header) catch unreachable;1549 while (stdout.buffered().len < header.bytes_len) if (!try poller.poll()) break :poll false;
1549 while (stdout.readableLength() < header.bytes_len) {1550 const body = stdout.take(header.bytes_len) catch unreachable;
1550 if (!(try poller.poll())) break :poll false;
1551 }
1552 const body = stdout.readableSliceOfLen(header.bytes_len);
1553
1554 switch (header.tag) {1551 switch (header.tag) {
1555 .zig_version => {1552 .zig_version => {
1556 if (!std.mem.eql(u8, builtin.zig_version_string, body)) {1553 if (!std.mem.eql(u8, builtin.zig_version_string, body)) {
...@@ -1607,9 +1604,9 @@ fn evalZigTest(...@@ -1607,9 +1604,9 @@ fn evalZigTest(
16071604
1608 if (tr_hdr.flags.fail or tr_hdr.flags.leak or tr_hdr.flags.log_err_count > 0) {1605 if (tr_hdr.flags.fail or tr_hdr.flags.leak or tr_hdr.flags.log_err_count > 0) {
1609 const name = std.mem.sliceTo(md.string_bytes[md.names[tr_hdr.index]..], 0);1606 const name = std.mem.sliceTo(md.string_bytes[md.names[tr_hdr.index]..], 0);
1610 const orig_msg = stderr.readableSlice(0);1607 const stderr_contents = stderr.buffered();
1611 defer stderr.discard(orig_msg.len);1608 stderr.toss(stderr_contents.len);
1612 const msg = std.mem.trim(u8, orig_msg, "\n");1609 const msg = std.mem.trim(u8, stderr_contents, "\n");
1613 const label = if (tr_hdr.flags.fail)1610 const label = if (tr_hdr.flags.fail)
1614 "failed"1611 "failed"
1615 else if (tr_hdr.flags.leak)1612 else if (tr_hdr.flags.leak)
...@@ -1660,8 +1657,6 @@ fn evalZigTest(...@@ -1660,8 +1657,6 @@ fn evalZigTest(
1660 },1657 },
1661 else => {}, // ignore other messages1658 else => {}, // ignore other messages
1662 }1659 }
1663
1664 stdout.discard(body.len);
1665 };1660 };
16661661
1667 if (any_write_failed) {1662 if (any_write_failed) {
...@@ -1670,9 +1665,9 @@ fn evalZigTest(...@@ -1670,9 +1665,9 @@ fn evalZigTest(
1670 while (try poller.poll()) {}1665 while (try poller.poll()) {}
1671 }1666 }
16721667
1673 if (stderr.readableLength() > 0) {1668 const stderr_contents = std.mem.trim(u8, stderr.buffered(), "\n");
1674 const msg = std.mem.trim(u8, try stderr.toOwnedSlice(), "\n");1669 if (stderr_contents.len > 0) {
1675 if (msg.len > 0) run.step.result_stderr = msg;1670 run.step.result_stderr = try arena.dupe(u8, stderr_contents);
1676 }1671 }
16771672
1678 // Send EOF to stdin.1673 // Send EOF to stdin.
...@@ -1769,13 +1764,22 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !StdIoResult {...@@ -1769,13 +1764,22 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !StdIoResult {
1769 child.stdin = null;1764 child.stdin = null;
1770 },1765 },
1771 .lazy_path => |lazy_path| {1766 .lazy_path => |lazy_path| {
1772 const path = lazy_path.getPath2(b, &run.step);1767 const path = lazy_path.getPath3(b, &run.step);
1773 const file = b.build_root.handle.openFile(path, .{}) catch |err| {1768 const file = path.root_dir.handle.openFile(path.subPathOrDot(), .{}) catch |err| {
1774 return run.step.fail("unable to open stdin file: {s}", .{@errorName(err)});1769 return run.step.fail("unable to open stdin file: {s}", .{@errorName(err)});
1775 };1770 };
1776 defer file.close();1771 defer file.close();
1777 child.stdin.?.writeFileAll(file, .{}) catch |err| {1772 // TODO https://github.com/ziglang/zig/issues/23955
1778 return run.step.fail("unable to write file to stdin: {s}", .{@errorName(err)});1773 var buffer: [1024]u8 = undefined;
1774 var file_reader = file.reader(&buffer);
1775 var stdin_writer = child.stdin.?.writer(&.{});
1776 _ = stdin_writer.interface.sendFileAll(&file_reader, .unlimited) catch |err| switch (err) {
1777 error.ReadFailed => return run.step.fail("failed to read from {f}: {t}", .{
1778 path, file_reader.err.?,
1779 }),
1780 error.WriteFailed => return run.step.fail("failed to write to stdin: {t}", .{
1781 stdin_writer.err.?,
1782 }),
1779 };1783 };
1780 child.stdin.?.close();1784 child.stdin.?.close();
1781 child.stdin = null;1785 child.stdin = null;
...@@ -1786,28 +1790,43 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !StdIoResult {...@@ -1786,28 +1790,43 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !StdIoResult {
1786 var stdout_bytes: ?[]const u8 = null;1790 var stdout_bytes: ?[]const u8 = null;
1787 var stderr_bytes: ?[]const u8 = null;1791 var stderr_bytes: ?[]const u8 = null;
17881792
1793 run.stdio_limit = run.stdio_limit.min(.limited(run.max_stdio_size));
1789 if (child.stdout) |stdout| {1794 if (child.stdout) |stdout| {
1790 if (child.stderr) |stderr| {1795 if (child.stderr) |stderr| {
1791 var poller = std.io.poll(arena, enum { stdout, stderr }, .{1796 var poller = std.Io.poll(arena, enum { stdout, stderr }, .{
1792 .stdout = stdout,1797 .stdout = stdout,
1793 .stderr = stderr,1798 .stderr = stderr,
1794 });1799 });
1795 defer poller.deinit();1800 defer poller.deinit();
17961801
1797 while (try poller.poll()) {1802 while (try poller.poll()) {
1798 if (poller.fifo(.stdout).count > run.max_stdio_size)1803 if (run.stdio_limit.toInt()) |limit| {
1799 return error.StdoutStreamTooLong;1804 if (poller.reader(.stderr).buffered().len > limit)
1800 if (poller.fifo(.stderr).count > run.max_stdio_size)1805 return error.StdoutStreamTooLong;
1801 return error.StderrStreamTooLong;1806 if (poller.reader(.stderr).buffered().len > limit)
1807 return error.StderrStreamTooLong;
1808 }
1802 }1809 }
18031810
1804 stdout_bytes = try poller.fifo(.stdout).toOwnedSlice();1811 stdout_bytes = try poller.toOwnedSlice(.stdout);
1805 stderr_bytes = try poller.fifo(.stderr).toOwnedSlice();1812 stderr_bytes = try poller.toOwnedSlice(.stderr);
1806 } else {1813 } else {
1807 stdout_bytes = try stdout.deprecatedReader().readAllAlloc(arena, run.max_stdio_size);1814 var small_buffer: [1]u8 = undefined;
1815 var stdout_reader = stdout.readerStreaming(&small_buffer);
1816 stdout_bytes = stdout_reader.interface.allocRemaining(arena, run.stdio_limit) catch |err| switch (err) {
1817 error.OutOfMemory => return error.OutOfMemory,
1818 error.ReadFailed => return stdout_reader.err.?,
1819 error.StreamTooLong => return error.StdoutStreamTooLong,
1820 };
1808 }1821 }
1809 } else if (child.stderr) |stderr| {1822 } else if (child.stderr) |stderr| {
1810 stderr_bytes = try stderr.deprecatedReader().readAllAlloc(arena, run.max_stdio_size);1823 var small_buffer: [1]u8 = undefined;
1824 var stderr_reader = stderr.readerStreaming(&small_buffer);
1825 stderr_bytes = stderr_reader.interface.allocRemaining(arena, run.stdio_limit) catch |err| switch (err) {
1826 error.OutOfMemory => return error.OutOfMemory,
1827 error.ReadFailed => return stderr_reader.err.?,
1828 error.StreamTooLong => return error.StderrStreamTooLong,
1829 };
1811 }1830 }
18121831
1813 if (stderr_bytes) |bytes| if (bytes.len > 0) {1832 if (stderr_bytes) |bytes| if (bytes.len > 0) {
lib/std/Io.zig+264-215
...@@ -1,16 +1,11 @@...@@ -1,16 +1,11 @@
1const std = @import("std.zig");
2const builtin = @import("builtin");1const builtin = @import("builtin");
3const root = @import("root");
4const c = std.c;
5const is_windows = builtin.os.tag == .windows;2const is_windows = builtin.os.tag == .windows;
3
4const std = @import("std.zig");
6const windows = std.os.windows;5const windows = std.os.windows;
7const posix = std.posix;6const posix = std.posix;
8const math = std.math;7const math = std.math;
9const assert = std.debug.assert;8const assert = std.debug.assert;
10const fs = std.fs;
11const mem = std.mem;
12const meta = std.meta;
13const File = std.fs.File;
14const Allocator = std.mem.Allocator;9const Allocator = std.mem.Allocator;
15const Alignment = std.mem.Alignment;10const Alignment = std.mem.Alignment;
1611
...@@ -314,11 +309,11 @@ pub fn GenericReader(...@@ -314,11 +309,11 @@ pub fn GenericReader(
314 }309 }
315310
316 /// Helper for bridging to the new `Reader` API while upgrading.311 /// Helper for bridging to the new `Reader` API while upgrading.
317 pub fn adaptToNewApi(self: *const Self) Adapter {312 pub fn adaptToNewApi(self: *const Self, buffer: []u8) Adapter {
318 return .{313 return .{
319 .derp_reader = self.*,314 .derp_reader = self.*,
320 .new_interface = .{315 .new_interface = .{
321 .buffer = &.{},316 .buffer = buffer,
322 .vtable = &.{ .stream = Adapter.stream },317 .vtable = &.{ .stream = Adapter.stream },
323 .seek = 0,318 .seek = 0,
324 .end = 0,319 .end = 0,
...@@ -334,10 +329,12 @@ pub fn GenericReader(...@@ -334,10 +329,12 @@ pub fn GenericReader(
334 fn stream(r: *Reader, w: *Writer, limit: Limit) Reader.StreamError!usize {329 fn stream(r: *Reader, w: *Writer, limit: Limit) Reader.StreamError!usize {
335 const a: *@This() = @alignCast(@fieldParentPtr("new_interface", r));330 const a: *@This() = @alignCast(@fieldParentPtr("new_interface", r));
336 const buf = limit.slice(try w.writableSliceGreedy(1));331 const buf = limit.slice(try w.writableSliceGreedy(1));
337 return a.derp_reader.read(buf) catch |err| {332 const n = a.derp_reader.read(buf) catch |err| {
338 a.err = err;333 a.err = err;
339 return error.ReadFailed;334 return error.ReadFailed;
340 };335 };
336 w.advance(n);
337 return n;
341 }338 }
342 };339 };
343 };340 };
...@@ -419,9 +416,14 @@ pub fn GenericWriter(...@@ -419,9 +416,14 @@ pub fn GenericWriter(
419 new_interface: Writer,416 new_interface: Writer,
420 err: ?Error = null,417 err: ?Error = null,
421418
422 fn drain(w: *Writer, data: []const []const u8, splat: usize) Writer.Error!usize {419 fn drain(w: *std.io.Writer, data: []const []const u8, splat: usize) std.io.Writer.Error!usize {
423 _ = splat;420 _ = splat;
424 const a: *@This() = @alignCast(@fieldParentPtr("new_interface", w));421 const a: *@This() = @alignCast(@fieldParentPtr("new_interface", w));
422 const buffered = w.buffered();
423 if (buffered.len != 0) return w.consume(a.derp_writer.write(buffered) catch |err| {
424 a.err = err;
425 return error.WriteFailed;
426 });
425 return a.derp_writer.write(data[0]) catch |err| {427 return a.derp_writer.write(data[0]) catch |err| {
426 a.err = err;428 a.err = err;
427 return error.WriteFailed;429 return error.WriteFailed;
...@@ -435,54 +437,46 @@ pub fn GenericWriter(...@@ -435,54 +437,46 @@ pub fn GenericWriter(
435pub const AnyReader = @import("Io/DeprecatedReader.zig");437pub const AnyReader = @import("Io/DeprecatedReader.zig");
436/// Deprecated in favor of `Writer`.438/// Deprecated in favor of `Writer`.
437pub const AnyWriter = @import("Io/DeprecatedWriter.zig");439pub const AnyWriter = @import("Io/DeprecatedWriter.zig");
438440/// Deprecated in favor of `File.Reader` and `File.Writer`.
439pub const SeekableStream = @import("Io/seekable_stream.zig").SeekableStream;441pub const SeekableStream = @import("Io/seekable_stream.zig").SeekableStream;
440442/// Deprecated in favor of `Writer`.
441pub const BufferedWriter = @import("Io/buffered_writer.zig").BufferedWriter;443pub const BufferedWriter = @import("Io/buffered_writer.zig").BufferedWriter;
444/// Deprecated in favor of `Writer`.
442pub const bufferedWriter = @import("Io/buffered_writer.zig").bufferedWriter;445pub const bufferedWriter = @import("Io/buffered_writer.zig").bufferedWriter;
443446/// Deprecated in favor of `Reader`.
444pub const BufferedReader = @import("Io/buffered_reader.zig").BufferedReader;447pub const BufferedReader = @import("Io/buffered_reader.zig").BufferedReader;
448/// Deprecated in favor of `Reader`.
445pub const bufferedReader = @import("Io/buffered_reader.zig").bufferedReader;449pub const bufferedReader = @import("Io/buffered_reader.zig").bufferedReader;
450/// Deprecated in favor of `Reader`.
446pub const bufferedReaderSize = @import("Io/buffered_reader.zig").bufferedReaderSize;451pub const bufferedReaderSize = @import("Io/buffered_reader.zig").bufferedReaderSize;
447452/// Deprecated in favor of `Reader`.
448pub const FixedBufferStream = @import("Io/fixed_buffer_stream.zig").FixedBufferStream;453pub const FixedBufferStream = @import("Io/fixed_buffer_stream.zig").FixedBufferStream;
454/// Deprecated in favor of `Reader`.
449pub const fixedBufferStream = @import("Io/fixed_buffer_stream.zig").fixedBufferStream;455pub const fixedBufferStream = @import("Io/fixed_buffer_stream.zig").fixedBufferStream;
450456/// Deprecated in favor of `Reader.Limited`.
451pub const CWriter = @import("Io/c_writer.zig").CWriter;
452pub const cWriter = @import("Io/c_writer.zig").cWriter;
453
454pub const LimitedReader = @import("Io/limited_reader.zig").LimitedReader;457pub const LimitedReader = @import("Io/limited_reader.zig").LimitedReader;
458/// Deprecated in favor of `Reader.Limited`.
455pub const limitedReader = @import("Io/limited_reader.zig").limitedReader;459pub const limitedReader = @import("Io/limited_reader.zig").limitedReader;
456460/// Deprecated with no replacement; inefficient pattern
457pub const CountingWriter = @import("Io/counting_writer.zig").CountingWriter;461pub const CountingWriter = @import("Io/counting_writer.zig").CountingWriter;
462/// Deprecated with no replacement; inefficient pattern
458pub const countingWriter = @import("Io/counting_writer.zig").countingWriter;463pub const countingWriter = @import("Io/counting_writer.zig").countingWriter;
464/// Deprecated with no replacement; inefficient pattern
459pub const CountingReader = @import("Io/counting_reader.zig").CountingReader;465pub const CountingReader = @import("Io/counting_reader.zig").CountingReader;
466/// Deprecated with no replacement; inefficient pattern
460pub const countingReader = @import("Io/counting_reader.zig").countingReader;467pub const countingReader = @import("Io/counting_reader.zig").countingReader;
461468
462pub const MultiWriter = @import("Io/multi_writer.zig").MultiWriter;
463pub const multiWriter = @import("Io/multi_writer.zig").multiWriter;
464
465pub const BitReader = @import("Io/bit_reader.zig").BitReader;469pub const BitReader = @import("Io/bit_reader.zig").BitReader;
466pub const bitReader = @import("Io/bit_reader.zig").bitReader;470pub const bitReader = @import("Io/bit_reader.zig").bitReader;
467471
468pub const BitWriter = @import("Io/bit_writer.zig").BitWriter;472pub const BitWriter = @import("Io/bit_writer.zig").BitWriter;
469pub const bitWriter = @import("Io/bit_writer.zig").bitWriter;473pub const bitWriter = @import("Io/bit_writer.zig").bitWriter;
470474
471pub const ChangeDetectionStream = @import("Io/change_detection_stream.zig").ChangeDetectionStream;
472pub const changeDetectionStream = @import("Io/change_detection_stream.zig").changeDetectionStream;
473
474pub const FindByteWriter = @import("Io/find_byte_writer.zig").FindByteWriter;
475pub const findByteWriter = @import("Io/find_byte_writer.zig").findByteWriter;
476
477pub const BufferedAtomicFile = @import("Io/buffered_atomic_file.zig").BufferedAtomicFile;
478
479pub const StreamSource = @import("Io/stream_source.zig").StreamSource;
480
481pub const tty = @import("Io/tty.zig");475pub const tty = @import("Io/tty.zig");
482476
483/// A Writer that doesn't write to anything.477/// Deprecated in favor of `Writer.Discarding`.
484pub const null_writer: NullWriter = .{ .context = {} };478pub const null_writer: NullWriter = .{ .context = {} };
485479/// Deprecated in favor of `Writer.Discarding`.
486pub const NullWriter = GenericWriter(void, error{}, dummyWrite);480pub const NullWriter = GenericWriter(void, error{}, dummyWrite);
487fn dummyWrite(context: void, data: []const u8) error{}!usize {481fn dummyWrite(context: void, data: []const u8) error{}!usize {
488 _ = context;482 _ = context;
...@@ -494,54 +488,51 @@ test null_writer {...@@ -494,54 +488,51 @@ test null_writer {
494}488}
495489
496pub fn poll(490pub fn poll(
497 allocator: Allocator,491 gpa: Allocator,
498 comptime StreamEnum: type,492 comptime StreamEnum: type,
499 files: PollFiles(StreamEnum),493 files: PollFiles(StreamEnum),
500) Poller(StreamEnum) {494) Poller(StreamEnum) {
501 const enum_fields = @typeInfo(StreamEnum).@"enum".fields;495 const enum_fields = @typeInfo(StreamEnum).@"enum".fields;
502 var result: Poller(StreamEnum) = undefined;496 var result: Poller(StreamEnum) = .{
503497 .gpa = gpa,
504 if (is_windows) result.windows = .{498 .readers = @splat(.failing),
505 .first_read_done = false,499 .poll_fds = undefined,
506 .overlapped = [1]windows.OVERLAPPED{500 .windows = if (is_windows) .{
507 mem.zeroes(windows.OVERLAPPED),501 .first_read_done = false,
508 } ** enum_fields.len,502 .overlapped = [1]windows.OVERLAPPED{
509 .small_bufs = undefined,503 std.mem.zeroes(windows.OVERLAPPED),
510 .active = .{504 } ** enum_fields.len,
511 .count = 0,505 .small_bufs = undefined,
512 .handles_buf = undefined,506 .active = .{
513 .stream_map = undefined,507 .count = 0,
514 },508 .handles_buf = undefined,
509 .stream_map = undefined,
510 },
511 } else {},
515 };512 };
516513
517 inline for (0..enum_fields.len) |i| {514 inline for (enum_fields, 0..) |field, i| {
518 result.fifos[i] = .{
519 .allocator = allocator,
520 .buf = &.{},
521 .head = 0,
522 .count = 0,
523 };
524 if (is_windows) {515 if (is_windows) {
525 result.windows.active.handles_buf[i] = @field(files, enum_fields[i].name).handle;516 result.windows.active.handles_buf[i] = @field(files, field.name).handle;
526 } else {517 } else {
527 result.poll_fds[i] = .{518 result.poll_fds[i] = .{
528 .fd = @field(files, enum_fields[i].name).handle,519 .fd = @field(files, field.name).handle,
529 .events = posix.POLL.IN,520 .events = posix.POLL.IN,
530 .revents = undefined,521 .revents = undefined,
531 };522 };
532 }523 }
533 }524 }
525
534 return result;526 return result;
535}527}
536528
537pub const PollFifo = std.fifo.LinearFifo(u8, .Dynamic);
538
539pub fn Poller(comptime StreamEnum: type) type {529pub fn Poller(comptime StreamEnum: type) type {
540 return struct {530 return struct {
541 const enum_fields = @typeInfo(StreamEnum).@"enum".fields;531 const enum_fields = @typeInfo(StreamEnum).@"enum".fields;
542 const PollFd = if (is_windows) void else posix.pollfd;532 const PollFd = if (is_windows) void else posix.pollfd;
543533
544 fifos: [enum_fields.len]PollFifo,534 gpa: Allocator,
535 readers: [enum_fields.len]Reader,
545 poll_fds: [enum_fields.len]PollFd,536 poll_fds: [enum_fields.len]PollFd,
546 windows: if (is_windows) struct {537 windows: if (is_windows) struct {
547 first_read_done: bool,538 first_read_done: bool,
...@@ -553,7 +544,7 @@ pub fn Poller(comptime StreamEnum: type) type {...@@ -553,7 +544,7 @@ pub fn Poller(comptime StreamEnum: type) type {
553 stream_map: [enum_fields.len]StreamEnum,544 stream_map: [enum_fields.len]StreamEnum,
554545
555 pub fn removeAt(self: *@This(), index: u32) void {546 pub fn removeAt(self: *@This(), index: u32) void {
556 std.debug.assert(index < self.count);547 assert(index < self.count);
557 for (index + 1..self.count) |i| {548 for (index + 1..self.count) |i| {
558 self.handles_buf[i - 1] = self.handles_buf[i];549 self.handles_buf[i - 1] = self.handles_buf[i];
559 self.stream_map[i - 1] = self.stream_map[i];550 self.stream_map[i - 1] = self.stream_map[i];
...@@ -566,13 +557,14 @@ pub fn Poller(comptime StreamEnum: type) type {...@@ -566,13 +557,14 @@ pub fn Poller(comptime StreamEnum: type) type {
566 const Self = @This();557 const Self = @This();
567558
568 pub fn deinit(self: *Self) void {559 pub fn deinit(self: *Self) void {
560 const gpa = self.gpa;
569 if (is_windows) {561 if (is_windows) {
570 // cancel any pending IO to prevent clobbering OVERLAPPED value562 // cancel any pending IO to prevent clobbering OVERLAPPED value
571 for (self.windows.active.handles_buf[0..self.windows.active.count]) |h| {563 for (self.windows.active.handles_buf[0..self.windows.active.count]) |h| {
572 _ = windows.kernel32.CancelIo(h);564 _ = windows.kernel32.CancelIo(h);
573 }565 }
574 }566 }
575 inline for (&self.fifos) |*q| q.deinit();567 inline for (&self.readers) |*r| gpa.free(r.buffer);
576 self.* = undefined;568 self.* = undefined;
577 }569 }
578570
...@@ -592,21 +584,40 @@ pub fn Poller(comptime StreamEnum: type) type {...@@ -592,21 +584,40 @@ pub fn Poller(comptime StreamEnum: type) type {
592 }584 }
593 }585 }
594586
595 pub inline fn fifo(self: *Self, comptime which: StreamEnum) *PollFifo {587 pub fn reader(self: *Self, which: StreamEnum) *Reader {
596 return &self.fifos[@intFromEnum(which)];588 return &self.readers[@intFromEnum(which)];
589 }
590
591 pub fn toOwnedSlice(self: *Self, which: StreamEnum) error{OutOfMemory}![]u8 {
592 const gpa = self.gpa;
593 const r = reader(self, which);
594 if (r.seek == 0) {
595 const new = try gpa.realloc(r.buffer, r.end);
596 r.buffer = &.{};
597 r.end = 0;
598 return new;
599 }
600 const new = try gpa.dupe(u8, r.buffered());
601 gpa.free(r.buffer);
602 r.buffer = &.{};
603 r.seek = 0;
604 r.end = 0;
605 return new;
597 }606 }
598607
599 fn pollWindows(self: *Self, nanoseconds: ?u64) !bool {608 fn pollWindows(self: *Self, nanoseconds: ?u64) !bool {
600 const bump_amt = 512;609 const bump_amt = 512;
610 const gpa = self.gpa;
601611
602 if (!self.windows.first_read_done) {612 if (!self.windows.first_read_done) {
603 var already_read_data = false;613 var already_read_data = false;
604 for (0..enum_fields.len) |i| {614 for (0..enum_fields.len) |i| {
605 const handle = self.windows.active.handles_buf[i];615 const handle = self.windows.active.handles_buf[i];
606 switch (try windowsAsyncReadToFifoAndQueueSmallRead(616 switch (try windowsAsyncReadToFifoAndQueueSmallRead(
617 gpa,
607 handle,618 handle,
608 &self.windows.overlapped[i],619 &self.windows.overlapped[i],
609 &self.fifos[i],620 &self.readers[i],
610 &self.windows.small_bufs[i],621 &self.windows.small_bufs[i],
611 bump_amt,622 bump_amt,
612 )) {623 )) {
...@@ -653,7 +664,7 @@ pub fn Poller(comptime StreamEnum: type) type {...@@ -653,7 +664,7 @@ pub fn Poller(comptime StreamEnum: type) type {
653 const handle = self.windows.active.handles_buf[active_idx];664 const handle = self.windows.active.handles_buf[active_idx];
654665
655 const overlapped = &self.windows.overlapped[stream_idx];666 const overlapped = &self.windows.overlapped[stream_idx];
656 const stream_fifo = &self.fifos[stream_idx];667 const stream_reader = &self.readers[stream_idx];
657 const small_buf = &self.windows.small_bufs[stream_idx];668 const small_buf = &self.windows.small_bufs[stream_idx];
658669
659 const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, false)) {670 const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, false)) {
...@@ -664,12 +675,16 @@ pub fn Poller(comptime StreamEnum: type) type {...@@ -664,12 +675,16 @@ pub fn Poller(comptime StreamEnum: type) type {
664 },675 },
665 .aborted => unreachable,676 .aborted => unreachable,
666 };677 };
667 try stream_fifo.write(small_buf[0..num_bytes_read]);678 const buf = small_buf[0..num_bytes_read];
679 const dest = try writableSliceGreedyAlloc(stream_reader, gpa, buf.len);
680 @memcpy(dest[0..buf.len], buf);
681 advanceBufferEnd(stream_reader, buf.len);
668682
669 switch (try windowsAsyncReadToFifoAndQueueSmallRead(683 switch (try windowsAsyncReadToFifoAndQueueSmallRead(
684 gpa,
670 handle,685 handle,
671 overlapped,686 overlapped,
672 stream_fifo,687 stream_reader,
673 small_buf,688 small_buf,
674 bump_amt,689 bump_amt,
675 )) {690 )) {
...@@ -684,6 +699,7 @@ pub fn Poller(comptime StreamEnum: type) type {...@@ -684,6 +699,7 @@ pub fn Poller(comptime StreamEnum: type) type {
684 }699 }
685700
686 fn pollPosix(self: *Self, nanoseconds: ?u64) !bool {701 fn pollPosix(self: *Self, nanoseconds: ?u64) !bool {
702 const gpa = self.gpa;
687 // We ask for ensureUnusedCapacity with this much extra space. This703 // We ask for ensureUnusedCapacity with this much extra space. This
688 // has more of an effect on small reads because once the reads704 // has more of an effect on small reads because once the reads
689 // start to get larger the amount of space an ArrayList will705 // start to get larger the amount of space an ArrayList will
...@@ -703,18 +719,18 @@ pub fn Poller(comptime StreamEnum: type) type {...@@ -703,18 +719,18 @@ pub fn Poller(comptime StreamEnum: type) type {
703 }719 }
704720
705 var keep_polling = false;721 var keep_polling = false;
706 inline for (&self.poll_fds, &self.fifos) |*poll_fd, *q| {722 for (&self.poll_fds, &self.readers) |*poll_fd, *r| {
707 // Try reading whatever is available before checking the error723 // Try reading whatever is available before checking the error
708 // conditions.724 // conditions.
709 // It's still possible to read after a POLL.HUP is received,725 // It's still possible to read after a POLL.HUP is received,
710 // always check if there's some data waiting to be read first.726 // always check if there's some data waiting to be read first.
711 if (poll_fd.revents & posix.POLL.IN != 0) {727 if (poll_fd.revents & posix.POLL.IN != 0) {
712 const buf = try q.writableWithSize(bump_amt);728 const buf = try writableSliceGreedyAlloc(r, gpa, bump_amt);
713 const amt = posix.read(poll_fd.fd, buf) catch |err| switch (err) {729 const amt = posix.read(poll_fd.fd, buf) catch |err| switch (err) {
714 error.BrokenPipe => 0, // Handle the same as EOF.730 error.BrokenPipe => 0, // Handle the same as EOF.
715 else => |e| return e,731 else => |e| return e,
716 };732 };
717 q.update(amt);733 advanceBufferEnd(r, amt);
718 if (amt == 0) {734 if (amt == 0) {
719 // Remove the fd when the EOF condition is met.735 // Remove the fd when the EOF condition is met.
720 poll_fd.fd = -1;736 poll_fd.fd = -1;
...@@ -730,146 +746,181 @@ pub fn Poller(comptime StreamEnum: type) type {...@@ -730,146 +746,181 @@ pub fn Poller(comptime StreamEnum: type) type {
730 }746 }
731 return keep_polling;747 return keep_polling;
732 }748 }
733 };
734}
735749
736/// The `ReadFile` docuementation states that `lpNumberOfBytesRead` does not have a meaningful750 /// Returns a slice into the unused capacity of `buffer` with at least
737/// result when using overlapped I/O, but also that it cannot be `null` on Windows 7. For751 /// `min_len` bytes, extending `buffer` by resizing it with `gpa` as necessary.
738/// compatibility, we point it to this dummy variables, which we never otherwise access.752 ///
739/// See: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile753 /// After calling this function, typically the caller will follow up with a
740var win_dummy_bytes_read: u32 = undefined;754 /// call to `advanceBufferEnd` to report the actual number of bytes buffered.
741755 fn writableSliceGreedyAlloc(r: *Reader, allocator: Allocator, min_len: usize) Allocator.Error![]u8 {
742/// Read as much data as possible from `handle` with `overlapped`, and write it to the FIFO. Before756 {
743/// returning, queue a read into `small_buf` so that `WaitForMultipleObjects` returns when more data757 const unused = r.buffer[r.end..];
744/// is available. `handle` must have no pending asynchronous operation.758 if (unused.len >= min_len) return unused;
745fn windowsAsyncReadToFifoAndQueueSmallRead(759 }
746 handle: windows.HANDLE,760 if (r.seek > 0) r.rebase(r.buffer.len) catch unreachable;
747 overlapped: *windows.OVERLAPPED,761 {
748 fifo: *PollFifo,762 var list: std.ArrayListUnmanaged(u8) = .{
749 small_buf: *[128]u8,763 .items = r.buffer[0..r.end],
750 bump_amt: usize,764 .capacity = r.buffer.len,
751) !enum { empty, populated, closed_populated, closed } {765 };
752 var read_any_data = false;766 defer r.buffer = list.allocatedSlice();
753 while (true) {767 try list.ensureUnusedCapacity(allocator, min_len);
754 const fifo_read_pending = while (true) {768 }
755 const buf = try fifo.writableWithSize(bump_amt);769 const unused = r.buffer[r.end..];
756 const buf_len = math.cast(u32, buf.len) orelse math.maxInt(u32);770 assert(unused.len >= min_len);
757771 return unused;
758 if (0 == windows.kernel32.ReadFile(772 }
759 handle,773
760 buf.ptr,774 /// After writing directly into the unused capacity of `buffer`, this function
761 buf_len,775 /// updates `end` so that users of `Reader` can receive the data.
762 &win_dummy_bytes_read,776 fn advanceBufferEnd(r: *Reader, n: usize) void {
763 overlapped,777 assert(n <= r.buffer.len - r.end);
764 )) switch (windows.GetLastError()) {778 r.end += n;
765 .IO_PENDING => break true,779 }
766 .BROKEN_PIPE => return if (read_any_data) .closed_populated else .closed,780
767 else => |err| return windows.unexpectedError(err),781 /// The `ReadFile` docuementation states that `lpNumberOfBytesRead` does not have a meaningful
768 };782 /// result when using overlapped I/O, but also that it cannot be `null` on Windows 7. For
783 /// compatibility, we point it to this dummy variables, which we never otherwise access.
784 /// See: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile
785 var win_dummy_bytes_read: u32 = undefined;
786
787 /// Read as much data as possible from `handle` with `overlapped`, and write it to the FIFO. Before
788 /// returning, queue a read into `small_buf` so that `WaitForMultipleObjects` returns when more data
789 /// is available. `handle` must have no pending asynchronous operation.
790 fn windowsAsyncReadToFifoAndQueueSmallRead(
791 gpa: Allocator,
792 handle: windows.HANDLE,
793 overlapped: *windows.OVERLAPPED,
794 r: *Reader,
795 small_buf: *[128]u8,
796 bump_amt: usize,
797 ) !enum { empty, populated, closed_populated, closed } {
798 var read_any_data = false;
799 while (true) {
800 const fifo_read_pending = while (true) {
801 const buf = try writableSliceGreedyAlloc(r, gpa, bump_amt);
802 const buf_len = math.cast(u32, buf.len) orelse math.maxInt(u32);
769803
770 const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, false)) {804 if (0 == windows.kernel32.ReadFile(
771 .success => |n| n,805 handle,
772 .closed => return if (read_any_data) .closed_populated else .closed,806 buf.ptr,
773 .aborted => unreachable,807 buf_len,
774 };808 &win_dummy_bytes_read,
809 overlapped,
810 )) switch (windows.GetLastError()) {
811 .IO_PENDING => break true,
812 .BROKEN_PIPE => return if (read_any_data) .closed_populated else .closed,
813 else => |err| return windows.unexpectedError(err),
814 };
775815
776 read_any_data = true;816 const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, false)) {
777 fifo.update(num_bytes_read);817 .success => |n| n,
818 .closed => return if (read_any_data) .closed_populated else .closed,
819 .aborted => unreachable,
820 };
778821
779 if (num_bytes_read == buf_len) {822 read_any_data = true;
780 // We filled the buffer, so there's probably more data available.823 advanceBufferEnd(r, num_bytes_read);
781 continue;
782 } else {
783 // We didn't fill the buffer, so assume we're out of data.
784 // There is no pending read.
785 break false;
786 }
787 };
788824
789 if (fifo_read_pending) cancel_read: {825 if (num_bytes_read == buf_len) {
790 // Cancel the pending read into the FIFO.826 // We filled the buffer, so there's probably more data available.
791 _ = windows.kernel32.CancelIo(handle);827 continue;
828 } else {
829 // We didn't fill the buffer, so assume we're out of data.
830 // There is no pending read.
831 break false;
832 }
833 };
792834
793 // We have to wait for the handle to be signalled, i.e. for the cancellation to complete.835 if (fifo_read_pending) cancel_read: {
794 switch (windows.kernel32.WaitForSingleObject(handle, windows.INFINITE)) {836 // Cancel the pending read into the FIFO.
795 windows.WAIT_OBJECT_0 => {},837 _ = windows.kernel32.CancelIo(handle);
796 windows.WAIT_FAILED => return windows.unexpectedError(windows.GetLastError()),
797 else => unreachable,
798 }
799838
800 // If it completed before we canceled, make sure to tell the FIFO!839 // We have to wait for the handle to be signalled, i.e. for the cancellation to complete.
801 const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, true)) {840 switch (windows.kernel32.WaitForSingleObject(handle, windows.INFINITE)) {
802 .success => |n| n,841 windows.WAIT_OBJECT_0 => {},
803 .closed => return if (read_any_data) .closed_populated else .closed,842 windows.WAIT_FAILED => return windows.unexpectedError(windows.GetLastError()),
804 .aborted => break :cancel_read,843 else => unreachable,
805 };844 }
806 read_any_data = true;
807 fifo.update(num_bytes_read);
808 }
809
810 // Try to queue the 1-byte read.
811 if (0 == windows.kernel32.ReadFile(
812 handle,
813 small_buf,
814 small_buf.len,
815 &win_dummy_bytes_read,
816 overlapped,
817 )) switch (windows.GetLastError()) {
818 .IO_PENDING => {
819 // 1-byte read pending as intended
820 return if (read_any_data) .populated else .empty;
821 },
822 .BROKEN_PIPE => return if (read_any_data) .closed_populated else .closed,
823 else => |err| return windows.unexpectedError(err),
824 };
825845
826 // We got data back this time. Write it to the FIFO and run the main loop again.846 // If it completed before we canceled, make sure to tell the FIFO!
827 const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, false)) {847 const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, true)) {
828 .success => |n| n,848 .success => |n| n,
829 .closed => return if (read_any_data) .closed_populated else .closed,849 .closed => return if (read_any_data) .closed_populated else .closed,
830 .aborted => unreachable,850 .aborted => break :cancel_read,
831 };851 };
832 try fifo.write(small_buf[0..num_bytes_read]);852 read_any_data = true;
833 read_any_data = true;853 advanceBufferEnd(r, num_bytes_read);
834 }854 }
835}
836855
837/// Simple wrapper around `GetOverlappedResult` to determine the result of a `ReadFile` operation.856 // Try to queue the 1-byte read.
838/// If `!allow_aborted`, then `aborted` is never returned (`OPERATION_ABORTED` is considered unexpected).857 if (0 == windows.kernel32.ReadFile(
839///858 handle,
840/// The `ReadFile` documentation states that the number of bytes read by an overlapped `ReadFile` must be determined using `GetOverlappedResult`, even if the859 small_buf,
841/// operation immediately returns data:860 small_buf.len,
842/// "Use NULL for [lpNumberOfBytesRead] if this is an asynchronous operation to avoid potentially861 &win_dummy_bytes_read,
843/// erroneous results."862 overlapped,
844/// "If `hFile` was opened with `FILE_FLAG_OVERLAPPED`, the following conditions are in effect: [...]863 )) switch (windows.GetLastError()) {
845/// The lpNumberOfBytesRead parameter should be set to NULL. Use the GetOverlappedResult function to864 .IO_PENDING => {
846/// get the actual number of bytes read."865 // 1-byte read pending as intended
847/// See: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile866 return if (read_any_data) .populated else .empty;
848fn windowsGetReadResult(867 },
849 handle: windows.HANDLE,868 .BROKEN_PIPE => return if (read_any_data) .closed_populated else .closed,
850 overlapped: *windows.OVERLAPPED,869 else => |err| return windows.unexpectedError(err),
851 allow_aborted: bool,870 };
852) !union(enum) {871
853 success: u32,872 // We got data back this time. Write it to the FIFO and run the main loop again.
854 closed,873 const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, false)) {
855 aborted,874 .success => |n| n,
856} {875 .closed => return if (read_any_data) .closed_populated else .closed,
857 var num_bytes_read: u32 = undefined;876 .aborted => unreachable,
858 if (0 == windows.kernel32.GetOverlappedResult(877 };
859 handle,878 const buf = small_buf[0..num_bytes_read];
860 overlapped,879 const dest = try writableSliceGreedyAlloc(r, gpa, buf.len);
861 &num_bytes_read,880 @memcpy(dest[0..buf.len], buf);
862 0,881 advanceBufferEnd(r, buf.len);
863 )) switch (windows.GetLastError()) {882 read_any_data = true;
864 .BROKEN_PIPE => return .closed,883 }
865 .OPERATION_ABORTED => |err| if (allow_aborted) {884 }
866 return .aborted;885
867 } else {886 /// Simple wrapper around `GetOverlappedResult` to determine the result of a `ReadFile` operation.
868 return windows.unexpectedError(err);887 /// If `!allow_aborted`, then `aborted` is never returned (`OPERATION_ABORTED` is considered unexpected).
869 },888 ///
870 else => |err| return windows.unexpectedError(err),889 /// The `ReadFile` documentation states that the number of bytes read by an overlapped `ReadFile` must be determined using `GetOverlappedResult`, even if the
890 /// operation immediately returns data:
891 /// "Use NULL for [lpNumberOfBytesRead] if this is an asynchronous operation to avoid potentially
892 /// erroneous results."
893 /// "If `hFile` was opened with `FILE_FLAG_OVERLAPPED`, the following conditions are in effect: [...]
894 /// The lpNumberOfBytesRead parameter should be set to NULL. Use the GetOverlappedResult function to
895 /// get the actual number of bytes read."
896 /// See: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile
897 fn windowsGetReadResult(
898 handle: windows.HANDLE,
899 overlapped: *windows.OVERLAPPED,
900 allow_aborted: bool,
901 ) !union(enum) {
902 success: u32,
903 closed,
904 aborted,
905 } {
906 var num_bytes_read: u32 = undefined;
907 if (0 == windows.kernel32.GetOverlappedResult(
908 handle,
909 overlapped,
910 &num_bytes_read,
911 0,
912 )) switch (windows.GetLastError()) {
913 .BROKEN_PIPE => return .closed,
914 .OPERATION_ABORTED => |err| if (allow_aborted) {
915 return .aborted;
916 } else {
917 return windows.unexpectedError(err);
918 },
919 else => |err| return windows.unexpectedError(err),
920 };
921 return .{ .success = num_bytes_read };
922 }
871 };923 };
872 return .{ .success = num_bytes_read };
873}924}
874925
875/// Given an enum, returns a struct with fields of that enum, each field926/// Given an enum, returns a struct with fields of that enum, each field
...@@ -880,10 +931,10 @@ pub fn PollFiles(comptime StreamEnum: type) type {...@@ -880,10 +931,10 @@ pub fn PollFiles(comptime StreamEnum: type) type {
880 for (&struct_fields, enum_fields) |*struct_field, enum_field| {931 for (&struct_fields, enum_fields) |*struct_field, enum_field| {
881 struct_field.* = .{932 struct_field.* = .{
882 .name = enum_field.name,933 .name = enum_field.name,
883 .type = fs.File,934 .type = std.fs.File,
884 .default_value_ptr = null,935 .default_value_ptr = null,
885 .is_comptime = false,936 .is_comptime = false,
886 .alignment = @alignOf(fs.File),937 .alignment = @alignOf(std.fs.File),
887 };938 };
888 }939 }
889 return @Type(.{ .@"struct" = .{940 return @Type(.{ .@"struct" = .{
...@@ -898,16 +949,14 @@ test {...@@ -898,16 +949,14 @@ test {
898 _ = Reader;949 _ = Reader;
899 _ = Reader.Limited;950 _ = Reader.Limited;
900 _ = Writer;951 _ = Writer;
901 _ = @import("Io/bit_reader.zig");952 _ = BitReader;
902 _ = @import("Io/bit_writer.zig");953 _ = BitWriter;
903 _ = @import("Io/buffered_atomic_file.zig");954 _ = BufferedReader;
904 _ = @import("Io/buffered_reader.zig");955 _ = BufferedWriter;
905 _ = @import("Io/buffered_writer.zig");956 _ = CountingWriter;
906 _ = @import("Io/c_writer.zig");957 _ = CountingReader;
907 _ = @import("Io/counting_writer.zig");958 _ = FixedBufferStream;
908 _ = @import("Io/counting_reader.zig");959 _ = SeekableStream;
909 _ = @import("Io/fixed_buffer_stream.zig");960 _ = tty;
910 _ = @import("Io/seekable_stream.zig");
911 _ = @import("Io/stream_source.zig");
912 _ = @import("Io/test.zig");961 _ = @import("Io/test.zig");
913}962}
lib/std/Io/DeprecatedReader.zig+5-3
...@@ -373,11 +373,11 @@ pub fn discard(self: Self) anyerror!u64 {...@@ -373,11 +373,11 @@ pub fn discard(self: Self) anyerror!u64 {
373}373}
374374
375/// Helper for bridging to the new `Reader` API while upgrading.375/// Helper for bridging to the new `Reader` API while upgrading.
376pub fn adaptToNewApi(self: *const Self) Adapter {376pub fn adaptToNewApi(self: *const Self, buffer: []u8) Adapter {
377 return .{377 return .{
378 .derp_reader = self.*,378 .derp_reader = self.*,
379 .new_interface = .{379 .new_interface = .{
380 .buffer = &.{},380 .buffer = buffer,
381 .vtable = &.{ .stream = Adapter.stream },381 .vtable = &.{ .stream = Adapter.stream },
382 .seek = 0,382 .seek = 0,
383 .end = 0,383 .end = 0,
...@@ -393,10 +393,12 @@ pub const Adapter = struct {...@@ -393,10 +393,12 @@ pub const Adapter = struct {
393 fn stream(r: *std.io.Reader, w: *std.io.Writer, limit: std.io.Limit) std.io.Reader.StreamError!usize {393 fn stream(r: *std.io.Reader, w: *std.io.Writer, limit: std.io.Limit) std.io.Reader.StreamError!usize {
394 const a: *@This() = @alignCast(@fieldParentPtr("new_interface", r));394 const a: *@This() = @alignCast(@fieldParentPtr("new_interface", r));
395 const buf = limit.slice(try w.writableSliceGreedy(1));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 a.err = err;397 a.err = err;
398 return error.ReadFailed;398 return error.ReadFailed;
399 };399 };
400 w.advance(n);
401 return n;
400 }402 }
401};403};
402404
lib/std/Io/DeprecatedWriter.zig+6-1
...@@ -100,7 +100,12 @@ pub const Adapter = struct {...@@ -100,7 +100,12 @@ pub const Adapter = struct {
100100
101 fn drain(w: *std.io.Writer, data: []const []const u8, splat: usize) std.io.Writer.Error!usize {101 fn drain(w: *std.io.Writer, data: []const []const u8, splat: usize) std.io.Writer.Error!usize {
102 _ = splat;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 return a.derp_writer.write(data[0]) catch |err| {109 return a.derp_writer.write(data[0]) catch |err| {
105 a.err = err;110 a.err = err;
106 return error.WriteFailed;111 return error.WriteFailed;
lib/std/Io/Reader.zig+70-70
...@@ -67,6 +67,18 @@ pub const VTable = struct {...@@ -67,6 +67,18 @@ pub const VTable = struct {
67 ///67 ///
68 /// This function is only called when `buffer` is empty.68 /// This function is only called when `buffer` is empty.
69 discard: *const fn (r: *Reader, limit: Limit) Error!usize = defaultDiscard,69 discard: *const fn (r: *Reader, limit: Limit) Error!usize = defaultDiscard,
70
71 /// Ensures `capacity` more data can be buffered without rebasing.
72 ///
73 /// Asserts `capacity` is within buffer capacity, or that the stream ends
74 /// within `capacity` bytes.
75 ///
76 /// Only called when `capacity` cannot fit into the unused capacity of
77 /// `buffer`.
78 ///
79 /// The default implementation moves buffered data to the start of
80 /// `buffer`, setting `seek` to zero, and cannot fail.
81 rebase: *const fn (r: *Reader, capacity: usize) RebaseError!void = defaultRebase,
70};82};
7183
72pub const StreamError = error{84pub const StreamError = error{
...@@ -97,6 +109,10 @@ pub const ShortError = error{...@@ -97,6 +109,10 @@ pub const ShortError = error{
97 ReadFailed,109 ReadFailed,
98};110};
99111
112pub const RebaseError = error{
113 EndOfStream,
114};
115
100pub const failing: Reader = .{116pub const failing: Reader = .{
101 .vtable = &.{117 .vtable = &.{
102 .stream = failingStream,118 .stream = failingStream,
...@@ -122,6 +138,7 @@ pub fn fixed(buffer: []const u8) Reader {...@@ -122,6 +138,7 @@ pub fn fixed(buffer: []const u8) Reader {
122 .vtable = &.{138 .vtable = &.{
123 .stream = endingStream,139 .stream = endingStream,
124 .discard = endingDiscard,140 .discard = endingDiscard,
141 .rebase = endingRebase,
125 },142 },
126 // This cast is safe because all potential writes to it will instead143 // This cast is safe because all potential writes to it will instead
127 // return `error.EndOfStream`.144 // return `error.EndOfStream`.
...@@ -179,6 +196,38 @@ pub fn streamExact(r: *Reader, w: *Writer, n: usize) StreamError!void {...@@ -179,6 +196,38 @@ pub fn streamExact(r: *Reader, w: *Writer, n: usize) StreamError!void {
179 while (remaining != 0) remaining -= try r.stream(w, .limited(remaining));196 while (remaining != 0) remaining -= try r.stream(w, .limited(remaining));
180}197}
181198
199/// "Pump" exactly `n` bytes from the reader to the writer.
200pub fn streamExact64(r: *Reader, w: *Writer, n: u64) StreamError!void {
201 var remaining = n;
202 while (remaining != 0) remaining -= try r.stream(w, .limited64(remaining));
203}
204
205/// "Pump" exactly `n` bytes from the reader to the writer.
206///
207/// When draining `w`, ensures that at least `preserve_len` bytes remain
208/// buffered.
209///
210/// Asserts `Writer.buffer` capacity exceeds `preserve_len`.
211pub fn streamExactPreserve(r: *Reader, w: *Writer, preserve_len: usize, n: usize) StreamError!void {
212 if (w.end + n <= w.buffer.len) {
213 @branchHint(.likely);
214 return streamExact(r, w, n);
215 }
216 // If `n` is large, we can ignore `preserve_len` up to a point.
217 var remaining = n;
218 while (remaining > preserve_len) {
219 assert(remaining != 0);
220 remaining -= try r.stream(w, .limited(remaining - preserve_len));
221 if (w.end + remaining <= w.buffer.len) return streamExact(r, w, remaining);
222 }
223 // All the next bytes received must be preserved.
224 if (preserve_len < w.end) {
225 @memmove(w.buffer[0..preserve_len], w.buffer[w.end - preserve_len ..][0..preserve_len]);
226 w.end = preserve_len;
227 }
228 return streamExact(r, w, remaining);
229}
230
182/// "Pump" data from the reader to the writer, handling `error.EndOfStream` as231/// "Pump" data from the reader to the writer, handling `error.EndOfStream` as
183/// a success case.232/// a success case.
184///233///
...@@ -234,7 +283,7 @@ pub fn allocRemaining(r: *Reader, gpa: Allocator, limit: Limit) LimitedAllocErro...@@ -234,7 +283,7 @@ pub fn allocRemaining(r: *Reader, gpa: Allocator, limit: Limit) LimitedAllocErro
234/// such case, the next byte that would be read will be the first one to exceed283/// such case, the next byte that would be read will be the first one to exceed
235/// `limit`, and all preceeding bytes have been appended to `list`.284/// `limit`, and all preceeding bytes have been appended to `list`.
236///285///
237/// Asserts `buffer` has nonzero capacity.286/// If `limit` is not `Limit.unlimited`, asserts `buffer` has nonzero capacity.
238///287///
239/// See also:288/// See also:
240/// * `allocRemaining`289/// * `allocRemaining`
...@@ -245,7 +294,7 @@ pub fn appendRemaining(...@@ -245,7 +294,7 @@ pub fn appendRemaining(
245 list: *std.ArrayListAlignedUnmanaged(u8, alignment),294 list: *std.ArrayListAlignedUnmanaged(u8, alignment),
246 limit: Limit,295 limit: Limit,
247) LimitedAllocError!void {296) LimitedAllocError!void {
248 assert(r.buffer.len != 0); // Needed to detect limit exceeded without losing data.297 if (limit != .unlimited) assert(r.buffer.len != 0); // Needed to detect limit exceeded without losing data.
249 const buffer_contents = r.buffer[r.seek..r.end];298 const buffer_contents = r.buffer[r.seek..r.end];
250 const copy_len = limit.minInt(buffer_contents.len);299 const copy_len = limit.minInt(buffer_contents.len);
251 try list.appendSlice(gpa, r.buffer[0..copy_len]);300 try list.appendSlice(gpa, r.buffer[0..copy_len]);
...@@ -748,11 +797,8 @@ pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {...@@ -748,11 +797,8 @@ pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 {
748 @branchHint(.likely);797 @branchHint(.likely);
749 return buffer[seek .. end + 1];798 return buffer[seek .. end + 1];
750 }799 }
751 if (r.vtable.stream == &endingStream) {800 // TODO take a parameter for max search length rather than relying on buffer capacity
752 // Protect the `@constCast` of `fixed`.801 try rebase(r, r.buffer.len);
753 return error.EndOfStream;
754 }
755 r.rebase();
756 while (r.buffer.len - r.end != 0) {802 while (r.buffer.len - r.end != 0) {
757 const end_cap = r.buffer[r.end..];803 const end_cap = r.buffer[r.end..];
758 var writer: Writer = .fixed(end_cap);804 var writer: Writer = .fixed(end_cap);
...@@ -1018,11 +1064,7 @@ fn fillUnbuffered(r: *Reader, n: usize) Error!void {...@@ -1018,11 +1064,7 @@ fn fillUnbuffered(r: *Reader, n: usize) Error!void {
1018 };1064 };
1019 if (r.seek + n <= r.end) return;1065 if (r.seek + n <= r.end) return;
1020 };1066 };
1021 if (r.vtable.stream == &endingStream) {1067 try rebase(r, n);
1022 // Protect the `@constCast` of `fixed`.
1023 return error.EndOfStream;
1024 }
1025 rebaseCapacity(r, n);
1026 var writer: Writer = .{1068 var writer: Writer = .{
1027 .buffer = r.buffer,1069 .buffer = r.buffer,
1028 .vtable = &.{ .drain = Writer.fixedDrain },1070 .vtable = &.{ .drain = Writer.fixedDrain },
...@@ -1042,7 +1084,7 @@ fn fillUnbuffered(r: *Reader, n: usize) Error!void {...@@ -1042,7 +1084,7 @@ fn fillUnbuffered(r: *Reader, n: usize) Error!void {
1042///1084///
1043/// Asserts buffer capacity is at least 1.1085/// Asserts buffer capacity is at least 1.
1044pub fn fillMore(r: *Reader) Error!void {1086pub fn fillMore(r: *Reader) Error!void {
1045 rebaseCapacity(r, 1);1087 try rebase(r, 1);
1046 var writer: Writer = .{1088 var writer: Writer = .{
1047 .buffer = r.buffer,1089 .buffer = r.buffer,
1048 .end = r.end,1090 .end = r.end,
...@@ -1219,7 +1261,7 @@ pub fn takeLeb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result {...@@ -1219,7 +1261,7 @@ pub fn takeLeb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result {
12191261
1220pub fn expandTotalCapacity(r: *Reader, allocator: Allocator, n: usize) Allocator.Error!void {1262pub fn expandTotalCapacity(r: *Reader, allocator: Allocator, n: usize) Allocator.Error!void {
1221 if (n <= r.buffer.len) return;1263 if (n <= r.buffer.len) return;
1222 if (r.seek > 0) rebase(r);1264 if (r.seek > 0) rebase(r, r.buffer.len);
1223 var list: ArrayList(u8) = .{1265 var list: ArrayList(u8) = .{
1224 .items = r.buffer[0..r.end],1266 .items = r.buffer[0..r.end],
1225 .capacity = r.buffer.len,1267 .capacity = r.buffer.len,
...@@ -1235,37 +1277,6 @@ pub fn fillAlloc(r: *Reader, allocator: Allocator, n: usize) FillAllocError!void...@@ -1235,37 +1277,6 @@ pub fn fillAlloc(r: *Reader, allocator: Allocator, n: usize) FillAllocError!void
1235 return fill(r, n);1277 return fill(r, n);
1236}1278}
12371279
1238/// Returns a slice into the unused capacity of `buffer` with at least
1239/// `min_len` bytes, extending `buffer` by resizing it with `gpa` as necessary.
1240///
1241/// After calling this function, typically the caller will follow up with a
1242/// call to `advanceBufferEnd` to report the actual number of bytes buffered.
1243pub fn writableSliceGreedyAlloc(r: *Reader, allocator: Allocator, min_len: usize) Allocator.Error![]u8 {
1244 {
1245 const unused = r.buffer[r.end..];
1246 if (unused.len >= min_len) return unused;
1247 }
1248 if (r.seek > 0) rebase(r);
1249 {
1250 var list: ArrayList(u8) = .{
1251 .items = r.buffer[0..r.end],
1252 .capacity = r.buffer.len,
1253 };
1254 defer r.buffer = list.allocatedSlice();
1255 try list.ensureUnusedCapacity(allocator, min_len);
1256 }
1257 const unused = r.buffer[r.end..];
1258 assert(unused.len >= min_len);
1259 return unused;
1260}
1261
1262/// After writing directly into the unused capacity of `buffer`, this function
1263/// updates `end` so that users of `Reader` can receive the data.
1264pub fn advanceBufferEnd(r: *Reader, n: usize) void {
1265 assert(n <= r.buffer.len - r.end);
1266 r.end += n;
1267}
1268
1269fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result {1280fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result {
1270 const result_info = @typeInfo(Result).int;1281 const result_info = @typeInfo(Result).int;
1271 comptime assert(result_info.bits % 7 == 0);1282 comptime assert(result_info.bits % 7 == 0);
...@@ -1296,37 +1307,20 @@ fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Resu...@@ -1296,37 +1307,20 @@ fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Resu
1296 }1307 }
1297}1308}
12981309
1299/// Left-aligns data such that `r.seek` becomes zero.1310/// Ensures `capacity` more data can be buffered without rebasing.
1300///1311pub fn rebase(r: *Reader, capacity: usize) RebaseError!void {
1301/// If `r.seek` is not already zero then `buffer` is mutated, making it illegal1312 if (r.end + capacity <= r.buffer.len) return;
1302/// to call this function with a const-casted `buffer`, such as in the case of1313 return r.vtable.rebase(r, capacity);
1303/// `fixed`. This issue can be avoided:1314}
1304/// * in implementations, by attempting a read before a rebase, in which1315
1305/// case the read will return `error.EndOfStream`, preventing the rebase.1316pub fn defaultRebase(r: *Reader, capacity: usize) RebaseError!void {
1306/// * in usage, by copying into a mutable buffer before initializing `fixed`.1317 if (r.end <= r.buffer.len - capacity) return;
1307pub fn rebase(r: *Reader) void {
1308 if (r.seek == 0) return;
1309 const data = r.buffer[r.seek..r.end];1318 const data = r.buffer[r.seek..r.end];
1310 @memmove(r.buffer[0..data.len], data);1319 @memmove(r.buffer[0..data.len], data);
1311 r.seek = 0;1320 r.seek = 0;
1312 r.end = data.len;1321 r.end = data.len;
1313}1322}
13141323
1315/// Ensures `capacity` more data can be buffered without rebasing, by rebasing
1316/// if necessary.
1317///
1318/// Asserts `capacity` is within the buffer capacity.
1319///
1320/// If the rebase occurs then `buffer` is mutated, making it illegal to call
1321/// this function with a const-casted `buffer`, such as in the case of `fixed`.
1322/// This issue can be avoided:
1323/// * in implementations, by attempting a read before a rebase, in which
1324/// case the read will return `error.EndOfStream`, preventing the rebase.
1325/// * in usage, by copying into a mutable buffer before initializing `fixed`.
1326pub fn rebaseCapacity(r: *Reader, capacity: usize) void {
1327 if (r.end > r.buffer.len - capacity) rebase(r);
1328}
1329
1330/// Advances the stream and decreases the size of the storage buffer by `n`,1324/// Advances the stream and decreases the size of the storage buffer by `n`,
1331/// returning the range of bytes no longer accessible by `r`.1325/// returning the range of bytes no longer accessible by `r`.
1332///1326///
...@@ -1682,6 +1676,12 @@ fn endingDiscard(r: *Reader, limit: Limit) Error!usize {...@@ -1682,6 +1676,12 @@ fn endingDiscard(r: *Reader, limit: Limit) Error!usize {
1682 return error.EndOfStream;1676 return error.EndOfStream;
1683}1677}
16841678
1679fn endingRebase(r: *Reader, capacity: usize) RebaseError!void {
1680 _ = r;
1681 _ = capacity;
1682 return error.EndOfStream;
1683}
1684
1685fn failingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {1685fn failingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize {
1686 _ = r;1686 _ = r;
1687 _ = w;1687 _ = w;
lib/std/Io/Writer.zig+85-28
...@@ -256,10 +256,10 @@ test "fixed buffer flush" {...@@ -256,10 +256,10 @@ test "fixed buffer flush" {
256 try testing.expectEqual(10, buffer[0]);256 try testing.expectEqual(10, buffer[0]);
257}257}
258258
259/// Calls `VTable.drain` but hides the last `preserve_length` bytes from the259/// Calls `VTable.drain` but hides the last `preserve_len` bytes from the
260/// implementation, keeping them buffered.260/// implementation, keeping them buffered.
261pub fn drainPreserve(w: *Writer, preserve_length: usize) Error!void {261pub fn drainPreserve(w: *Writer, preserve_len: usize) Error!void {
262 const temp_end = w.end -| preserve_length;262 const temp_end = w.end -| preserve_len;
263 const preserved = w.buffer[temp_end..w.end];263 const preserved = w.buffer[temp_end..w.end];
264 w.end = temp_end;264 w.end = temp_end;
265 defer w.end += preserved.len;265 defer w.end += preserved.len;
...@@ -310,24 +310,38 @@ pub fn writableSliceGreedy(w: *Writer, minimum_length: usize) Error![]u8 {...@@ -310,24 +310,38 @@ pub fn writableSliceGreedy(w: *Writer, minimum_length: usize) Error![]u8 {
310}310}
311311
312/// Asserts the provided buffer has total capacity enough for `minimum_length`312/// Asserts the provided buffer has total capacity enough for `minimum_length`
313/// and `preserve_length` combined.313/// and `preserve_len` combined.
314///314///
315/// Does not `advance` the buffer end position.315/// Does not `advance` the buffer end position.
316///316///
317/// When draining the buffer, ensures that at least `preserve_length` bytes317/// When draining the buffer, ensures that at least `preserve_len` bytes
318/// remain buffered.318/// remain buffered.
319///319///
320/// If `preserve_length` is zero, this is equivalent to `writableSliceGreedy`.320/// If `preserve_len` is zero, this is equivalent to `writableSliceGreedy`.
321pub fn writableSliceGreedyPreserve(w: *Writer, preserve_length: usize, minimum_length: usize) Error![]u8 {321pub fn writableSliceGreedyPreserve(w: *Writer, preserve_len: usize, minimum_length: usize) Error![]u8 {
322 assert(w.buffer.len >= preserve_length + minimum_length);322 assert(w.buffer.len >= preserve_len + minimum_length);
323 while (w.buffer.len - w.end < minimum_length) {323 while (w.buffer.len - w.end < minimum_length) {
324 try drainPreserve(w, preserve_length);324 try drainPreserve(w, preserve_len);
325 } else {325 } else {
326 @branchHint(.likely);326 @branchHint(.likely);
327 return w.buffer[w.end..];327 return w.buffer[w.end..];
328 }328 }
329}329}
330330
331/// Asserts the provided buffer has total capacity enough for `len`.
332///
333/// Advances the buffer end position by `len`.
334///
335/// When draining the buffer, ensures that at least `preserve_len` bytes
336/// remain buffered.
337///
338/// If `preserve_len` is zero, this is equivalent to `writableSlice`.
339pub fn writableSlicePreserve(w: *Writer, preserve_len: usize, len: usize) Error![]u8 {
340 const big_slice = try w.writableSliceGreedyPreserve(preserve_len, len);
341 advance(w, len);
342 return big_slice[0..len];
343}
344
331pub const WritableVectorIterator = struct {345pub const WritableVectorIterator = struct {
332 first: []u8,346 first: []u8,
333 middle: []const []u8 = &.{},347 middle: []const []u8 = &.{},
...@@ -523,16 +537,16 @@ pub fn write(w: *Writer, bytes: []const u8) Error!usize {...@@ -523,16 +537,16 @@ pub fn write(w: *Writer, bytes: []const u8) Error!usize {
523 return w.vtable.drain(w, &.{bytes}, 1);537 return w.vtable.drain(w, &.{bytes}, 1);
524}538}
525539
526/// Asserts `buffer` capacity exceeds `preserve_length`.540/// Asserts `buffer` capacity exceeds `preserve_len`.
527pub fn writePreserve(w: *Writer, preserve_length: usize, bytes: []const u8) Error!usize {541pub fn writePreserve(w: *Writer, preserve_len: usize, bytes: []const u8) Error!usize {
528 assert(preserve_length <= w.buffer.len);542 assert(preserve_len <= w.buffer.len);
529 if (w.end + bytes.len <= w.buffer.len) {543 if (w.end + bytes.len <= w.buffer.len) {
530 @branchHint(.likely);544 @branchHint(.likely);
531 @memcpy(w.buffer[w.end..][0..bytes.len], bytes);545 @memcpy(w.buffer[w.end..][0..bytes.len], bytes);
532 w.end += bytes.len;546 w.end += bytes.len;
533 return bytes.len;547 return bytes.len;
534 }548 }
535 const temp_end = w.end -| preserve_length;549 const temp_end = w.end -| preserve_len;
536 const preserved = w.buffer[temp_end..w.end];550 const preserved = w.buffer[temp_end..w.end];
537 w.end = temp_end;551 w.end = temp_end;
538 defer w.end += preserved.len;552 defer w.end += preserved.len;
...@@ -552,13 +566,13 @@ pub fn writeAll(w: *Writer, bytes: []const u8) Error!void {...@@ -552,13 +566,13 @@ pub fn writeAll(w: *Writer, bytes: []const u8) Error!void {
552/// Calls `drain` as many times as necessary such that all of `bytes` are566/// Calls `drain` as many times as necessary such that all of `bytes` are
553/// transferred.567/// transferred.
554///568///
555/// When draining the buffer, ensures that at least `preserve_length` bytes569/// When draining the buffer, ensures that at least `preserve_len` bytes
556/// remain buffered.570/// remain buffered.
557///571///
558/// Asserts `buffer` capacity exceeds `preserve_length`.572/// Asserts `buffer` capacity exceeds `preserve_len`.
559pub fn writeAllPreserve(w: *Writer, preserve_length: usize, bytes: []const u8) Error!void {573pub fn writeAllPreserve(w: *Writer, preserve_len: usize, bytes: []const u8) Error!void {
560 var index: usize = 0;574 var index: usize = 0;
561 while (index < bytes.len) index += try w.writePreserve(preserve_length, bytes[index..]);575 while (index < bytes.len) index += try w.writePreserve(preserve_len, bytes[index..]);
562}576}
563577
564/// Renders fmt string with args, calling `writer` with slices of bytes.578/// Renders fmt string with args, calling `writer` with slices of bytes.
...@@ -761,11 +775,11 @@ pub fn writeByte(w: *Writer, byte: u8) Error!void {...@@ -761,11 +775,11 @@ pub fn writeByte(w: *Writer, byte: u8) Error!void {
761 }775 }
762}776}
763777
764/// When draining the buffer, ensures that at least `preserve_length` bytes778/// When draining the buffer, ensures that at least `preserve_len` bytes
765/// remain buffered.779/// remain buffered.
766pub fn writeBytePreserve(w: *Writer, preserve_length: usize, byte: u8) Error!void {780pub fn writeBytePreserve(w: *Writer, preserve_len: usize, byte: u8) Error!void {
767 while (w.buffer.len - w.end == 0) {781 while (w.buffer.len - w.end == 0) {
768 try drainPreserve(w, preserve_length);782 try drainPreserve(w, preserve_len);
769 } else {783 } else {
770 @branchHint(.likely);784 @branchHint(.likely);
771 w.buffer[w.end] = byte;785 w.buffer[w.end] = byte;
...@@ -788,10 +802,42 @@ test splatByteAll {...@@ -788,10 +802,42 @@ test splatByteAll {
788 try testing.expectEqualStrings("7" ** 45, aw.writer.buffered());802 try testing.expectEqualStrings("7" ** 45, aw.writer.buffered());
789}803}
790804
805pub fn splatBytePreserve(w: *Writer, preserve_len: usize, byte: u8, n: usize) Error!void {
806 const new_end = w.end + n;
807 if (new_end <= w.buffer.len) {
808 @memset(w.buffer[w.end..][0..n], byte);
809 w.end = new_end;
810 return;
811 }
812 // If `n` is large, we can ignore `preserve_len` up to a point.
813 var remaining = n;
814 while (remaining > preserve_len) {
815 assert(remaining != 0);
816 remaining -= try splatByte(w, byte, remaining - preserve_len);
817 if (w.end + remaining <= w.buffer.len) {
818 @memset(w.buffer[w.end..][0..remaining], byte);
819 w.end += remaining;
820 return;
821 }
822 }
823 // All the next bytes received must be preserved.
824 if (preserve_len < w.end) {
825 @memmove(w.buffer[0..preserve_len], w.buffer[w.end - preserve_len ..][0..preserve_len]);
826 w.end = preserve_len;
827 }
828 while (remaining > 0) remaining -= try w.splatByte(byte, remaining);
829}
830
791/// Writes the same byte many times, allowing short writes.831/// Writes the same byte many times, allowing short writes.
792///832///
793/// Does maximum of one underlying `VTable.drain`.833/// Does maximum of one underlying `VTable.drain`.
794pub fn splatByte(w: *Writer, byte: u8, n: usize) Error!usize {834pub fn splatByte(w: *Writer, byte: u8, n: usize) Error!usize {
835 if (w.end + n <= w.buffer.len) {
836 @branchHint(.likely);
837 @memset(w.buffer[w.end..][0..n], byte);
838 w.end += n;
839 return n;
840 }
795 return writeSplat(w, &.{&.{byte}}, n);841 return writeSplat(w, &.{&.{byte}}, n);
796}842}
797843
...@@ -801,9 +847,10 @@ pub fn splatBytesAll(w: *Writer, bytes: []const u8, splat: usize) Error!void {...@@ -801,9 +847,10 @@ pub fn splatBytesAll(w: *Writer, bytes: []const u8, splat: usize) Error!void {
801 var remaining_bytes: usize = bytes.len * splat;847 var remaining_bytes: usize = bytes.len * splat;
802 remaining_bytes -= try w.splatBytes(bytes, splat);848 remaining_bytes -= try w.splatBytes(bytes, splat);
803 while (remaining_bytes > 0) {849 while (remaining_bytes > 0) {
804 const leftover = remaining_bytes % bytes.len;850 const leftover_splat = remaining_bytes / bytes.len;
805 const buffers: [2][]const u8 = .{ bytes[bytes.len - leftover ..], bytes };851 const leftover_bytes = remaining_bytes % bytes.len;
806 remaining_bytes -= try w.writeSplat(&buffers, splat);852 const buffers: [2][]const u8 = .{ bytes[bytes.len - leftover_bytes ..], bytes };
853 remaining_bytes -= try w.writeSplat(&buffers, leftover_splat);
807 }854 }
808}855}
809856
...@@ -1564,17 +1611,23 @@ pub fn printFloatHexOptions(w: *Writer, value: anytype, options: std.fmt.Number)...@@ -1564,17 +1611,23 @@ pub fn printFloatHexOptions(w: *Writer, value: anytype, options: std.fmt.Number)
1564}1611}
15651612
1566pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precision: ?usize) Error!void {1613pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precision: ?usize) Error!void {
1567 if (std.math.signbit(value)) try w.writeByte('-');1614 const v = switch (@TypeOf(value)) {
1568 if (std.math.isNan(value)) return w.writeAll(switch (case) {1615 // comptime_float internally is a f128; this preserves precision.
1616 comptime_float => @as(f128, value),
1617 else => value,
1618 };
1619
1620 if (std.math.signbit(v)) try w.writeByte('-');
1621 if (std.math.isNan(v)) return w.writeAll(switch (case) {
1569 .lower => "nan",1622 .lower => "nan",
1570 .upper => "NAN",1623 .upper => "NAN",
1571 });1624 });
1572 if (std.math.isInf(value)) return w.writeAll(switch (case) {1625 if (std.math.isInf(v)) return w.writeAll(switch (case) {
1573 .lower => "inf",1626 .lower => "inf",
1574 .upper => "INF",1627 .upper => "INF",
1575 });1628 });
15761629
1577 const T = @TypeOf(value);1630 const T = @TypeOf(v);
1578 const TU = std.meta.Int(.unsigned, @bitSizeOf(T));1631 const TU = std.meta.Int(.unsigned, @bitSizeOf(T));
15791632
1580 const mantissa_bits = std.math.floatMantissaBits(T);1633 const mantissa_bits = std.math.floatMantissaBits(T);
...@@ -1584,7 +1637,7 @@ pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precisi...@@ -1584,7 +1637,7 @@ pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precisi
1584 const exponent_mask = (1 << exponent_bits) - 1;1637 const exponent_mask = (1 << exponent_bits) - 1;
1585 const exponent_bias = (1 << (exponent_bits - 1)) - 1;1638 const exponent_bias = (1 << (exponent_bits - 1)) - 1;
15861639
1587 const as_bits: TU = @bitCast(value);1640 const as_bits: TU = @bitCast(v);
1588 var mantissa = as_bits & mantissa_mask;1641 var mantissa = as_bits & mantissa_mask;
1589 var exponent: i32 = @as(u16, @truncate((as_bits >> mantissa_bits) & exponent_mask));1642 var exponent: i32 = @as(u16, @truncate((as_bits >> mantissa_bits) & exponent_mask));
15901643
...@@ -2239,6 +2292,10 @@ pub const Discarding = struct {...@@ -2239,6 +2292,10 @@ pub const Discarding = struct {
22392292
2240 pub fn sendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize {2293 pub fn sendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize {
2241 if (File.Handle == void) return error.Unimplemented;2294 if (File.Handle == void) return error.Unimplemented;
2295 switch (builtin.zig_backend) {
2296 else => {},
2297 .stage2_aarch64 => return error.Unimplemented,
2298 }
2242 const d: *Discarding = @alignCast(@fieldParentPtr("writer", w));2299 const d: *Discarding = @alignCast(@fieldParentPtr("writer", w));
2243 d.count += w.end;2300 d.count += w.end;
2244 w.end = 0;2301 w.end = 0;
lib/std/Io/buffered_atomic_file.zig deleted-55
...@@ -1,55 +0,0 @@
1const std = @import("../std.zig");
2const mem = std.mem;
3const fs = std.fs;
4const File = std.fs.File;
5
6pub const BufferedAtomicFile = struct {
7 atomic_file: fs.AtomicFile,
8 file_writer: File.Writer,
9 buffered_writer: BufferedWriter,
10 allocator: mem.Allocator,
11
12 pub const buffer_size = 4096;
13 pub const BufferedWriter = std.io.BufferedWriter(buffer_size, File.Writer);
14 pub const Writer = std.io.GenericWriter(*BufferedWriter, BufferedWriter.Error, BufferedWriter.write);
15
16 /// TODO when https://github.com/ziglang/zig/issues/2761 is solved
17 /// this API will not need an allocator
18 pub fn create(
19 allocator: mem.Allocator,
20 dir: fs.Dir,
21 dest_path: []const u8,
22 atomic_file_options: fs.Dir.AtomicFileOptions,
23 ) !*BufferedAtomicFile {
24 var self = try allocator.create(BufferedAtomicFile);
25 self.* = BufferedAtomicFile{
26 .atomic_file = undefined,
27 .file_writer = undefined,
28 .buffered_writer = undefined,
29 .allocator = allocator,
30 };
31 errdefer allocator.destroy(self);
32
33 self.atomic_file = try dir.atomicFile(dest_path, atomic_file_options);
34 errdefer self.atomic_file.deinit();
35
36 self.file_writer = self.atomic_file.file.deprecatedWriter();
37 self.buffered_writer = .{ .unbuffered_writer = self.file_writer };
38 return self;
39 }
40
41 /// always call destroy, even after successful finish()
42 pub fn destroy(self: *BufferedAtomicFile) void {
43 self.atomic_file.deinit();
44 self.allocator.destroy(self);
45 }
46
47 pub fn finish(self: *BufferedAtomicFile) !void {
48 try self.buffered_writer.flush();
49 try self.atomic_file.finish();
50 }
51
52 pub fn writer(self: *BufferedAtomicFile) Writer {
53 return .{ .context = &self.buffered_writer };
54 }
55};
lib/std/Io/c_writer.zig deleted-44
...@@ -1,44 +0,0 @@
1const std = @import("../std.zig");
2const builtin = @import("builtin");
3const io = std.io;
4const testing = std.testing;
5
6pub const CWriter = io.GenericWriter(*std.c.FILE, std.fs.File.WriteError, cWriterWrite);
7
8pub fn cWriter(c_file: *std.c.FILE) CWriter {
9 return .{ .context = c_file };
10}
11
12fn cWriterWrite(c_file: *std.c.FILE, bytes: []const u8) std.fs.File.WriteError!usize {
13 const amt_written = std.c.fwrite(bytes.ptr, 1, bytes.len, c_file);
14 if (amt_written >= 0) return amt_written;
15 switch (@as(std.c.E, @enumFromInt(std.c._errno().*))) {
16 .SUCCESS => unreachable,
17 .INVAL => unreachable,
18 .FAULT => unreachable,
19 .AGAIN => unreachable, // this is a blocking API
20 .BADF => unreachable, // always a race condition
21 .DESTADDRREQ => unreachable, // connect was never called
22 .DQUOT => return error.DiskQuota,
23 .FBIG => return error.FileTooBig,
24 .IO => return error.InputOutput,
25 .NOSPC => return error.NoSpaceLeft,
26 .PERM => return error.PermissionDenied,
27 .PIPE => return error.BrokenPipe,
28 else => |err| return std.posix.unexpectedErrno(err),
29 }
30}
31
32test cWriter {
33 if (!builtin.link_libc or builtin.os.tag == .wasi) return error.SkipZigTest;
34
35 const filename = "tmp_io_test_file.txt";
36 const out_file = std.c.fopen(filename, "w") orelse return error.UnableToOpenTestFile;
37 defer {
38 _ = std.c.fclose(out_file);
39 std.fs.cwd().deleteFileZ(filename) catch {};
40 }
41
42 const writer = cWriter(out_file);
43 try writer.print("hi: {}\n", .{@as(i32, 123)});
44}
lib/std/Io/change_detection_stream.zig deleted-55
...@@ -1,55 +0,0 @@
1const std = @import("../std.zig");
2const io = std.io;
3const mem = std.mem;
4const assert = std.debug.assert;
5
6/// Used to detect if the data written to a stream differs from a source buffer
7pub fn ChangeDetectionStream(comptime WriterType: type) type {
8 return struct {
9 const Self = @This();
10 pub const Error = WriterType.Error;
11 pub const Writer = io.GenericWriter(*Self, Error, write);
12
13 anything_changed: bool,
14 underlying_writer: WriterType,
15 source_index: usize,
16 source: []const u8,
17
18 pub fn writer(self: *Self) Writer {
19 return .{ .context = self };
20 }
21
22 fn write(self: *Self, bytes: []const u8) Error!usize {
23 if (!self.anything_changed) {
24 const end = self.source_index + bytes.len;
25 if (end > self.source.len) {
26 self.anything_changed = true;
27 } else {
28 const src_slice = self.source[self.source_index..end];
29 self.source_index += bytes.len;
30 if (!mem.eql(u8, bytes, src_slice)) {
31 self.anything_changed = true;
32 }
33 }
34 }
35
36 return self.underlying_writer.write(bytes);
37 }
38
39 pub fn changeDetected(self: *Self) bool {
40 return self.anything_changed or (self.source_index != self.source.len);
41 }
42 };
43}
44
45pub fn changeDetectionStream(
46 source: []const u8,
47 underlying_writer: anytype,
48) ChangeDetectionStream(@TypeOf(underlying_writer)) {
49 return ChangeDetectionStream(@TypeOf(underlying_writer)){
50 .anything_changed = false,
51 .underlying_writer = underlying_writer,
52 .source_index = 0,
53 .source = source,
54 };
55}
lib/std/Io/find_byte_writer.zig deleted-40
...@@ -1,40 +0,0 @@
1const std = @import("../std.zig");
2const io = std.io;
3const 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.
7pub 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
34pub 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/Io/multi_writer.zig deleted-53
...@@ -1,53 +0,0 @@
1const std = @import("../std.zig");
2const io = std.io;
3
4/// Takes a tuple of streams, and constructs a new stream that writes to all of them
5pub fn MultiWriter(comptime Writers: type) type {
6 comptime var ErrSet = error{};
7 inline for (@typeInfo(Writers).@"struct".fields) |field| {
8 const StreamType = field.type;
9 ErrSet = ErrSet || StreamType.Error;
10 }
11
12 return struct {
13 const Self = @This();
14
15 streams: Writers,
16
17 pub const Error = ErrSet;
18 pub const Writer = io.GenericWriter(*Self, Error, write);
19
20 pub fn writer(self: *Self) Writer {
21 return .{ .context = self };
22 }
23
24 pub fn write(self: *Self, bytes: []const u8) Error!usize {
25 inline for (self.streams) |stream|
26 try stream.writeAll(bytes);
27 return bytes.len;
28 }
29 };
30}
31
32pub fn multiWriter(streams: anytype) MultiWriter(@TypeOf(streams)) {
33 return .{ .streams = streams };
34}
35
36const testing = std.testing;
37
38test "MultiWriter" {
39 var tmp = testing.tmpDir(.{});
40 defer tmp.cleanup();
41 var f = try tmp.dir.createFile("t.txt", .{});
42
43 var buf1: [255]u8 = undefined;
44 var fbs1 = io.fixedBufferStream(&buf1);
45 var buf2: [255]u8 = undefined;
46 var stream = multiWriter(.{ fbs1.writer(), f.writer() });
47
48 try stream.writer().print("HI", .{});
49 f.close();
50
51 try testing.expectEqualSlices(u8, "HI", fbs1.getWritten());
52 try testing.expectEqualSlices(u8, "HI", try tmp.dir.readFile("t.txt", &buf2));
53}
lib/std/Io/stream_source.zig deleted-127
...@@ -1,127 +0,0 @@
1const std = @import("../std.zig");
2const builtin = @import("builtin");
3const io = std.io;
4
5/// Provides `io.GenericReader`, `io.GenericWriter`, and `io.SeekableStream` for in-memory buffers as
6/// well as files.
7/// For memory sources, if the supplied byte buffer is const, then `io.GenericWriter` is not available.
8/// The error set of the stream functions is the error set of the corresponding file functions.
9pub const StreamSource = union(enum) {
10 // TODO: expose UEFI files to std.os in a way that allows this to be true
11 const has_file = (builtin.os.tag != .freestanding and builtin.os.tag != .uefi);
12
13 /// The stream access is redirected to this buffer.
14 buffer: io.FixedBufferStream([]u8),
15
16 /// The stream access is redirected to this buffer.
17 /// Writing to the source will always yield `error.AccessDenied`.
18 const_buffer: io.FixedBufferStream([]const u8),
19
20 /// The stream access is redirected to this file.
21 /// On freestanding, this must never be initialized!
22 file: if (has_file) std.fs.File else void,
23
24 pub const ReadError = io.FixedBufferStream([]u8).ReadError || (if (has_file) std.fs.File.ReadError else error{});
25 pub const WriteError = error{AccessDenied} || io.FixedBufferStream([]u8).WriteError || (if (has_file) std.fs.File.WriteError else error{});
26 pub const SeekError = io.FixedBufferStream([]u8).SeekError || (if (has_file) std.fs.File.SeekError else error{});
27 pub const GetSeekPosError = io.FixedBufferStream([]u8).GetSeekPosError || (if (has_file) std.fs.File.GetSeekPosError else error{});
28
29 pub const Reader = io.GenericReader(*StreamSource, ReadError, read);
30 pub const Writer = io.GenericWriter(*StreamSource, WriteError, write);
31 pub const SeekableStream = io.SeekableStream(
32 *StreamSource,
33 SeekError,
34 GetSeekPosError,
35 seekTo,
36 seekBy,
37 getPos,
38 getEndPos,
39 );
40
41 pub fn read(self: *StreamSource, dest: []u8) ReadError!usize {
42 switch (self.*) {
43 .buffer => |*x| return x.read(dest),
44 .const_buffer => |*x| return x.read(dest),
45 .file => |x| if (!has_file) unreachable else return x.read(dest),
46 }
47 }
48
49 pub fn write(self: *StreamSource, bytes: []const u8) WriteError!usize {
50 switch (self.*) {
51 .buffer => |*x| return x.write(bytes),
52 .const_buffer => return error.AccessDenied,
53 .file => |x| if (!has_file) unreachable else return x.write(bytes),
54 }
55 }
56
57 pub fn seekTo(self: *StreamSource, pos: u64) SeekError!void {
58 switch (self.*) {
59 .buffer => |*x| return x.seekTo(pos),
60 .const_buffer => |*x| return x.seekTo(pos),
61 .file => |x| if (!has_file) unreachable else return x.seekTo(pos),
62 }
63 }
64
65 pub fn seekBy(self: *StreamSource, amt: i64) SeekError!void {
66 switch (self.*) {
67 .buffer => |*x| return x.seekBy(amt),
68 .const_buffer => |*x| return x.seekBy(amt),
69 .file => |x| if (!has_file) unreachable else return x.seekBy(amt),
70 }
71 }
72
73 pub fn getEndPos(self: *StreamSource) GetSeekPosError!u64 {
74 switch (self.*) {
75 .buffer => |*x| return x.getEndPos(),
76 .const_buffer => |*x| return x.getEndPos(),
77 .file => |x| if (!has_file) unreachable else return x.getEndPos(),
78 }
79 }
80
81 pub fn getPos(self: *StreamSource) GetSeekPosError!u64 {
82 switch (self.*) {
83 .buffer => |*x| return x.getPos(),
84 .const_buffer => |*x| return x.getPos(),
85 .file => |x| if (!has_file) unreachable else return x.getPos(),
86 }
87 }
88
89 pub fn reader(self: *StreamSource) Reader {
90 return .{ .context = self };
91 }
92
93 pub fn writer(self: *StreamSource) Writer {
94 return .{ .context = self };
95 }
96
97 pub fn seekableStream(self: *StreamSource) SeekableStream {
98 return .{ .context = self };
99 }
100};
101
102test "refs" {
103 std.testing.refAllDecls(StreamSource);
104}
105
106test "mutable buffer" {
107 var buffer: [64]u8 = undefined;
108 var source = StreamSource{ .buffer = std.io.fixedBufferStream(&buffer) };
109
110 var writer = source.writer();
111
112 try writer.writeAll("Hello, World!");
113
114 try std.testing.expectEqualStrings("Hello, World!", source.buffer.getWritten());
115}
116
117test "const buffer" {
118 const buffer: [64]u8 = "Hello, World!".* ++ ([1]u8{0xAA} ** 51);
119 var source = StreamSource{ .const_buffer = std.io.fixedBufferStream(&buffer) };
120
121 var reader = source.reader();
122
123 var dst_buffer: [13]u8 = undefined;
124 try reader.readNoEof(&dst_buffer);
125
126 try std.testing.expectEqualStrings("Hello, World!", &dst_buffer);
127}
lib/std/Progress.zig+73-2
...@@ -25,6 +25,7 @@ redraw_event: std.Thread.ResetEvent,...@@ -25,6 +25,7 @@ redraw_event: std.Thread.ResetEvent,
25/// Accessed atomically.25/// Accessed atomically.
26done: bool,26done: bool,
27need_clear: bool,27need_clear: bool,
28status: Status,
2829
29refresh_rate_ns: u64,30refresh_rate_ns: u64,
30initial_delay_ns: u64,31initial_delay_ns: u64,
...@@ -47,6 +48,22 @@ node_freelist: Freelist,...@@ -47,6 +48,22 @@ node_freelist: Freelist,
47/// value may at times temporarily exceed the node count.48/// value may at times temporarily exceed the node count.
48node_end_index: u32,49node_end_index: u32,
4950
51pub const Status = enum {
52 /// Indicates the application is progressing towards completion of a task.
53 /// Unless the application is interactive, this is the only status the
54 /// program will ever have!
55 working,
56 /// The application has completed an operation, and is now waiting for user
57 /// input rather than calling exit(0).
58 success,
59 /// The application encountered an error, and is now waiting for user input
60 /// rather than calling exit(1).
61 failure,
62 /// The application encountered at least one error, but is still working on
63 /// more tasks.
64 failure_working,
65};
66
50const Freelist = packed struct(u32) {67const Freelist = packed struct(u32) {
51 head: Node.OptionalIndex,68 head: Node.OptionalIndex,
52 /// Whenever `node_freelist` is added to, this generation is incremented69 /// Whenever `node_freelist` is added to, this generation is incremented
...@@ -383,6 +400,7 @@ var global_progress: Progress = .{...@@ -383,6 +400,7 @@ var global_progress: Progress = .{
383 .draw_buffer = undefined,400 .draw_buffer = undefined,
384 .done = false,401 .done = false,
385 .need_clear = false,402 .need_clear = false,
403 .status = .working,
386404
387 .node_parents = &node_parents_buffer,405 .node_parents = &node_parents_buffer,
388 .node_storage = &node_storage_buffer,406 .node_storage = &node_storage_buffer,
...@@ -408,6 +426,9 @@ pub const have_ipc = switch (builtin.os.tag) {...@@ -408,6 +426,9 @@ pub const have_ipc = switch (builtin.os.tag) {
408const noop_impl = builtin.single_threaded or switch (builtin.os.tag) {426const noop_impl = builtin.single_threaded or switch (builtin.os.tag) {
409 .wasi, .freestanding => true,427 .wasi, .freestanding => true,
410 else => false,428 else => false,
429} or switch (builtin.zig_backend) {
430 .stage2_aarch64 => true,
431 else => false,
411};432};
412433
413/// Initializes a global Progress instance.434/// Initializes a global Progress instance.
...@@ -495,6 +516,11 @@ pub fn start(options: Options) Node {...@@ -495,6 +516,11 @@ pub fn start(options: Options) Node {
495 return root_node;516 return root_node;
496}517}
497518
519pub fn setStatus(new_status: Status) void {
520 if (noop_impl) return;
521 @atomicStore(Status, &global_progress.status, new_status, .monotonic);
522}
523
498/// Returns whether a resize is needed to learn the terminal size.524/// Returns whether a resize is needed to learn the terminal size.
499fn wait(timeout_ns: u64) bool {525fn wait(timeout_ns: u64) bool {
500 const resize_flag = if (global_progress.redraw_event.timedWait(timeout_ns)) |_|526 const resize_flag = if (global_progress.redraw_event.timedWait(timeout_ns)) |_|
...@@ -675,6 +701,14 @@ const save = "\x1b7";...@@ -675,6 +701,14 @@ const save = "\x1b7";
675const restore = "\x1b8";701const restore = "\x1b8";
676const finish_sync = "\x1b[?2026l";702const finish_sync = "\x1b[?2026l";
677703
704const progress_remove = "\x1b]9;4;0\x07";
705const @"progress_normal {d}" = "\x1b]9;4;1;{d}\x07";
706const @"progress_error {d}" = "\x1b]9;4;2;{d}\x07";
707const progress_pulsing = "\x1b]9;4;3\x07";
708const progress_pulsing_error = "\x1b]9;4;2\x07";
709const progress_normal_100 = "\x1b]9;4;1;100\x07";
710const progress_error_100 = "\x1b]9;4;2;100\x07";
711
678const TreeSymbol = enum {712const TreeSymbol = enum {
679 /// ├─713 /// ├─
680 tee,714 tee,
...@@ -754,10 +788,10 @@ fn appendTreeSymbol(symbol: TreeSymbol, buf: []u8, start_i: usize) usize {...@@ -754,10 +788,10 @@ fn appendTreeSymbol(symbol: TreeSymbol, buf: []u8, start_i: usize) usize {
754}788}
755789
756fn clearWrittenWithEscapeCodes() anyerror!void {790fn clearWrittenWithEscapeCodes() anyerror!void {
757 if (!global_progress.need_clear) return;791 if (noop_impl or !global_progress.need_clear) return;
758792
759 global_progress.need_clear = false;793 global_progress.need_clear = false;
760 try write(clear);794 try write(clear ++ progress_remove);
761}795}
762796
763/// U+25BA or â–º797/// U+25BA or â–º
...@@ -1200,6 +1234,43 @@ fn computeRedraw(serialized_buffer: *Serialized.Buffer) struct { []u8, usize } {...@@ -1200,6 +1234,43 @@ fn computeRedraw(serialized_buffer: *Serialized.Buffer) struct { []u8, usize } {
1200 i, const nl_n = computeNode(buf, i, 0, serialized, children, root_node_index);1234 i, const nl_n = computeNode(buf, i, 0, serialized, children, root_node_index);
12011235
1202 if (global_progress.terminal_mode == .ansi_escape_codes) {1236 if (global_progress.terminal_mode == .ansi_escape_codes) {
1237 {
1238 // Set progress state https://conemu.github.io/en/AnsiEscapeCodes.html#ConEmu_specific_OSC
1239 const root_storage = &serialized.storage[0];
1240 const storage = if (root_storage.name[0] != 0 or children[0].child == .none) root_storage else &serialized.storage[@intFromEnum(children[0].child)];
1241 const estimated_total = storage.estimated_total_count;
1242 const completed_items = storage.completed_count;
1243 const status = @atomicLoad(Status, &global_progress.status, .monotonic);
1244 switch (status) {
1245 .working => {
1246 if (estimated_total == 0) {
1247 buf[i..][0..progress_pulsing.len].* = progress_pulsing.*;
1248 i += progress_pulsing.len;
1249 } else {
1250 const percent = completed_items * 100 / estimated_total;
1251 i += (std.fmt.bufPrint(buf[i..], @"progress_normal {d}", .{percent}) catch &.{}).len;
1252 }
1253 },
1254 .success => {
1255 buf[i..][0..progress_remove.len].* = progress_remove.*;
1256 i += progress_remove.len;
1257 },
1258 .failure => {
1259 buf[i..][0..progress_error_100.len].* = progress_error_100.*;
1260 i += progress_error_100.len;
1261 },
1262 .failure_working => {
1263 if (estimated_total == 0) {
1264 buf[i..][0..progress_pulsing_error.len].* = progress_pulsing_error.*;
1265 i += progress_pulsing_error.len;
1266 } else {
1267 const percent = completed_items * 100 / estimated_total;
1268 i += (std.fmt.bufPrint(buf[i..], @"progress_error {d}", .{percent}) catch &.{}).len;
1269 }
1270 },
1271 }
1272 }
1273
1203 if (nl_n > 0) {1274 if (nl_n > 0) {
1204 buf[i] = '\r';1275 buf[i] = '\r';
1205 i += 1;1276 i += 1;
lib/std/builtin.zig+5-2
...@@ -772,7 +772,7 @@ pub const Endian = enum {...@@ -772,7 +772,7 @@ pub const Endian = enum {
772772
773/// This data structure is used by the Zig language code generation and773/// This data structure is used by the Zig language code generation and
774/// therefore must be kept in sync with the compiler implementation.774/// therefore must be kept in sync with the compiler implementation.
775pub const Signedness = enum {775pub const Signedness = enum(u1) {
776 signed,776 signed,
777 unsigned,777 unsigned,
778};778};
...@@ -894,7 +894,10 @@ pub const VaList = switch (builtin.cpu.arch) {...@@ -894,7 +894,10 @@ pub const VaList = switch (builtin.cpu.arch) {
894 .aarch64, .aarch64_be => switch (builtin.os.tag) {894 .aarch64, .aarch64_be => switch (builtin.os.tag) {
895 .windows => *u8,895 .windows => *u8,
896 .ios, .macos, .tvos, .watchos, .visionos => *u8,896 .ios, .macos, .tvos, .watchos, .visionos => *u8,
897 else => @compileError("disabled due to miscompilations"), // VaListAarch64,897 else => switch (builtin.zig_backend) {
898 .stage2_aarch64 => VaListAarch64,
899 else => @compileError("disabled due to miscompilations"),
900 },
898 },901 },
899 .arm, .armeb, .thumb, .thumbeb => switch (builtin.os.tag) {902 .arm, .armeb, .thumb, .thumbeb => switch (builtin.os.tag) {
900 .ios, .macos, .tvos, .watchos, .visionos => *u8,903 .ios, .macos, .tvos, .watchos, .visionos => *u8,
lib/std/c.zig+3-3
...@@ -7147,7 +7147,7 @@ pub const dirent = switch (native_os) {...@@ -7147,7 +7147,7 @@ pub const dirent = switch (native_os) {
7147 off: off_t,7147 off: off_t,
7148 reclen: c_ushort,7148 reclen: c_ushort,
7149 type: u8,7149 type: u8,
7150 name: [256:0]u8,7150 name: [255:0]u8,
7151 },7151 },
7152 else => void,7152 else => void,
7153};7153};
...@@ -10497,9 +10497,9 @@ pub const sysconf = switch (native_os) {...@@ -10497,9 +10497,9 @@ pub const sysconf = switch (native_os) {
1049710497
10498pub const sf_hdtr = switch (native_os) {10498pub const sf_hdtr = switch (native_os) {
10499 .freebsd, .macos, .ios, .tvos, .watchos, .visionos => extern struct {10499 .freebsd, .macos, .ios, .tvos, .watchos, .visionos => extern struct {
10500 headers: [*]const iovec_const,10500 headers: ?[*]const iovec_const,
10501 hdr_cnt: c_int,10501 hdr_cnt: c_int,
10502 trailers: [*]const iovec_const,10502 trailers: ?[*]const iovec_const,
10503 trl_cnt: c_int,10503 trl_cnt: c_int,
10504 },10504 },
10505 else => void,10505 else => void,
lib/std/compress.zig+2-58
...@@ -1,75 +1,19 @@...@@ -1,75 +1,19 @@
1//! Compression algorithms.1//! Compression algorithms.
22
3const std = @import("std.zig");
4
5pub const flate = @import("compress/flate.zig");3pub const flate = @import("compress/flate.zig");
6pub const gzip = @import("compress/gzip.zig");4pub const gzip = @import("compress/gzip.zig");
7pub const zlib = @import("compress/zlib.zig");5pub const zlib = @import("compress/zlib.zig");
8pub const lzma = @import("compress/lzma.zig");6pub const lzma = @import("compress/lzma.zig");
9pub const lzma2 = @import("compress/lzma2.zig");7pub const lzma2 = @import("compress/lzma2.zig");
10pub const xz = @import("compress/xz.zig");8pub const xz = @import("compress/xz.zig");
11pub const zstd = @import("compress/zstandard.zig");9pub const zstd = @import("compress/zstd.zig");
12
13pub fn HashedReader(ReaderType: type, HasherType: type) type {
14 return struct {
15 child_reader: ReaderType,
16 hasher: HasherType,
17
18 pub const Error = ReaderType.Error;
19 pub const Reader = std.io.GenericReader(*@This(), Error, read);
20
21 pub fn read(self: *@This(), buf: []u8) Error!usize {
22 const amt = try self.child_reader.read(buf);
23 self.hasher.update(buf[0..amt]);
24 return amt;
25 }
26
27 pub fn reader(self: *@This()) Reader {
28 return .{ .context = self };
29 }
30 };
31}
32
33pub fn hashedReader(
34 reader: anytype,
35 hasher: anytype,
36) HashedReader(@TypeOf(reader), @TypeOf(hasher)) {
37 return .{ .child_reader = reader, .hasher = hasher };
38}
39
40pub fn HashedWriter(WriterType: type, HasherType: type) type {
41 return struct {
42 child_writer: WriterType,
43 hasher: HasherType,
44
45 pub const Error = WriterType.Error;
46 pub const Writer = std.io.GenericWriter(*@This(), Error, write);
47
48 pub fn write(self: *@This(), buf: []const u8) Error!usize {
49 const amt = try self.child_writer.write(buf);
50 self.hasher.update(buf[0..amt]);
51 return amt;
52 }
53
54 pub fn writer(self: *@This()) Writer {
55 return .{ .context = self };
56 }
57 };
58}
59
60pub fn hashedWriter(
61 writer: anytype,
62 hasher: anytype,
63) HashedWriter(@TypeOf(writer), @TypeOf(hasher)) {
64 return .{ .child_writer = writer, .hasher = hasher };
65}
6610
67test {11test {
12 _ = flate;
68 _ = lzma;13 _ = lzma;
69 _ = lzma2;14 _ = lzma2;
70 _ = xz;15 _ = xz;
71 _ = zstd;16 _ = zstd;
72 _ = flate;
73 _ = gzip;17 _ = gzip;
74 _ = zlib;18 _ = zlib;
75}19}
lib/std/compress/xz.zig+35-14
...@@ -12,17 +12,11 @@ pub const Check = enum(u4) {...@@ -12,17 +12,11 @@ pub const Check = enum(u4) {
12};12};
1313
14fn readStreamFlags(reader: anytype, check: *Check) !void {14fn readStreamFlags(reader: anytype, check: *Check) !void {
15 var bit_reader = std.io.bitReader(.little, reader);15 const reserved1 = try reader.readByte();
1616 if (reserved1 != 0) return error.CorruptInput;
17 const reserved1 = try bit_reader.readBitsNoEof(u8, 8);17 const byte = try reader.readByte();
18 if (reserved1 != 0)18 if ((byte >> 4) != 0) return error.CorruptInput;
19 return error.CorruptInput;19 check.* = @enumFromInt(@as(u4, @truncate(byte)));
20
21 check.* = @as(Check, @enumFromInt(try bit_reader.readBitsNoEof(u4, 4)));
22
23 const reserved2 = try bit_reader.readBitsNoEof(u4, 4);
24 if (reserved2 != 0)
25 return error.CorruptInput;
26}20}
2721
28pub fn decompress(allocator: Allocator, reader: anytype) !Decompress(@TypeOf(reader)) {22pub fn decompress(allocator: Allocator, reader: anytype) !Decompress(@TypeOf(reader)) {
...@@ -47,7 +41,7 @@ pub fn Decompress(comptime ReaderType: type) type {...@@ -47,7 +41,7 @@ pub fn Decompress(comptime ReaderType: type) type {
4741
48 var check: Check = undefined;42 var check: Check = undefined;
49 const hash_a = blk: {43 const hash_a = blk: {
50 var hasher = std.compress.hashedReader(source, Crc32.init());44 var hasher = hashedReader(source, Crc32.init());
51 try readStreamFlags(hasher.reader(), &check);45 try readStreamFlags(hasher.reader(), &check);
52 break :blk hasher.hasher.final();46 break :blk hasher.hasher.final();
53 };47 };
...@@ -80,7 +74,7 @@ pub fn Decompress(comptime ReaderType: type) type {...@@ -80,7 +74,7 @@ pub fn Decompress(comptime ReaderType: type) type {
80 return r;74 return r;
8175
82 const index_size = blk: {76 const index_size = blk: {
83 var hasher = std.compress.hashedReader(self.in_reader, Crc32.init());77 var hasher = hashedReader(self.in_reader, Crc32.init());
84 hasher.hasher.update(&[1]u8{0x00});78 hasher.hasher.update(&[1]u8{0x00});
8579
86 var counter = std.io.countingReader(hasher.reader());80 var counter = std.io.countingReader(hasher.reader());
...@@ -115,7 +109,7 @@ pub fn Decompress(comptime ReaderType: type) type {...@@ -115,7 +109,7 @@ pub fn Decompress(comptime ReaderType: type) type {
115 const hash_a = try self.in_reader.readInt(u32, .little);109 const hash_a = try self.in_reader.readInt(u32, .little);
116110
117 const hash_b = blk: {111 const hash_b = blk: {
118 var hasher = std.compress.hashedReader(self.in_reader, Crc32.init());112 var hasher = hashedReader(self.in_reader, Crc32.init());
119 const hashed_reader = hasher.reader();113 const hashed_reader = hasher.reader();
120114
121 const backward_size = (@as(u64, try hashed_reader.readInt(u32, .little)) + 1) * 4;115 const backward_size = (@as(u64, try hashed_reader.readInt(u32, .little)) + 1) * 4;
...@@ -140,6 +134,33 @@ pub fn Decompress(comptime ReaderType: type) type {...@@ -140,6 +134,33 @@ pub fn Decompress(comptime ReaderType: type) type {
140 };134 };
141}135}
142136
137pub fn HashedReader(ReaderType: type, HasherType: type) type {
138 return struct {
139 child_reader: ReaderType,
140 hasher: HasherType,
141
142 pub const Error = ReaderType.Error;
143 pub const Reader = std.io.GenericReader(*@This(), Error, read);
144
145 pub fn read(self: *@This(), buf: []u8) Error!usize {
146 const amt = try self.child_reader.read(buf);
147 self.hasher.update(buf[0..amt]);
148 return amt;
149 }
150
151 pub fn reader(self: *@This()) Reader {
152 return .{ .context = self };
153 }
154 };
155}
156
157pub fn hashedReader(
158 reader: anytype,
159 hasher: anytype,
160) HashedReader(@TypeOf(reader), @TypeOf(hasher)) {
161 return .{ .child_reader = reader, .hasher = hasher };
162}
163
143test {164test {
144 _ = @import("xz/test.zig");165 _ = @import("xz/test.zig");
145}166}
lib/std/compress/xz/block.zig+1-1
...@@ -91,7 +91,7 @@ pub fn Decoder(comptime ReaderType: type) type {...@@ -91,7 +91,7 @@ pub fn Decoder(comptime ReaderType: type) type {
9191
92 // Block Header92 // Block Header
93 {93 {
94 var header_hasher = std.compress.hashedReader(block_reader, Crc32.init());94 var header_hasher = xz.hashedReader(block_reader, Crc32.init());
95 const header_reader = header_hasher.reader();95 const header_reader = header_hasher.reader();
9696
97 const header_size = @as(u64, try header_reader.readByte()) * 4;97 const header_size = @as(u64, try header_reader.readByte()) * 4;
lib/std/compress/zstandard.zig deleted-310
...@@ -1,310 +0,0 @@
1const std = @import("std");
2const RingBuffer = std.RingBuffer;
3
4const types = @import("zstandard/types.zig");
5pub const frame = types.frame;
6pub const compressed_block = types.compressed_block;
7
8pub const decompress = @import("zstandard/decompress.zig");
9
10pub const DecompressorOptions = struct {
11 verify_checksum: bool = true,
12 window_buffer: []u8,
13
14 /// Recommended amount by the standard. Lower than this may result
15 /// in inability to decompress common streams.
16 pub const default_window_buffer_len = 8 * 1024 * 1024;
17};
18
19pub fn Decompressor(comptime ReaderType: type) type {
20 return struct {
21 const Self = @This();
22
23 const table_size_max = types.compressed_block.table_size_max;
24
25 source: std.io.CountingReader(ReaderType),
26 state: enum { NewFrame, InFrame, LastBlock },
27 decode_state: decompress.block.DecodeState,
28 frame_context: decompress.FrameContext,
29 buffer: WindowBuffer,
30 literal_fse_buffer: [table_size_max.literal]types.compressed_block.Table.Fse,
31 match_fse_buffer: [table_size_max.match]types.compressed_block.Table.Fse,
32 offset_fse_buffer: [table_size_max.offset]types.compressed_block.Table.Fse,
33 literals_buffer: [types.block_size_max]u8,
34 sequence_buffer: [types.block_size_max]u8,
35 verify_checksum: bool,
36 checksum: ?u32,
37 current_frame_decompressed_size: usize,
38
39 const WindowBuffer = struct {
40 data: []u8 = undefined,
41 read_index: usize = 0,
42 write_index: usize = 0,
43 };
44
45 pub const Error = ReaderType.Error || error{
46 ChecksumFailure,
47 DictionaryIdFlagUnsupported,
48 MalformedBlock,
49 MalformedFrame,
50 OutOfMemory,
51 };
52
53 pub const Reader = std.io.GenericReader(*Self, Error, read);
54
55 pub fn init(source: ReaderType, options: DecompressorOptions) Self {
56 return .{
57 .source = std.io.countingReader(source),
58 .state = .NewFrame,
59 .decode_state = undefined,
60 .frame_context = undefined,
61 .buffer = .{ .data = options.window_buffer },
62 .literal_fse_buffer = undefined,
63 .match_fse_buffer = undefined,
64 .offset_fse_buffer = undefined,
65 .literals_buffer = undefined,
66 .sequence_buffer = undefined,
67 .verify_checksum = options.verify_checksum,
68 .checksum = undefined,
69 .current_frame_decompressed_size = undefined,
70 };
71 }
72
73 fn frameInit(self: *Self) !void {
74 const source_reader = self.source.reader();
75 switch (try decompress.decodeFrameHeader(source_reader)) {
76 .skippable => |header| {
77 try source_reader.skipBytes(header.frame_size, .{});
78 self.state = .NewFrame;
79 },
80 .zstandard => |header| {
81 const frame_context = try decompress.FrameContext.init(
82 header,
83 self.buffer.data.len,
84 self.verify_checksum,
85 );
86
87 const decode_state = decompress.block.DecodeState.init(
88 &self.literal_fse_buffer,
89 &self.match_fse_buffer,
90 &self.offset_fse_buffer,
91 );
92
93 self.decode_state = decode_state;
94 self.frame_context = frame_context;
95
96 self.checksum = null;
97 self.current_frame_decompressed_size = 0;
98
99 self.state = .InFrame;
100 },
101 }
102 }
103
104 pub fn reader(self: *Self) Reader {
105 return .{ .context = self };
106 }
107
108 pub fn read(self: *Self, buffer: []u8) Error!usize {
109 if (buffer.len == 0) return 0;
110
111 var size: usize = 0;
112 while (size == 0) {
113 while (self.state == .NewFrame) {
114 const initial_count = self.source.bytes_read;
115 self.frameInit() catch |err| switch (err) {
116 error.DictionaryIdFlagUnsupported => return error.DictionaryIdFlagUnsupported,
117 error.EndOfStream => return if (self.source.bytes_read == initial_count)
118 0
119 else
120 error.MalformedFrame,
121 else => return error.MalformedFrame,
122 };
123 }
124 size = try self.readInner(buffer);
125 }
126 return size;
127 }
128
129 fn readInner(self: *Self, buffer: []u8) Error!usize {
130 std.debug.assert(self.state != .NewFrame);
131
132 var ring_buffer = RingBuffer{
133 .data = self.buffer.data,
134 .read_index = self.buffer.read_index,
135 .write_index = self.buffer.write_index,
136 };
137 defer {
138 self.buffer.read_index = ring_buffer.read_index;
139 self.buffer.write_index = ring_buffer.write_index;
140 }
141
142 const source_reader = self.source.reader();
143 while (ring_buffer.isEmpty() and self.state != .LastBlock) {
144 const header_bytes = source_reader.readBytesNoEof(3) catch
145 return error.MalformedFrame;
146 const block_header = decompress.block.decodeBlockHeader(&header_bytes);
147
148 decompress.block.decodeBlockReader(
149 &ring_buffer,
150 source_reader,
151 block_header,
152 &self.decode_state,
153 self.frame_context.block_size_max,
154 &self.literals_buffer,
155 &self.sequence_buffer,
156 ) catch
157 return error.MalformedBlock;
158
159 if (self.frame_context.content_size) |size| {
160 if (self.current_frame_decompressed_size > size) return error.MalformedFrame;
161 }
162
163 const size = ring_buffer.len();
164 self.current_frame_decompressed_size += size;
165
166 if (self.frame_context.hasher_opt) |*hasher| {
167 if (size > 0) {
168 const written_slice = ring_buffer.sliceLast(size);
169 hasher.update(written_slice.first);
170 hasher.update(written_slice.second);
171 }
172 }
173 if (block_header.last_block) {
174 self.state = .LastBlock;
175 if (self.frame_context.has_checksum) {
176 const checksum = source_reader.readInt(u32, .little) catch
177 return error.MalformedFrame;
178 if (self.verify_checksum) {
179 if (self.frame_context.hasher_opt) |*hasher| {
180 if (checksum != decompress.computeChecksum(hasher))
181 return error.ChecksumFailure;
182 }
183 }
184 }
185 if (self.frame_context.content_size) |content_size| {
186 if (content_size != self.current_frame_decompressed_size) {
187 return error.MalformedFrame;
188 }
189 }
190 }
191 }
192
193 const size = @min(ring_buffer.len(), buffer.len);
194 if (size > 0) {
195 ring_buffer.readFirstAssumeLength(buffer, size);
196 }
197 if (self.state == .LastBlock and ring_buffer.len() == 0) {
198 self.state = .NewFrame;
199 }
200 return size;
201 }
202 };
203}
204
205pub fn decompressor(reader: anytype, options: DecompressorOptions) Decompressor(@TypeOf(reader)) {
206 return Decompressor(@TypeOf(reader)).init(reader, options);
207}
208
209fn testDecompress(data: []const u8) ![]u8 {
210 const window_buffer = try std.testing.allocator.alloc(u8, 1 << 23);
211 defer std.testing.allocator.free(window_buffer);
212
213 var in_stream = std.io.fixedBufferStream(data);
214 var zstd_stream = decompressor(in_stream.reader(), .{ .window_buffer = window_buffer });
215 const result = zstd_stream.reader().readAllAlloc(std.testing.allocator, std.math.maxInt(usize));
216 return result;
217}
218
219fn testReader(data: []const u8, comptime expected: []const u8) !void {
220 const buf = try testDecompress(data);
221 defer std.testing.allocator.free(buf);
222 try std.testing.expectEqualSlices(u8, expected, buf);
223}
224
225test "decompression" {
226 const uncompressed = @embedFile("testdata/rfc8478.txt");
227 const compressed3 = @embedFile("testdata/rfc8478.txt.zst.3");
228 const compressed19 = @embedFile("testdata/rfc8478.txt.zst.19");
229
230 const buffer = try std.testing.allocator.alloc(u8, uncompressed.len);
231 defer std.testing.allocator.free(buffer);
232
233 const res3 = try decompress.decode(buffer, compressed3, true);
234 try std.testing.expectEqual(uncompressed.len, res3);
235 try std.testing.expectEqualSlices(u8, uncompressed, buffer);
236
237 @memset(buffer, undefined);
238 const res19 = try decompress.decode(buffer, compressed19, true);
239 try std.testing.expectEqual(uncompressed.len, res19);
240 try std.testing.expectEqualSlices(u8, uncompressed, buffer);
241
242 try testReader(compressed3, uncompressed);
243 try testReader(compressed19, uncompressed);
244}
245
246fn expectEqualDecoded(expected: []const u8, input: []const u8) !void {
247 {
248 const result = try decompress.decodeAlloc(std.testing.allocator, input, false, 1 << 23);
249 defer std.testing.allocator.free(result);
250 try std.testing.expectEqualStrings(expected, result);
251 }
252
253 {
254 var buffer = try std.testing.allocator.alloc(u8, 2 * expected.len);
255 defer std.testing.allocator.free(buffer);
256
257 const size = try decompress.decode(buffer, input, false);
258 try std.testing.expectEqualStrings(expected, buffer[0..size]);
259 }
260}
261
262fn expectEqualDecodedStreaming(expected: []const u8, input: []const u8) !void {
263 const window_buffer = try std.testing.allocator.alloc(u8, 1 << 23);
264 defer std.testing.allocator.free(window_buffer);
265
266 var in_stream = std.io.fixedBufferStream(input);
267 var stream = decompressor(in_stream.reader(), .{ .window_buffer = window_buffer });
268
269 const result = try stream.reader().readAllAlloc(std.testing.allocator, std.math.maxInt(usize));
270 defer std.testing.allocator.free(result);
271
272 try std.testing.expectEqualStrings(expected, result);
273}
274
275test "zero sized block" {
276 const input_raw =
277 "\x28\xb5\x2f\xfd" ++ // zstandard frame magic number
278 "\x20\x00" ++ // frame header: only single_segment_flag set, frame_content_size zero
279 "\x01\x00\x00"; // block header with: last_block set, block_type raw, block_size zero
280
281 const input_rle =
282 "\x28\xb5\x2f\xfd" ++ // zstandard frame magic number
283 "\x20\x00" ++ // frame header: only single_segment_flag set, frame_content_size zero
284 "\x03\x00\x00" ++ // block header with: last_block set, block_type rle, block_size zero
285 "\xaa"; // block_content
286
287 try expectEqualDecoded("", input_raw);
288 try expectEqualDecoded("", input_rle);
289 try expectEqualDecodedStreaming("", input_raw);
290 try expectEqualDecodedStreaming("", input_rle);
291}
292
293test "declared raw literals size too large" {
294 const input_raw =
295 "\x28\xb5\x2f\xfd" ++ // zstandard frame magic number
296 "\x00\x00" ++ // frame header: everything unset, window descriptor zero
297 "\x95\x00\x00" ++ // block header with: last_block set, block_type compressed, block_size 18
298 "\xbc\xf3\xae" ++ // literals section header with: type raw, size_format 3, regenerated_size 716603
299 "\xa5\x9f\xe3"; // some bytes of literal content - the content is shorter than regenerated_size
300
301 // Note that the regenerated_size in the above input is larger than block maximum size, so the
302 // block can't be valid as it is a raw literals block.
303
304 var fbs = std.io.fixedBufferStream(input_raw);
305 var window: [1024]u8 = undefined;
306 var stream = decompressor(fbs.reader(), .{ .window_buffer = &window });
307
308 var buf: [1024]u8 = undefined;
309 try std.testing.expectError(error.MalformedBlock, stream.read(&buf));
310}
lib/std/compress/zstandard/decode/block.zig deleted-1149
...@@ -1,1149 +0,0 @@
1const std = @import("std");
2const assert = std.debug.assert;
3const RingBuffer = std.RingBuffer;
4
5const types = @import("../types.zig");
6const frame = types.frame;
7const Table = types.compressed_block.Table;
8const LiteralsSection = types.compressed_block.LiteralsSection;
9const SequencesSection = types.compressed_block.SequencesSection;
10
11const huffman = @import("huffman.zig");
12const readers = @import("../readers.zig");
13
14const decodeFseTable = @import("fse.zig").decodeFseTable;
15
16pub const Error = error{
17 BlockSizeOverMaximum,
18 MalformedBlockSize,
19 ReservedBlock,
20 MalformedRleBlock,
21 MalformedCompressedBlock,
22};
23
24pub const DecodeState = struct {
25 repeat_offsets: [3]u32,
26
27 offset: StateData(8),
28 match: StateData(9),
29 literal: StateData(9),
30
31 offset_fse_buffer: []Table.Fse,
32 match_fse_buffer: []Table.Fse,
33 literal_fse_buffer: []Table.Fse,
34
35 fse_tables_undefined: bool,
36
37 literal_stream_reader: readers.ReverseBitReader,
38 literal_stream_index: usize,
39 literal_streams: LiteralsSection.Streams,
40 literal_header: LiteralsSection.Header,
41 huffman_tree: ?LiteralsSection.HuffmanTree,
42
43 literal_written_count: usize,
44 written_count: usize = 0,
45
46 fn StateData(comptime max_accuracy_log: comptime_int) type {
47 return struct {
48 state: State,
49 table: Table,
50 accuracy_log: u8,
51
52 const State = std.meta.Int(.unsigned, max_accuracy_log);
53 };
54 }
55
56 pub fn init(
57 literal_fse_buffer: []Table.Fse,
58 match_fse_buffer: []Table.Fse,
59 offset_fse_buffer: []Table.Fse,
60 ) DecodeState {
61 return DecodeState{
62 .repeat_offsets = .{
63 types.compressed_block.start_repeated_offset_1,
64 types.compressed_block.start_repeated_offset_2,
65 types.compressed_block.start_repeated_offset_3,
66 },
67
68 .offset = undefined,
69 .match = undefined,
70 .literal = undefined,
71
72 .literal_fse_buffer = literal_fse_buffer,
73 .match_fse_buffer = match_fse_buffer,
74 .offset_fse_buffer = offset_fse_buffer,
75
76 .fse_tables_undefined = true,
77
78 .literal_written_count = 0,
79 .literal_header = undefined,
80 .literal_streams = undefined,
81 .literal_stream_reader = undefined,
82 .literal_stream_index = undefined,
83 .huffman_tree = null,
84
85 .written_count = 0,
86 };
87 }
88
89 /// Prepare the decoder to decode a compressed block. Loads the literals
90 /// stream and Huffman tree from `literals` and reads the FSE tables from
91 /// `source`.
92 ///
93 /// Errors returned:
94 /// - `error.BitStreamHasNoStartBit` if the (reversed) literal bitstream's
95 /// first byte does not have any bits set
96 /// - `error.TreelessLiteralsFirst` `literals` is a treeless literals
97 /// section and the decode state does not have a Huffman tree from a
98 /// previous block
99 /// - `error.RepeatModeFirst` on the first call if one of the sequence FSE
100 /// tables is set to repeat mode
101 /// - `error.MalformedAccuracyLog` if an FSE table has an invalid accuracy
102 /// - `error.MalformedFseTable` if there are errors decoding an FSE table
103 /// - `error.EndOfStream` if `source` ends before all FSE tables are read
104 pub fn prepare(
105 self: *DecodeState,
106 source: anytype,
107 literals: LiteralsSection,
108 sequences_header: SequencesSection.Header,
109 ) !void {
110 self.literal_written_count = 0;
111 self.literal_header = literals.header;
112 self.literal_streams = literals.streams;
113
114 if (literals.huffman_tree) |tree| {
115 self.huffman_tree = tree;
116 } else if (literals.header.block_type == .treeless and self.huffman_tree == null) {
117 return error.TreelessLiteralsFirst;
118 }
119
120 switch (literals.header.block_type) {
121 .raw, .rle => {},
122 .compressed, .treeless => {
123 self.literal_stream_index = 0;
124 switch (literals.streams) {
125 .one => |slice| try self.initLiteralStream(slice),
126 .four => |streams| try self.initLiteralStream(streams[0]),
127 }
128 },
129 }
130
131 if (sequences_header.sequence_count > 0) {
132 try self.updateFseTable(source, .literal, sequences_header.literal_lengths);
133 try self.updateFseTable(source, .offset, sequences_header.offsets);
134 try self.updateFseTable(source, .match, sequences_header.match_lengths);
135 self.fse_tables_undefined = false;
136 }
137 }
138
139 /// Read initial FSE states for sequence decoding.
140 ///
141 /// Errors returned:
142 /// - `error.EndOfStream` if `bit_reader` does not contain enough bits.
143 pub fn readInitialFseState(self: *DecodeState, bit_reader: *readers.ReverseBitReader) error{EndOfStream}!void {
144 self.literal.state = try bit_reader.readBitsNoEof(u9, self.literal.accuracy_log);
145 self.offset.state = try bit_reader.readBitsNoEof(u8, self.offset.accuracy_log);
146 self.match.state = try bit_reader.readBitsNoEof(u9, self.match.accuracy_log);
147 }
148
149 fn updateRepeatOffset(self: *DecodeState, offset: u32) void {
150 self.repeat_offsets[2] = self.repeat_offsets[1];
151 self.repeat_offsets[1] = self.repeat_offsets[0];
152 self.repeat_offsets[0] = offset;
153 }
154
155 fn useRepeatOffset(self: *DecodeState, index: usize) u32 {
156 if (index == 1)
157 std.mem.swap(u32, &self.repeat_offsets[0], &self.repeat_offsets[1])
158 else if (index == 2) {
159 std.mem.swap(u32, &self.repeat_offsets[0], &self.repeat_offsets[2]);
160 std.mem.swap(u32, &self.repeat_offsets[1], &self.repeat_offsets[2]);
161 }
162 return self.repeat_offsets[0];
163 }
164
165 const DataType = enum { offset, match, literal };
166
167 fn updateState(
168 self: *DecodeState,
169 comptime choice: DataType,
170 bit_reader: *readers.ReverseBitReader,
171 ) error{ MalformedFseBits, EndOfStream }!void {
172 switch (@field(self, @tagName(choice)).table) {
173 .rle => {},
174 .fse => |table| {
175 const data = table[@field(self, @tagName(choice)).state];
176 const T = @TypeOf(@field(self, @tagName(choice))).State;
177 const bits_summand = try bit_reader.readBitsNoEof(T, data.bits);
178 const next_state = std.math.cast(
179 @TypeOf(@field(self, @tagName(choice))).State,
180 data.baseline + bits_summand,
181 ) orelse return error.MalformedFseBits;
182 @field(self, @tagName(choice)).state = next_state;
183 },
184 }
185 }
186
187 const FseTableError = error{
188 MalformedFseTable,
189 MalformedAccuracyLog,
190 RepeatModeFirst,
191 EndOfStream,
192 };
193
194 fn updateFseTable(
195 self: *DecodeState,
196 source: anytype,
197 comptime choice: DataType,
198 mode: SequencesSection.Header.Mode,
199 ) !void {
200 const field_name = @tagName(choice);
201 switch (mode) {
202 .predefined => {
203 @field(self, field_name).accuracy_log =
204 @field(types.compressed_block.default_accuracy_log, field_name);
205
206 @field(self, field_name).table =
207 @field(types.compressed_block, "predefined_" ++ field_name ++ "_fse_table");
208 },
209 .rle => {
210 @field(self, field_name).accuracy_log = 0;
211 @field(self, field_name).table = .{ .rle = try source.readByte() };
212 },
213 .fse => {
214 var bit_reader = readers.bitReader(source);
215
216 const table_size = try decodeFseTable(
217 &bit_reader,
218 @field(types.compressed_block.table_symbol_count_max, field_name),
219 @field(types.compressed_block.table_accuracy_log_max, field_name),
220 @field(self, field_name ++ "_fse_buffer"),
221 );
222 @field(self, field_name).table = .{
223 .fse = @field(self, field_name ++ "_fse_buffer")[0..table_size],
224 };
225 @field(self, field_name).accuracy_log = std.math.log2_int_ceil(usize, table_size);
226 },
227 .repeat => if (self.fse_tables_undefined) return error.RepeatModeFirst,
228 }
229 }
230
231 const Sequence = struct {
232 literal_length: u32,
233 match_length: u32,
234 offset: u32,
235 };
236
237 fn nextSequence(
238 self: *DecodeState,
239 bit_reader: *readers.ReverseBitReader,
240 ) error{ InvalidBitStream, EndOfStream }!Sequence {
241 const raw_code = self.getCode(.offset);
242 const offset_code = std.math.cast(u5, raw_code) orelse {
243 return error.InvalidBitStream;
244 };
245 const offset_value = (@as(u32, 1) << offset_code) + try bit_reader.readBitsNoEof(u32, offset_code);
246
247 const match_code = self.getCode(.match);
248 if (match_code >= types.compressed_block.match_length_code_table.len)
249 return error.InvalidBitStream;
250 const match = types.compressed_block.match_length_code_table[match_code];
251 const match_length = match[0] + try bit_reader.readBitsNoEof(u32, match[1]);
252
253 const literal_code = self.getCode(.literal);
254 if (literal_code >= types.compressed_block.literals_length_code_table.len)
255 return error.InvalidBitStream;
256 const literal = types.compressed_block.literals_length_code_table[literal_code];
257 const literal_length = literal[0] + try bit_reader.readBitsNoEof(u32, literal[1]);
258
259 const offset = if (offset_value > 3) offset: {
260 const offset = offset_value - 3;
261 self.updateRepeatOffset(offset);
262 break :offset offset;
263 } else offset: {
264 if (literal_length == 0) {
265 if (offset_value == 3) {
266 const offset = self.repeat_offsets[0] - 1;
267 self.updateRepeatOffset(offset);
268 break :offset offset;
269 }
270 break :offset self.useRepeatOffset(offset_value);
271 }
272 break :offset self.useRepeatOffset(offset_value - 1);
273 };
274
275 if (offset == 0) return error.InvalidBitStream;
276
277 return .{
278 .literal_length = literal_length,
279 .match_length = match_length,
280 .offset = offset,
281 };
282 }
283
284 fn executeSequenceSlice(
285 self: *DecodeState,
286 dest: []u8,
287 write_pos: usize,
288 sequence: Sequence,
289 ) (error{MalformedSequence} || DecodeLiteralsError)!void {
290 if (sequence.offset > write_pos + sequence.literal_length) return error.MalformedSequence;
291
292 try self.decodeLiteralsSlice(dest[write_pos..], sequence.literal_length);
293 const copy_start = write_pos + sequence.literal_length - sequence.offset;
294 for (
295 dest[write_pos + sequence.literal_length ..][0..sequence.match_length],
296 dest[copy_start..][0..sequence.match_length],
297 ) |*d, s| d.* = s;
298 self.written_count += sequence.match_length;
299 }
300
301 fn executeSequenceRingBuffer(
302 self: *DecodeState,
303 dest: *RingBuffer,
304 sequence: Sequence,
305 ) (error{MalformedSequence} || DecodeLiteralsError)!void {
306 if (sequence.offset > @min(dest.data.len, self.written_count + sequence.literal_length))
307 return error.MalformedSequence;
308
309 try self.decodeLiteralsRingBuffer(dest, sequence.literal_length);
310 const copy_start = dest.write_index + dest.data.len - sequence.offset;
311 const copy_slice = dest.sliceAt(copy_start, sequence.match_length);
312 dest.writeSliceForwardsAssumeCapacity(copy_slice.first);
313 dest.writeSliceForwardsAssumeCapacity(copy_slice.second);
314 self.written_count += sequence.match_length;
315 }
316
317 const DecodeSequenceError = error{
318 InvalidBitStream,
319 EndOfStream,
320 MalformedSequence,
321 MalformedFseBits,
322 } || DecodeLiteralsError;
323
324 /// Decode one sequence from `bit_reader` into `dest`, written starting at
325 /// `write_pos` and update FSE states if `last_sequence` is `false`.
326 /// `prepare()` must be called for the block before attempting to decode
327 /// sequences.
328 ///
329 /// Errors returned:
330 /// - `error.MalformedSequence` if the decompressed sequence would be
331 /// longer than `sequence_size_limit` or the sequence's offset is too
332 /// large
333 /// - `error.UnexpectedEndOfLiteralStream` if the decoder state's literal
334 /// streams do not contain enough literals for the sequence (this may
335 /// mean the literal stream or the sequence is malformed).
336 /// - `error.InvalidBitStream` if the FSE sequence bitstream is malformed
337 /// - `error.EndOfStream` if `bit_reader` does not contain enough bits
338 /// - `error.DestTooSmall` if `dest` is not large enough to holde the
339 /// decompressed sequence
340 pub fn decodeSequenceSlice(
341 self: *DecodeState,
342 dest: []u8,
343 write_pos: usize,
344 bit_reader: *readers.ReverseBitReader,
345 sequence_size_limit: usize,
346 last_sequence: bool,
347 ) (error{DestTooSmall} || DecodeSequenceError)!usize {
348 const sequence = try self.nextSequence(bit_reader);
349 const sequence_length = @as(usize, sequence.literal_length) + sequence.match_length;
350 if (sequence_length > sequence_size_limit) return error.MalformedSequence;
351 if (sequence_length > dest[write_pos..].len) return error.DestTooSmall;
352
353 try self.executeSequenceSlice(dest, write_pos, sequence);
354 if (!last_sequence) {
355 try self.updateState(.literal, bit_reader);
356 try self.updateState(.match, bit_reader);
357 try self.updateState(.offset, bit_reader);
358 }
359 return sequence_length;
360 }
361
362 /// Decode one sequence from `bit_reader` into `dest`; see
363 /// `decodeSequenceSlice`.
364 pub fn decodeSequenceRingBuffer(
365 self: *DecodeState,
366 dest: *RingBuffer,
367 bit_reader: anytype,
368 sequence_size_limit: usize,
369 last_sequence: bool,
370 ) DecodeSequenceError!usize {
371 const sequence = try self.nextSequence(bit_reader);
372 const sequence_length = @as(usize, sequence.literal_length) + sequence.match_length;
373 if (sequence_length > sequence_size_limit) return error.MalformedSequence;
374
375 try self.executeSequenceRingBuffer(dest, sequence);
376 if (!last_sequence) {
377 try self.updateState(.literal, bit_reader);
378 try self.updateState(.match, bit_reader);
379 try self.updateState(.offset, bit_reader);
380 }
381 return sequence_length;
382 }
383
384 fn nextLiteralMultiStream(
385 self: *DecodeState,
386 ) error{BitStreamHasNoStartBit}!void {
387 self.literal_stream_index += 1;
388 try self.initLiteralStream(self.literal_streams.four[self.literal_stream_index]);
389 }
390
391 fn initLiteralStream(self: *DecodeState, bytes: []const u8) error{BitStreamHasNoStartBit}!void {
392 try self.literal_stream_reader.init(bytes);
393 }
394
395 fn isLiteralStreamEmpty(self: *DecodeState) bool {
396 switch (self.literal_streams) {
397 .one => return self.literal_stream_reader.isEmpty(),
398 .four => return self.literal_stream_index == 3 and self.literal_stream_reader.isEmpty(),
399 }
400 }
401
402 const LiteralBitsError = error{
403 BitStreamHasNoStartBit,
404 UnexpectedEndOfLiteralStream,
405 };
406 fn readLiteralsBits(
407 self: *DecodeState,
408 bit_count_to_read: u16,
409 ) LiteralBitsError!u16 {
410 return self.literal_stream_reader.readBitsNoEof(u16, bit_count_to_read) catch bits: {
411 if (self.literal_streams == .four and self.literal_stream_index < 3) {
412 try self.nextLiteralMultiStream();
413 break :bits self.literal_stream_reader.readBitsNoEof(u16, bit_count_to_read) catch
414 return error.UnexpectedEndOfLiteralStream;
415 } else {
416 return error.UnexpectedEndOfLiteralStream;
417 }
418 };
419 }
420
421 const DecodeLiteralsError = error{
422 MalformedLiteralsLength,
423 NotFound,
424 } || LiteralBitsError;
425
426 /// Decode `len` bytes of literals into `dest`.
427 ///
428 /// Errors returned:
429 /// - `error.MalformedLiteralsLength` if the number of literal bytes
430 /// decoded by `self` plus `len` is greater than the regenerated size of
431 /// `literals`
432 /// - `error.UnexpectedEndOfLiteralStream` and `error.NotFound` if there
433 /// are problems decoding Huffman compressed literals
434 pub fn decodeLiteralsSlice(
435 self: *DecodeState,
436 dest: []u8,
437 len: usize,
438 ) DecodeLiteralsError!void {
439 if (self.literal_written_count + len > self.literal_header.regenerated_size)
440 return error.MalformedLiteralsLength;
441
442 switch (self.literal_header.block_type) {
443 .raw => {
444 const literal_data = self.literal_streams.one[self.literal_written_count..][0..len];
445 @memcpy(dest[0..len], literal_data);
446 self.literal_written_count += len;
447 self.written_count += len;
448 },
449 .rle => {
450 for (0..len) |i| {
451 dest[i] = self.literal_streams.one[0];
452 }
453 self.literal_written_count += len;
454 self.written_count += len;
455 },
456 .compressed, .treeless => {
457 // const written_bytes_per_stream = (literals.header.regenerated_size + 3) / 4;
458 const huffman_tree = self.huffman_tree orelse unreachable;
459 const max_bit_count = huffman_tree.max_bit_count;
460 const starting_bit_count = LiteralsSection.HuffmanTree.weightToBitCount(
461 huffman_tree.nodes[huffman_tree.symbol_count_minus_one].weight,
462 max_bit_count,
463 );
464 var bits_read: u4 = 0;
465 var huffman_tree_index: usize = huffman_tree.symbol_count_minus_one;
466 var bit_count_to_read: u4 = starting_bit_count;
467 for (0..len) |i| {
468 var prefix: u16 = 0;
469 while (true) {
470 const new_bits = self.readLiteralsBits(bit_count_to_read) catch |err| {
471 return err;
472 };
473 prefix <<= bit_count_to_read;
474 prefix |= new_bits;
475 bits_read += bit_count_to_read;
476 const result = huffman_tree.query(huffman_tree_index, prefix) catch |err| {
477 return err;
478 };
479
480 switch (result) {
481 .symbol => |sym| {
482 dest[i] = sym;
483 bit_count_to_read = starting_bit_count;
484 bits_read = 0;
485 huffman_tree_index = huffman_tree.symbol_count_minus_one;
486 break;
487 },
488 .index => |index| {
489 huffman_tree_index = index;
490 const bit_count = LiteralsSection.HuffmanTree.weightToBitCount(
491 huffman_tree.nodes[index].weight,
492 max_bit_count,
493 );
494 bit_count_to_read = bit_count - bits_read;
495 },
496 }
497 }
498 }
499 self.literal_written_count += len;
500 self.written_count += len;
501 },
502 }
503 }
504
505 /// Decode literals into `dest`; see `decodeLiteralsSlice()`.
506 pub fn decodeLiteralsRingBuffer(
507 self: *DecodeState,
508 dest: *RingBuffer,
509 len: usize,
510 ) DecodeLiteralsError!void {
511 if (self.literal_written_count + len > self.literal_header.regenerated_size)
512 return error.MalformedLiteralsLength;
513
514 switch (self.literal_header.block_type) {
515 .raw => {
516 const literals_end = self.literal_written_count + len;
517 const literal_data = self.literal_streams.one[self.literal_written_count..literals_end];
518 dest.writeSliceAssumeCapacity(literal_data);
519 self.literal_written_count += len;
520 self.written_count += len;
521 },
522 .rle => {
523 for (0..len) |_| {
524 dest.writeAssumeCapacity(self.literal_streams.one[0]);
525 }
526 self.literal_written_count += len;
527 self.written_count += len;
528 },
529 .compressed, .treeless => {
530 // const written_bytes_per_stream = (literals.header.regenerated_size + 3) / 4;
531 const huffman_tree = self.huffman_tree orelse unreachable;
532 const max_bit_count = huffman_tree.max_bit_count;
533 const starting_bit_count = LiteralsSection.HuffmanTree.weightToBitCount(
534 huffman_tree.nodes[huffman_tree.symbol_count_minus_one].weight,
535 max_bit_count,
536 );
537 var bits_read: u4 = 0;
538 var huffman_tree_index: usize = huffman_tree.symbol_count_minus_one;
539 var bit_count_to_read: u4 = starting_bit_count;
540 for (0..len) |_| {
541 var prefix: u16 = 0;
542 while (true) {
543 const new_bits = try self.readLiteralsBits(bit_count_to_read);
544 prefix <<= bit_count_to_read;
545 prefix |= new_bits;
546 bits_read += bit_count_to_read;
547 const result = try huffman_tree.query(huffman_tree_index, prefix);
548
549 switch (result) {
550 .symbol => |sym| {
551 dest.writeAssumeCapacity(sym);
552 bit_count_to_read = starting_bit_count;
553 bits_read = 0;
554 huffman_tree_index = huffman_tree.symbol_count_minus_one;
555 break;
556 },
557 .index => |index| {
558 huffman_tree_index = index;
559 const bit_count = LiteralsSection.HuffmanTree.weightToBitCount(
560 huffman_tree.nodes[index].weight,
561 max_bit_count,
562 );
563 bit_count_to_read = bit_count - bits_read;
564 },
565 }
566 }
567 }
568 self.literal_written_count += len;
569 self.written_count += len;
570 },
571 }
572 }
573
574 fn getCode(self: *DecodeState, comptime choice: DataType) u32 {
575 return switch (@field(self, @tagName(choice)).table) {
576 .rle => |value| value,
577 .fse => |table| table[@field(self, @tagName(choice)).state].symbol,
578 };
579 }
580};
581
582/// Decode a single block from `src` into `dest`. The beginning of `src` must be
583/// the start of the block content (i.e. directly after the block header).
584/// Increments `consumed_count` by the number of bytes read from `src` to decode
585/// the block and returns the decompressed size of the block.
586///
587/// Errors returned:
588///
589/// - `error.BlockSizeOverMaximum` if block's size is larger than 1 << 17 or
590/// `dest[written_count..].len`
591/// - `error.MalformedBlockSize` if `src.len` is smaller than the block size
592/// and the block is a raw or compressed block
593/// - `error.ReservedBlock` if the block is a reserved block
594/// - `error.MalformedRleBlock` if the block is an RLE block and `src.len < 1`
595/// - `error.MalformedCompressedBlock` if there are errors decoding a
596/// compressed block
597/// - `error.DestTooSmall` is `dest` is not large enough to hold the
598/// decompressed block
599pub fn decodeBlock(
600 dest: []u8,
601 src: []const u8,
602 block_header: frame.Zstandard.Block.Header,
603 decode_state: *DecodeState,
604 consumed_count: *usize,
605 block_size_max: usize,
606 written_count: usize,
607) (error{DestTooSmall} || Error)!usize {
608 const block_size = block_header.block_size;
609 if (block_size_max < block_size) return error.BlockSizeOverMaximum;
610 switch (block_header.block_type) {
611 .raw => {
612 if (src.len < block_size) return error.MalformedBlockSize;
613 if (dest[written_count..].len < block_size) return error.DestTooSmall;
614 @memcpy(dest[written_count..][0..block_size], src[0..block_size]);
615 consumed_count.* += block_size;
616 decode_state.written_count += block_size;
617 return block_size;
618 },
619 .rle => {
620 if (src.len < 1) return error.MalformedRleBlock;
621 if (dest[written_count..].len < block_size) return error.DestTooSmall;
622 for (written_count..block_size + written_count) |write_pos| {
623 dest[write_pos] = src[0];
624 }
625 consumed_count.* += 1;
626 decode_state.written_count += block_size;
627 return block_size;
628 },
629 .compressed => {
630 if (src.len < block_size) return error.MalformedBlockSize;
631 var bytes_read: usize = 0;
632 const literals = decodeLiteralsSectionSlice(src[0..block_size], &bytes_read) catch
633 return error.MalformedCompressedBlock;
634 var fbs = std.io.fixedBufferStream(src[bytes_read..block_size]);
635 const fbs_reader = fbs.reader();
636 const sequences_header = decodeSequencesHeader(fbs_reader) catch
637 return error.MalformedCompressedBlock;
638
639 decode_state.prepare(fbs_reader, literals, sequences_header) catch
640 return error.MalformedCompressedBlock;
641
642 bytes_read += fbs.pos;
643
644 var bytes_written: usize = 0;
645 {
646 const bit_stream_bytes = src[bytes_read..block_size];
647 var bit_stream: readers.ReverseBitReader = undefined;
648 bit_stream.init(bit_stream_bytes) catch return error.MalformedCompressedBlock;
649
650 if (sequences_header.sequence_count > 0) {
651 decode_state.readInitialFseState(&bit_stream) catch
652 return error.MalformedCompressedBlock;
653
654 var sequence_size_limit = block_size_max;
655 for (0..sequences_header.sequence_count) |i| {
656 const write_pos = written_count + bytes_written;
657 const decompressed_size = decode_state.decodeSequenceSlice(
658 dest,
659 write_pos,
660 &bit_stream,
661 sequence_size_limit,
662 i == sequences_header.sequence_count - 1,
663 ) catch |err| switch (err) {
664 error.DestTooSmall => return error.DestTooSmall,
665 else => return error.MalformedCompressedBlock,
666 };
667 bytes_written += decompressed_size;
668 sequence_size_limit -= decompressed_size;
669 }
670 }
671
672 if (!bit_stream.isEmpty()) {
673 return error.MalformedCompressedBlock;
674 }
675 }
676
677 if (decode_state.literal_written_count < literals.header.regenerated_size) {
678 const len = literals.header.regenerated_size - decode_state.literal_written_count;
679 if (len > dest[written_count + bytes_written ..].len) return error.DestTooSmall;
680 decode_state.decodeLiteralsSlice(dest[written_count + bytes_written ..], len) catch
681 return error.MalformedCompressedBlock;
682 bytes_written += len;
683 }
684
685 switch (decode_state.literal_header.block_type) {
686 .treeless, .compressed => {
687 if (!decode_state.isLiteralStreamEmpty()) return error.MalformedCompressedBlock;
688 },
689 .raw, .rle => {},
690 }
691
692 consumed_count.* += block_size;
693 return bytes_written;
694 },
695 .reserved => return error.ReservedBlock,
696 }
697}
698
699/// Decode a single block from `src` into `dest`; see `decodeBlock()`. Returns
700/// the size of the decompressed block, which can be used with `dest.sliceLast()`
701/// to get the decompressed bytes. `error.BlockSizeOverMaximum` is returned if
702/// the block's compressed or decompressed size is larger than `block_size_max`.
703pub fn decodeBlockRingBuffer(
704 dest: *RingBuffer,
705 src: []const u8,
706 block_header: frame.Zstandard.Block.Header,
707 decode_state: *DecodeState,
708 consumed_count: *usize,
709 block_size_max: usize,
710) Error!usize {
711 const block_size = block_header.block_size;
712 if (block_size_max < block_size) return error.BlockSizeOverMaximum;
713 switch (block_header.block_type) {
714 .raw => {
715 if (src.len < block_size) return error.MalformedBlockSize;
716 // dest may have length zero if block_size == 0, causing division by zero in
717 // writeSliceAssumeCapacity()
718 if (block_size > 0) {
719 const data = src[0..block_size];
720 dest.writeSliceAssumeCapacity(data);
721 consumed_count.* += block_size;
722 decode_state.written_count += block_size;
723 }
724 return block_size;
725 },
726 .rle => {
727 if (src.len < 1) return error.MalformedRleBlock;
728 for (0..block_size) |_| {
729 dest.writeAssumeCapacity(src[0]);
730 }
731 consumed_count.* += 1;
732 decode_state.written_count += block_size;
733 return block_size;
734 },
735 .compressed => {
736 if (src.len < block_size) return error.MalformedBlockSize;
737 var bytes_read: usize = 0;
738 const literals = decodeLiteralsSectionSlice(src[0..block_size], &bytes_read) catch
739 return error.MalformedCompressedBlock;
740 var fbs = std.io.fixedBufferStream(src[bytes_read..block_size]);
741 const fbs_reader = fbs.reader();
742 const sequences_header = decodeSequencesHeader(fbs_reader) catch
743 return error.MalformedCompressedBlock;
744
745 decode_state.prepare(fbs_reader, literals, sequences_header) catch
746 return error.MalformedCompressedBlock;
747
748 bytes_read += fbs.pos;
749
750 var bytes_written: usize = 0;
751 {
752 const bit_stream_bytes = src[bytes_read..block_size];
753 var bit_stream: readers.ReverseBitReader = undefined;
754 bit_stream.init(bit_stream_bytes) catch return error.MalformedCompressedBlock;
755
756 if (sequences_header.sequence_count > 0) {
757 decode_state.readInitialFseState(&bit_stream) catch
758 return error.MalformedCompressedBlock;
759
760 var sequence_size_limit = block_size_max;
761 for (0..sequences_header.sequence_count) |i| {
762 const decompressed_size = decode_state.decodeSequenceRingBuffer(
763 dest,
764 &bit_stream,
765 sequence_size_limit,
766 i == sequences_header.sequence_count - 1,
767 ) catch return error.MalformedCompressedBlock;
768 bytes_written += decompressed_size;
769 sequence_size_limit -= decompressed_size;
770 }
771 }
772
773 if (!bit_stream.isEmpty()) {
774 return error.MalformedCompressedBlock;
775 }
776 }
777
778 if (decode_state.literal_written_count < literals.header.regenerated_size) {
779 const len = literals.header.regenerated_size - decode_state.literal_written_count;
780 decode_state.decodeLiteralsRingBuffer(dest, len) catch
781 return error.MalformedCompressedBlock;
782 bytes_written += len;
783 }
784
785 switch (decode_state.literal_header.block_type) {
786 .treeless, .compressed => {
787 if (!decode_state.isLiteralStreamEmpty()) return error.MalformedCompressedBlock;
788 },
789 .raw, .rle => {},
790 }
791
792 consumed_count.* += block_size;
793 if (bytes_written > block_size_max) return error.BlockSizeOverMaximum;
794 return bytes_written;
795 },
796 .reserved => return error.ReservedBlock,
797 }
798}
799
800/// Decode a single block from `source` into `dest`. Literal and sequence data
801/// from the block is copied into `literals_buffer` and `sequence_buffer`, which
802/// must be large enough or `error.LiteralsBufferTooSmall` and
803/// `error.SequenceBufferTooSmall` are returned (the maximum block size is an
804/// upper bound for the size of both buffers). See `decodeBlock`
805/// and `decodeBlockRingBuffer` for function that can decode a block without
806/// these extra copies. `error.EndOfStream` is returned if `source` does not
807/// contain enough bytes.
808pub fn decodeBlockReader(
809 dest: *RingBuffer,
810 source: anytype,
811 block_header: frame.Zstandard.Block.Header,
812 decode_state: *DecodeState,
813 block_size_max: usize,
814 literals_buffer: []u8,
815 sequence_buffer: []u8,
816) !void {
817 const block_size = block_header.block_size;
818 var block_reader_limited = std.io.limitedReader(source, block_size);
819 const block_reader = block_reader_limited.reader();
820 if (block_size_max < block_size) return error.BlockSizeOverMaximum;
821 switch (block_header.block_type) {
822 .raw => {
823 if (block_size == 0) return;
824 const slice = dest.sliceAt(dest.write_index, block_size);
825 try source.readNoEof(slice.first);
826 try source.readNoEof(slice.second);
827 dest.write_index = dest.mask2(dest.write_index + block_size);
828 decode_state.written_count += block_size;
829 },
830 .rle => {
831 const byte = try source.readByte();
832 for (0..block_size) |_| {
833 dest.writeAssumeCapacity(byte);
834 }
835 decode_state.written_count += block_size;
836 },
837 .compressed => {
838 const literals = try decodeLiteralsSection(block_reader, literals_buffer);
839 const sequences_header = try decodeSequencesHeader(block_reader);
840
841 try decode_state.prepare(block_reader, literals, sequences_header);
842
843 var bytes_written: usize = 0;
844 {
845 const size = try block_reader.readAll(sequence_buffer);
846 var bit_stream: readers.ReverseBitReader = undefined;
847 try bit_stream.init(sequence_buffer[0..size]);
848
849 if (sequences_header.sequence_count > 0) {
850 if (sequence_buffer.len < block_reader_limited.bytes_left)
851 return error.SequenceBufferTooSmall;
852
853 decode_state.readInitialFseState(&bit_stream) catch
854 return error.MalformedCompressedBlock;
855
856 var sequence_size_limit = block_size_max;
857 for (0..sequences_header.sequence_count) |i| {
858 const decompressed_size = decode_state.decodeSequenceRingBuffer(
859 dest,
860 &bit_stream,
861 sequence_size_limit,
862 i == sequences_header.sequence_count - 1,
863 ) catch return error.MalformedCompressedBlock;
864 sequence_size_limit -= decompressed_size;
865 bytes_written += decompressed_size;
866 }
867 }
868
869 if (!bit_stream.isEmpty()) {
870 return error.MalformedCompressedBlock;
871 }
872 }
873
874 if (decode_state.literal_written_count < literals.header.regenerated_size) {
875 const len = literals.header.regenerated_size - decode_state.literal_written_count;
876 decode_state.decodeLiteralsRingBuffer(dest, len) catch
877 return error.MalformedCompressedBlock;
878 bytes_written += len;
879 }
880
881 switch (decode_state.literal_header.block_type) {
882 .treeless, .compressed => {
883 if (!decode_state.isLiteralStreamEmpty()) return error.MalformedCompressedBlock;
884 },
885 .raw, .rle => {},
886 }
887
888 if (bytes_written > block_size_max) return error.BlockSizeOverMaximum;
889 if (block_reader_limited.bytes_left != 0) return error.MalformedCompressedBlock;
890 decode_state.literal_written_count = 0;
891 },
892 .reserved => return error.ReservedBlock,
893 }
894}
895
896/// Decode the header of a block.
897pub fn decodeBlockHeader(src: *const [3]u8) frame.Zstandard.Block.Header {
898 const last_block = src[0] & 1 == 1;
899 const block_type = @as(frame.Zstandard.Block.Type, @enumFromInt((src[0] & 0b110) >> 1));
900 const block_size = ((src[0] & 0b11111000) >> 3) + (@as(u21, src[1]) << 5) + (@as(u21, src[2]) << 13);
901 return .{
902 .last_block = last_block,
903 .block_type = block_type,
904 .block_size = block_size,
905 };
906}
907
908/// Decode the header of a block.
909///
910/// Errors returned:
911/// - `error.EndOfStream` if `src.len < 3`
912pub fn decodeBlockHeaderSlice(src: []const u8) error{EndOfStream}!frame.Zstandard.Block.Header {
913 if (src.len < 3) return error.EndOfStream;
914 return decodeBlockHeader(src[0..3]);
915}
916
917/// Decode a `LiteralsSection` from `src`, incrementing `consumed_count` by the
918/// number of bytes the section uses.
919///
920/// Errors returned:
921/// - `error.MalformedLiteralsHeader` if the header is invalid
922/// - `error.MalformedLiteralsSection` if there are decoding errors
923/// - `error.MalformedAccuracyLog` if compressed literals have invalid
924/// accuracy
925/// - `error.MalformedFseTable` if compressed literals have invalid FSE table
926/// - `error.MalformedHuffmanTree` if there are errors decoding a Huffamn tree
927/// - `error.EndOfStream` if there are not enough bytes in `src`
928pub fn decodeLiteralsSectionSlice(
929 src: []const u8,
930 consumed_count: *usize,
931) (error{ MalformedLiteralsHeader, MalformedLiteralsSection, EndOfStream } || huffman.Error)!LiteralsSection {
932 var bytes_read: usize = 0;
933 const header = header: {
934 var fbs = std.io.fixedBufferStream(src);
935 defer bytes_read = fbs.pos;
936 break :header decodeLiteralsHeader(fbs.reader()) catch return error.MalformedLiteralsHeader;
937 };
938 switch (header.block_type) {
939 .raw => {
940 if (src.len < bytes_read + header.regenerated_size) return error.MalformedLiteralsSection;
941 const stream = src[bytes_read..][0..header.regenerated_size];
942 consumed_count.* += header.regenerated_size + bytes_read;
943 return LiteralsSection{
944 .header = header,
945 .huffman_tree = null,
946 .streams = .{ .one = stream },
947 };
948 },
949 .rle => {
950 if (src.len < bytes_read + 1) return error.MalformedLiteralsSection;
951 const stream = src[bytes_read..][0..1];
952 consumed_count.* += 1 + bytes_read;
953 return LiteralsSection{
954 .header = header,
955 .huffman_tree = null,
956 .streams = .{ .one = stream },
957 };
958 },
959 .compressed, .treeless => {
960 const huffman_tree_start = bytes_read;
961 const huffman_tree = if (header.block_type == .compressed)
962 try huffman.decodeHuffmanTreeSlice(src[bytes_read..], &bytes_read)
963 else
964 null;
965 const huffman_tree_size = bytes_read - huffman_tree_start;
966 const total_streams_size = std.math.sub(usize, header.compressed_size.?, huffman_tree_size) catch
967 return error.MalformedLiteralsSection;
968
969 if (src.len < bytes_read + total_streams_size) return error.MalformedLiteralsSection;
970 const stream_data = src[bytes_read .. bytes_read + total_streams_size];
971
972 const streams = try decodeStreams(header.size_format, stream_data);
973 consumed_count.* += bytes_read + total_streams_size;
974 return LiteralsSection{
975 .header = header,
976 .huffman_tree = huffman_tree,
977 .streams = streams,
978 };
979 },
980 }
981}
982
983/// Decode a `LiteralsSection` from `src`, incrementing `consumed_count` by the
984/// number of bytes the section uses. See `decodeLiterasSectionSlice()`.
985pub fn decodeLiteralsSection(
986 source: anytype,
987 buffer: []u8,
988) !LiteralsSection {
989 const header = try decodeLiteralsHeader(source);
990 switch (header.block_type) {
991 .raw => {
992 if (buffer.len < header.regenerated_size) return error.LiteralsBufferTooSmall;
993 try source.readNoEof(buffer[0..header.regenerated_size]);
994 return LiteralsSection{
995 .header = header,
996 .huffman_tree = null,
997 .streams = .{ .one = buffer },
998 };
999 },
1000 .rle => {
1001 buffer[0] = try source.readByte();
1002 return LiteralsSection{
1003 .header = header,
1004 .huffman_tree = null,
1005 .streams = .{ .one = buffer[0..1] },
1006 };
1007 },
1008 .compressed, .treeless => {
1009 var counting_reader = std.io.countingReader(source);
1010 const huffman_tree = if (header.block_type == .compressed)
1011 try huffman.decodeHuffmanTree(counting_reader.reader(), buffer)
1012 else
1013 null;
1014 const huffman_tree_size = @as(usize, @intCast(counting_reader.bytes_read));
1015 const total_streams_size = std.math.sub(usize, header.compressed_size.?, huffman_tree_size) catch
1016 return error.MalformedLiteralsSection;
1017
1018 if (total_streams_size > buffer.len) return error.LiteralsBufferTooSmall;
1019 try source.readNoEof(buffer[0..total_streams_size]);
1020 const stream_data = buffer[0..total_streams_size];
1021
1022 const streams = try decodeStreams(header.size_format, stream_data);
1023 return LiteralsSection{
1024 .header = header,
1025 .huffman_tree = huffman_tree,
1026 .streams = streams,
1027 };
1028 },
1029 }
1030}
1031
1032fn decodeStreams(size_format: u2, stream_data: []const u8) !LiteralsSection.Streams {
1033 if (size_format == 0) {
1034 return .{ .one = stream_data };
1035 }
1036
1037 if (stream_data.len < 6) return error.MalformedLiteralsSection;
1038
1039 const stream_1_length: usize = std.mem.readInt(u16, stream_data[0..2], .little);
1040 const stream_2_length: usize = std.mem.readInt(u16, stream_data[2..4], .little);
1041 const stream_3_length: usize = std.mem.readInt(u16, stream_data[4..6], .little);
1042
1043 const stream_1_start = 6;
1044 const stream_2_start = stream_1_start + stream_1_length;
1045 const stream_3_start = stream_2_start + stream_2_length;
1046 const stream_4_start = stream_3_start + stream_3_length;
1047
1048 if (stream_data.len < stream_4_start) return error.MalformedLiteralsSection;
1049
1050 return .{ .four = .{
1051 stream_data[stream_1_start .. stream_1_start + stream_1_length],
1052 stream_data[stream_2_start .. stream_2_start + stream_2_length],
1053 stream_data[stream_3_start .. stream_3_start + stream_3_length],
1054 stream_data[stream_4_start..],
1055 } };
1056}
1057
1058/// Decode a literals section header.
1059///
1060/// Errors returned:
1061/// - `error.EndOfStream` if there are not enough bytes in `source`
1062pub fn decodeLiteralsHeader(source: anytype) !LiteralsSection.Header {
1063 const byte0 = try source.readByte();
1064 const block_type = @as(LiteralsSection.BlockType, @enumFromInt(byte0 & 0b11));
1065 const size_format = @as(u2, @intCast((byte0 & 0b1100) >> 2));
1066 var regenerated_size: u20 = undefined;
1067 var compressed_size: ?u18 = null;
1068 switch (block_type) {
1069 .raw, .rle => {
1070 switch (size_format) {
1071 0, 2 => {
1072 regenerated_size = byte0 >> 3;
1073 },
1074 1 => regenerated_size = (byte0 >> 4) + (@as(u20, try source.readByte()) << 4),
1075 3 => regenerated_size = (byte0 >> 4) +
1076 (@as(u20, try source.readByte()) << 4) +
1077 (@as(u20, try source.readByte()) << 12),
1078 }
1079 },
1080 .compressed, .treeless => {
1081 const byte1 = try source.readByte();
1082 const byte2 = try source.readByte();
1083 switch (size_format) {
1084 0, 1 => {
1085 regenerated_size = (byte0 >> 4) + ((@as(u20, byte1) & 0b00111111) << 4);
1086 compressed_size = ((byte1 & 0b11000000) >> 6) + (@as(u18, byte2) << 2);
1087 },
1088 2 => {
1089 const byte3 = try source.readByte();
1090 regenerated_size = (byte0 >> 4) + (@as(u20, byte1) << 4) + ((@as(u20, byte2) & 0b00000011) << 12);
1091 compressed_size = ((byte2 & 0b11111100) >> 2) + (@as(u18, byte3) << 6);
1092 },
1093 3 => {
1094 const byte3 = try source.readByte();
1095 const byte4 = try source.readByte();
1096 regenerated_size = (byte0 >> 4) + (@as(u20, byte1) << 4) + ((@as(u20, byte2) & 0b00111111) << 12);
1097 compressed_size = ((byte2 & 0b11000000) >> 6) + (@as(u18, byte3) << 2) + (@as(u18, byte4) << 10);
1098 },
1099 }
1100 },
1101 }
1102 return LiteralsSection.Header{
1103 .block_type = block_type,
1104 .size_format = size_format,
1105 .regenerated_size = regenerated_size,
1106 .compressed_size = compressed_size,
1107 };
1108}
1109
1110/// Decode a sequences section header.
1111///
1112/// Errors returned:
1113/// - `error.ReservedBitSet` if the reserved bit is set
1114/// - `error.EndOfStream` if there are not enough bytes in `source`
1115pub fn decodeSequencesHeader(
1116 source: anytype,
1117) !SequencesSection.Header {
1118 var sequence_count: u24 = undefined;
1119
1120 const byte0 = try source.readByte();
1121 if (byte0 == 0) {
1122 return SequencesSection.Header{
1123 .sequence_count = 0,
1124 .offsets = undefined,
1125 .match_lengths = undefined,
1126 .literal_lengths = undefined,
1127 };
1128 } else if (byte0 < 128) {
1129 sequence_count = byte0;
1130 } else if (byte0 < 255) {
1131 sequence_count = (@as(u24, (byte0 - 128)) << 8) + try source.readByte();
1132 } else {
1133 sequence_count = (try source.readByte()) + (@as(u24, try source.readByte()) << 8) + 0x7F00;
1134 }
1135
1136 const compression_modes = try source.readByte();
1137
1138 const matches_mode = @as(SequencesSection.Header.Mode, @enumFromInt((compression_modes & 0b00001100) >> 2));
1139 const offsets_mode = @as(SequencesSection.Header.Mode, @enumFromInt((compression_modes & 0b00110000) >> 4));
1140 const literal_mode = @as(SequencesSection.Header.Mode, @enumFromInt((compression_modes & 0b11000000) >> 6));
1141 if (compression_modes & 0b11 != 0) return error.ReservedBitSet;
1142
1143 return SequencesSection.Header{
1144 .sequence_count = sequence_count,
1145 .offsets = offsets_mode,
1146 .match_lengths = matches_mode,
1147 .literal_lengths = literal_mode,
1148 };
1149}
lib/std/compress/zstandard/decode/fse.zig deleted-153
...@@ -1,153 +0,0 @@
1const std = @import("std");
2const assert = std.debug.assert;
3
4const types = @import("../types.zig");
5const Table = types.compressed_block.Table;
6
7pub fn decodeFseTable(
8 bit_reader: anytype,
9 expected_symbol_count: usize,
10 max_accuracy_log: u4,
11 entries: []Table.Fse,
12) !usize {
13 const accuracy_log_biased = try bit_reader.readBitsNoEof(u4, 4);
14 if (accuracy_log_biased > max_accuracy_log -| 5) return error.MalformedAccuracyLog;
15 const accuracy_log = accuracy_log_biased + 5;
16
17 var values: [256]u16 = undefined;
18 var value_count: usize = 0;
19
20 const total_probability = @as(u16, 1) << accuracy_log;
21 var accumulated_probability: u16 = 0;
22
23 while (accumulated_probability < total_probability) {
24 // WARNING: The RFC is poorly worded, and would suggest std.math.log2_int_ceil is correct here,
25 // but power of two (remaining probabilities + 1) need max bits set to 1 more.
26 const max_bits = std.math.log2_int(u16, total_probability - accumulated_probability + 1) + 1;
27 const small = try bit_reader.readBitsNoEof(u16, max_bits - 1);
28
29 const cutoff = (@as(u16, 1) << max_bits) - 1 - (total_probability - accumulated_probability + 1);
30
31 const value = if (small < cutoff)
32 small
33 else value: {
34 const value_read = small + (try bit_reader.readBitsNoEof(u16, 1) << (max_bits - 1));
35 break :value if (value_read < @as(u16, 1) << (max_bits - 1))
36 value_read
37 else
38 value_read - cutoff;
39 };
40
41 accumulated_probability += if (value != 0) value - 1 else 1;
42
43 values[value_count] = value;
44 value_count += 1;
45
46 if (value == 1) {
47 while (true) {
48 const repeat_flag = try bit_reader.readBitsNoEof(u2, 2);
49 if (repeat_flag + value_count > 256) return error.MalformedFseTable;
50 for (0..repeat_flag) |_| {
51 values[value_count] = 1;
52 value_count += 1;
53 }
54 if (repeat_flag < 3) break;
55 }
56 }
57 if (value_count == 256) break;
58 }
59 bit_reader.alignToByte();
60
61 if (value_count < 2) return error.MalformedFseTable;
62 if (accumulated_probability != total_probability) return error.MalformedFseTable;
63 if (value_count > expected_symbol_count) return error.MalformedFseTable;
64
65 const table_size = total_probability;
66
67 try buildFseTable(values[0..value_count], entries[0..table_size]);
68 return table_size;
69}
70
71fn buildFseTable(values: []const u16, entries: []Table.Fse) !void {
72 const total_probability = @as(u16, @intCast(entries.len));
73 const accuracy_log = std.math.log2_int(u16, total_probability);
74 assert(total_probability <= 1 << 9);
75
76 var less_than_one_count: usize = 0;
77 for (values, 0..) |value, i| {
78 if (value == 0) {
79 entries[entries.len - 1 - less_than_one_count] = Table.Fse{
80 .symbol = @as(u8, @intCast(i)),
81 .baseline = 0,
82 .bits = accuracy_log,
83 };
84 less_than_one_count += 1;
85 }
86 }
87
88 var position: usize = 0;
89 var temp_states: [1 << 9]u16 = undefined;
90 for (values, 0..) |value, symbol| {
91 if (value == 0 or value == 1) continue;
92 const probability = value - 1;
93
94 const state_share_dividend = std.math.ceilPowerOfTwo(u16, probability) catch
95 return error.MalformedFseTable;
96 const share_size = @divExact(total_probability, state_share_dividend);
97 const double_state_count = state_share_dividend - probability;
98 const single_state_count = probability - double_state_count;
99 const share_size_log = std.math.log2_int(u16, share_size);
100
101 for (0..probability) |i| {
102 temp_states[i] = @as(u16, @intCast(position));
103 position += (entries.len >> 1) + (entries.len >> 3) + 3;
104 position &= entries.len - 1;
105 while (position >= entries.len - less_than_one_count) {
106 position += (entries.len >> 1) + (entries.len >> 3) + 3;
107 position &= entries.len - 1;
108 }
109 }
110 std.mem.sort(u16, temp_states[0..probability], {}, std.sort.asc(u16));
111 for (0..probability) |i| {
112 entries[temp_states[i]] = if (i < double_state_count) Table.Fse{
113 .symbol = @as(u8, @intCast(symbol)),
114 .bits = share_size_log + 1,
115 .baseline = single_state_count * share_size + @as(u16, @intCast(i)) * 2 * share_size,
116 } else Table.Fse{
117 .symbol = @as(u8, @intCast(symbol)),
118 .bits = share_size_log,
119 .baseline = (@as(u16, @intCast(i)) - double_state_count) * share_size,
120 };
121 }
122 }
123}
124
125test buildFseTable {
126 const literals_length_default_values = [36]u16{
127 5, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2,
128 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 2, 2, 2, 2, 2,
129 0, 0, 0, 0,
130 };
131
132 const match_lengths_default_values = [53]u16{
133 2, 5, 4, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2,
134 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
135 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0,
136 0, 0, 0, 0, 0,
137 };
138
139 const offset_codes_default_values = [29]u16{
140 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2,
141 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0,
142 };
143
144 var entries: [64]Table.Fse = undefined;
145 try buildFseTable(&literals_length_default_values, &entries);
146 try std.testing.expectEqualSlices(Table.Fse, types.compressed_block.predefined_literal_fse_table.fse, &entries);
147
148 try buildFseTable(&match_lengths_default_values, &entries);
149 try std.testing.expectEqualSlices(Table.Fse, types.compressed_block.predefined_match_fse_table.fse, &entries);
150
151 try buildFseTable(&offset_codes_default_values, entries[0..32]);
152 try std.testing.expectEqualSlices(Table.Fse, types.compressed_block.predefined_offset_fse_table.fse, entries[0..32]);
153}
lib/std/compress/zstandard/decode/huffman.zig deleted-234
...@@ -1,234 +0,0 @@
1const std = @import("std");
2
3const types = @import("../types.zig");
4const LiteralsSection = types.compressed_block.LiteralsSection;
5const Table = types.compressed_block.Table;
6
7const readers = @import("../readers.zig");
8
9const decodeFseTable = @import("fse.zig").decodeFseTable;
10
11pub const Error = error{
12 MalformedHuffmanTree,
13 MalformedFseTable,
14 MalformedAccuracyLog,
15 EndOfStream,
16};
17
18fn decodeFseHuffmanTree(
19 source: anytype,
20 compressed_size: usize,
21 buffer: []u8,
22 weights: *[256]u4,
23) !usize {
24 var stream = std.io.limitedReader(source, compressed_size);
25 var bit_reader = readers.bitReader(stream.reader());
26
27 var entries: [1 << 6]Table.Fse = undefined;
28 const table_size = decodeFseTable(&bit_reader, 256, 6, &entries) catch |err| switch (err) {
29 error.MalformedAccuracyLog, error.MalformedFseTable => |e| return e,
30 error.EndOfStream => return error.MalformedFseTable,
31 else => |e| return e,
32 };
33 const accuracy_log = std.math.log2_int_ceil(usize, table_size);
34
35 const amount = try stream.reader().readAll(buffer);
36 var huff_bits: readers.ReverseBitReader = undefined;
37 huff_bits.init(buffer[0..amount]) catch return error.MalformedHuffmanTree;
38
39 return assignWeights(&huff_bits, accuracy_log, &entries, weights);
40}
41
42fn decodeFseHuffmanTreeSlice(src: []const u8, compressed_size: usize, weights: *[256]u4) !usize {
43 if (src.len < compressed_size) return error.MalformedHuffmanTree;
44 var stream = std.io.fixedBufferStream(src[0..compressed_size]);
45 var counting_reader = std.io.countingReader(stream.reader());
46 var bit_reader = readers.bitReader(counting_reader.reader());
47
48 var entries: [1 << 6]Table.Fse = undefined;
49 const table_size = decodeFseTable(&bit_reader, 256, 6, &entries) catch |err| switch (err) {
50 error.MalformedAccuracyLog, error.MalformedFseTable => |e| return e,
51 error.EndOfStream => return error.MalformedFseTable,
52 };
53 const accuracy_log = std.math.log2_int_ceil(usize, table_size);
54
55 const start_index = std.math.cast(usize, counting_reader.bytes_read) orelse
56 return error.MalformedHuffmanTree;
57 const huff_data = src[start_index..compressed_size];
58 var huff_bits: readers.ReverseBitReader = undefined;
59 huff_bits.init(huff_data) catch return error.MalformedHuffmanTree;
60
61 return assignWeights(&huff_bits, accuracy_log, &entries, weights);
62}
63
64fn assignWeights(
65 huff_bits: *readers.ReverseBitReader,
66 accuracy_log: u16,
67 entries: *[1 << 6]Table.Fse,
68 weights: *[256]u4,
69) !usize {
70 var i: usize = 0;
71 var even_state: u32 = huff_bits.readBitsNoEof(u32, accuracy_log) catch return error.MalformedHuffmanTree;
72 var odd_state: u32 = huff_bits.readBitsNoEof(u32, accuracy_log) catch return error.MalformedHuffmanTree;
73
74 while (i < 254) {
75 const even_data = entries[even_state];
76 var read_bits: u16 = 0;
77 const even_bits = huff_bits.readBits(u32, even_data.bits, &read_bits) catch unreachable;
78 weights[i] = std.math.cast(u4, even_data.symbol) orelse return error.MalformedHuffmanTree;
79 i += 1;
80 if (read_bits < even_data.bits) {
81 weights[i] = std.math.cast(u4, entries[odd_state].symbol) orelse return error.MalformedHuffmanTree;
82 i += 1;
83 break;
84 }
85 even_state = even_data.baseline + even_bits;
86
87 read_bits = 0;
88 const odd_data = entries[odd_state];
89 const odd_bits = huff_bits.readBits(u32, odd_data.bits, &read_bits) catch unreachable;
90 weights[i] = std.math.cast(u4, odd_data.symbol) orelse return error.MalformedHuffmanTree;
91 i += 1;
92 if (read_bits < odd_data.bits) {
93 if (i == 255) return error.MalformedHuffmanTree;
94 weights[i] = std.math.cast(u4, entries[even_state].symbol) orelse return error.MalformedHuffmanTree;
95 i += 1;
96 break;
97 }
98 odd_state = odd_data.baseline + odd_bits;
99 } else return error.MalformedHuffmanTree;
100
101 if (!huff_bits.isEmpty()) {
102 return error.MalformedHuffmanTree;
103 }
104
105 return i + 1; // stream contains all but the last symbol
106}
107
108fn decodeDirectHuffmanTree(source: anytype, encoded_symbol_count: usize, weights: *[256]u4) !usize {
109 const weights_byte_count = (encoded_symbol_count + 1) / 2;
110 for (0..weights_byte_count) |i| {
111 const byte = try source.readByte();
112 weights[2 * i] = @as(u4, @intCast(byte >> 4));
113 weights[2 * i + 1] = @as(u4, @intCast(byte & 0xF));
114 }
115 return encoded_symbol_count + 1;
116}
117
118fn assignSymbols(weight_sorted_prefixed_symbols: []LiteralsSection.HuffmanTree.PrefixedSymbol, weights: [256]u4) usize {
119 for (0..weight_sorted_prefixed_symbols.len) |i| {
120 weight_sorted_prefixed_symbols[i] = .{
121 .symbol = @as(u8, @intCast(i)),
122 .weight = undefined,
123 .prefix = undefined,
124 };
125 }
126
127 std.mem.sort(
128 LiteralsSection.HuffmanTree.PrefixedSymbol,
129 weight_sorted_prefixed_symbols,
130 weights,
131 lessThanByWeight,
132 );
133
134 var prefix: u16 = 0;
135 var prefixed_symbol_count: usize = 0;
136 var sorted_index: usize = 0;
137 const symbol_count = weight_sorted_prefixed_symbols.len;
138 while (sorted_index < symbol_count) {
139 var symbol = weight_sorted_prefixed_symbols[sorted_index].symbol;
140 const weight = weights[symbol];
141 if (weight == 0) {
142 sorted_index += 1;
143 continue;
144 }
145
146 while (sorted_index < symbol_count) : ({
147 sorted_index += 1;
148 prefixed_symbol_count += 1;
149 prefix += 1;
150 }) {
151 symbol = weight_sorted_prefixed_symbols[sorted_index].symbol;
152 if (weights[symbol] != weight) {
153 prefix = ((prefix - 1) >> (weights[symbol] - weight)) + 1;
154 break;
155 }
156 weight_sorted_prefixed_symbols[prefixed_symbol_count].symbol = symbol;
157 weight_sorted_prefixed_symbols[prefixed_symbol_count].prefix = prefix;
158 weight_sorted_prefixed_symbols[prefixed_symbol_count].weight = weight;
159 }
160 }
161 return prefixed_symbol_count;
162}
163
164fn buildHuffmanTree(weights: *[256]u4, symbol_count: usize) error{MalformedHuffmanTree}!LiteralsSection.HuffmanTree {
165 var weight_power_sum_big: u32 = 0;
166 for (weights[0 .. symbol_count - 1]) |value| {
167 weight_power_sum_big += (@as(u16, 1) << value) >> 1;
168 }
169 if (weight_power_sum_big >= 1 << 11) return error.MalformedHuffmanTree;
170 const weight_power_sum = @as(u16, @intCast(weight_power_sum_big));
171
172 // advance to next power of two (even if weight_power_sum is a power of 2)
173 // TODO: is it valid to have weight_power_sum == 0?
174 const max_number_of_bits = if (weight_power_sum == 0) 1 else std.math.log2_int(u16, weight_power_sum) + 1;
175 const next_power_of_two = @as(u16, 1) << max_number_of_bits;
176 weights[symbol_count - 1] = std.math.log2_int(u16, next_power_of_two - weight_power_sum) + 1;
177
178 var weight_sorted_prefixed_symbols: [256]LiteralsSection.HuffmanTree.PrefixedSymbol = undefined;
179 const prefixed_symbol_count = assignSymbols(weight_sorted_prefixed_symbols[0..symbol_count], weights.*);
180 const tree = LiteralsSection.HuffmanTree{
181 .max_bit_count = max_number_of_bits,
182 .symbol_count_minus_one = @as(u8, @intCast(prefixed_symbol_count - 1)),
183 .nodes = weight_sorted_prefixed_symbols,
184 };
185 return tree;
186}
187
188pub fn decodeHuffmanTree(
189 source: anytype,
190 buffer: []u8,
191) (@TypeOf(source).Error || Error)!LiteralsSection.HuffmanTree {
192 const header = try source.readByte();
193 var weights: [256]u4 = undefined;
194 const symbol_count = if (header < 128)
195 // FSE compressed weights
196 try decodeFseHuffmanTree(source, header, buffer, &weights)
197 else
198 try decodeDirectHuffmanTree(source, header - 127, &weights);
199
200 return buildHuffmanTree(&weights, symbol_count);
201}
202
203pub fn decodeHuffmanTreeSlice(
204 src: []const u8,
205 consumed_count: *usize,
206) Error!LiteralsSection.HuffmanTree {
207 if (src.len == 0) return error.MalformedHuffmanTree;
208 const header = src[0];
209 var bytes_read: usize = 1;
210 var weights: [256]u4 = undefined;
211 const symbol_count = if (header < 128) count: {
212 // FSE compressed weights
213 bytes_read += header;
214 break :count try decodeFseHuffmanTreeSlice(src[1..], header, &weights);
215 } else count: {
216 var fbs = std.io.fixedBufferStream(src[1..]);
217 defer bytes_read += fbs.pos;
218 break :count try decodeDirectHuffmanTree(fbs.reader(), header - 127, &weights);
219 };
220
221 consumed_count.* += bytes_read;
222 return buildHuffmanTree(&weights, symbol_count);
223}
224
225fn lessThanByWeight(
226 weights: [256]u4,
227 lhs: LiteralsSection.HuffmanTree.PrefixedSymbol,
228 rhs: LiteralsSection.HuffmanTree.PrefixedSymbol,
229) bool {
230 // NOTE: this function relies on the use of a stable sorting algorithm,
231 // otherwise a special case of if (weights[lhs] == weights[rhs]) return lhs < rhs;
232 // should be added
233 return weights[lhs.symbol] < weights[rhs.symbol];
234}
lib/std/compress/zstandard/decompress.zig deleted-633
...@@ -1,633 +0,0 @@
1const std = @import("std");
2const assert = std.debug.assert;
3const Allocator = std.mem.Allocator;
4const RingBuffer = std.RingBuffer;
5
6const types = @import("types.zig");
7const frame = types.frame;
8const LiteralsSection = types.compressed_block.LiteralsSection;
9const SequencesSection = types.compressed_block.SequencesSection;
10const SkippableHeader = types.frame.Skippable.Header;
11const ZstandardHeader = types.frame.Zstandard.Header;
12const Table = types.compressed_block.Table;
13
14pub const block = @import("decode/block.zig");
15
16const readers = @import("readers.zig");
17
18/// Returns `true` is `magic` is a valid magic number for a skippable frame
19pub fn isSkippableMagic(magic: u32) bool {
20 return frame.Skippable.magic_number_min <= magic and magic <= frame.Skippable.magic_number_max;
21}
22
23/// Returns the kind of frame at the beginning of `source`.
24///
25/// Errors returned:
26/// - `error.BadMagic` if `source` begins with bytes not equal to the
27/// Zstandard frame magic number, or outside the range of magic numbers for
28/// skippable frames.
29/// - `error.EndOfStream` if `source` contains fewer than 4 bytes
30pub fn decodeFrameType(source: anytype) error{ BadMagic, EndOfStream }!frame.Kind {
31 const magic = try source.readInt(u32, .little);
32 return frameType(magic);
33}
34
35/// Returns the kind of frame associated to `magic`.
36///
37/// Errors returned:
38/// - `error.BadMagic` if `magic` is not a valid magic number.
39pub fn frameType(magic: u32) error{BadMagic}!frame.Kind {
40 return if (magic == frame.Zstandard.magic_number)
41 .zstandard
42 else if (isSkippableMagic(magic))
43 .skippable
44 else
45 error.BadMagic;
46}
47
48pub const FrameHeader = union(enum) {
49 zstandard: ZstandardHeader,
50 skippable: SkippableHeader,
51};
52
53pub const HeaderError = error{ BadMagic, EndOfStream, ReservedBitSet };
54
55/// Returns the header of the frame at the beginning of `source`.
56///
57/// Errors returned:
58/// - `error.BadMagic` if `source` begins with bytes not equal to the
59/// Zstandard frame magic number, or outside the range of magic numbers for
60/// skippable frames.
61/// - `error.EndOfStream` if `source` contains fewer than 4 bytes
62/// - `error.ReservedBitSet` if the frame is a Zstandard frame and any of the
63/// reserved bits are set
64pub fn decodeFrameHeader(source: anytype) (@TypeOf(source).Error || HeaderError)!FrameHeader {
65 const magic = try source.readInt(u32, .little);
66 const frame_type = try frameType(magic);
67 switch (frame_type) {
68 .zstandard => return FrameHeader{ .zstandard = try decodeZstandardHeader(source) },
69 .skippable => return FrameHeader{
70 .skippable = .{
71 .magic_number = magic,
72 .frame_size = try source.readInt(u32, .little),
73 },
74 },
75 }
76}
77
78pub const ReadWriteCount = struct {
79 read_count: usize,
80 write_count: usize,
81};
82
83/// Decodes frames from `src` into `dest`; returns the length of the result.
84/// The stream should not have extra trailing bytes - either all bytes in `src`
85/// will be decoded, or an error will be returned. An error will be returned if
86/// a Zstandard frame in `src` does not declare its content size.
87///
88/// Errors returned:
89/// - `error.DictionaryIdFlagUnsupported` if a `src` contains a frame that
90/// uses a dictionary
91/// - `error.MalformedFrame` if a frame in `src` is invalid
92/// - `error.UnknownContentSizeUnsupported` if a frame in `src` does not
93/// declare its content size
94pub fn decode(dest: []u8, src: []const u8, verify_checksum: bool) error{
95 MalformedFrame,
96 UnknownContentSizeUnsupported,
97 DictionaryIdFlagUnsupported,
98}!usize {
99 var write_count: usize = 0;
100 var read_count: usize = 0;
101 while (read_count < src.len) {
102 const counts = decodeFrame(dest, src[read_count..], verify_checksum) catch |err| {
103 switch (err) {
104 error.UnknownContentSizeUnsupported => return error.UnknownContentSizeUnsupported,
105 error.DictionaryIdFlagUnsupported => return error.DictionaryIdFlagUnsupported,
106 else => return error.MalformedFrame,
107 }
108 };
109 read_count += counts.read_count;
110 write_count += counts.write_count;
111 }
112 return write_count;
113}
114
115/// Decodes a stream of frames from `src`; returns the decoded bytes. The stream
116/// should not have extra trailing bytes - either all bytes in `src` will be
117/// decoded, or an error will be returned.
118///
119/// Errors returned:
120/// - `error.DictionaryIdFlagUnsupported` if a `src` contains a frame that
121/// uses a dictionary
122/// - `error.MalformedFrame` if a frame in `src` is invalid
123/// - `error.OutOfMemory` if `allocator` cannot allocate enough memory
124pub fn decodeAlloc(
125 allocator: Allocator,
126 src: []const u8,
127 verify_checksum: bool,
128 window_size_max: usize,
129) error{ DictionaryIdFlagUnsupported, MalformedFrame, OutOfMemory }![]u8 {
130 var result = std.ArrayList(u8).init(allocator);
131 errdefer result.deinit();
132
133 var read_count: usize = 0;
134 while (read_count < src.len) {
135 read_count += decodeFrameArrayList(
136 allocator,
137 &result,
138 src[read_count..],
139 verify_checksum,
140 window_size_max,
141 ) catch |err| switch (err) {
142 error.OutOfMemory => return error.OutOfMemory,
143 error.DictionaryIdFlagUnsupported => return error.DictionaryIdFlagUnsupported,
144 else => return error.MalformedFrame,
145 };
146 }
147 return result.toOwnedSlice();
148}
149
150/// Decodes the frame at the start of `src` into `dest`. Returns the number of
151/// bytes read from `src` and written to `dest`. This function can only decode
152/// frames that declare the decompressed content size.
153///
154/// Errors returned:
155/// - `error.BadMagic` if the first 4 bytes of `src` is not a valid magic
156/// number for a Zstandard or skippable frame
157/// - `error.UnknownContentSizeUnsupported` if the frame does not declare the
158/// uncompressed content size
159/// - `error.WindowSizeUnknown` if the frame does not have a valid window size
160/// - `error.ContentTooLarge` if `dest` is smaller than the uncompressed data
161/// size declared by the frame header
162/// - `error.ContentSizeTooLarge` if the frame header indicates a content size
163/// that is larger than `std.math.maxInt(usize)`
164/// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary
165/// - `error.ChecksumFailure` if `verify_checksum` is true and the frame
166/// contains a checksum that does not match the checksum of the decompressed
167/// data
168/// - `error.ReservedBitSet` if any of the reserved bits of the frame header
169/// are set
170/// - `error.EndOfStream` if `src` does not contain a complete frame
171/// - `error.BadContentSize` if the content size declared by the frame does
172/// not equal the actual size of decompressed data
173/// - an error in `block.Error` if there are errors decoding a block
174/// - `error.SkippableSizeTooLarge` if the frame is skippable and reports a
175/// size greater than `src.len`
176pub fn decodeFrame(
177 dest: []u8,
178 src: []const u8,
179 verify_checksum: bool,
180) (error{
181 BadMagic,
182 UnknownContentSizeUnsupported,
183 ContentTooLarge,
184 ContentSizeTooLarge,
185 WindowSizeUnknown,
186 DictionaryIdFlagUnsupported,
187 SkippableSizeTooLarge,
188} || FrameError)!ReadWriteCount {
189 var fbs = std.io.fixedBufferStream(src);
190 switch (try decodeFrameType(fbs.reader())) {
191 .zstandard => return decodeZstandardFrame(dest, src, verify_checksum),
192 .skippable => {
193 const content_size = try fbs.reader().readInt(u32, .little);
194 if (content_size > std.math.maxInt(usize) - 8) return error.SkippableSizeTooLarge;
195 const read_count = @as(usize, content_size) + 8;
196 if (read_count > src.len) return error.SkippableSizeTooLarge;
197 return ReadWriteCount{
198 .read_count = read_count,
199 .write_count = 0,
200 };
201 },
202 }
203}
204
205/// Decodes the frame at the start of `src` into `dest`. Returns the number of
206/// bytes read from `src`.
207///
208/// Errors returned:
209/// - `error.BadMagic` if the first 4 bytes of `src` is not a valid magic
210/// number for a Zstandard or skippable frame
211/// - `error.WindowSizeUnknown` if the frame does not have a valid window size
212/// - `error.WindowTooLarge` if the window size is larger than
213/// `window_size_max`
214/// - `error.ContentSizeTooLarge` if the frame header indicates a content size
215/// that is larger than `std.math.maxInt(usize)`
216/// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary
217/// - `error.ChecksumFailure` if `verify_checksum` is true and the frame
218/// contains a checksum that does not match the checksum of the decompressed
219/// data
220/// - `error.ReservedBitSet` if any of the reserved bits of the frame header
221/// are set
222/// - `error.EndOfStream` if `src` does not contain a complete frame
223/// - `error.BadContentSize` if the content size declared by the frame does
224/// not equal the actual size of decompressed data
225/// - `error.OutOfMemory` if `allocator` cannot allocate enough memory
226/// - an error in `block.Error` if there are errors decoding a block
227/// - `error.SkippableSizeTooLarge` if the frame is skippable and reports a
228/// size greater than `src.len`
229pub fn decodeFrameArrayList(
230 allocator: Allocator,
231 dest: *std.ArrayList(u8),
232 src: []const u8,
233 verify_checksum: bool,
234 window_size_max: usize,
235) (error{ BadMagic, OutOfMemory, SkippableSizeTooLarge } || FrameContext.Error || FrameError)!usize {
236 var fbs = std.io.fixedBufferStream(src);
237 const reader = fbs.reader();
238 const magic = try reader.readInt(u32, .little);
239 switch (try frameType(magic)) {
240 .zstandard => return decodeZstandardFrameArrayList(
241 allocator,
242 dest,
243 src,
244 verify_checksum,
245 window_size_max,
246 ),
247 .skippable => {
248 const content_size = try fbs.reader().readInt(u32, .little);
249 if (content_size > std.math.maxInt(usize) - 8) return error.SkippableSizeTooLarge;
250 const read_count = @as(usize, content_size) + 8;
251 if (read_count > src.len) return error.SkippableSizeTooLarge;
252 return read_count;
253 },
254 }
255}
256
257/// Returns the frame checksum corresponding to the data fed into `hasher`
258pub fn computeChecksum(hasher: *std.hash.XxHash64) u32 {
259 const hash = hasher.final();
260 return @as(u32, @intCast(hash & 0xFFFFFFFF));
261}
262
263const FrameError = error{
264 ChecksumFailure,
265 BadContentSize,
266 EndOfStream,
267 ReservedBitSet,
268} || block.Error;
269
270/// Decode a Zstandard frame from `src` into `dest`, returning the number of
271/// bytes read from `src` and written to `dest`. The first four bytes of `src`
272/// must be the magic number for a Zstandard frame.
273///
274/// Error returned:
275/// - `error.UnknownContentSizeUnsupported` if the frame does not declare the
276/// uncompressed content size
277/// - `error.ContentTooLarge` if `dest` is smaller than the uncompressed data
278/// size declared by the frame header
279/// - `error.WindowSizeUnknown` if the frame does not have a valid window size
280/// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary
281/// - `error.ContentSizeTooLarge` if the frame header indicates a content size
282/// that is larger than `std.math.maxInt(usize)`
283/// - `error.ChecksumFailure` if `verify_checksum` is true and the frame
284/// contains a checksum that does not match the checksum of the decompressed
285/// data
286/// - `error.ReservedBitSet` if the reserved bit of the frame header is set
287/// - `error.EndOfStream` if `src` does not contain a complete frame
288/// - an error in `block.Error` if there are errors decoding a block
289/// - `error.BadContentSize` if the content size declared by the frame does
290/// not equal the actual size of decompressed data
291pub fn decodeZstandardFrame(
292 dest: []u8,
293 src: []const u8,
294 verify_checksum: bool,
295) (error{
296 UnknownContentSizeUnsupported,
297 ContentTooLarge,
298 ContentSizeTooLarge,
299 WindowSizeUnknown,
300 DictionaryIdFlagUnsupported,
301} || FrameError)!ReadWriteCount {
302 assert(std.mem.readInt(u32, src[0..4], .little) == frame.Zstandard.magic_number);
303 var consumed_count: usize = 4;
304
305 var frame_context = context: {
306 var fbs = std.io.fixedBufferStream(src[consumed_count..]);
307 const source = fbs.reader();
308 const frame_header = try decodeZstandardHeader(source);
309 consumed_count += fbs.pos;
310 break :context FrameContext.init(
311 frame_header,
312 std.math.maxInt(usize),
313 verify_checksum,
314 ) catch |err| switch (err) {
315 error.WindowTooLarge => unreachable,
316 inline else => |e| return e,
317 };
318 };
319 const counts = try decodeZStandardFrameBlocks(
320 dest,
321 src[consumed_count..],
322 &frame_context,
323 );
324 return ReadWriteCount{
325 .read_count = counts.read_count + consumed_count,
326 .write_count = counts.write_count,
327 };
328}
329
330pub fn decodeZStandardFrameBlocks(
331 dest: []u8,
332 src: []const u8,
333 frame_context: *FrameContext,
334) (error{ ContentTooLarge, UnknownContentSizeUnsupported } || FrameError)!ReadWriteCount {
335 const content_size = frame_context.content_size orelse
336 return error.UnknownContentSizeUnsupported;
337 if (dest.len < content_size) return error.ContentTooLarge;
338
339 var consumed_count: usize = 0;
340 const written_count = decodeFrameBlocksInner(
341 dest[0..content_size],
342 src[consumed_count..],
343 &consumed_count,
344 if (frame_context.hasher_opt) |*hasher| hasher else null,
345 frame_context.block_size_max,
346 ) catch |err| switch (err) {
347 error.DestTooSmall => return error.BadContentSize,
348 inline else => |e| return e,
349 };
350
351 if (written_count != content_size) return error.BadContentSize;
352 if (frame_context.has_checksum) {
353 if (src.len < consumed_count + 4) return error.EndOfStream;
354 const checksum = std.mem.readInt(u32, src[consumed_count..][0..4], .little);
355 consumed_count += 4;
356 if (frame_context.hasher_opt) |*hasher| {
357 if (checksum != computeChecksum(hasher)) return error.ChecksumFailure;
358 }
359 }
360 return ReadWriteCount{ .read_count = consumed_count, .write_count = written_count };
361}
362
363pub const FrameContext = struct {
364 hasher_opt: ?std.hash.XxHash64,
365 window_size: usize,
366 has_checksum: bool,
367 block_size_max: usize,
368 content_size: ?usize,
369
370 const Error = error{
371 DictionaryIdFlagUnsupported,
372 WindowSizeUnknown,
373 WindowTooLarge,
374 ContentSizeTooLarge,
375 };
376 /// Validates `frame_header` and returns the associated `FrameContext`.
377 ///
378 /// Errors returned:
379 /// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary
380 /// - `error.WindowSizeUnknown` if the frame does not have a valid window
381 /// size
382 /// - `error.WindowTooLarge` if the window size is larger than
383 /// `window_size_max` or `std.math.intMax(usize)`
384 /// - `error.ContentSizeTooLarge` if the frame header indicates a content
385 /// size larger than `std.math.maxInt(usize)`
386 pub fn init(
387 frame_header: ZstandardHeader,
388 window_size_max: usize,
389 verify_checksum: bool,
390 ) Error!FrameContext {
391 if (frame_header.descriptor.dictionary_id_flag != 0)
392 return error.DictionaryIdFlagUnsupported;
393
394 const window_size_raw = frameWindowSize(frame_header) orelse return error.WindowSizeUnknown;
395 const window_size = if (window_size_raw > window_size_max)
396 return error.WindowTooLarge
397 else
398 std.math.cast(usize, window_size_raw) orelse return error.WindowTooLarge;
399
400 const should_compute_checksum =
401 frame_header.descriptor.content_checksum_flag and verify_checksum;
402
403 const content_size = if (frame_header.content_size) |size|
404 std.math.cast(usize, size) orelse return error.ContentSizeTooLarge
405 else
406 null;
407
408 return .{
409 .hasher_opt = if (should_compute_checksum) std.hash.XxHash64.init(0) else null,
410 .window_size = window_size,
411 .has_checksum = frame_header.descriptor.content_checksum_flag,
412 .block_size_max = @min(types.block_size_max, window_size),
413 .content_size = content_size,
414 };
415 }
416};
417
418/// Decode a Zstandard from from `src` and return number of bytes read; see
419/// `decodeZstandardFrame()`. The first four bytes of `src` must be the magic
420/// number for a Zstandard frame.
421///
422/// Errors returned:
423/// - `error.WindowSizeUnknown` if the frame does not have a valid window size
424/// - `error.WindowTooLarge` if the window size is larger than
425/// `window_size_max`
426/// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary
427/// - `error.ContentSizeTooLarge` if the frame header indicates a content size
428/// that is larger than `std.math.maxInt(usize)`
429/// - `error.ChecksumFailure` if `verify_checksum` is true and the frame
430/// contains a checksum that does not match the checksum of the decompressed
431/// data
432/// - `error.ReservedBitSet` if the reserved bit of the frame header is set
433/// - `error.EndOfStream` if `src` does not contain a complete frame
434/// - `error.OutOfMemory` if `allocator` cannot allocate enough memory
435/// - an error in `block.Error` if there are errors decoding a block
436/// - `error.BadContentSize` if the content size declared by the frame does
437/// not equal the size of decompressed data
438pub fn decodeZstandardFrameArrayList(
439 allocator: Allocator,
440 dest: *std.ArrayList(u8),
441 src: []const u8,
442 verify_checksum: bool,
443 window_size_max: usize,
444) (error{OutOfMemory} || FrameContext.Error || FrameError)!usize {
445 assert(std.mem.readInt(u32, src[0..4], .little) == frame.Zstandard.magic_number);
446 var consumed_count: usize = 4;
447
448 var frame_context = context: {
449 var fbs = std.io.fixedBufferStream(src[consumed_count..]);
450 const source = fbs.reader();
451 const frame_header = try decodeZstandardHeader(source);
452 consumed_count += fbs.pos;
453 break :context try FrameContext.init(frame_header, window_size_max, verify_checksum);
454 };
455
456 consumed_count += try decodeZstandardFrameBlocksArrayList(
457 allocator,
458 dest,
459 src[consumed_count..],
460 &frame_context,
461 );
462 return consumed_count;
463}
464
465pub fn decodeZstandardFrameBlocksArrayList(
466 allocator: Allocator,
467 dest: *std.ArrayList(u8),
468 src: []const u8,
469 frame_context: *FrameContext,
470) (error{OutOfMemory} || FrameError)!usize {
471 const initial_len = dest.items.len;
472
473 var ring_buffer = try RingBuffer.init(allocator, frame_context.window_size);
474 defer ring_buffer.deinit(allocator);
475
476 // These tables take 7680 bytes
477 var literal_fse_data: [types.compressed_block.table_size_max.literal]Table.Fse = undefined;
478 var match_fse_data: [types.compressed_block.table_size_max.match]Table.Fse = undefined;
479 var offset_fse_data: [types.compressed_block.table_size_max.offset]Table.Fse = undefined;
480
481 var block_header = try block.decodeBlockHeaderSlice(src);
482 var consumed_count: usize = 3;
483 var decode_state = block.DecodeState.init(&literal_fse_data, &match_fse_data, &offset_fse_data);
484 while (true) : ({
485 block_header = try block.decodeBlockHeaderSlice(src[consumed_count..]);
486 consumed_count += 3;
487 }) {
488 const written_size = try block.decodeBlockRingBuffer(
489 &ring_buffer,
490 src[consumed_count..],
491 block_header,
492 &decode_state,
493 &consumed_count,
494 frame_context.block_size_max,
495 );
496 if (frame_context.content_size) |size| {
497 if (dest.items.len - initial_len > size) {
498 return error.BadContentSize;
499 }
500 }
501 if (written_size > 0) {
502 const written_slice = ring_buffer.sliceLast(written_size);
503 try dest.appendSlice(written_slice.first);
504 try dest.appendSlice(written_slice.second);
505 if (frame_context.hasher_opt) |*hasher| {
506 hasher.update(written_slice.first);
507 hasher.update(written_slice.second);
508 }
509 }
510 if (block_header.last_block) break;
511 }
512 if (frame_context.content_size) |size| {
513 if (dest.items.len - initial_len != size) {
514 return error.BadContentSize;
515 }
516 }
517
518 if (frame_context.has_checksum) {
519 if (src.len < consumed_count + 4) return error.EndOfStream;
520 const checksum = std.mem.readInt(u32, src[consumed_count..][0..4], .little);
521 consumed_count += 4;
522 if (frame_context.hasher_opt) |*hasher| {
523 if (checksum != computeChecksum(hasher)) return error.ChecksumFailure;
524 }
525 }
526 return consumed_count;
527}
528
529fn decodeFrameBlocksInner(
530 dest: []u8,
531 src: []const u8,
532 consumed_count: *usize,
533 hash: ?*std.hash.XxHash64,
534 block_size_max: usize,
535) (error{ EndOfStream, DestTooSmall } || block.Error)!usize {
536 // These tables take 7680 bytes
537 var literal_fse_data: [types.compressed_block.table_size_max.literal]Table.Fse = undefined;
538 var match_fse_data: [types.compressed_block.table_size_max.match]Table.Fse = undefined;
539 var offset_fse_data: [types.compressed_block.table_size_max.offset]Table.Fse = undefined;
540
541 var block_header = try block.decodeBlockHeaderSlice(src);
542 var bytes_read: usize = 3;
543 defer consumed_count.* += bytes_read;
544 var decode_state = block.DecodeState.init(&literal_fse_data, &match_fse_data, &offset_fse_data);
545 var count: usize = 0;
546 while (true) : ({
547 block_header = try block.decodeBlockHeaderSlice(src[bytes_read..]);
548 bytes_read += 3;
549 }) {
550 const written_size = try block.decodeBlock(
551 dest,
552 src[bytes_read..],
553 block_header,
554 &decode_state,
555 &bytes_read,
556 block_size_max,
557 count,
558 );
559 if (hash) |hash_state| hash_state.update(dest[count .. count + written_size]);
560 count += written_size;
561 if (block_header.last_block) break;
562 }
563 return count;
564}
565
566/// Decode the header of a skippable frame. The first four bytes of `src` must
567/// be a valid magic number for a skippable frame.
568pub fn decodeSkippableHeader(src: *const [8]u8) SkippableHeader {
569 const magic = std.mem.readInt(u32, src[0..4], .little);
570 assert(isSkippableMagic(magic));
571 const frame_size = std.mem.readInt(u32, src[4..8], .little);
572 return .{
573 .magic_number = magic,
574 .frame_size = frame_size,
575 };
576}
577
578/// Returns the window size required to decompress a frame, or `null` if it
579/// cannot be determined (which indicates a malformed frame header).
580pub fn frameWindowSize(header: ZstandardHeader) ?u64 {
581 if (header.window_descriptor) |descriptor| {
582 const exponent = (descriptor & 0b11111000) >> 3;
583 const mantissa = descriptor & 0b00000111;
584 const window_log = 10 + exponent;
585 const window_base = @as(u64, 1) << @as(u6, @intCast(window_log));
586 const window_add = (window_base / 8) * mantissa;
587 return window_base + window_add;
588 } else return header.content_size;
589}
590
591/// Decode the header of a Zstandard frame.
592///
593/// Errors returned:
594/// - `error.ReservedBitSet` if any of the reserved bits of the header are set
595/// - `error.EndOfStream` if `source` does not contain a complete header
596pub fn decodeZstandardHeader(
597 source: anytype,
598) (@TypeOf(source).Error || error{ EndOfStream, ReservedBitSet })!ZstandardHeader {
599 const descriptor = @as(ZstandardHeader.Descriptor, @bitCast(try source.readByte()));
600
601 if (descriptor.reserved) return error.ReservedBitSet;
602
603 var window_descriptor: ?u8 = null;
604 if (!descriptor.single_segment_flag) {
605 window_descriptor = try source.readByte();
606 }
607
608 var dictionary_id: ?u32 = null;
609 if (descriptor.dictionary_id_flag > 0) {
610 // if flag is 3 then field_size = 4, else field_size = flag
611 const field_size = (@as(u4, 1) << descriptor.dictionary_id_flag) >> 1;
612 dictionary_id = try source.readVarInt(u32, .little, field_size);
613 }
614
615 var content_size: ?u64 = null;
616 if (descriptor.single_segment_flag or descriptor.content_size_flag > 0) {
617 const field_size = @as(u4, 1) << descriptor.content_size_flag;
618 content_size = try source.readVarInt(u64, .little, field_size);
619 if (field_size == 2) content_size.? += 256;
620 }
621
622 const header = ZstandardHeader{
623 .descriptor = descriptor,
624 .window_descriptor = window_descriptor,
625 .dictionary_id = dictionary_id,
626 .content_size = content_size,
627 };
628 return header;
629}
630
631test {
632 std.testing.refAllDecls(@This());
633}
lib/std/compress/zstandard/readers.zig deleted-82
...@@ -1,82 +0,0 @@
1const std = @import("std");
2
3pub const ReversedByteReader = struct {
4 remaining_bytes: usize,
5 bytes: []const u8,
6
7 const Reader = std.io.GenericReader(*ReversedByteReader, error{}, readFn);
8
9 pub fn init(bytes: []const u8) ReversedByteReader {
10 return .{
11 .bytes = bytes,
12 .remaining_bytes = bytes.len,
13 };
14 }
15
16 pub fn reader(self: *ReversedByteReader) Reader {
17 return .{ .context = self };
18 }
19
20 fn readFn(ctx: *ReversedByteReader, buffer: []u8) !usize {
21 if (ctx.remaining_bytes == 0) return 0;
22 const byte_index = ctx.remaining_bytes - 1;
23 buffer[0] = ctx.bytes[byte_index];
24 // buffer[0] = @bitReverse(ctx.bytes[byte_index]);
25 ctx.remaining_bytes = byte_index;
26 return 1;
27 }
28};
29
30/// A bit reader for reading the reversed bit streams used to encode
31/// FSE compressed data.
32pub const ReverseBitReader = struct {
33 byte_reader: ReversedByteReader,
34 bit_reader: std.io.BitReader(.big, ReversedByteReader.Reader),
35
36 pub fn init(self: *ReverseBitReader, bytes: []const u8) error{BitStreamHasNoStartBit}!void {
37 self.byte_reader = ReversedByteReader.init(bytes);
38 self.bit_reader = std.io.bitReader(.big, self.byte_reader.reader());
39 if (bytes.len == 0) return;
40 var i: usize = 0;
41 while (i < 8 and 0 == self.readBitsNoEof(u1, 1) catch unreachable) : (i += 1) {}
42 if (i == 8) return error.BitStreamHasNoStartBit;
43 }
44
45 pub fn readBitsNoEof(self: *@This(), comptime U: type, num_bits: u16) error{EndOfStream}!U {
46 return self.bit_reader.readBitsNoEof(U, num_bits);
47 }
48
49 pub fn readBits(self: *@This(), comptime U: type, num_bits: u16, out_bits: *u16) error{}!U {
50 return try self.bit_reader.readBits(U, num_bits, out_bits);
51 }
52
53 pub fn alignToByte(self: *@This()) void {
54 self.bit_reader.alignToByte();
55 }
56
57 pub fn isEmpty(self: ReverseBitReader) bool {
58 return self.byte_reader.remaining_bytes == 0 and self.bit_reader.count == 0;
59 }
60};
61
62pub fn BitReader(comptime Reader: type) type {
63 return struct {
64 underlying: std.io.BitReader(.little, Reader),
65
66 pub fn readBitsNoEof(self: *@This(), comptime U: type, num_bits: u16) !U {
67 return self.underlying.readBitsNoEof(U, num_bits);
68 }
69
70 pub fn readBits(self: *@This(), comptime U: type, num_bits: u16, out_bits: *u16) !U {
71 return self.underlying.readBits(U, num_bits, out_bits);
72 }
73
74 pub fn alignToByte(self: *@This()) void {
75 self.underlying.alignToByte();
76 }
77 };
78}
79
80pub fn bitReader(reader: anytype) BitReader(@TypeOf(reader)) {
81 return .{ .underlying = std.io.bitReader(.little, reader) };
82}
lib/std/compress/zstandard/types.zig deleted-403
...@@ -1,403 +0,0 @@
1pub const block_size_max = 1 << 17;
2
3pub const frame = struct {
4 pub const Kind = enum { zstandard, skippable };
5
6 pub const Zstandard = struct {
7 pub const magic_number = 0xFD2FB528;
8
9 header: Header,
10 data_blocks: []Block,
11 checksum: ?u32,
12
13 pub const Header = struct {
14 descriptor: Descriptor,
15 window_descriptor: ?u8,
16 dictionary_id: ?u32,
17 content_size: ?u64,
18
19 pub const Descriptor = packed struct {
20 dictionary_id_flag: u2,
21 content_checksum_flag: bool,
22 reserved: bool,
23 unused: bool,
24 single_segment_flag: bool,
25 content_size_flag: u2,
26 };
27 };
28
29 pub const Block = struct {
30 pub const Header = struct {
31 last_block: bool,
32 block_type: Block.Type,
33 block_size: u21,
34 };
35
36 pub const Type = enum(u2) {
37 raw,
38 rle,
39 compressed,
40 reserved,
41 };
42 };
43 };
44
45 pub const Skippable = struct {
46 pub const magic_number_min = 0x184D2A50;
47 pub const magic_number_max = 0x184D2A5F;
48
49 pub const Header = struct {
50 magic_number: u32,
51 frame_size: u32,
52 };
53 };
54};
55
56pub const compressed_block = struct {
57 pub const LiteralsSection = struct {
58 header: Header,
59 huffman_tree: ?HuffmanTree,
60 streams: Streams,
61
62 pub const Streams = union(enum) {
63 one: []const u8,
64 four: [4][]const u8,
65 };
66
67 pub const Header = struct {
68 block_type: BlockType,
69 size_format: u2,
70 regenerated_size: u20,
71 compressed_size: ?u18,
72 };
73
74 pub const BlockType = enum(u2) {
75 raw,
76 rle,
77 compressed,
78 treeless,
79 };
80
81 pub const HuffmanTree = struct {
82 max_bit_count: u4,
83 symbol_count_minus_one: u8,
84 nodes: [256]PrefixedSymbol,
85
86 pub const PrefixedSymbol = struct {
87 symbol: u8,
88 prefix: u16,
89 weight: u4,
90 };
91
92 pub const Result = union(enum) {
93 symbol: u8,
94 index: usize,
95 };
96
97 pub fn query(self: HuffmanTree, index: usize, prefix: u16) error{NotFound}!Result {
98 var node = self.nodes[index];
99 const weight = node.weight;
100 var i: usize = index;
101 while (node.weight == weight) {
102 if (node.prefix == prefix) return Result{ .symbol = node.symbol };
103 if (i == 0) return error.NotFound;
104 i -= 1;
105 node = self.nodes[i];
106 }
107 return Result{ .index = i };
108 }
109
110 pub fn weightToBitCount(weight: u4, max_bit_count: u4) u4 {
111 return if (weight == 0) 0 else ((max_bit_count + 1) - weight);
112 }
113 };
114
115 pub const StreamCount = enum { one, four };
116 pub fn streamCount(size_format: u2, block_type: BlockType) StreamCount {
117 return switch (block_type) {
118 .raw, .rle => .one,
119 .compressed, .treeless => if (size_format == 0) .one else .four,
120 };
121 }
122 };
123
124 pub const SequencesSection = struct {
125 header: SequencesSection.Header,
126 literals_length_table: Table,
127 offset_table: Table,
128 match_length_table: Table,
129
130 pub const Header = struct {
131 sequence_count: u24,
132 match_lengths: Mode,
133 offsets: Mode,
134 literal_lengths: Mode,
135
136 pub const Mode = enum(u2) {
137 predefined,
138 rle,
139 fse,
140 repeat,
141 };
142 };
143 };
144
145 pub const Table = union(enum) {
146 fse: []const Fse,
147 rle: u8,
148
149 pub const Fse = struct {
150 symbol: u8,
151 baseline: u16,
152 bits: u8,
153 };
154 };
155
156 pub const literals_length_code_table = [36]struct { u32, u5 }{
157 .{ 0, 0 }, .{ 1, 0 }, .{ 2, 0 }, .{ 3, 0 },
158 .{ 4, 0 }, .{ 5, 0 }, .{ 6, 0 }, .{ 7, 0 },
159 .{ 8, 0 }, .{ 9, 0 }, .{ 10, 0 }, .{ 11, 0 },
160 .{ 12, 0 }, .{ 13, 0 }, .{ 14, 0 }, .{ 15, 0 },
161 .{ 16, 1 }, .{ 18, 1 }, .{ 20, 1 }, .{ 22, 1 },
162 .{ 24, 2 }, .{ 28, 2 }, .{ 32, 3 }, .{ 40, 3 },
163 .{ 48, 4 }, .{ 64, 6 }, .{ 128, 7 }, .{ 256, 8 },
164 .{ 512, 9 }, .{ 1024, 10 }, .{ 2048, 11 }, .{ 4096, 12 },
165 .{ 8192, 13 }, .{ 16384, 14 }, .{ 32768, 15 }, .{ 65536, 16 },
166 };
167
168 pub const match_length_code_table = [53]struct { u32, u5 }{
169 .{ 3, 0 }, .{ 4, 0 }, .{ 5, 0 }, .{ 6, 0 }, .{ 7, 0 }, .{ 8, 0 },
170 .{ 9, 0 }, .{ 10, 0 }, .{ 11, 0 }, .{ 12, 0 }, .{ 13, 0 }, .{ 14, 0 },
171 .{ 15, 0 }, .{ 16, 0 }, .{ 17, 0 }, .{ 18, 0 }, .{ 19, 0 }, .{ 20, 0 },
172 .{ 21, 0 }, .{ 22, 0 }, .{ 23, 0 }, .{ 24, 0 }, .{ 25, 0 }, .{ 26, 0 },
173 .{ 27, 0 }, .{ 28, 0 }, .{ 29, 0 }, .{ 30, 0 }, .{ 31, 0 }, .{ 32, 0 },
174 .{ 33, 0 }, .{ 34, 0 }, .{ 35, 1 }, .{ 37, 1 }, .{ 39, 1 }, .{ 41, 1 },
175 .{ 43, 2 }, .{ 47, 2 }, .{ 51, 3 }, .{ 59, 3 }, .{ 67, 4 }, .{ 83, 4 },
176 .{ 99, 5 }, .{ 131, 7 }, .{ 259, 8 }, .{ 515, 9 }, .{ 1027, 10 }, .{ 2051, 11 },
177 .{ 4099, 12 }, .{ 8195, 13 }, .{ 16387, 14 }, .{ 32771, 15 }, .{ 65539, 16 },
178 };
179
180 pub const literals_length_default_distribution = [36]i16{
181 4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
182 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1,
183 -1, -1, -1, -1,
184 };
185
186 pub const match_lengths_default_distribution = [53]i16{
187 1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
188 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
189 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1,
190 -1, -1, -1, -1, -1,
191 };
192
193 pub const offset_codes_default_distribution = [29]i16{
194 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
195 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
196 };
197
198 pub const predefined_literal_fse_table = Table{
199 .fse = &[64]Table.Fse{
200 .{ .symbol = 0, .bits = 4, .baseline = 0 },
201 .{ .symbol = 0, .bits = 4, .baseline = 16 },
202 .{ .symbol = 1, .bits = 5, .baseline = 32 },
203 .{ .symbol = 3, .bits = 5, .baseline = 0 },
204 .{ .symbol = 4, .bits = 5, .baseline = 0 },
205 .{ .symbol = 6, .bits = 5, .baseline = 0 },
206 .{ .symbol = 7, .bits = 5, .baseline = 0 },
207 .{ .symbol = 9, .bits = 5, .baseline = 0 },
208 .{ .symbol = 10, .bits = 5, .baseline = 0 },
209 .{ .symbol = 12, .bits = 5, .baseline = 0 },
210 .{ .symbol = 14, .bits = 6, .baseline = 0 },
211 .{ .symbol = 16, .bits = 5, .baseline = 0 },
212 .{ .symbol = 18, .bits = 5, .baseline = 0 },
213 .{ .symbol = 19, .bits = 5, .baseline = 0 },
214 .{ .symbol = 21, .bits = 5, .baseline = 0 },
215 .{ .symbol = 22, .bits = 5, .baseline = 0 },
216 .{ .symbol = 24, .bits = 5, .baseline = 0 },
217 .{ .symbol = 25, .bits = 5, .baseline = 32 },
218 .{ .symbol = 26, .bits = 5, .baseline = 0 },
219 .{ .symbol = 27, .bits = 6, .baseline = 0 },
220 .{ .symbol = 29, .bits = 6, .baseline = 0 },
221 .{ .symbol = 31, .bits = 6, .baseline = 0 },
222 .{ .symbol = 0, .bits = 4, .baseline = 32 },
223 .{ .symbol = 1, .bits = 4, .baseline = 0 },
224 .{ .symbol = 2, .bits = 5, .baseline = 0 },
225 .{ .symbol = 4, .bits = 5, .baseline = 32 },
226 .{ .symbol = 5, .bits = 5, .baseline = 0 },
227 .{ .symbol = 7, .bits = 5, .baseline = 32 },
228 .{ .symbol = 8, .bits = 5, .baseline = 0 },
229 .{ .symbol = 10, .bits = 5, .baseline = 32 },
230 .{ .symbol = 11, .bits = 5, .baseline = 0 },
231 .{ .symbol = 13, .bits = 6, .baseline = 0 },
232 .{ .symbol = 16, .bits = 5, .baseline = 32 },
233 .{ .symbol = 17, .bits = 5, .baseline = 0 },
234 .{ .symbol = 19, .bits = 5, .baseline = 32 },
235 .{ .symbol = 20, .bits = 5, .baseline = 0 },
236 .{ .symbol = 22, .bits = 5, .baseline = 32 },
237 .{ .symbol = 23, .bits = 5, .baseline = 0 },
238 .{ .symbol = 25, .bits = 4, .baseline = 0 },
239 .{ .symbol = 25, .bits = 4, .baseline = 16 },
240 .{ .symbol = 26, .bits = 5, .baseline = 32 },
241 .{ .symbol = 28, .bits = 6, .baseline = 0 },
242 .{ .symbol = 30, .bits = 6, .baseline = 0 },
243 .{ .symbol = 0, .bits = 4, .baseline = 48 },
244 .{ .symbol = 1, .bits = 4, .baseline = 16 },
245 .{ .symbol = 2, .bits = 5, .baseline = 32 },
246 .{ .symbol = 3, .bits = 5, .baseline = 32 },
247 .{ .symbol = 5, .bits = 5, .baseline = 32 },
248 .{ .symbol = 6, .bits = 5, .baseline = 32 },
249 .{ .symbol = 8, .bits = 5, .baseline = 32 },
250 .{ .symbol = 9, .bits = 5, .baseline = 32 },
251 .{ .symbol = 11, .bits = 5, .baseline = 32 },
252 .{ .symbol = 12, .bits = 5, .baseline = 32 },
253 .{ .symbol = 15, .bits = 6, .baseline = 0 },
254 .{ .symbol = 17, .bits = 5, .baseline = 32 },
255 .{ .symbol = 18, .bits = 5, .baseline = 32 },
256 .{ .symbol = 20, .bits = 5, .baseline = 32 },
257 .{ .symbol = 21, .bits = 5, .baseline = 32 },
258 .{ .symbol = 23, .bits = 5, .baseline = 32 },
259 .{ .symbol = 24, .bits = 5, .baseline = 32 },
260 .{ .symbol = 35, .bits = 6, .baseline = 0 },
261 .{ .symbol = 34, .bits = 6, .baseline = 0 },
262 .{ .symbol = 33, .bits = 6, .baseline = 0 },
263 .{ .symbol = 32, .bits = 6, .baseline = 0 },
264 },
265 };
266
267 pub const predefined_match_fse_table = Table{
268 .fse = &[64]Table.Fse{
269 .{ .symbol = 0, .bits = 6, .baseline = 0 },
270 .{ .symbol = 1, .bits = 4, .baseline = 0 },
271 .{ .symbol = 2, .bits = 5, .baseline = 32 },
272 .{ .symbol = 3, .bits = 5, .baseline = 0 },
273 .{ .symbol = 5, .bits = 5, .baseline = 0 },
274 .{ .symbol = 6, .bits = 5, .baseline = 0 },
275 .{ .symbol = 8, .bits = 5, .baseline = 0 },
276 .{ .symbol = 10, .bits = 6, .baseline = 0 },
277 .{ .symbol = 13, .bits = 6, .baseline = 0 },
278 .{ .symbol = 16, .bits = 6, .baseline = 0 },
279 .{ .symbol = 19, .bits = 6, .baseline = 0 },
280 .{ .symbol = 22, .bits = 6, .baseline = 0 },
281 .{ .symbol = 25, .bits = 6, .baseline = 0 },
282 .{ .symbol = 28, .bits = 6, .baseline = 0 },
283 .{ .symbol = 31, .bits = 6, .baseline = 0 },
284 .{ .symbol = 33, .bits = 6, .baseline = 0 },
285 .{ .symbol = 35, .bits = 6, .baseline = 0 },
286 .{ .symbol = 37, .bits = 6, .baseline = 0 },
287 .{ .symbol = 39, .bits = 6, .baseline = 0 },
288 .{ .symbol = 41, .bits = 6, .baseline = 0 },
289 .{ .symbol = 43, .bits = 6, .baseline = 0 },
290 .{ .symbol = 45, .bits = 6, .baseline = 0 },
291 .{ .symbol = 1, .bits = 4, .baseline = 16 },
292 .{ .symbol = 2, .bits = 4, .baseline = 0 },
293 .{ .symbol = 3, .bits = 5, .baseline = 32 },
294 .{ .symbol = 4, .bits = 5, .baseline = 0 },
295 .{ .symbol = 6, .bits = 5, .baseline = 32 },
296 .{ .symbol = 7, .bits = 5, .baseline = 0 },
297 .{ .symbol = 9, .bits = 6, .baseline = 0 },
298 .{ .symbol = 12, .bits = 6, .baseline = 0 },
299 .{ .symbol = 15, .bits = 6, .baseline = 0 },
300 .{ .symbol = 18, .bits = 6, .baseline = 0 },
301 .{ .symbol = 21, .bits = 6, .baseline = 0 },
302 .{ .symbol = 24, .bits = 6, .baseline = 0 },
303 .{ .symbol = 27, .bits = 6, .baseline = 0 },
304 .{ .symbol = 30, .bits = 6, .baseline = 0 },
305 .{ .symbol = 32, .bits = 6, .baseline = 0 },
306 .{ .symbol = 34, .bits = 6, .baseline = 0 },
307 .{ .symbol = 36, .bits = 6, .baseline = 0 },
308 .{ .symbol = 38, .bits = 6, .baseline = 0 },
309 .{ .symbol = 40, .bits = 6, .baseline = 0 },
310 .{ .symbol = 42, .bits = 6, .baseline = 0 },
311 .{ .symbol = 44, .bits = 6, .baseline = 0 },
312 .{ .symbol = 1, .bits = 4, .baseline = 32 },
313 .{ .symbol = 1, .bits = 4, .baseline = 48 },
314 .{ .symbol = 2, .bits = 4, .baseline = 16 },
315 .{ .symbol = 4, .bits = 5, .baseline = 32 },
316 .{ .symbol = 5, .bits = 5, .baseline = 32 },
317 .{ .symbol = 7, .bits = 5, .baseline = 32 },
318 .{ .symbol = 8, .bits = 5, .baseline = 32 },
319 .{ .symbol = 11, .bits = 6, .baseline = 0 },
320 .{ .symbol = 14, .bits = 6, .baseline = 0 },
321 .{ .symbol = 17, .bits = 6, .baseline = 0 },
322 .{ .symbol = 20, .bits = 6, .baseline = 0 },
323 .{ .symbol = 23, .bits = 6, .baseline = 0 },
324 .{ .symbol = 26, .bits = 6, .baseline = 0 },
325 .{ .symbol = 29, .bits = 6, .baseline = 0 },
326 .{ .symbol = 52, .bits = 6, .baseline = 0 },
327 .{ .symbol = 51, .bits = 6, .baseline = 0 },
328 .{ .symbol = 50, .bits = 6, .baseline = 0 },
329 .{ .symbol = 49, .bits = 6, .baseline = 0 },
330 .{ .symbol = 48, .bits = 6, .baseline = 0 },
331 .{ .symbol = 47, .bits = 6, .baseline = 0 },
332 .{ .symbol = 46, .bits = 6, .baseline = 0 },
333 },
334 };
335
336 pub const predefined_offset_fse_table = Table{
337 .fse = &[32]Table.Fse{
338 .{ .symbol = 0, .bits = 5, .baseline = 0 },
339 .{ .symbol = 6, .bits = 4, .baseline = 0 },
340 .{ .symbol = 9, .bits = 5, .baseline = 0 },
341 .{ .symbol = 15, .bits = 5, .baseline = 0 },
342 .{ .symbol = 21, .bits = 5, .baseline = 0 },
343 .{ .symbol = 3, .bits = 5, .baseline = 0 },
344 .{ .symbol = 7, .bits = 4, .baseline = 0 },
345 .{ .symbol = 12, .bits = 5, .baseline = 0 },
346 .{ .symbol = 18, .bits = 5, .baseline = 0 },
347 .{ .symbol = 23, .bits = 5, .baseline = 0 },
348 .{ .symbol = 5, .bits = 5, .baseline = 0 },
349 .{ .symbol = 8, .bits = 4, .baseline = 0 },
350 .{ .symbol = 14, .bits = 5, .baseline = 0 },
351 .{ .symbol = 20, .bits = 5, .baseline = 0 },
352 .{ .symbol = 2, .bits = 5, .baseline = 0 },
353 .{ .symbol = 7, .bits = 4, .baseline = 16 },
354 .{ .symbol = 11, .bits = 5, .baseline = 0 },
355 .{ .symbol = 17, .bits = 5, .baseline = 0 },
356 .{ .symbol = 22, .bits = 5, .baseline = 0 },
357 .{ .symbol = 4, .bits = 5, .baseline = 0 },
358 .{ .symbol = 8, .bits = 4, .baseline = 16 },
359 .{ .symbol = 13, .bits = 5, .baseline = 0 },
360 .{ .symbol = 19, .bits = 5, .baseline = 0 },
361 .{ .symbol = 1, .bits = 5, .baseline = 0 },
362 .{ .symbol = 6, .bits = 4, .baseline = 16 },
363 .{ .symbol = 10, .bits = 5, .baseline = 0 },
364 .{ .symbol = 16, .bits = 5, .baseline = 0 },
365 .{ .symbol = 28, .bits = 5, .baseline = 0 },
366 .{ .symbol = 27, .bits = 5, .baseline = 0 },
367 .{ .symbol = 26, .bits = 5, .baseline = 0 },
368 .{ .symbol = 25, .bits = 5, .baseline = 0 },
369 .{ .symbol = 24, .bits = 5, .baseline = 0 },
370 },
371 };
372 pub const start_repeated_offset_1 = 1;
373 pub const start_repeated_offset_2 = 4;
374 pub const start_repeated_offset_3 = 8;
375
376 pub const table_accuracy_log_max = struct {
377 pub const literal = 9;
378 pub const match = 9;
379 pub const offset = 8;
380 };
381
382 pub const table_symbol_count_max = struct {
383 pub const literal = 36;
384 pub const match = 53;
385 pub const offset = 32;
386 };
387
388 pub const default_accuracy_log = struct {
389 pub const literal = 6;
390 pub const match = 6;
391 pub const offset = 5;
392 };
393 pub const table_size_max = struct {
394 pub const literal = 1 << table_accuracy_log_max.literal;
395 pub const match = 1 << table_accuracy_log_max.match;
396 pub const offset = 1 << table_accuracy_log_max.offset;
397 };
398};
399
400test {
401 const testing = @import("std").testing;
402 testing.refAllDeclsRecursive(@This());
403}
lib/std/compress/zstd.zig created+152
...@@ -0,0 +1,152 @@
1const std = @import("../std.zig");
2const assert = std.debug.assert;
3
4pub const Decompress = @import("zstd/Decompress.zig");
5
6/// Recommended amount by the standard. Lower than this may result in inability
7/// to decompress common streams.
8pub const default_window_len = 8 * 1024 * 1024;
9pub const block_size_max = 1 << 17;
10
11pub const literals_length_default_distribution = [36]i16{
12 4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
13 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1,
14 -1, -1, -1, -1,
15};
16
17pub const match_lengths_default_distribution = [53]i16{
18 1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
19 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
20 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1,
21 -1, -1, -1, -1, -1,
22};
23
24pub const offset_codes_default_distribution = [29]i16{
25 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
26 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1,
27};
28
29pub const start_repeated_offset_1 = 1;
30pub const start_repeated_offset_2 = 4;
31pub const start_repeated_offset_3 = 8;
32
33pub const literals_length_code_table = [36]struct { u32, u5 }{
34 .{ 0, 0 }, .{ 1, 0 }, .{ 2, 0 }, .{ 3, 0 },
35 .{ 4, 0 }, .{ 5, 0 }, .{ 6, 0 }, .{ 7, 0 },
36 .{ 8, 0 }, .{ 9, 0 }, .{ 10, 0 }, .{ 11, 0 },
37 .{ 12, 0 }, .{ 13, 0 }, .{ 14, 0 }, .{ 15, 0 },
38 .{ 16, 1 }, .{ 18, 1 }, .{ 20, 1 }, .{ 22, 1 },
39 .{ 24, 2 }, .{ 28, 2 }, .{ 32, 3 }, .{ 40, 3 },
40 .{ 48, 4 }, .{ 64, 6 }, .{ 128, 7 }, .{ 256, 8 },
41 .{ 512, 9 }, .{ 1024, 10 }, .{ 2048, 11 }, .{ 4096, 12 },
42 .{ 8192, 13 }, .{ 16384, 14 }, .{ 32768, 15 }, .{ 65536, 16 },
43};
44
45pub const match_length_code_table = [53]struct { u32, u5 }{
46 .{ 3, 0 }, .{ 4, 0 }, .{ 5, 0 }, .{ 6, 0 }, .{ 7, 0 }, .{ 8, 0 },
47 .{ 9, 0 }, .{ 10, 0 }, .{ 11, 0 }, .{ 12, 0 }, .{ 13, 0 }, .{ 14, 0 },
48 .{ 15, 0 }, .{ 16, 0 }, .{ 17, 0 }, .{ 18, 0 }, .{ 19, 0 }, .{ 20, 0 },
49 .{ 21, 0 }, .{ 22, 0 }, .{ 23, 0 }, .{ 24, 0 }, .{ 25, 0 }, .{ 26, 0 },
50 .{ 27, 0 }, .{ 28, 0 }, .{ 29, 0 }, .{ 30, 0 }, .{ 31, 0 }, .{ 32, 0 },
51 .{ 33, 0 }, .{ 34, 0 }, .{ 35, 1 }, .{ 37, 1 }, .{ 39, 1 }, .{ 41, 1 },
52 .{ 43, 2 }, .{ 47, 2 }, .{ 51, 3 }, .{ 59, 3 }, .{ 67, 4 }, .{ 83, 4 },
53 .{ 99, 5 }, .{ 131, 7 }, .{ 259, 8 }, .{ 515, 9 }, .{ 1027, 10 }, .{ 2051, 11 },
54 .{ 4099, 12 }, .{ 8195, 13 }, .{ 16387, 14 }, .{ 32771, 15 }, .{ 65539, 16 },
55};
56
57pub const table_accuracy_log_max = struct {
58 pub const literal = 9;
59 pub const match = 9;
60 pub const offset = 8;
61};
62
63pub const table_symbol_count_max = struct {
64 pub const literal = 36;
65 pub const match = 53;
66 pub const offset = 32;
67};
68
69pub const default_accuracy_log = struct {
70 pub const literal = 6;
71 pub const match = 6;
72 pub const offset = 5;
73};
74pub const table_size_max = struct {
75 pub const literal = 1 << table_accuracy_log_max.literal;
76 pub const match = 1 << table_accuracy_log_max.match;
77 pub const offset = 1 << table_accuracy_log_max.offset;
78};
79
80fn testDecompress(gpa: std.mem.Allocator, compressed: []const u8) ![]u8 {
81 var out: std.ArrayListUnmanaged(u8) = .empty;
82 defer out.deinit(gpa);
83 try out.ensureUnusedCapacity(gpa, default_window_len);
84
85 var in: std.io.Reader = .fixed(compressed);
86 var zstd_stream: Decompress = .init(&in, &.{}, .{});
87 try zstd_stream.reader.appendRemaining(gpa, null, &out, .unlimited);
88
89 return out.toOwnedSlice(gpa);
90}
91
92fn testExpectDecompress(uncompressed: []const u8, compressed: []const u8) !void {
93 const gpa = std.testing.allocator;
94 const result = try testDecompress(gpa, compressed);
95 defer gpa.free(result);
96 try std.testing.expectEqualSlices(u8, uncompressed, result);
97}
98
99fn testExpectDecompressError(err: anyerror, compressed: []const u8) !void {
100 const gpa = std.testing.allocator;
101
102 var out: std.ArrayListUnmanaged(u8) = .empty;
103 defer out.deinit(gpa);
104 try out.ensureUnusedCapacity(gpa, default_window_len);
105
106 var in: std.io.Reader = .fixed(compressed);
107 var zstd_stream: Decompress = .init(&in, &.{}, .{});
108 try std.testing.expectError(
109 error.ReadFailed,
110 zstd_stream.reader.appendRemaining(gpa, null, &out, .unlimited),
111 );
112 try std.testing.expectError(err, zstd_stream.err orelse {});
113}
114
115test Decompress {
116 const uncompressed = @embedFile("testdata/rfc8478.txt");
117 const compressed3 = @embedFile("testdata/rfc8478.txt.zst.3");
118 const compressed19 = @embedFile("testdata/rfc8478.txt.zst.19");
119
120 try testExpectDecompress(uncompressed, compressed3);
121 try testExpectDecompress(uncompressed, compressed19);
122}
123
124test "zero sized raw block" {
125 const input_raw =
126 "\x28\xb5\x2f\xfd" ++ // zstandard frame magic number
127 "\x20\x00" ++ // frame header: only single_segment_flag set, frame_content_size zero
128 "\x01\x00\x00"; // block header with: last_block set, block_type raw, block_size zero
129 try testExpectDecompress("", input_raw);
130}
131
132test "zero sized rle block" {
133 const input_rle =
134 "\x28\xb5\x2f\xfd" ++ // zstandard frame magic number
135 "\x20\x00" ++ // frame header: only single_segment_flag set, frame_content_size zero
136 "\x03\x00\x00" ++ // block header with: last_block set, block_type rle, block_size zero
137 "\xaa"; // block_content
138 try testExpectDecompress("", input_rle);
139}
140
141test "declared raw literals size too large" {
142 const input_raw =
143 "\x28\xb5\x2f\xfd" ++ // zstandard frame magic number
144 "\x00\x00" ++ // frame header: everything unset, window descriptor zero
145 "\x95\x00\x00" ++ // block header with: last_block set, block_type compressed, block_size 18
146 "\xbc\xf3\xae" ++ // literals section header with: type raw, size_format 3, regenerated_size 716603
147 "\xa5\x9f\xe3"; // some bytes of literal content - the content is shorter than regenerated_size
148
149 // Note that the regenerated_size in the above input is larger than block maximum size, so the
150 // block can't be valid as it is a raw literals block.
151 try testExpectDecompressError(error.MalformedLiteralsSection, input_raw);
152}
lib/std/compress/zstd/Decompress.zig created+1840
...@@ -0,0 +1,1840 @@
1const Decompress = @This();
2const std = @import("std");
3const assert = std.debug.assert;
4const Reader = std.io.Reader;
5const Limit = std.io.Limit;
6const zstd = @import("../zstd.zig");
7const Writer = std.io.Writer;
8
9input: *Reader,
10reader: Reader,
11state: State,
12verify_checksum: bool,
13window_len: u32,
14err: ?Error = null,
15
16const State = union(enum) {
17 new_frame,
18 in_frame: InFrame,
19 skipping_frame: usize,
20 end,
21
22 const InFrame = struct {
23 frame: Frame,
24 checksum: ?u32,
25 decompressed_size: usize,
26 decode: Frame.Zstandard.Decode,
27 };
28};
29
30pub const Options = struct {
31 /// Verifying checksums is not implemented yet and will cause a panic if
32 /// you set this to true.
33 verify_checksum: bool = false,
34
35 /// The output buffer is asserted to have capacity for `window_len` plus
36 /// `zstd.block_size_max`.
37 ///
38 /// If `window_len` is too small, then some streams will fail to decompress
39 /// with `error.OutputBufferUndersize`.
40 window_len: u32 = zstd.default_window_len,
41};
42
43pub const Error = error{
44 BadMagic,
45 BlockOversize,
46 ChecksumFailure,
47 ContentOversize,
48 DictionaryIdFlagUnsupported,
49 EndOfStream,
50 HuffmanTreeIncomplete,
51 InvalidBitStream,
52 MalformedAccuracyLog,
53 MalformedBlock,
54 MalformedCompressedBlock,
55 MalformedFrame,
56 MalformedFseBits,
57 MalformedFseTable,
58 MalformedHuffmanTree,
59 MalformedLiteralsHeader,
60 MalformedLiteralsLength,
61 MalformedLiteralsSection,
62 MalformedSequence,
63 MissingStartBit,
64 OutputBufferUndersize,
65 InputBufferUndersize,
66 ReadFailed,
67 RepeatModeFirst,
68 ReservedBitSet,
69 ReservedBlock,
70 SequenceBufferUndersize,
71 TreelessLiteralsFirst,
72 UnexpectedEndOfLiteralStream,
73 WindowOversize,
74 WindowSizeUnknown,
75};
76
77/// When connecting `reader` to a `Writer`, `buffer` should be empty, and
78/// `Writer.buffer` capacity has requirements based on `Options.window_len`.
79///
80/// Otherwise, `buffer` has those requirements.
81pub fn init(input: *Reader, buffer: []u8, options: Options) Decompress {
82 return .{
83 .input = input,
84 .state = .new_frame,
85 .verify_checksum = options.verify_checksum,
86 .window_len = options.window_len,
87 .reader = .{
88 .vtable = &.{
89 .stream = stream,
90 .rebase = rebase,
91 },
92 .buffer = buffer,
93 .seek = 0,
94 .end = 0,
95 },
96 };
97}
98
99fn rebase(r: *Reader, capacity: usize) Reader.RebaseError!void {
100 const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
101 assert(capacity <= r.buffer.len - d.window_len);
102 assert(r.end + capacity > r.buffer.len);
103 const buffered = r.buffer[0..r.end];
104 const discard = buffered.len - d.window_len;
105 const keep = buffered[discard..];
106 @memmove(r.buffer[0..keep.len], keep);
107 r.end = keep.len;
108 r.seek -= discard;
109}
110
111fn stream(r: *Reader, w: *Writer, limit: Limit) Reader.StreamError!usize {
112 const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
113 const in = d.input;
114
115 switch (d.state) {
116 .new_frame => {
117 // Allow error.EndOfStream only on the frame magic.
118 const magic = try in.takeEnumNonexhaustive(Frame.Magic, .little);
119 initFrame(d, w.buffer.len, magic) catch |err| {
120 d.err = err;
121 return error.ReadFailed;
122 };
123 return readInFrame(d, w, limit, &d.state.in_frame) catch |err| switch (err) {
124 error.ReadFailed => return error.ReadFailed,
125 error.WriteFailed => return error.WriteFailed,
126 else => |e| {
127 d.err = e;
128 return error.ReadFailed;
129 },
130 };
131 },
132 .in_frame => |*in_frame| {
133 return readInFrame(d, w, limit, in_frame) catch |err| switch (err) {
134 error.ReadFailed => return error.ReadFailed,
135 error.WriteFailed => return error.WriteFailed,
136 else => |e| {
137 d.err = e;
138 return error.ReadFailed;
139 },
140 };
141 },
142 .skipping_frame => |*remaining| {
143 const n = in.discard(.limited(remaining.*)) catch |err| {
144 d.err = err;
145 return error.ReadFailed;
146 };
147 remaining.* -= n;
148 if (remaining.* == 0) d.state = .new_frame;
149 return 0;
150 },
151 .end => return error.EndOfStream,
152 }
153}
154
155fn initFrame(d: *Decompress, window_size_max: usize, magic: Frame.Magic) !void {
156 const in = d.input;
157 switch (magic.kind() orelse return error.BadMagic) {
158 .zstandard => {
159 const header = try Frame.Zstandard.Header.decode(in);
160 d.state = .{ .in_frame = .{
161 .frame = try Frame.init(header, window_size_max, d.verify_checksum),
162 .checksum = null,
163 .decompressed_size = 0,
164 .decode = .init,
165 } };
166 },
167 .skippable => {
168 const frame_size = try in.takeInt(u32, .little);
169 d.state = .{ .skipping_frame = frame_size };
170 },
171 }
172}
173
174fn readInFrame(d: *Decompress, w: *Writer, limit: Limit, state: *State.InFrame) !usize {
175 const in = d.input;
176 const window_len = d.window_len;
177
178 const block_header = try in.takeStruct(Frame.Zstandard.Block.Header, .little);
179 const block_size = block_header.size;
180 const frame_block_size_max = state.frame.block_size_max;
181 if (frame_block_size_max < block_size) return error.BlockOversize;
182 if (@intFromEnum(limit) < block_size) return error.OutputBufferUndersize;
183 var bytes_written: usize = 0;
184 switch (block_header.type) {
185 .raw => {
186 try in.streamExactPreserve(w, window_len, block_size);
187 bytes_written = block_size;
188 },
189 .rle => {
190 const byte = try in.takeByte();
191 try w.splatBytePreserve(window_len, byte, block_size);
192 bytes_written = block_size;
193 },
194 .compressed => {
195 var literals_buffer: [zstd.block_size_max]u8 = undefined;
196 var sequence_buffer: [zstd.block_size_max]u8 = undefined;
197 var remaining: Limit = .limited(block_size);
198 const literals = try LiteralsSection.decode(in, &remaining, &literals_buffer);
199 const sequences_header = try SequencesSection.Header.decode(in, &remaining);
200
201 const decode = &state.decode;
202 try decode.prepare(in, &remaining, literals, sequences_header);
203
204 {
205 if (sequence_buffer.len < @intFromEnum(remaining))
206 return error.SequenceBufferUndersize;
207 const seq_slice = remaining.slice(&sequence_buffer);
208 try in.readSliceAll(seq_slice);
209 var bit_stream = try ReverseBitReader.init(seq_slice);
210
211 if (sequences_header.sequence_count > 0) {
212 try decode.readInitialFseState(&bit_stream);
213
214 // Ensures the following calls to `decodeSequence` will not flush.
215 if (window_len + frame_block_size_max > w.buffer.len) return error.OutputBufferUndersize;
216 const dest = (try w.writableSliceGreedyPreserve(window_len, frame_block_size_max))[0..frame_block_size_max];
217 const write_pos = dest.ptr - w.buffer.ptr;
218 for (0..sequences_header.sequence_count - 1) |_| {
219 bytes_written += try decode.decodeSequence(w.buffer, write_pos + bytes_written, &bit_stream);
220 try decode.updateState(.literal, &bit_stream);
221 try decode.updateState(.match, &bit_stream);
222 try decode.updateState(.offset, &bit_stream);
223 }
224 bytes_written += try decode.decodeSequence(w.buffer, write_pos + bytes_written, &bit_stream);
225 if (bytes_written > dest.len) return error.MalformedSequence;
226 w.advance(bytes_written);
227 }
228
229 if (!bit_stream.isEmpty()) {
230 return error.MalformedCompressedBlock;
231 }
232 }
233
234 if (decode.literal_written_count < literals.header.regenerated_size) {
235 const len = literals.header.regenerated_size - decode.literal_written_count;
236 try decode.decodeLiterals(w, len);
237 decode.literal_written_count += len;
238 bytes_written += len;
239 }
240
241 switch (decode.literal_header.block_type) {
242 .treeless, .compressed => {
243 if (!decode.isLiteralStreamEmpty()) return error.MalformedCompressedBlock;
244 },
245 .raw, .rle => {},
246 }
247
248 if (bytes_written > frame_block_size_max) return error.BlockOversize;
249 },
250 .reserved => return error.ReservedBlock,
251 }
252
253 if (state.frame.hasher_opt) |*hasher| {
254 if (bytes_written > 0) {
255 _ = hasher;
256 @panic("TODO all those bytes written needed to go through the hasher too");
257 }
258 }
259
260 state.decompressed_size += bytes_written;
261
262 if (block_header.last) {
263 if (state.frame.has_checksum) {
264 const expected_checksum = try in.takeInt(u32, .little);
265 if (state.frame.hasher_opt) |*hasher| {
266 const actual_checksum: u32 = @truncate(hasher.final());
267 if (expected_checksum != actual_checksum) return error.ChecksumFailure;
268 }
269 }
270 if (state.frame.content_size) |content_size| {
271 if (content_size != state.decompressed_size) {
272 return error.MalformedFrame;
273 }
274 }
275 d.state = .new_frame;
276 } else if (state.frame.content_size) |content_size| {
277 if (state.decompressed_size > content_size) return error.MalformedFrame;
278 }
279
280 return bytes_written;
281}
282
283pub const Frame = struct {
284 hasher_opt: ?std.hash.XxHash64,
285 window_size: usize,
286 has_checksum: bool,
287 block_size_max: usize,
288 content_size: ?usize,
289
290 pub const Magic = enum(u32) {
291 zstandard = 0xFD2FB528,
292 _,
293
294 pub fn kind(m: Magic) ?Kind {
295 return switch (@intFromEnum(m)) {
296 @intFromEnum(Magic.zstandard) => .zstandard,
297 @intFromEnum(Skippable.magic_min)...@intFromEnum(Skippable.magic_max) => .skippable,
298 else => null,
299 };
300 }
301
302 pub fn isSkippable(m: Magic) bool {
303 return switch (@intFromEnum(m)) {
304 @intFromEnum(Skippable.magic_min)...@intFromEnum(Skippable.magic_max) => true,
305 else => false,
306 };
307 }
308 };
309
310 pub const Kind = enum { zstandard, skippable };
311
312 pub const Zstandard = struct {
313 pub const magic: Magic = .zstandard;
314
315 header: Header,
316 data_blocks: []Block,
317 checksum: ?u32,
318
319 pub const Header = struct {
320 descriptor: Descriptor,
321 window_descriptor: ?u8,
322 dictionary_id: ?u32,
323 content_size: ?u64,
324
325 pub const Descriptor = packed struct {
326 dictionary_id_flag: u2,
327 content_checksum_flag: bool,
328 reserved: bool,
329 unused: bool,
330 single_segment_flag: bool,
331 content_size_flag: u2,
332 };
333
334 pub const DecodeError = Reader.Error || error{ReservedBitSet};
335
336 pub fn decode(in: *Reader) DecodeError!Header {
337 const descriptor: Descriptor = @bitCast(try in.takeByte());
338
339 if (descriptor.reserved) return error.ReservedBitSet;
340
341 const window_descriptor: ?u8 = if (descriptor.single_segment_flag) null else try in.takeByte();
342
343 const dictionary_id: ?u32 = if (descriptor.dictionary_id_flag > 0) d: {
344 // if flag is 3 then field_size = 4, else field_size = flag
345 const field_size = (@as(u4, 1) << descriptor.dictionary_id_flag) >> 1;
346 break :d try in.takeVarInt(u32, .little, field_size);
347 } else null;
348
349 const content_size: ?u64 = if (descriptor.single_segment_flag or descriptor.content_size_flag > 0) c: {
350 const field_size = @as(u4, 1) << descriptor.content_size_flag;
351 const content_size = try in.takeVarInt(u64, .little, field_size);
352 break :c if (field_size == 2) content_size + 256 else content_size;
353 } else null;
354
355 return .{
356 .descriptor = descriptor,
357 .window_descriptor = window_descriptor,
358 .dictionary_id = dictionary_id,
359 .content_size = content_size,
360 };
361 }
362
363 /// Returns the window size required to decompress a frame, or `null` if it
364 /// cannot be determined (which indicates a malformed frame header).
365 pub fn windowSize(header: Header) ?u64 {
366 if (header.window_descriptor) |descriptor| {
367 const exponent = (descriptor & 0b11111000) >> 3;
368 const mantissa = descriptor & 0b00000111;
369 const window_log = 10 + exponent;
370 const window_base = @as(u64, 1) << @as(u6, @intCast(window_log));
371 const window_add = (window_base / 8) * mantissa;
372 return window_base + window_add;
373 } else return header.content_size;
374 }
375 };
376
377 pub const Block = struct {
378 pub const Header = packed struct(u24) {
379 last: bool,
380 type: Type,
381 size: u21,
382 };
383
384 pub const Type = enum(u2) {
385 raw,
386 rle,
387 compressed,
388 reserved,
389 };
390 };
391
392 pub const Decode = struct {
393 repeat_offsets: [3]u32,
394
395 offset: StateData(8),
396 match: StateData(9),
397 literal: StateData(9),
398
399 literal_fse_buffer: [zstd.table_size_max.literal]Table.Fse,
400 match_fse_buffer: [zstd.table_size_max.match]Table.Fse,
401 offset_fse_buffer: [zstd.table_size_max.offset]Table.Fse,
402
403 fse_tables_undefined: bool,
404
405 literal_stream_reader: ReverseBitReader,
406 literal_stream_index: usize,
407 literal_streams: LiteralsSection.Streams,
408 literal_header: LiteralsSection.Header,
409 huffman_tree: ?LiteralsSection.HuffmanTree,
410
411 literal_written_count: usize,
412
413 fn StateData(comptime max_accuracy_log: comptime_int) type {
414 return struct {
415 state: @This().State,
416 table: Table,
417 accuracy_log: u8,
418
419 const State = std.meta.Int(.unsigned, max_accuracy_log);
420 };
421 }
422
423 const init: Decode = .{
424 .repeat_offsets = .{
425 zstd.start_repeated_offset_1,
426 zstd.start_repeated_offset_2,
427 zstd.start_repeated_offset_3,
428 },
429
430 .offset = undefined,
431 .match = undefined,
432 .literal = undefined,
433
434 .literal_fse_buffer = undefined,
435 .match_fse_buffer = undefined,
436 .offset_fse_buffer = undefined,
437
438 .fse_tables_undefined = true,
439
440 .literal_written_count = 0,
441 .literal_header = undefined,
442 .literal_streams = undefined,
443 .literal_stream_reader = undefined,
444 .literal_stream_index = undefined,
445 .huffman_tree = null,
446 };
447
448 pub const PrepareError = error{
449 /// the (reversed) literal bitstream's first byte does not have any bits set
450 MissingStartBit,
451 /// `literals` is a treeless literals section and the decode state does not
452 /// have a Huffman tree from a previous block
453 TreelessLiteralsFirst,
454 /// on the first call if one of the sequence FSE tables is set to repeat mode
455 RepeatModeFirst,
456 /// an FSE table has an invalid accuracy
457 MalformedAccuracyLog,
458 /// failed decoding an FSE table
459 MalformedFseTable,
460 /// input stream ends before all FSE tables are read
461 EndOfStream,
462 ReadFailed,
463 InputBufferUndersize,
464 };
465
466 /// Prepare the decoder to decode a compressed block. Loads the
467 /// literals stream and Huffman tree from `literals` and reads the
468 /// FSE tables from `in`.
469 pub fn prepare(
470 self: *Decode,
471 in: *Reader,
472 remaining: *Limit,
473 literals: LiteralsSection,
474 sequences_header: SequencesSection.Header,
475 ) PrepareError!void {
476 self.literal_written_count = 0;
477 self.literal_header = literals.header;
478 self.literal_streams = literals.streams;
479
480 if (literals.huffman_tree) |tree| {
481 self.huffman_tree = tree;
482 } else if (literals.header.block_type == .treeless and self.huffman_tree == null) {
483 return error.TreelessLiteralsFirst;
484 }
485
486 switch (literals.header.block_type) {
487 .raw, .rle => {},
488 .compressed, .treeless => {
489 self.literal_stream_index = 0;
490 switch (literals.streams) {
491 .one => |slice| try self.initLiteralStream(slice),
492 .four => |streams| try self.initLiteralStream(streams[0]),
493 }
494 },
495 }
496
497 if (sequences_header.sequence_count > 0) {
498 try self.updateFseTable(in, remaining, .literal, sequences_header.literal_lengths);
499 try self.updateFseTable(in, remaining, .offset, sequences_header.offsets);
500 try self.updateFseTable(in, remaining, .match, sequences_header.match_lengths);
501 self.fse_tables_undefined = false;
502 }
503 }
504
505 /// Read initial FSE states for sequence decoding.
506 pub fn readInitialFseState(self: *Decode, bit_reader: *ReverseBitReader) error{EndOfStream}!void {
507 self.literal.state = try bit_reader.readBitsNoEof(u9, self.literal.accuracy_log);
508 self.offset.state = try bit_reader.readBitsNoEof(u8, self.offset.accuracy_log);
509 self.match.state = try bit_reader.readBitsNoEof(u9, self.match.accuracy_log);
510 }
511
512 fn updateRepeatOffset(self: *Decode, offset: u32) void {
513 self.repeat_offsets[2] = self.repeat_offsets[1];
514 self.repeat_offsets[1] = self.repeat_offsets[0];
515 self.repeat_offsets[0] = offset;
516 }
517
518 fn useRepeatOffset(self: *Decode, index: usize) u32 {
519 if (index == 1)
520 std.mem.swap(u32, &self.repeat_offsets[0], &self.repeat_offsets[1])
521 else if (index == 2) {
522 std.mem.swap(u32, &self.repeat_offsets[0], &self.repeat_offsets[2]);
523 std.mem.swap(u32, &self.repeat_offsets[1], &self.repeat_offsets[2]);
524 }
525 return self.repeat_offsets[0];
526 }
527
528 const WhichFse = enum { offset, match, literal };
529
530 /// TODO: don't use `@field`
531 fn updateState(
532 self: *Decode,
533 comptime choice: WhichFse,
534 bit_reader: *ReverseBitReader,
535 ) error{ MalformedFseBits, EndOfStream }!void {
536 switch (@field(self, @tagName(choice)).table) {
537 .rle => {},
538 .fse => |table| {
539 const data = table[@field(self, @tagName(choice)).state];
540 const T = @TypeOf(@field(self, @tagName(choice))).State;
541 const bits_summand = try bit_reader.readBitsNoEof(T, data.bits);
542 const next_state = std.math.cast(
543 @TypeOf(@field(self, @tagName(choice))).State,
544 data.baseline + bits_summand,
545 ) orelse return error.MalformedFseBits;
546 @field(self, @tagName(choice)).state = next_state;
547 },
548 }
549 }
550
551 const FseTableError = error{
552 MalformedFseTable,
553 MalformedAccuracyLog,
554 RepeatModeFirst,
555 EndOfStream,
556 };
557
558 /// TODO: don't use `@field`
559 fn updateFseTable(
560 self: *Decode,
561 in: *Reader,
562 remaining: *Limit,
563 comptime choice: WhichFse,
564 mode: SequencesSection.Header.Mode,
565 ) !void {
566 const field_name = @tagName(choice);
567 switch (mode) {
568 .predefined => {
569 @field(self, field_name).accuracy_log =
570 @field(zstd.default_accuracy_log, field_name);
571
572 @field(self, field_name).table =
573 @field(Table, "predefined_" ++ field_name);
574 },
575 .rle => {
576 @field(self, field_name).accuracy_log = 0;
577 remaining.* = remaining.subtract(1) orelse return error.EndOfStream;
578 @field(self, field_name).table = .{ .rle = try in.takeByte() };
579 },
580 .fse => {
581 const max_table_size = 2048;
582 const peek_len: usize = remaining.minInt(max_table_size);
583 if (in.buffer.len < peek_len) return error.InputBufferUndersize;
584 const limited_buffer = try in.peek(peek_len);
585 var bit_reader: BitReader = .{ .bytes = limited_buffer };
586 const table_size = try Table.decode(
587 &bit_reader,
588 @field(zstd.table_symbol_count_max, field_name),
589 @field(zstd.table_accuracy_log_max, field_name),
590 &@field(self, field_name ++ "_fse_buffer"),
591 );
592 @field(self, field_name).table = .{
593 .fse = (&@field(self, field_name ++ "_fse_buffer"))[0..table_size],
594 };
595 @field(self, field_name).accuracy_log = std.math.log2_int_ceil(usize, table_size);
596 in.toss(bit_reader.index);
597 remaining.* = remaining.subtract(bit_reader.index).?;
598 },
599 .repeat => if (self.fse_tables_undefined) return error.RepeatModeFirst,
600 }
601 }
602
603 const Sequence = struct {
604 literal_length: u32,
605 match_length: u32,
606 offset: u32,
607 };
608
609 fn nextSequence(
610 self: *Decode,
611 bit_reader: *ReverseBitReader,
612 ) error{ InvalidBitStream, EndOfStream }!Sequence {
613 const raw_code = self.getCode(.offset);
614 const offset_code = std.math.cast(u5, raw_code) orelse {
615 return error.InvalidBitStream;
616 };
617 const offset_value = (@as(u32, 1) << offset_code) + try bit_reader.readBitsNoEof(u32, offset_code);
618
619 const match_code = self.getCode(.match);
620 if (match_code >= zstd.match_length_code_table.len)
621 return error.InvalidBitStream;
622 const match = zstd.match_length_code_table[match_code];
623 const match_length = match[0] + try bit_reader.readBitsNoEof(u32, match[1]);
624
625 const literal_code = self.getCode(.literal);
626 if (literal_code >= zstd.literals_length_code_table.len)
627 return error.InvalidBitStream;
628 const literal = zstd.literals_length_code_table[literal_code];
629 const literal_length = literal[0] + try bit_reader.readBitsNoEof(u32, literal[1]);
630
631 const offset = if (offset_value > 3) offset: {
632 const offset = offset_value - 3;
633 self.updateRepeatOffset(offset);
634 break :offset offset;
635 } else offset: {
636 if (literal_length == 0) {
637 if (offset_value == 3) {
638 const offset = self.repeat_offsets[0] - 1;
639 self.updateRepeatOffset(offset);
640 break :offset offset;
641 }
642 break :offset self.useRepeatOffset(offset_value);
643 }
644 break :offset self.useRepeatOffset(offset_value - 1);
645 };
646
647 if (offset == 0) return error.InvalidBitStream;
648
649 return .{
650 .literal_length = literal_length,
651 .match_length = match_length,
652 .offset = offset,
653 };
654 }
655
656 /// Decode one sequence from `bit_reader` into `dest`. Updates FSE states
657 /// if `last_sequence` is `false`. Assumes `prepare` called for the block
658 /// before attempting to decode sequences.
659 fn decodeSequence(
660 decode: *Decode,
661 dest: []u8,
662 write_pos: usize,
663 bit_reader: *ReverseBitReader,
664 ) !usize {
665 const sequence = try decode.nextSequence(bit_reader);
666 const literal_length: usize = sequence.literal_length;
667 const match_length: usize = sequence.match_length;
668 const sequence_length = literal_length + match_length;
669
670 const copy_start = std.math.sub(usize, write_pos + sequence.literal_length, sequence.offset) catch
671 return error.MalformedSequence;
672
673 if (decode.literal_written_count + literal_length > decode.literal_header.regenerated_size)
674 return error.MalformedLiteralsLength;
675 var sub_bw: Writer = .fixed(dest[write_pos..]);
676 try decodeLiterals(decode, &sub_bw, literal_length);
677 decode.literal_written_count += literal_length;
678 // This is not a @memmove; it intentionally repeats patterns
679 // caused by iterating one byte at a time.
680 for (
681 dest[write_pos + literal_length ..][0..match_length],
682 dest[copy_start..][0..match_length],
683 ) |*d, s| d.* = s;
684 return sequence_length;
685 }
686
687 fn nextLiteralMultiStream(self: *Decode) error{MissingStartBit}!void {
688 self.literal_stream_index += 1;
689 try self.initLiteralStream(self.literal_streams.four[self.literal_stream_index]);
690 }
691
692 fn initLiteralStream(self: *Decode, bytes: []const u8) error{MissingStartBit}!void {
693 self.literal_stream_reader = try ReverseBitReader.init(bytes);
694 }
695
696 fn isLiteralStreamEmpty(self: *Decode) bool {
697 switch (self.literal_streams) {
698 .one => return self.literal_stream_reader.isEmpty(),
699 .four => return self.literal_stream_index == 3 and self.literal_stream_reader.isEmpty(),
700 }
701 }
702
703 const LiteralBitsError = error{
704 MissingStartBit,
705 UnexpectedEndOfLiteralStream,
706 };
707 fn readLiteralsBits(
708 self: *Decode,
709 bit_count_to_read: u16,
710 ) LiteralBitsError!u16 {
711 return self.literal_stream_reader.readBitsNoEof(u16, bit_count_to_read) catch bits: {
712 if (self.literal_streams == .four and self.literal_stream_index < 3) {
713 try self.nextLiteralMultiStream();
714 break :bits self.literal_stream_reader.readBitsNoEof(u16, bit_count_to_read) catch
715 return error.UnexpectedEndOfLiteralStream;
716 } else {
717 return error.UnexpectedEndOfLiteralStream;
718 }
719 };
720 }
721
722 /// Decode `len` bytes of literals into `w`.
723 fn decodeLiterals(d: *Decode, w: *Writer, len: usize) !void {
724 switch (d.literal_header.block_type) {
725 .raw => {
726 try w.writeAll(d.literal_streams.one[d.literal_written_count..][0..len]);
727 },
728 .rle => {
729 try w.splatByteAll(d.literal_streams.one[0], len);
730 },
731 .compressed, .treeless => {
732 if (len > w.buffer.len) return error.OutputBufferUndersize;
733 const buf = try w.writableSlice(len);
734 const huffman_tree = d.huffman_tree.?;
735 const max_bit_count = huffman_tree.max_bit_count;
736 const starting_bit_count = LiteralsSection.HuffmanTree.weightToBitCount(
737 huffman_tree.nodes[huffman_tree.symbol_count_minus_one].weight,
738 max_bit_count,
739 );
740 var bits_read: u4 = 0;
741 var huffman_tree_index: usize = huffman_tree.symbol_count_minus_one;
742 var bit_count_to_read: u4 = starting_bit_count;
743 for (buf) |*out| {
744 var prefix: u16 = 0;
745 while (true) {
746 const new_bits = try d.readLiteralsBits(bit_count_to_read);
747 prefix <<= bit_count_to_read;
748 prefix |= new_bits;
749 bits_read += bit_count_to_read;
750 const result = try huffman_tree.query(huffman_tree_index, prefix);
751
752 switch (result) {
753 .symbol => |sym| {
754 out.* = sym;
755 bit_count_to_read = starting_bit_count;
756 bits_read = 0;
757 huffman_tree_index = huffman_tree.symbol_count_minus_one;
758 break;
759 },
760 .index => |index| {
761 huffman_tree_index = index;
762 const bit_count = LiteralsSection.HuffmanTree.weightToBitCount(
763 huffman_tree.nodes[index].weight,
764 max_bit_count,
765 );
766 bit_count_to_read = bit_count - bits_read;
767 },
768 }
769 }
770 }
771 },
772 }
773 }
774
775 /// TODO: don't use `@field`
776 fn getCode(self: *Decode, comptime choice: WhichFse) u32 {
777 return switch (@field(self, @tagName(choice)).table) {
778 .rle => |value| value,
779 .fse => |table| table[@field(self, @tagName(choice)).state].symbol,
780 };
781 }
782 };
783 };
784
785 pub const Skippable = struct {
786 pub const magic_min: Magic = @enumFromInt(0x184D2A50);
787 pub const magic_max: Magic = @enumFromInt(0x184D2A5F);
788
789 pub const Header = struct {
790 magic_number: u32,
791 frame_size: u32,
792 };
793 };
794
795 const InitError = error{
796 /// Frame uses a dictionary.
797 DictionaryIdFlagUnsupported,
798 /// Frame does not have a valid window size.
799 WindowSizeUnknown,
800 /// Window size exceeds `window_size_max` or max `usize` value.
801 WindowOversize,
802 /// Frame header indicates a content size exceeding max `usize` value.
803 ContentOversize,
804 };
805
806 /// Validates `frame_header` and returns the associated `Frame`.
807 pub fn init(
808 frame_header: Frame.Zstandard.Header,
809 window_size_max: usize,
810 verify_checksum: bool,
811 ) InitError!Frame {
812 if (frame_header.descriptor.dictionary_id_flag != 0)
813 return error.DictionaryIdFlagUnsupported;
814
815 const window_size_raw = frame_header.windowSize() orelse return error.WindowSizeUnknown;
816 const window_size = if (window_size_raw > window_size_max)
817 return error.WindowOversize
818 else
819 std.math.cast(usize, window_size_raw) orelse return error.WindowOversize;
820
821 const should_compute_checksum =
822 frame_header.descriptor.content_checksum_flag and verify_checksum;
823
824 const content_size = if (frame_header.content_size) |size|
825 std.math.cast(usize, size) orelse return error.ContentOversize
826 else
827 null;
828
829 return .{
830 .hasher_opt = if (should_compute_checksum) std.hash.XxHash64.init(0) else null,
831 .window_size = window_size,
832 .has_checksum = frame_header.descriptor.content_checksum_flag,
833 .block_size_max = @min(zstd.block_size_max, window_size),
834 .content_size = content_size,
835 };
836 }
837};
838
839pub const LiteralsSection = struct {
840 header: Header,
841 huffman_tree: ?HuffmanTree,
842 streams: Streams,
843
844 pub const Streams = union(enum) {
845 one: []const u8,
846 four: [4][]const u8,
847
848 fn decode(size_format: u2, stream_data: []const u8) !Streams {
849 if (size_format == 0) {
850 return .{ .one = stream_data };
851 }
852
853 if (stream_data.len < 6) return error.MalformedLiteralsSection;
854
855 const stream_1_length: usize = std.mem.readInt(u16, stream_data[0..2], .little);
856 const stream_2_length: usize = std.mem.readInt(u16, stream_data[2..4], .little);
857 const stream_3_length: usize = std.mem.readInt(u16, stream_data[4..6], .little);
858
859 const stream_1_start = 6;
860 const stream_2_start = stream_1_start + stream_1_length;
861 const stream_3_start = stream_2_start + stream_2_length;
862 const stream_4_start = stream_3_start + stream_3_length;
863
864 if (stream_data.len < stream_4_start) return error.MalformedLiteralsSection;
865
866 return .{ .four = .{
867 stream_data[stream_1_start .. stream_1_start + stream_1_length],
868 stream_data[stream_2_start .. stream_2_start + stream_2_length],
869 stream_data[stream_3_start .. stream_3_start + stream_3_length],
870 stream_data[stream_4_start..],
871 } };
872 }
873 };
874
875 pub const Header = struct {
876 block_type: BlockType,
877 size_format: u2,
878 regenerated_size: u20,
879 compressed_size: ?u18,
880
881 /// Decode a literals section header.
882 pub fn decode(in: *Reader, remaining: *Limit) !Header {
883 remaining.* = remaining.subtract(1) orelse return error.EndOfStream;
884 const byte0 = try in.takeByte();
885 const block_type: BlockType = @enumFromInt(byte0 & 0b11);
886 const size_format: u2 = @intCast((byte0 & 0b1100) >> 2);
887 var regenerated_size: u20 = undefined;
888 var compressed_size: ?u18 = null;
889 switch (block_type) {
890 .raw, .rle => {
891 switch (size_format) {
892 0, 2 => {
893 regenerated_size = byte0 >> 3;
894 },
895 1 => {
896 remaining.* = remaining.subtract(1) orelse return error.EndOfStream;
897 regenerated_size = (byte0 >> 4) + (@as(u20, try in.takeByte()) << 4);
898 },
899 3 => {
900 remaining.* = remaining.subtract(2) orelse return error.EndOfStream;
901 regenerated_size = (byte0 >> 4) +
902 (@as(u20, try in.takeByte()) << 4) +
903 (@as(u20, try in.takeByte()) << 12);
904 },
905 }
906 },
907 .compressed, .treeless => {
908 remaining.* = remaining.subtract(2) orelse return error.EndOfStream;
909 const byte1 = try in.takeByte();
910 const byte2 = try in.takeByte();
911 switch (size_format) {
912 0, 1 => {
913 regenerated_size = (byte0 >> 4) + ((@as(u20, byte1) & 0b00111111) << 4);
914 compressed_size = ((byte1 & 0b11000000) >> 6) + (@as(u18, byte2) << 2);
915 },
916 2 => {
917 remaining.* = remaining.subtract(1) orelse return error.EndOfStream;
918 const byte3 = try in.takeByte();
919 regenerated_size = (byte0 >> 4) + (@as(u20, byte1) << 4) + ((@as(u20, byte2) & 0b00000011) << 12);
920 compressed_size = ((byte2 & 0b11111100) >> 2) + (@as(u18, byte3) << 6);
921 },
922 3 => {
923 remaining.* = remaining.subtract(2) orelse return error.EndOfStream;
924 const byte3 = try in.takeByte();
925 const byte4 = try in.takeByte();
926 regenerated_size = (byte0 >> 4) + (@as(u20, byte1) << 4) + ((@as(u20, byte2) & 0b00111111) << 12);
927 compressed_size = ((byte2 & 0b11000000) >> 6) + (@as(u18, byte3) << 2) + (@as(u18, byte4) << 10);
928 },
929 }
930 },
931 }
932 return .{
933 .block_type = block_type,
934 .size_format = size_format,
935 .regenerated_size = regenerated_size,
936 .compressed_size = compressed_size,
937 };
938 }
939 };
940
941 pub const BlockType = enum(u2) {
942 raw,
943 rle,
944 compressed,
945 treeless,
946 };
947
948 pub const HuffmanTree = struct {
949 max_bit_count: u4,
950 symbol_count_minus_one: u8,
951 nodes: [256]PrefixedSymbol,
952
953 pub const PrefixedSymbol = struct {
954 symbol: u8,
955 prefix: u16,
956 weight: u4,
957 };
958
959 pub const Result = union(enum) {
960 symbol: u8,
961 index: usize,
962 };
963
964 pub fn query(self: HuffmanTree, index: usize, prefix: u16) error{HuffmanTreeIncomplete}!Result {
965 var node = self.nodes[index];
966 const weight = node.weight;
967 var i: usize = index;
968 while (node.weight == weight) {
969 if (node.prefix == prefix) return .{ .symbol = node.symbol };
970 if (i == 0) return error.HuffmanTreeIncomplete;
971 i -= 1;
972 node = self.nodes[i];
973 }
974 return .{ .index = i };
975 }
976
977 pub fn weightToBitCount(weight: u4, max_bit_count: u4) u4 {
978 return if (weight == 0) 0 else ((max_bit_count + 1) - weight);
979 }
980
981 pub const DecodeError = Reader.Error || error{
982 MalformedHuffmanTree,
983 MalformedFseTable,
984 MalformedAccuracyLog,
985 EndOfStream,
986 MissingStartBit,
987 };
988
989 pub fn decode(in: *Reader, remaining: *Limit) HuffmanTree.DecodeError!HuffmanTree {
990 remaining.* = remaining.subtract(1) orelse return error.EndOfStream;
991 const header = try in.takeByte();
992 if (header < 128) {
993 return decodeFse(in, remaining, header);
994 } else {
995 return decodeDirect(in, remaining, header - 127);
996 }
997 }
998
999 fn decodeDirect(
1000 in: *Reader,
1001 remaining: *Limit,
1002 encoded_symbol_count: usize,
1003 ) HuffmanTree.DecodeError!HuffmanTree {
1004 var weights: [256]u4 = undefined;
1005 const weights_byte_count = (encoded_symbol_count + 1) / 2;
1006 remaining.* = remaining.subtract(weights_byte_count) orelse return error.EndOfStream;
1007 for (0..weights_byte_count) |i| {
1008 const byte = try in.takeByte();
1009 weights[2 * i] = @as(u4, @intCast(byte >> 4));
1010 weights[2 * i + 1] = @as(u4, @intCast(byte & 0xF));
1011 }
1012 const symbol_count = encoded_symbol_count + 1;
1013 return build(&weights, symbol_count);
1014 }
1015
1016 fn decodeFse(
1017 in: *Reader,
1018 remaining: *Limit,
1019 compressed_size: usize,
1020 ) HuffmanTree.DecodeError!HuffmanTree {
1021 var weights: [256]u4 = undefined;
1022 remaining.* = remaining.subtract(compressed_size) orelse return error.EndOfStream;
1023 const compressed_buffer = try in.take(compressed_size);
1024 var bit_reader: BitReader = .{ .bytes = compressed_buffer };
1025 var entries: [1 << 6]Table.Fse = undefined;
1026 const table_size = try Table.decode(&bit_reader, 256, 6, &entries);
1027 const accuracy_log = std.math.log2_int_ceil(usize, table_size);
1028 const remaining_buffer = bit_reader.bytes[bit_reader.index..];
1029 const symbol_count = try assignWeights(remaining_buffer, accuracy_log, &entries, &weights);
1030 return build(&weights, symbol_count);
1031 }
1032
1033 fn assignWeights(
1034 huff_bits_buffer: []const u8,
1035 accuracy_log: u16,
1036 entries: *[1 << 6]Table.Fse,
1037 weights: *[256]u4,
1038 ) !usize {
1039 var huff_bits = try ReverseBitReader.init(huff_bits_buffer);
1040
1041 var i: usize = 0;
1042 var even_state: u32 = try huff_bits.readBitsNoEof(u32, accuracy_log);
1043 var odd_state: u32 = try huff_bits.readBitsNoEof(u32, accuracy_log);
1044
1045 while (i < 254) {
1046 const even_data = entries[even_state];
1047 var read_bits: u16 = 0;
1048 const even_bits = huff_bits.readBits(u32, even_data.bits, &read_bits) catch unreachable;
1049 weights[i] = std.math.cast(u4, even_data.symbol) orelse return error.MalformedHuffmanTree;
1050 i += 1;
1051 if (read_bits < even_data.bits) {
1052 weights[i] = std.math.cast(u4, entries[odd_state].symbol) orelse return error.MalformedHuffmanTree;
1053 i += 1;
1054 break;
1055 }
1056 even_state = even_data.baseline + even_bits;
1057
1058 read_bits = 0;
1059 const odd_data = entries[odd_state];
1060 const odd_bits = huff_bits.readBits(u32, odd_data.bits, &read_bits) catch unreachable;
1061 weights[i] = std.math.cast(u4, odd_data.symbol) orelse return error.MalformedHuffmanTree;
1062 i += 1;
1063 if (read_bits < odd_data.bits) {
1064 if (i == 255) return error.MalformedHuffmanTree;
1065 weights[i] = std.math.cast(u4, entries[even_state].symbol) orelse return error.MalformedHuffmanTree;
1066 i += 1;
1067 break;
1068 }
1069 odd_state = odd_data.baseline + odd_bits;
1070 } else return error.MalformedHuffmanTree;
1071
1072 if (!huff_bits.isEmpty()) {
1073 return error.MalformedHuffmanTree;
1074 }
1075
1076 return i + 1; // stream contains all but the last symbol
1077 }
1078
1079 fn assignSymbols(weight_sorted_prefixed_symbols: []PrefixedSymbol, weights: [256]u4) usize {
1080 for (0..weight_sorted_prefixed_symbols.len) |i| {
1081 weight_sorted_prefixed_symbols[i] = .{
1082 .symbol = @as(u8, @intCast(i)),
1083 .weight = undefined,
1084 .prefix = undefined,
1085 };
1086 }
1087
1088 std.mem.sort(
1089 PrefixedSymbol,
1090 weight_sorted_prefixed_symbols,
1091 weights,
1092 lessThanByWeight,
1093 );
1094
1095 var prefix: u16 = 0;
1096 var prefixed_symbol_count: usize = 0;
1097 var sorted_index: usize = 0;
1098 const symbol_count = weight_sorted_prefixed_symbols.len;
1099 while (sorted_index < symbol_count) {
1100 var symbol = weight_sorted_prefixed_symbols[sorted_index].symbol;
1101 const weight = weights[symbol];
1102 if (weight == 0) {
1103 sorted_index += 1;
1104 continue;
1105 }
1106
1107 while (sorted_index < symbol_count) : ({
1108 sorted_index += 1;
1109 prefixed_symbol_count += 1;
1110 prefix += 1;
1111 }) {
1112 symbol = weight_sorted_prefixed_symbols[sorted_index].symbol;
1113 if (weights[symbol] != weight) {
1114 prefix = ((prefix - 1) >> (weights[symbol] - weight)) + 1;
1115 break;
1116 }
1117 weight_sorted_prefixed_symbols[prefixed_symbol_count].symbol = symbol;
1118 weight_sorted_prefixed_symbols[prefixed_symbol_count].prefix = prefix;
1119 weight_sorted_prefixed_symbols[prefixed_symbol_count].weight = weight;
1120 }
1121 }
1122 return prefixed_symbol_count;
1123 }
1124
1125 fn build(weights: *[256]u4, symbol_count: usize) error{MalformedHuffmanTree}!HuffmanTree {
1126 var weight_power_sum_big: u32 = 0;
1127 for (weights[0 .. symbol_count - 1]) |value| {
1128 weight_power_sum_big += (@as(u16, 1) << value) >> 1;
1129 }
1130 if (weight_power_sum_big >= 1 << 11) return error.MalformedHuffmanTree;
1131 const weight_power_sum = @as(u16, @intCast(weight_power_sum_big));
1132
1133 // advance to next power of two (even if weight_power_sum is a power of 2)
1134 // TODO: is it valid to have weight_power_sum == 0?
1135 const max_number_of_bits = if (weight_power_sum == 0) 1 else std.math.log2_int(u16, weight_power_sum) + 1;
1136 const next_power_of_two = @as(u16, 1) << max_number_of_bits;
1137 weights[symbol_count - 1] = std.math.log2_int(u16, next_power_of_two - weight_power_sum) + 1;
1138
1139 var weight_sorted_prefixed_symbols: [256]PrefixedSymbol = undefined;
1140 const prefixed_symbol_count = assignSymbols(weight_sorted_prefixed_symbols[0..symbol_count], weights.*);
1141 const tree: HuffmanTree = .{
1142 .max_bit_count = max_number_of_bits,
1143 .symbol_count_minus_one = @as(u8, @intCast(prefixed_symbol_count - 1)),
1144 .nodes = weight_sorted_prefixed_symbols,
1145 };
1146 return tree;
1147 }
1148
1149 fn lessThanByWeight(
1150 weights: [256]u4,
1151 lhs: PrefixedSymbol,
1152 rhs: PrefixedSymbol,
1153 ) bool {
1154 // NOTE: this function relies on the use of a stable sorting algorithm,
1155 // otherwise a special case of if (weights[lhs] == weights[rhs]) return lhs < rhs;
1156 // should be added
1157 return weights[lhs.symbol] < weights[rhs.symbol];
1158 }
1159 };
1160
1161 pub const StreamCount = enum { one, four };
1162 pub fn streamCount(size_format: u2, block_type: BlockType) StreamCount {
1163 return switch (block_type) {
1164 .raw, .rle => .one,
1165 .compressed, .treeless => if (size_format == 0) .one else .four,
1166 };
1167 }
1168
1169 pub const DecodeError = error{
1170 /// Invalid header.
1171 MalformedLiteralsHeader,
1172 /// Decoding errors.
1173 MalformedLiteralsSection,
1174 /// Compressed literals have invalid accuracy.
1175 MalformedAccuracyLog,
1176 /// Compressed literals have invalid FSE table.
1177 MalformedFseTable,
1178 /// Failed decoding a Huffamn tree.
1179 MalformedHuffmanTree,
1180 /// Not enough bytes to complete the section.
1181 EndOfStream,
1182 ReadFailed,
1183 MissingStartBit,
1184 };
1185
1186 pub fn decode(in: *Reader, remaining: *Limit, buffer: []u8) DecodeError!LiteralsSection {
1187 const header = try Header.decode(in, remaining);
1188 switch (header.block_type) {
1189 .raw => {
1190 if (buffer.len < header.regenerated_size) return error.MalformedLiteralsSection;
1191 remaining.* = remaining.subtract(header.regenerated_size) orelse return error.EndOfStream;
1192 try in.readSliceAll(buffer[0..header.regenerated_size]);
1193 return .{
1194 .header = header,
1195 .huffman_tree = null,
1196 .streams = .{ .one = buffer },
1197 };
1198 },
1199 .rle => {
1200 remaining.* = remaining.subtract(1) orelse return error.EndOfStream;
1201 buffer[0] = try in.takeByte();
1202 return .{
1203 .header = header,
1204 .huffman_tree = null,
1205 .streams = .{ .one = buffer[0..1] },
1206 };
1207 },
1208 .compressed, .treeless => {
1209 const before_remaining = remaining.*;
1210 const huffman_tree = if (header.block_type == .compressed)
1211 try HuffmanTree.decode(in, remaining)
1212 else
1213 null;
1214 const huffman_tree_size = @intFromEnum(before_remaining) - @intFromEnum(remaining.*);
1215 const total_streams_size = std.math.sub(usize, header.compressed_size.?, huffman_tree_size) catch
1216 return error.MalformedLiteralsSection;
1217 if (total_streams_size > buffer.len) return error.MalformedLiteralsSection;
1218 remaining.* = remaining.subtract(total_streams_size) orelse return error.EndOfStream;
1219 try in.readSliceAll(buffer[0..total_streams_size]);
1220 const stream_data = buffer[0..total_streams_size];
1221 const streams = try Streams.decode(header.size_format, stream_data);
1222 return .{
1223 .header = header,
1224 .huffman_tree = huffman_tree,
1225 .streams = streams,
1226 };
1227 },
1228 }
1229 }
1230};
1231
1232pub const SequencesSection = struct {
1233 header: Header,
1234 literals_length_table: Table,
1235 offset_table: Table,
1236 match_length_table: Table,
1237
1238 pub const Header = struct {
1239 sequence_count: u24,
1240 match_lengths: Mode,
1241 offsets: Mode,
1242 literal_lengths: Mode,
1243
1244 pub const Mode = enum(u2) {
1245 predefined,
1246 rle,
1247 fse,
1248 repeat,
1249 };
1250
1251 pub const DecodeError = error{
1252 ReservedBitSet,
1253 EndOfStream,
1254 ReadFailed,
1255 };
1256
1257 pub fn decode(in: *Reader, remaining: *Limit) DecodeError!Header {
1258 var sequence_count: u24 = undefined;
1259
1260 remaining.* = remaining.subtract(1) orelse return error.EndOfStream;
1261 const byte0 = try in.takeByte();
1262 if (byte0 == 0) {
1263 return .{
1264 .sequence_count = 0,
1265 .offsets = undefined,
1266 .match_lengths = undefined,
1267 .literal_lengths = undefined,
1268 };
1269 } else if (byte0 < 128) {
1270 remaining.* = remaining.subtract(1) orelse return error.EndOfStream;
1271 sequence_count = byte0;
1272 } else if (byte0 < 255) {
1273 remaining.* = remaining.subtract(2) orelse return error.EndOfStream;
1274 sequence_count = (@as(u24, (byte0 - 128)) << 8) + try in.takeByte();
1275 } else {
1276 remaining.* = remaining.subtract(3) orelse return error.EndOfStream;
1277 sequence_count = (try in.takeByte()) + (@as(u24, try in.takeByte()) << 8) + 0x7F00;
1278 }
1279
1280 const compression_modes = try in.takeByte();
1281
1282 const matches_mode: Header.Mode = @enumFromInt((compression_modes & 0b00001100) >> 2);
1283 const offsets_mode: Header.Mode = @enumFromInt((compression_modes & 0b00110000) >> 4);
1284 const literal_mode: Header.Mode = @enumFromInt((compression_modes & 0b11000000) >> 6);
1285 if (compression_modes & 0b11 != 0) return error.ReservedBitSet;
1286
1287 return .{
1288 .sequence_count = sequence_count,
1289 .offsets = offsets_mode,
1290 .match_lengths = matches_mode,
1291 .literal_lengths = literal_mode,
1292 };
1293 }
1294 };
1295};
1296
1297pub const Table = union(enum) {
1298 fse: []const Fse,
1299 rle: u8,
1300
1301 pub const Fse = struct {
1302 symbol: u8,
1303 baseline: u16,
1304 bits: u8,
1305 };
1306
1307 pub fn decode(
1308 bit_reader: *BitReader,
1309 expected_symbol_count: usize,
1310 max_accuracy_log: u4,
1311 entries: []Table.Fse,
1312 ) !usize {
1313 const accuracy_log_biased = try bit_reader.readBitsNoEof(u4, 4);
1314 if (accuracy_log_biased > max_accuracy_log -| 5) return error.MalformedAccuracyLog;
1315 const accuracy_log = accuracy_log_biased + 5;
1316
1317 var values: [256]u16 = undefined;
1318 var value_count: usize = 0;
1319
1320 const total_probability = @as(u16, 1) << accuracy_log;
1321 var accumulated_probability: u16 = 0;
1322
1323 while (accumulated_probability < total_probability) {
1324 // WARNING: The RFC is poorly worded, and would suggest std.math.log2_int_ceil is correct here,
1325 // but power of two (remaining probabilities + 1) need max bits set to 1 more.
1326 const max_bits = std.math.log2_int(u16, total_probability - accumulated_probability + 1) + 1;
1327 const small = try bit_reader.readBitsNoEof(u16, max_bits - 1);
1328
1329 const cutoff = (@as(u16, 1) << max_bits) - 1 - (total_probability - accumulated_probability + 1);
1330
1331 const value = if (small < cutoff)
1332 small
1333 else value: {
1334 const value_read = small + (try bit_reader.readBitsNoEof(u16, 1) << (max_bits - 1));
1335 break :value if (value_read < @as(u16, 1) << (max_bits - 1))
1336 value_read
1337 else
1338 value_read - cutoff;
1339 };
1340
1341 accumulated_probability += if (value != 0) value - 1 else 1;
1342
1343 values[value_count] = value;
1344 value_count += 1;
1345
1346 if (value == 1) {
1347 while (true) {
1348 const repeat_flag = try bit_reader.readBitsNoEof(u2, 2);
1349 if (repeat_flag + value_count > 256) return error.MalformedFseTable;
1350 for (0..repeat_flag) |_| {
1351 values[value_count] = 1;
1352 value_count += 1;
1353 }
1354 if (repeat_flag < 3) break;
1355 }
1356 }
1357 if (value_count == 256) break;
1358 }
1359 bit_reader.alignToByte();
1360
1361 if (value_count < 2) return error.MalformedFseTable;
1362 if (accumulated_probability != total_probability) return error.MalformedFseTable;
1363 if (value_count > expected_symbol_count) return error.MalformedFseTable;
1364
1365 const table_size = total_probability;
1366
1367 try build(values[0..value_count], entries[0..table_size]);
1368 return table_size;
1369 }
1370
1371 pub fn build(values: []const u16, entries: []Table.Fse) !void {
1372 const total_probability = @as(u16, @intCast(entries.len));
1373 const accuracy_log = std.math.log2_int(u16, total_probability);
1374 assert(total_probability <= 1 << 9);
1375
1376 var less_than_one_count: usize = 0;
1377 for (values, 0..) |value, i| {
1378 if (value == 0) {
1379 entries[entries.len - 1 - less_than_one_count] = Table.Fse{
1380 .symbol = @as(u8, @intCast(i)),
1381 .baseline = 0,
1382 .bits = accuracy_log,
1383 };
1384 less_than_one_count += 1;
1385 }
1386 }
1387
1388 var position: usize = 0;
1389 var temp_states: [1 << 9]u16 = undefined;
1390 for (values, 0..) |value, symbol| {
1391 if (value == 0 or value == 1) continue;
1392 const probability = value - 1;
1393
1394 const state_share_dividend = std.math.ceilPowerOfTwo(u16, probability) catch
1395 return error.MalformedFseTable;
1396 const share_size = @divExact(total_probability, state_share_dividend);
1397 const double_state_count = state_share_dividend - probability;
1398 const single_state_count = probability - double_state_count;
1399 const share_size_log = std.math.log2_int(u16, share_size);
1400
1401 for (0..probability) |i| {
1402 temp_states[i] = @as(u16, @intCast(position));
1403 position += (entries.len >> 1) + (entries.len >> 3) + 3;
1404 position &= entries.len - 1;
1405 while (position >= entries.len - less_than_one_count) {
1406 position += (entries.len >> 1) + (entries.len >> 3) + 3;
1407 position &= entries.len - 1;
1408 }
1409 }
1410 std.mem.sort(u16, temp_states[0..probability], {}, std.sort.asc(u16));
1411 for (0..probability) |i| {
1412 entries[temp_states[i]] = if (i < double_state_count) Table.Fse{
1413 .symbol = @as(u8, @intCast(symbol)),
1414 .bits = share_size_log + 1,
1415 .baseline = single_state_count * share_size + @as(u16, @intCast(i)) * 2 * share_size,
1416 } else Table.Fse{
1417 .symbol = @as(u8, @intCast(symbol)),
1418 .bits = share_size_log,
1419 .baseline = (@as(u16, @intCast(i)) - double_state_count) * share_size,
1420 };
1421 }
1422 }
1423 }
1424
1425 test build {
1426 const literals_length_default_values = [36]u16{
1427 5, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2,
1428 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 2, 2, 2, 2, 2,
1429 0, 0, 0, 0,
1430 };
1431
1432 const match_lengths_default_values = [53]u16{
1433 2, 5, 4, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2,
1434 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1435 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0,
1436 0, 0, 0, 0, 0,
1437 };
1438
1439 const offset_codes_default_values = [29]u16{
1440 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2,
1441 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0,
1442 };
1443
1444 var entries: [64]Table.Fse = undefined;
1445 try build(&literals_length_default_values, &entries);
1446 try std.testing.expectEqualSlices(Table.Fse, Table.predefined_literal.fse, &entries);
1447
1448 try build(&match_lengths_default_values, &entries);
1449 try std.testing.expectEqualSlices(Table.Fse, Table.predefined_match.fse, &entries);
1450
1451 try build(&offset_codes_default_values, entries[0..32]);
1452 try std.testing.expectEqualSlices(Table.Fse, Table.predefined_offset.fse, entries[0..32]);
1453 }
1454
1455 pub const predefined_literal: Table = .{
1456 .fse = &[64]Table.Fse{
1457 .{ .symbol = 0, .bits = 4, .baseline = 0 },
1458 .{ .symbol = 0, .bits = 4, .baseline = 16 },
1459 .{ .symbol = 1, .bits = 5, .baseline = 32 },
1460 .{ .symbol = 3, .bits = 5, .baseline = 0 },
1461 .{ .symbol = 4, .bits = 5, .baseline = 0 },
1462 .{ .symbol = 6, .bits = 5, .baseline = 0 },
1463 .{ .symbol = 7, .bits = 5, .baseline = 0 },
1464 .{ .symbol = 9, .bits = 5, .baseline = 0 },
1465 .{ .symbol = 10, .bits = 5, .baseline = 0 },
1466 .{ .symbol = 12, .bits = 5, .baseline = 0 },
1467 .{ .symbol = 14, .bits = 6, .baseline = 0 },
1468 .{ .symbol = 16, .bits = 5, .baseline = 0 },
1469 .{ .symbol = 18, .bits = 5, .baseline = 0 },
1470 .{ .symbol = 19, .bits = 5, .baseline = 0 },
1471 .{ .symbol = 21, .bits = 5, .baseline = 0 },
1472 .{ .symbol = 22, .bits = 5, .baseline = 0 },
1473 .{ .symbol = 24, .bits = 5, .baseline = 0 },
1474 .{ .symbol = 25, .bits = 5, .baseline = 32 },
1475 .{ .symbol = 26, .bits = 5, .baseline = 0 },
1476 .{ .symbol = 27, .bits = 6, .baseline = 0 },
1477 .{ .symbol = 29, .bits = 6, .baseline = 0 },
1478 .{ .symbol = 31, .bits = 6, .baseline = 0 },
1479 .{ .symbol = 0, .bits = 4, .baseline = 32 },
1480 .{ .symbol = 1, .bits = 4, .baseline = 0 },
1481 .{ .symbol = 2, .bits = 5, .baseline = 0 },
1482 .{ .symbol = 4, .bits = 5, .baseline = 32 },
1483 .{ .symbol = 5, .bits = 5, .baseline = 0 },
1484 .{ .symbol = 7, .bits = 5, .baseline = 32 },
1485 .{ .symbol = 8, .bits = 5, .baseline = 0 },
1486 .{ .symbol = 10, .bits = 5, .baseline = 32 },
1487 .{ .symbol = 11, .bits = 5, .baseline = 0 },
1488 .{ .symbol = 13, .bits = 6, .baseline = 0 },
1489 .{ .symbol = 16, .bits = 5, .baseline = 32 },
1490 .{ .symbol = 17, .bits = 5, .baseline = 0 },
1491 .{ .symbol = 19, .bits = 5, .baseline = 32 },
1492 .{ .symbol = 20, .bits = 5, .baseline = 0 },
1493 .{ .symbol = 22, .bits = 5, .baseline = 32 },
1494 .{ .symbol = 23, .bits = 5, .baseline = 0 },
1495 .{ .symbol = 25, .bits = 4, .baseline = 0 },
1496 .{ .symbol = 25, .bits = 4, .baseline = 16 },
1497 .{ .symbol = 26, .bits = 5, .baseline = 32 },
1498 .{ .symbol = 28, .bits = 6, .baseline = 0 },
1499 .{ .symbol = 30, .bits = 6, .baseline = 0 },
1500 .{ .symbol = 0, .bits = 4, .baseline = 48 },
1501 .{ .symbol = 1, .bits = 4, .baseline = 16 },
1502 .{ .symbol = 2, .bits = 5, .baseline = 32 },
1503 .{ .symbol = 3, .bits = 5, .baseline = 32 },
1504 .{ .symbol = 5, .bits = 5, .baseline = 32 },
1505 .{ .symbol = 6, .bits = 5, .baseline = 32 },
1506 .{ .symbol = 8, .bits = 5, .baseline = 32 },
1507 .{ .symbol = 9, .bits = 5, .baseline = 32 },
1508 .{ .symbol = 11, .bits = 5, .baseline = 32 },
1509 .{ .symbol = 12, .bits = 5, .baseline = 32 },
1510 .{ .symbol = 15, .bits = 6, .baseline = 0 },
1511 .{ .symbol = 17, .bits = 5, .baseline = 32 },
1512 .{ .symbol = 18, .bits = 5, .baseline = 32 },
1513 .{ .symbol = 20, .bits = 5, .baseline = 32 },
1514 .{ .symbol = 21, .bits = 5, .baseline = 32 },
1515 .{ .symbol = 23, .bits = 5, .baseline = 32 },
1516 .{ .symbol = 24, .bits = 5, .baseline = 32 },
1517 .{ .symbol = 35, .bits = 6, .baseline = 0 },
1518 .{ .symbol = 34, .bits = 6, .baseline = 0 },
1519 .{ .symbol = 33, .bits = 6, .baseline = 0 },
1520 .{ .symbol = 32, .bits = 6, .baseline = 0 },
1521 },
1522 };
1523
1524 pub const predefined_match: Table = .{
1525 .fse = &[64]Table.Fse{
1526 .{ .symbol = 0, .bits = 6, .baseline = 0 },
1527 .{ .symbol = 1, .bits = 4, .baseline = 0 },
1528 .{ .symbol = 2, .bits = 5, .baseline = 32 },
1529 .{ .symbol = 3, .bits = 5, .baseline = 0 },
1530 .{ .symbol = 5, .bits = 5, .baseline = 0 },
1531 .{ .symbol = 6, .bits = 5, .baseline = 0 },
1532 .{ .symbol = 8, .bits = 5, .baseline = 0 },
1533 .{ .symbol = 10, .bits = 6, .baseline = 0 },
1534 .{ .symbol = 13, .bits = 6, .baseline = 0 },
1535 .{ .symbol = 16, .bits = 6, .baseline = 0 },
1536 .{ .symbol = 19, .bits = 6, .baseline = 0 },
1537 .{ .symbol = 22, .bits = 6, .baseline = 0 },
1538 .{ .symbol = 25, .bits = 6, .baseline = 0 },
1539 .{ .symbol = 28, .bits = 6, .baseline = 0 },
1540 .{ .symbol = 31, .bits = 6, .baseline = 0 },
1541 .{ .symbol = 33, .bits = 6, .baseline = 0 },
1542 .{ .symbol = 35, .bits = 6, .baseline = 0 },
1543 .{ .symbol = 37, .bits = 6, .baseline = 0 },
1544 .{ .symbol = 39, .bits = 6, .baseline = 0 },
1545 .{ .symbol = 41, .bits = 6, .baseline = 0 },
1546 .{ .symbol = 43, .bits = 6, .baseline = 0 },
1547 .{ .symbol = 45, .bits = 6, .baseline = 0 },
1548 .{ .symbol = 1, .bits = 4, .baseline = 16 },
1549 .{ .symbol = 2, .bits = 4, .baseline = 0 },
1550 .{ .symbol = 3, .bits = 5, .baseline = 32 },
1551 .{ .symbol = 4, .bits = 5, .baseline = 0 },
1552 .{ .symbol = 6, .bits = 5, .baseline = 32 },
1553 .{ .symbol = 7, .bits = 5, .baseline = 0 },
1554 .{ .symbol = 9, .bits = 6, .baseline = 0 },
1555 .{ .symbol = 12, .bits = 6, .baseline = 0 },
1556 .{ .symbol = 15, .bits = 6, .baseline = 0 },
1557 .{ .symbol = 18, .bits = 6, .baseline = 0 },
1558 .{ .symbol = 21, .bits = 6, .baseline = 0 },
1559 .{ .symbol = 24, .bits = 6, .baseline = 0 },
1560 .{ .symbol = 27, .bits = 6, .baseline = 0 },
1561 .{ .symbol = 30, .bits = 6, .baseline = 0 },
1562 .{ .symbol = 32, .bits = 6, .baseline = 0 },
1563 .{ .symbol = 34, .bits = 6, .baseline = 0 },
1564 .{ .symbol = 36, .bits = 6, .baseline = 0 },
1565 .{ .symbol = 38, .bits = 6, .baseline = 0 },
1566 .{ .symbol = 40, .bits = 6, .baseline = 0 },
1567 .{ .symbol = 42, .bits = 6, .baseline = 0 },
1568 .{ .symbol = 44, .bits = 6, .baseline = 0 },
1569 .{ .symbol = 1, .bits = 4, .baseline = 32 },
1570 .{ .symbol = 1, .bits = 4, .baseline = 48 },
1571 .{ .symbol = 2, .bits = 4, .baseline = 16 },
1572 .{ .symbol = 4, .bits = 5, .baseline = 32 },
1573 .{ .symbol = 5, .bits = 5, .baseline = 32 },
1574 .{ .symbol = 7, .bits = 5, .baseline = 32 },
1575 .{ .symbol = 8, .bits = 5, .baseline = 32 },
1576 .{ .symbol = 11, .bits = 6, .baseline = 0 },
1577 .{ .symbol = 14, .bits = 6, .baseline = 0 },
1578 .{ .symbol = 17, .bits = 6, .baseline = 0 },
1579 .{ .symbol = 20, .bits = 6, .baseline = 0 },
1580 .{ .symbol = 23, .bits = 6, .baseline = 0 },
1581 .{ .symbol = 26, .bits = 6, .baseline = 0 },
1582 .{ .symbol = 29, .bits = 6, .baseline = 0 },
1583 .{ .symbol = 52, .bits = 6, .baseline = 0 },
1584 .{ .symbol = 51, .bits = 6, .baseline = 0 },
1585 .{ .symbol = 50, .bits = 6, .baseline = 0 },
1586 .{ .symbol = 49, .bits = 6, .baseline = 0 },
1587 .{ .symbol = 48, .bits = 6, .baseline = 0 },
1588 .{ .symbol = 47, .bits = 6, .baseline = 0 },
1589 .{ .symbol = 46, .bits = 6, .baseline = 0 },
1590 },
1591 };
1592
1593 pub const predefined_offset: Table = .{
1594 .fse = &[32]Table.Fse{
1595 .{ .symbol = 0, .bits = 5, .baseline = 0 },
1596 .{ .symbol = 6, .bits = 4, .baseline = 0 },
1597 .{ .symbol = 9, .bits = 5, .baseline = 0 },
1598 .{ .symbol = 15, .bits = 5, .baseline = 0 },
1599 .{ .symbol = 21, .bits = 5, .baseline = 0 },
1600 .{ .symbol = 3, .bits = 5, .baseline = 0 },
1601 .{ .symbol = 7, .bits = 4, .baseline = 0 },
1602 .{ .symbol = 12, .bits = 5, .baseline = 0 },
1603 .{ .symbol = 18, .bits = 5, .baseline = 0 },
1604 .{ .symbol = 23, .bits = 5, .baseline = 0 },
1605 .{ .symbol = 5, .bits = 5, .baseline = 0 },
1606 .{ .symbol = 8, .bits = 4, .baseline = 0 },
1607 .{ .symbol = 14, .bits = 5, .baseline = 0 },
1608 .{ .symbol = 20, .bits = 5, .baseline = 0 },
1609 .{ .symbol = 2, .bits = 5, .baseline = 0 },
1610 .{ .symbol = 7, .bits = 4, .baseline = 16 },
1611 .{ .symbol = 11, .bits = 5, .baseline = 0 },
1612 .{ .symbol = 17, .bits = 5, .baseline = 0 },
1613 .{ .symbol = 22, .bits = 5, .baseline = 0 },
1614 .{ .symbol = 4, .bits = 5, .baseline = 0 },
1615 .{ .symbol = 8, .bits = 4, .baseline = 16 },
1616 .{ .symbol = 13, .bits = 5, .baseline = 0 },
1617 .{ .symbol = 19, .bits = 5, .baseline = 0 },
1618 .{ .symbol = 1, .bits = 5, .baseline = 0 },
1619 .{ .symbol = 6, .bits = 4, .baseline = 16 },
1620 .{ .symbol = 10, .bits = 5, .baseline = 0 },
1621 .{ .symbol = 16, .bits = 5, .baseline = 0 },
1622 .{ .symbol = 28, .bits = 5, .baseline = 0 },
1623 .{ .symbol = 27, .bits = 5, .baseline = 0 },
1624 .{ .symbol = 26, .bits = 5, .baseline = 0 },
1625 .{ .symbol = 25, .bits = 5, .baseline = 0 },
1626 .{ .symbol = 24, .bits = 5, .baseline = 0 },
1627 },
1628 };
1629};
1630
1631const low_bit_mask = [9]u8{
1632 0b00000000,
1633 0b00000001,
1634 0b00000011,
1635 0b00000111,
1636 0b00001111,
1637 0b00011111,
1638 0b00111111,
1639 0b01111111,
1640 0b11111111,
1641};
1642
1643fn Bits(comptime T: type) type {
1644 return struct { T, u16 };
1645}
1646
1647/// For reading the reversed bit streams used to encode FSE compressed data.
1648const ReverseBitReader = struct {
1649 bytes: []const u8,
1650 remaining: usize,
1651 bits: u8,
1652 count: u4,
1653
1654 fn init(bytes: []const u8) error{MissingStartBit}!ReverseBitReader {
1655 var result: ReverseBitReader = .{
1656 .bytes = bytes,
1657 .remaining = bytes.len,
1658 .bits = 0,
1659 .count = 0,
1660 };
1661 if (bytes.len == 0) return result;
1662 for (0..8) |_| if (0 != (result.readBitsNoEof(u1, 1) catch unreachable)) return result;
1663 return error.MissingStartBit;
1664 }
1665
1666 fn initBits(comptime T: type, out: anytype, num: u16) Bits(T) {
1667 const UT = std.meta.Int(.unsigned, @bitSizeOf(T));
1668 return .{
1669 @bitCast(@as(UT, @intCast(out))),
1670 num,
1671 };
1672 }
1673
1674 fn readBitsNoEof(self: *ReverseBitReader, comptime T: type, num: u16) error{EndOfStream}!T {
1675 const b, const c = try self.readBitsTuple(T, num);
1676 if (c < num) return error.EndOfStream;
1677 return b;
1678 }
1679
1680 fn readBits(self: *ReverseBitReader, comptime T: type, num: u16, out_bits: *u16) !T {
1681 const b, const c = try self.readBitsTuple(T, num);
1682 out_bits.* = c;
1683 return b;
1684 }
1685
1686 fn readBitsTuple(self: *ReverseBitReader, comptime T: type, num: u16) !Bits(T) {
1687 const UT = std.meta.Int(.unsigned, @bitSizeOf(T));
1688 const U = if (@bitSizeOf(T) < 8) u8 else UT;
1689
1690 if (num <= self.count) return initBits(T, self.removeBits(@intCast(num)), num);
1691
1692 var out_count: u16 = self.count;
1693 var out: U = self.removeBits(self.count);
1694
1695 const full_bytes_left = (num - out_count) / 8;
1696
1697 for (0..full_bytes_left) |_| {
1698 const byte = takeByte(self) catch |err| switch (err) {
1699 error.EndOfStream => return initBits(T, out, out_count),
1700 };
1701 if (U == u8) out = 0 else out <<= 8;
1702 out |= byte;
1703 out_count += 8;
1704 }
1705
1706 const bits_left = num - out_count;
1707 const keep = 8 - bits_left;
1708
1709 if (bits_left == 0) return initBits(T, out, out_count);
1710
1711 const final_byte = takeByte(self) catch |err| switch (err) {
1712 error.EndOfStream => return initBits(T, out, out_count),
1713 };
1714
1715 out <<= @intCast(bits_left);
1716 out |= final_byte >> @intCast(keep);
1717 self.bits = final_byte & low_bit_mask[keep];
1718
1719 self.count = @intCast(keep);
1720 return initBits(T, out, num);
1721 }
1722
1723 fn takeByte(rbr: *ReverseBitReader) error{EndOfStream}!u8 {
1724 if (rbr.remaining == 0) return error.EndOfStream;
1725 rbr.remaining -= 1;
1726 return rbr.bytes[rbr.remaining];
1727 }
1728
1729 fn isEmpty(self: *const ReverseBitReader) bool {
1730 return self.remaining == 0 and self.count == 0;
1731 }
1732
1733 fn removeBits(self: *ReverseBitReader, num: u4) u8 {
1734 if (num == 8) {
1735 self.count = 0;
1736 return self.bits;
1737 }
1738
1739 const keep = self.count - num;
1740 const bits = self.bits >> @intCast(keep);
1741 self.bits &= low_bit_mask[keep];
1742
1743 self.count = keep;
1744 return bits;
1745 }
1746};
1747
1748const BitReader = struct {
1749 bytes: []const u8,
1750 index: usize = 0,
1751 bits: u8 = 0,
1752 count: u4 = 0,
1753
1754 fn initBits(comptime T: type, out: anytype, num: u16) Bits(T) {
1755 const UT = std.meta.Int(.unsigned, @bitSizeOf(T));
1756 return .{
1757 @bitCast(@as(UT, @intCast(out))),
1758 num,
1759 };
1760 }
1761
1762 fn readBitsNoEof(self: *@This(), comptime T: type, num: u16) !T {
1763 const b, const c = try self.readBitsTuple(T, num);
1764 if (c < num) return error.EndOfStream;
1765 return b;
1766 }
1767
1768 fn readBits(self: *@This(), comptime T: type, num: u16, out_bits: *u16) !T {
1769 const b, const c = try self.readBitsTuple(T, num);
1770 out_bits.* = c;
1771 return b;
1772 }
1773
1774 fn readBitsTuple(self: *@This(), comptime T: type, num: u16) !Bits(T) {
1775 const UT = std.meta.Int(.unsigned, @bitSizeOf(T));
1776 const U = if (@bitSizeOf(T) < 8) u8 else UT;
1777
1778 if (num <= self.count) return initBits(T, self.removeBits(@intCast(num)), num);
1779
1780 var out_count: u16 = self.count;
1781 var out: U = self.removeBits(self.count);
1782
1783 const full_bytes_left = (num - out_count) / 8;
1784
1785 for (0..full_bytes_left) |_| {
1786 const byte = takeByte(self) catch |err| switch (err) {
1787 error.EndOfStream => return initBits(T, out, out_count),
1788 };
1789
1790 const pos = @as(U, byte) << @intCast(out_count);
1791 out |= pos;
1792 out_count += 8;
1793 }
1794
1795 const bits_left = num - out_count;
1796 const keep = 8 - bits_left;
1797
1798 if (bits_left == 0) return initBits(T, out, out_count);
1799
1800 const final_byte = takeByte(self) catch |err| switch (err) {
1801 error.EndOfStream => return initBits(T, out, out_count),
1802 };
1803
1804 const pos = @as(U, final_byte & low_bit_mask[bits_left]) << @intCast(out_count);
1805 out |= pos;
1806 self.bits = final_byte >> @intCast(bits_left);
1807
1808 self.count = @intCast(keep);
1809 return initBits(T, out, num);
1810 }
1811
1812 fn takeByte(br: *BitReader) error{EndOfStream}!u8 {
1813 if (br.bytes.len - br.index == 0) return error.EndOfStream;
1814 const result = br.bytes[br.index];
1815 br.index += 1;
1816 return result;
1817 }
1818
1819 fn removeBits(self: *@This(), num: u4) u8 {
1820 if (num == 8) {
1821 self.count = 0;
1822 return self.bits;
1823 }
1824
1825 const keep = self.count - num;
1826 const bits = self.bits & low_bit_mask[num];
1827 self.bits >>= @intCast(num);
1828 self.count = keep;
1829 return bits;
1830 }
1831
1832 fn alignToByte(self: *@This()) void {
1833 self.bits = 0;
1834 self.count = 0;
1835 }
1836};
1837
1838test {
1839 _ = Table;
1840}
lib/std/crypto/md5.zig+10-2
...@@ -54,12 +54,20 @@ pub const Md5 = struct {...@@ -54,12 +54,20 @@ pub const Md5 = struct {
54 };54 };
55 }55 }
5656
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 var d = Md5.init(options);58 var d = Md5.init(options);
59 d.update(b);59 d.update(data);
60 d.final(out);60 d.final(out);
61 }61 }
6262
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 pub fn update(d: *Self, b: []const u8) void {71 pub fn update(d: *Self, b: []const u8) void {
64 var off: usize = 0;72 var off: usize = 0;
6573
lib/std/elf.zig+103-172
...@@ -482,6 +482,7 @@ pub const Header = struct {...@@ -482,6 +482,7 @@ pub const Header = struct {
482 is_64: bool,482 is_64: bool,
483 endian: std.builtin.Endian,483 endian: std.builtin.Endian,
484 os_abi: OSABI,484 os_abi: OSABI,
485 /// The meaning of this value depends on `os_abi`.
485 abi_version: u8,486 abi_version: u8,
486 type: ET,487 type: ET,
487 machine: EM,488 machine: EM,
...@@ -494,205 +495,135 @@ pub const Header = struct {...@@ -494,205 +495,135 @@ pub const Header = struct {
494 shnum: u16,495 shnum: u16,
495 shstrndx: u16,496 shstrndx: u16,
496497
497 pub fn program_header_iterator(self: Header, parse_source: anytype) ProgramHeaderIterator(@TypeOf(parse_source)) {498 pub fn iterateProgramHeaders(h: Header, file_reader: *std.fs.File.Reader) ProgramHeaderIterator {
498 return ProgramHeaderIterator(@TypeOf(parse_source)){499 return .{
499 .elf_header = self,500 .elf_header = h,
500 .parse_source = parse_source,501 .file_reader = file_reader,
501 };502 };
502 }503 }
503504
504 pub fn section_header_iterator(self: Header, parse_source: anytype) SectionHeaderIterator(@TypeOf(parse_source)) {505 pub fn iterateSectionHeaders(h: Header, file_reader: *std.fs.File.Reader) SectionHeaderIterator {
505 return SectionHeaderIterator(@TypeOf(parse_source)){506 return .{
506 .elf_header = self,507 .elf_header = h,
507 .parse_source = parse_source,508 .file_reader = file_reader,
508 };509 };
509 }510 }
510511
511 pub fn read(parse_source: anytype) !Header {512 pub const ReadError = std.Io.Reader.Error || error{
512 var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined;513 InvalidElfMagic,
513 try parse_source.seekableStream().seekTo(0);514 InvalidElfVersion,
514 try parse_source.deprecatedReader().readNoEof(&hdr_buf);515 InvalidElfClass,
515 return Header.parse(&hdr_buf);516 InvalidElfEndian,
516 }517 };
517518
518 pub fn parse(hdr_buf: *align(@alignOf(Elf64_Ehdr)) const [@sizeOf(Elf64_Ehdr)]u8) !Header {519 pub fn read(r: *std.Io.Reader) ReadError!Header {
519 const hdr32 = @as(*const Elf32_Ehdr, @ptrCast(hdr_buf));520 const buf = try r.peek(@sizeOf(Elf64_Ehdr));
520 const hdr64 = @as(*const Elf64_Ehdr, @ptrCast(hdr_buf));
521 if (!mem.eql(u8, hdr32.e_ident[0..4], MAGIC)) return error.InvalidElfMagic;
522 if (hdr32.e_ident[EI_VERSION] != 1) return error.InvalidElfVersion;
523521
524 const is_64 = switch (hdr32.e_ident[EI_CLASS]) {522 if (!mem.eql(u8, buf[0..4], MAGIC)) return error.InvalidElfMagic;
525 ELFCLASS32 => false,523 if (buf[EI_VERSION] != 1) return error.InvalidElfVersion;
526 ELFCLASS64 => true,
527 else => return error.InvalidElfClass,
528 };
529524
530 const endian: std.builtin.Endian = switch (hdr32.e_ident[EI_DATA]) {525 const endian: std.builtin.Endian = switch (buf[EI_DATA]) {
531 ELFDATA2LSB => .little,526 ELFDATA2LSB => .little,
532 ELFDATA2MSB => .big,527 ELFDATA2MSB => .big,
533 else => return error.InvalidElfEndian,528 else => return error.InvalidElfEndian,
534 };529 };
535 const need_bswap = endian != native_endian;
536530
531 return switch (buf[EI_CLASS]) {
532 ELFCLASS32 => .init(try r.takeStruct(Elf32_Ehdr, endian), endian),
533 ELFCLASS64 => .init(try r.takeStruct(Elf64_Ehdr, endian), endian),
534 else => return error.InvalidElfClass,
535 };
536 }
537
538 pub fn init(hdr: anytype, endian: std.builtin.Endian) Header {
537 // Converting integers to exhaustive enums using `@enumFromInt` could cause a panic.539 // Converting integers to exhaustive enums using `@enumFromInt` could cause a panic.
538 comptime assert(!@typeInfo(OSABI).@"enum".is_exhaustive);540 comptime assert(!@typeInfo(OSABI).@"enum".is_exhaustive);
539 const os_abi: OSABI = @enumFromInt(hdr32.e_ident[EI_OSABI]);541 return .{
542 .is_64 = switch (@TypeOf(hdr)) {
543 Elf32_Ehdr => false,
544 Elf64_Ehdr => true,
545 else => @compileError("bad type"),
546 },
547 .endian = endian,
548 .os_abi = @enumFromInt(hdr.e_ident[EI_OSABI]),
549 .abi_version = hdr.e_ident[EI_ABIVERSION],
550 .type = hdr.e_type,
551 .machine = hdr.e_machine,
552 .entry = hdr.e_entry,
553 .phoff = hdr.e_phoff,
554 .shoff = hdr.e_shoff,
555 .phentsize = hdr.e_phentsize,
556 .phnum = hdr.e_phnum,
557 .shentsize = hdr.e_shentsize,
558 .shnum = hdr.e_shnum,
559 .shstrndx = hdr.e_shstrndx,
560 };
561 }
562};
540563
541 // The meaning of this value depends on `os_abi` so just make it available as `u8`.564pub const ProgramHeaderIterator = struct {
542 const abi_version = hdr32.e_ident[EI_ABIVERSION];565 elf_header: Header,
566 file_reader: *std.fs.File.Reader,
567 index: usize = 0,
543568
544 const @"type" = if (need_bswap) blk: {569 pub fn next(it: *ProgramHeaderIterator) !?Elf64_Phdr {
545 comptime assert(!@typeInfo(ET).@"enum".is_exhaustive);570 if (it.index >= it.elf_header.phnum) return null;
546 const value = @intFromEnum(hdr32.e_type);571 defer it.index += 1;
547 break :blk @as(ET, @enumFromInt(@byteSwap(value)));
548 } else hdr32.e_type;
549572
550 const machine = if (need_bswap) blk: {573 if (it.elf_header.is_64) {
551 comptime assert(!@typeInfo(EM).@"enum".is_exhaustive);574 const offset = it.elf_header.phoff + @sizeOf(Elf64_Phdr) * it.index;
552 const value = @intFromEnum(hdr32.e_machine);575 try it.file_reader.seekTo(offset);
553 break :blk @as(EM, @enumFromInt(@byteSwap(value)));576 const phdr = try it.file_reader.interface.takeStruct(Elf64_Phdr, it.elf_header.endian);
554 } else hdr32.e_machine;577 return phdr;
578 }
555579
556 return @as(Header, .{580 const offset = it.elf_header.phoff + @sizeOf(Elf32_Phdr) * it.index;
557 .is_64 = is_64,581 try it.file_reader.seekTo(offset);
558 .endian = endian,582 const phdr = try it.file_reader.interface.takeStruct(Elf32_Phdr, it.elf_header.endian);
559 .os_abi = os_abi,583 return .{
560 .abi_version = abi_version,584 .p_type = phdr.p_type,
561 .type = @"type",585 .p_offset = phdr.p_offset,
562 .machine = machine,586 .p_vaddr = phdr.p_vaddr,
563 .entry = int(is_64, need_bswap, hdr32.e_entry, hdr64.e_entry),587 .p_paddr = phdr.p_paddr,
564 .phoff = int(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff),588 .p_filesz = phdr.p_filesz,
565 .shoff = int(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff),589 .p_memsz = phdr.p_memsz,
566 .phentsize = int(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize),590 .p_flags = phdr.p_flags,
567 .phnum = int(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum),591 .p_align = phdr.p_align,
568 .shentsize = int(is_64, need_bswap, hdr32.e_shentsize, hdr64.e_shentsize),592 };
569 .shnum = int(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum),
570 .shstrndx = int(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx),
571 });
572 }593 }
573};594};
574595
575pub fn ProgramHeaderIterator(comptime ParseSource: anytype) type {596pub const SectionHeaderIterator = struct {
576 return struct {597 elf_header: Header,
577 elf_header: Header,598 file_reader: *std.fs.File.Reader,
578 parse_source: ParseSource,599 index: usize = 0,
579 index: usize = 0,
580
581 pub fn next(self: *@This()) !?Elf64_Phdr {
582 if (self.index >= self.elf_header.phnum) return null;
583 defer self.index += 1;
584
585 if (self.elf_header.is_64) {
586 var phdr: Elf64_Phdr = undefined;
587 const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index;
588 try self.parse_source.seekableStream().seekTo(offset);
589 try self.parse_source.deprecatedReader().readNoEof(mem.asBytes(&phdr));
590
591 // ELF endianness matches native endianness.
592 if (self.elf_header.endian == native_endian) return phdr;
593
594 // Convert fields to native endianness.
595 mem.byteSwapAllFields(Elf64_Phdr, &phdr);
596 return phdr;
597 }
598
599 var phdr: Elf32_Phdr = undefined;
600 const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index;
601 try self.parse_source.seekableStream().seekTo(offset);
602 try self.parse_source.deprecatedReader().readNoEof(mem.asBytes(&phdr));
603
604 // ELF endianness does NOT match native endianness.
605 if (self.elf_header.endian != native_endian) {
606 // Convert fields to native endianness.
607 mem.byteSwapAllFields(Elf32_Phdr, &phdr);
608 }
609
610 // Convert 32-bit header to 64-bit.
611 return Elf64_Phdr{
612 .p_type = phdr.p_type,
613 .p_offset = phdr.p_offset,
614 .p_vaddr = phdr.p_vaddr,
615 .p_paddr = phdr.p_paddr,
616 .p_filesz = phdr.p_filesz,
617 .p_memsz = phdr.p_memsz,
618 .p_flags = phdr.p_flags,
619 .p_align = phdr.p_align,
620 };
621 }
622 };
623}
624600
625pub fn SectionHeaderIterator(comptime ParseSource: anytype) type {601 pub fn next(it: *SectionHeaderIterator) !?Elf64_Shdr {
626 return struct {602 if (it.index >= it.elf_header.shnum) return null;
627 elf_header: Header,603 defer it.index += 1;
628 parse_source: ParseSource,
629 index: usize = 0,
630
631 pub fn next(self: *@This()) !?Elf64_Shdr {
632 if (self.index >= self.elf_header.shnum) return null;
633 defer self.index += 1;
634
635 if (self.elf_header.is_64) {
636 var shdr: Elf64_Shdr = undefined;
637 const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index;
638 try self.parse_source.seekableStream().seekTo(offset);
639 try self.parse_source.deprecatedReader().readNoEof(mem.asBytes(&shdr));
640
641 // ELF endianness matches native endianness.
642 if (self.elf_header.endian == native_endian) return shdr;
643
644 // Convert fields to native endianness.
645 mem.byteSwapAllFields(Elf64_Shdr, &shdr);
646 return shdr;
647 }
648
649 var shdr: Elf32_Shdr = undefined;
650 const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index;
651 try self.parse_source.seekableStream().seekTo(offset);
652 try self.parse_source.deprecatedReader().readNoEof(mem.asBytes(&shdr));
653
654 // ELF endianness does NOT match native endianness.
655 if (self.elf_header.endian != native_endian) {
656 // Convert fields to native endianness.
657 mem.byteSwapAllFields(Elf32_Shdr, &shdr);
658 }
659
660 // Convert 32-bit header to 64-bit.
661 return Elf64_Shdr{
662 .sh_name = shdr.sh_name,
663 .sh_type = shdr.sh_type,
664 .sh_flags = shdr.sh_flags,
665 .sh_addr = shdr.sh_addr,
666 .sh_offset = shdr.sh_offset,
667 .sh_size = shdr.sh_size,
668 .sh_link = shdr.sh_link,
669 .sh_info = shdr.sh_info,
670 .sh_addralign = shdr.sh_addralign,
671 .sh_entsize = shdr.sh_entsize,
672 };
673 }
674 };
675}
676604
677fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) {605 if (it.elf_header.is_64) {
678 if (is_64) {606 try it.file_reader.seekTo(it.elf_header.shoff + @sizeOf(Elf64_Shdr) * it.index);
679 if (need_bswap) {607 const shdr = try it.file_reader.interface.takeStruct(Elf64_Shdr, it.elf_header.endian);
680 return @byteSwap(int_64);608 return shdr;
681 } else {
682 return int_64;
683 }609 }
684 } else {
685 return int32(need_bswap, int_32, @TypeOf(int_64));
686 }
687}
688610
689fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 {611 try it.file_reader.seekTo(it.elf_header.shoff + @sizeOf(Elf32_Shdr) * it.index);
690 if (need_bswap) {612 const shdr = try it.file_reader.interface.takeStruct(Elf32_Shdr, it.elf_header.endian);
691 return @byteSwap(int_32);613 return .{
692 } else {614 .sh_name = shdr.sh_name,
693 return int_32;615 .sh_type = shdr.sh_type,
616 .sh_flags = shdr.sh_flags,
617 .sh_addr = shdr.sh_addr,
618 .sh_offset = shdr.sh_offset,
619 .sh_size = shdr.sh_size,
620 .sh_link = shdr.sh_link,
621 .sh_info = shdr.sh_info,
622 .sh_addralign = shdr.sh_addralign,
623 .sh_entsize = shdr.sh_entsize,
624 };
694 }625 }
695}626};
696627
697pub const ELFCLASSNONE = 0;628pub const ELFCLASSNONE = 0;
698pub const ELFCLASS32 = 1;629pub const ELFCLASS32 = 1;
...@@ -2070,7 +2001,7 @@ pub const R_AARCH64 = enum(u32) {...@@ -2070,7 +2001,7 @@ pub const R_AARCH64 = enum(u32) {
2070 TLSLE_LDST64_TPREL_LO12 = 558,2001 TLSLE_LDST64_TPREL_LO12 = 558,
2071 /// Likewise; no check.2002 /// Likewise; no check.
2072 TLSLE_LDST64_TPREL_LO12_NC = 559,2003 TLSLE_LDST64_TPREL_LO12_NC = 559,
2073 /// PC-rel. load immediate 20:2.2004 /// PC-rel. load immediate 20:2.
2074 TLSDESC_LD_PREL19 = 560,2005 TLSDESC_LD_PREL19 = 560,
2075 /// PC-rel. ADR immediate 20:0.2006 /// PC-rel. ADR immediate 20:0.
2076 TLSDESC_ADR_PREL21 = 561,2007 TLSDESC_ADR_PREL21 = 561,
lib/std/fs/AtomicFile.zig+52-46
...@@ -1,6 +1,13 @@...@@ -1,6 +1,13 @@
1file: File,1const AtomicFile = @This();
2// TODO either replace this with rand_buf or use []u16 on Windows2const std = @import("../std.zig");
3tmp_path_buf: [tmp_path_len:0]u8,3const File = std.fs.File;
4const Dir = std.fs.Dir;
5const fs = std.fs;
6const assert = std.debug.assert;
7const posix = std.posix;
8
9file_writer: File.Writer,
10random_integer: u64,
4dest_basename: []const u8,11dest_basename: []const u8,
5file_open: bool,12file_open: bool,
6file_exists: bool,13file_exists: bool,
...@@ -9,35 +16,24 @@ dir: Dir,...@@ -9,35 +16,24 @@ dir: Dir,
916
10pub const InitError = File.OpenError;17pub const InitError = File.OpenError;
1118
12pub const random_bytes_len = 12;
13const tmp_path_len = fs.base64_encoder.calcSize(random_bytes_len);
14
15/// Note that the `Dir.atomicFile` API may be more handy than this lower-level function.19/// Note that the `Dir.atomicFile` API may be more handy than this lower-level function.
16pub fn init(20pub fn init(
17 dest_basename: []const u8,21 dest_basename: []const u8,
18 mode: File.Mode,22 mode: File.Mode,
19 dir: Dir,23 dir: Dir,
20 close_dir_on_deinit: bool,24 close_dir_on_deinit: bool,
25 write_buffer: []u8,
21) InitError!AtomicFile {26) InitError!AtomicFile {
22 var rand_buf: [random_bytes_len]u8 = undefined;
23 var tmp_path_buf: [tmp_path_len:0]u8 = undefined;
24
25 while (true) {27 while (true) {
26 std.crypto.random.bytes(rand_buf[0..]);28 const random_integer = std.crypto.random.int(u64);
27 const tmp_path = fs.base64_encoder.encode(&tmp_path_buf, &rand_buf);29 const tmp_sub_path = std.fmt.hex(random_integer);
28 tmp_path_buf[tmp_path.len] = 0;30 const file = dir.createFile(&tmp_sub_path, .{ .mode = mode, .exclusive = true }) catch |err| switch (err) {
29
30 const file = dir.createFile(
31 tmp_path,
32 .{ .mode = mode, .exclusive = true },
33 ) catch |err| switch (err) {
34 error.PathAlreadyExists => continue,31 error.PathAlreadyExists => continue,
35 else => |e| return e,32 else => |e| return e,
36 };33 };
3734 return .{
38 return AtomicFile{35 .file_writer = file.writer(write_buffer),
39 .file = file,36 .random_integer = random_integer,
40 .tmp_path_buf = tmp_path_buf,
41 .dest_basename = dest_basename,37 .dest_basename = dest_basename,
42 .file_open = true,38 .file_open = true,
43 .file_exists = true,39 .file_exists = true,
...@@ -48,41 +44,51 @@ pub fn init(...@@ -48,41 +44,51 @@ pub fn init(
48}44}
4945
50/// Always call deinit, even after a successful finish().46/// Always call deinit, even after a successful finish().
51pub fn deinit(self: *AtomicFile) void {47pub fn deinit(af: *AtomicFile) void {
52 if (self.file_open) {48 if (af.file_open) {
53 self.file.close();49 af.file_writer.file.close();
54 self.file_open = false;50 af.file_open = false;
55 }51 }
56 if (self.file_exists) {52 if (af.file_exists) {
57 self.dir.deleteFile(&self.tmp_path_buf) catch {};53 const tmp_sub_path = std.fmt.hex(af.random_integer);
58 self.file_exists = false;54 af.dir.deleteFile(&tmp_sub_path) catch {};
55 af.file_exists = false;
59 }56 }
60 if (self.close_dir_on_deinit) {57 if (af.close_dir_on_deinit) {
61 self.dir.close();58 af.dir.close();
62 }59 }
63 self.* = undefined;60 af.* = undefined;
64}61}
6562
66pub const FinishError = posix.RenameError;63pub const FlushError = File.WriteError;
64
65pub fn flush(af: *AtomicFile) FlushError!void {
66 af.file_writer.interface.flush() catch |err| switch (err) {
67 error.WriteFailed => return af.file_writer.err.?,
68 };
69}
70
71pub const RenameIntoPlaceError = posix.RenameError;
6772
68/// On Windows, this function introduces a period of time where some file73/// On Windows, this function introduces a period of time where some file
69/// system operations on the destination file will result in74/// system operations on the destination file will result in
70/// `error.AccessDenied`, including rename operations (such as the one used in75/// `error.AccessDenied`, including rename operations (such as the one used in
71/// this function).76/// this function).
72pub fn finish(self: *AtomicFile) FinishError!void {77pub fn renameIntoPlace(af: *AtomicFile) RenameIntoPlaceError!void {
73 assert(self.file_exists);78 assert(af.file_exists);
74 if (self.file_open) {79 if (af.file_open) {
75 self.file.close();80 af.file_writer.file.close();
76 self.file_open = false;81 af.file_open = false;
77 }82 }
78 try posix.renameat(self.dir.fd, self.tmp_path_buf[0..], self.dir.fd, self.dest_basename);83 const tmp_sub_path = std.fmt.hex(af.random_integer);
79 self.file_exists = false;84 try posix.renameat(af.dir.fd, &tmp_sub_path, af.dir.fd, af.dest_basename);
85 af.file_exists = false;
80}86}
8187
82const AtomicFile = @This();88pub const FinishError = FlushError || RenameIntoPlaceError;
83const std = @import("../std.zig");89
84const File = std.fs.File;90/// Combination of `flush` followed by `renameIntoPlace`.
85const Dir = std.fs.Dir;91pub fn finish(af: *AtomicFile) FinishError!void {
86const fs = std.fs;92 try af.flush();
87const assert = std.debug.assert;93 try af.renameIntoPlace();
88const posix = std.posix;94}
lib/std/fs/Dir.zig+71-109
...@@ -1,3 +1,20 @@...@@ -1,3 +1,20 @@
1const Dir = @This();
2const builtin = @import("builtin");
3const std = @import("../std.zig");
4const File = std.fs.File;
5const AtomicFile = std.fs.AtomicFile;
6const base64_encoder = fs.base64_encoder;
7const posix = std.posix;
8const mem = std.mem;
9const path = fs.path;
10const fs = std.fs;
11const Allocator = std.mem.Allocator;
12const assert = std.debug.assert;
13const linux = std.os.linux;
14const windows = std.os.windows;
15const native_os = builtin.os.tag;
16const have_flock = @TypeOf(posix.system.flock) != void;
17
1fd: Handle,18fd: Handle,
219
3pub const Handle = posix.fd_t;20pub const Handle = posix.fd_t;
...@@ -1862,9 +1879,10 @@ pub fn symLinkW(...@@ -1862,9 +1879,10 @@ pub fn symLinkW(
18621879
1863/// Same as `symLink`, except tries to create the symbolic link until it1880/// Same as `symLink`, except tries to create the symbolic link until it
1864/// succeeds or encounters an error other than `error.PathAlreadyExists`.1881/// succeeds or encounters an error other than `error.PathAlreadyExists`.
1865/// On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).1882///
1866/// On WASI, both paths should be encoded as valid UTF-8.1883/// * On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
1867/// On other platforms, both paths are an opaque sequence of bytes with no particular encoding.1884/// * On WASI, both paths should be encoded as valid UTF-8.
1885/// * On other platforms, both paths are an opaque sequence of bytes with no particular encoding.
1868pub fn atomicSymLink(1886pub fn atomicSymLink(
1869 dir: Dir,1887 dir: Dir,
1870 target_path: []const u8,1888 target_path: []const u8,
...@@ -1880,9 +1898,8 @@ pub fn atomicSymLink(...@@ -1880,9 +1898,8 @@ pub fn atomicSymLink(
18801898
1881 const dirname = path.dirname(sym_link_path) orelse ".";1899 const dirname = path.dirname(sym_link_path) orelse ".";
18821900
1883 var rand_buf: [AtomicFile.random_bytes_len]u8 = undefined;1901 const rand_len = @sizeOf(u64) * 2;
18841902 const temp_path_len = dirname.len + 1 + rand_len;
1885 const temp_path_len = dirname.len + 1 + base64_encoder.calcSize(rand_buf.len);
1886 var temp_path_buf: [fs.max_path_bytes]u8 = undefined;1903 var temp_path_buf: [fs.max_path_bytes]u8 = undefined;
18871904
1888 if (temp_path_len > temp_path_buf.len) return error.NameTooLong;1905 if (temp_path_len > temp_path_buf.len) return error.NameTooLong;
...@@ -1892,8 +1909,8 @@ pub fn atomicSymLink(...@@ -1892,8 +1909,8 @@ pub fn atomicSymLink(
1892 const temp_path = temp_path_buf[0..temp_path_len];1909 const temp_path = temp_path_buf[0..temp_path_len];
18931910
1894 while (true) {1911 while (true) {
1895 crypto.random.bytes(rand_buf[0..]);1912 const random_integer = std.crypto.random.int(u64);
1896 _ = base64_encoder.encode(temp_path[dirname.len + 1 ..], rand_buf[0..]);1913 temp_path[dirname.len + 1 ..][0..rand_len].* = std.fmt.hex(random_integer);
18971914
1898 if (dir.symLink(target_path, temp_path, flags)) {1915 if (dir.symLink(target_path, temp_path, flags)) {
1899 return dir.rename(temp_path, sym_link_path);1916 return dir.rename(temp_path, sym_link_path);
...@@ -2552,25 +2569,42 @@ pub fn updateFile(...@@ -2552,25 +2569,42 @@ pub fn updateFile(
2552 try dest_dir.makePath(dirname);2569 try dest_dir.makePath(dirname);
2553 }2570 }
25542571
2555 var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = actual_mode });2572 var buffer: [1000]u8 = undefined; // Used only when direct fd-to-fd is not available.
2573 var atomic_file = try dest_dir.atomicFile(dest_path, .{
2574 .mode = actual_mode,
2575 .write_buffer = &buffer,
2576 });
2556 defer atomic_file.deinit();2577 defer atomic_file.deinit();
25572578
2558 try atomic_file.file.writeFileAll(src_file, .{ .in_len = src_stat.size });2579 var src_reader: File.Reader = .initSize(src_file, &.{}, src_stat.size);
2559 try atomic_file.file.updateTimes(src_stat.atime, src_stat.mtime);2580 const dest_writer = &atomic_file.file_writer.interface;
2581
2582 _ = dest_writer.sendFileAll(&src_reader, .unlimited) catch |err| switch (err) {
2583 error.ReadFailed => return src_reader.err.?,
2584 error.WriteFailed => return atomic_file.file_writer.err.?,
2585 };
2586 try atomic_file.file_writer.file.updateTimes(src_stat.atime, src_stat.mtime);
2560 try atomic_file.finish();2587 try atomic_file.finish();
2561 return PrevStatus.stale;2588 return .stale;
2562}2589}
25632590
2564pub const CopyFileError = File.OpenError || File.StatError ||2591pub const CopyFileError = File.OpenError || File.StatError ||
2565 AtomicFile.InitError || CopyFileRawError || AtomicFile.FinishError;2592 AtomicFile.InitError || AtomicFile.FinishError ||
2593 File.ReadError || File.WriteError;
25662594
2567/// Guaranteed to be atomic.2595/// Atomically creates a new file at `dest_path` within `dest_dir` with the
2568/// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available,2596/// same contents as `source_path` within `source_dir`, overwriting any already
2569/// there is a possibility of power loss or application termination leaving temporary files present2597/// existing file.
2570/// in the same directory as dest_path.2598///
2571/// On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).2599/// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and
2572/// On WASI, both paths should be encoded as valid UTF-8.2600/// readily available, there is a possibility of power loss or application
2573/// On other platforms, both paths are an opaque sequence of bytes with no particular encoding.2601/// termination leaving temporary files present in the same directory as
2602/// dest_path.
2603///
2604/// On Windows, both paths should be encoded as
2605/// [WTF-8](https://simonsapin.github.io/wtf-8/). On WASI, both paths should be
2606/// encoded as valid UTF-8. On other platforms, both paths are an opaque
2607/// sequence of bytes with no particular encoding.
2574pub fn copyFile(2608pub fn copyFile(
2575 source_dir: Dir,2609 source_dir: Dir,
2576 source_path: []const u8,2610 source_path: []const u8,
...@@ -2578,79 +2612,34 @@ pub fn copyFile(...@@ -2578,79 +2612,34 @@ pub fn copyFile(
2578 dest_path: []const u8,2612 dest_path: []const u8,
2579 options: CopyFileOptions,2613 options: CopyFileOptions,
2580) CopyFileError!void {2614) CopyFileError!void {
2581 var in_file = try source_dir.openFile(source_path, .{});2615 var file_reader: File.Reader = .init(try source_dir.openFile(source_path, .{}), &.{});
2582 defer in_file.close();2616 defer file_reader.file.close();
25832617
2584 var size: ?u64 = null;
2585 const mode = options.override_mode orelse blk: {2618 const mode = options.override_mode orelse blk: {
2586 const st = try in_file.stat();2619 const st = try file_reader.file.stat();
2587 size = st.size;2620 file_reader.size = st.size;
2588 break :blk st.mode;2621 break :blk st.mode;
2589 };2622 };
25902623
2591 var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = mode });2624 var buffer: [1024]u8 = undefined; // Used only when direct fd-to-fd is not available.
2625 var atomic_file = try dest_dir.atomicFile(dest_path, .{
2626 .mode = mode,
2627 .write_buffer = &buffer,
2628 });
2592 defer atomic_file.deinit();2629 defer atomic_file.deinit();
25932630
2594 try copy_file(in_file.handle, atomic_file.file.handle, size);2631 _ = atomic_file.file_writer.interface.sendFileAll(&file_reader, .unlimited) catch |err| switch (err) {
2595 try atomic_file.finish();2632 error.ReadFailed => return file_reader.err.?,
2596}2633 error.WriteFailed => return atomic_file.file_writer.err.?,
25972634 };
2598const CopyFileRawError = error{SystemResources} || posix.CopyFileRangeError || posix.SendFileError;
2599
2600// Transfer all the data between two file descriptors in the most efficient way.
2601// The copy starts at offset 0, the initial offsets are preserved.
2602// No metadata is transferred over.
2603fn copy_file(fd_in: posix.fd_t, fd_out: posix.fd_t, maybe_size: ?u64) CopyFileRawError!void {
2604 if (builtin.target.os.tag.isDarwin()) {
2605 const rc = posix.system.fcopyfile(fd_in, fd_out, null, .{ .DATA = true });
2606 switch (posix.errno(rc)) {
2607 .SUCCESS => return,
2608 .INVAL => unreachable,
2609 .NOMEM => return error.SystemResources,
2610 // The source file is not a directory, symbolic link, or regular file.
2611 // Try with the fallback path before giving up.
2612 .OPNOTSUPP => {},
2613 else => |err| return posix.unexpectedErrno(err),
2614 }
2615 }
2616
2617 if (native_os == .linux) {
2618 // Try copy_file_range first as that works at the FS level and is the
2619 // most efficient method (if available).
2620 var offset: u64 = 0;
2621 cfr_loop: while (true) {
2622 // The kernel checks the u64 value `offset+count` for overflow, use
2623 // a 32 bit value so that the syscall won't return EINVAL except for
2624 // impossibly large files (> 2^64-1 - 2^32-1).
2625 const amt = try posix.copy_file_range(fd_in, offset, fd_out, offset, std.math.maxInt(u32), 0);
2626 // Terminate as soon as we have copied size bytes or no bytes
2627 if (maybe_size) |s| {
2628 if (s == amt) break :cfr_loop;
2629 }
2630 if (amt == 0) break :cfr_loop;
2631 offset += amt;
2632 }
2633 return;
2634 }
26352635
2636 // Sendfile is a zero-copy mechanism iff the OS supports it, otherwise the2636 try atomic_file.finish();
2637 // fallback code will copy the contents chunk by chunk.
2638 const empty_iovec = [0]posix.iovec_const{};
2639 var offset: u64 = 0;
2640 sendfile_loop: while (true) {
2641 const amt = try posix.sendfile(fd_out, fd_in, offset, 0, &empty_iovec, &empty_iovec, 0);
2642 // Terminate as soon as we have copied size bytes or no bytes
2643 if (maybe_size) |s| {
2644 if (s == amt) break :sendfile_loop;
2645 }
2646 if (amt == 0) break :sendfile_loop;
2647 offset += amt;
2648 }
2649}2637}
26502638
2651pub const AtomicFileOptions = struct {2639pub const AtomicFileOptions = struct {
2652 mode: File.Mode = File.default_mode,2640 mode: File.Mode = File.default_mode,
2653 make_path: bool = false,2641 make_path: bool = false,
2642 write_buffer: []u8,
2654};2643};
26552644
2656/// Directly access the `.file` field, and then call `AtomicFile.finish` to2645/// Directly access the `.file` field, and then call `AtomicFile.finish` to
...@@ -2668,9 +2657,9 @@ pub fn atomicFile(self: Dir, dest_path: []const u8, options: AtomicFileOptions)...@@ -2668,9 +2657,9 @@ pub fn atomicFile(self: Dir, dest_path: []const u8, options: AtomicFileOptions)
2668 else2657 else
2669 try self.openDir(dirname, .{});2658 try self.openDir(dirname, .{});
26702659
2671 return AtomicFile.init(fs.path.basename(dest_path), options.mode, dir, true);2660 return .init(fs.path.basename(dest_path), options.mode, dir, true, options.write_buffer);
2672 } else {2661 } else {
2673 return AtomicFile.init(dest_path, options.mode, self, false);2662 return .init(dest_path, options.mode, self, false, options.write_buffer);
2674 }2663 }
2675}2664}
26762665
...@@ -2768,30 +2757,3 @@ pub fn setPermissions(self: Dir, permissions: Permissions) SetPermissionsError!v...@@ -2768,30 +2757,3 @@ pub fn setPermissions(self: Dir, permissions: Permissions) SetPermissionsError!v
2768 const file: File = .{ .handle = self.fd };2757 const file: File = .{ .handle = self.fd };
2769 try file.setPermissions(permissions);2758 try file.setPermissions(permissions);
2770}2759}
2771
2772const Metadata = File.Metadata;
2773pub const MetadataError = File.MetadataError;
2774
2775/// Returns a `Metadata` struct, representing the permissions on the directory
2776pub fn metadata(self: Dir) MetadataError!Metadata {
2777 const file: File = .{ .handle = self.fd };
2778 return try file.metadata();
2779}
2780
2781const Dir = @This();
2782const builtin = @import("builtin");
2783const std = @import("../std.zig");
2784const File = std.fs.File;
2785const AtomicFile = std.fs.AtomicFile;
2786const base64_encoder = fs.base64_encoder;
2787const crypto = std.crypto;
2788const posix = std.posix;
2789const mem = std.mem;
2790const path = fs.path;
2791const fs = std.fs;
2792const Allocator = std.mem.Allocator;
2793const assert = std.debug.assert;
2794const linux = std.os.linux;
2795const windows = std.os.windows;
2796const native_os = builtin.os.tag;
2797const have_flock = @TypeOf(posix.system.flock) != void;
lib/std/fs/File.zig+188-129
...@@ -1089,113 +1089,6 @@ pub fn copyRangeAll(in: File, in_offset: u64, out: File, out_offset: u64, len: u...@@ -1089,113 +1089,6 @@ pub fn copyRangeAll(in: File, in_offset: u64, out: File, out_offset: u64, len: u
1089 return total_bytes_copied;1089 return total_bytes_copied;
1090}1090}
10911091
1092/// Deprecated in favor of `Writer`.
1093pub const WriteFileOptions = struct {
1094 in_offset: u64 = 0,
1095 in_len: ?u64 = null,
1096 headers_and_trailers: []posix.iovec_const = &[0]posix.iovec_const{},
1097 header_count: usize = 0,
1098};
1099
1100/// Deprecated in favor of `Writer`.
1101pub const WriteFileError = ReadError || error{EndOfStream} || WriteError;
1102
1103/// Deprecated in favor of `Writer`.
1104pub fn writeFileAll(self: File, in_file: File, args: WriteFileOptions) WriteFileError!void {
1105 return self.writeFileAllSendfile(in_file, args) catch |err| switch (err) {
1106 error.Unseekable,
1107 error.FastOpenAlreadyInProgress,
1108 error.MessageTooBig,
1109 error.FileDescriptorNotASocket,
1110 error.NetworkUnreachable,
1111 error.NetworkSubsystemFailed,
1112 error.ConnectionRefused,
1113 => return self.writeFileAllUnseekable(in_file, args),
1114 else => |e| return e,
1115 };
1116}
1117
1118/// Deprecated in favor of `Writer`.
1119pub fn writeFileAllUnseekable(self: File, in_file: File, args: WriteFileOptions) WriteFileError!void {
1120 const headers = args.headers_and_trailers[0..args.header_count];
1121 const trailers = args.headers_and_trailers[args.header_count..];
1122 try self.writevAll(headers);
1123 try in_file.deprecatedReader().skipBytes(args.in_offset, .{ .buf_size = 4096 });
1124 var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init();
1125 if (args.in_len) |len| {
1126 var stream = std.io.limitedReader(in_file.deprecatedReader(), len);
1127 try fifo.pump(stream.reader(), self.deprecatedWriter());
1128 } else {
1129 try fifo.pump(in_file.deprecatedReader(), self.deprecatedWriter());
1130 }
1131 try self.writevAll(trailers);
1132}
1133
1134/// Deprecated in favor of `Writer`.
1135fn writeFileAllSendfile(self: File, in_file: File, args: WriteFileOptions) posix.SendFileError!void {
1136 const count = blk: {
1137 if (args.in_len) |l| {
1138 if (l == 0) {
1139 return self.writevAll(args.headers_and_trailers);
1140 } else {
1141 break :blk l;
1142 }
1143 } else {
1144 break :blk 0;
1145 }
1146 };
1147 const headers = args.headers_and_trailers[0..args.header_count];
1148 const trailers = args.headers_and_trailers[args.header_count..];
1149 const zero_iovec = &[0]posix.iovec_const{};
1150 // When reading the whole file, we cannot put the trailers in the sendfile() syscall,
1151 // because we have no way to determine whether a partial write is past the end of the file or not.
1152 const trls = if (count == 0) zero_iovec else trailers;
1153 const offset = args.in_offset;
1154 const out_fd = self.handle;
1155 const in_fd = in_file.handle;
1156 const flags = 0;
1157 var amt: usize = 0;
1158 hdrs: {
1159 var i: usize = 0;
1160 while (i < headers.len) {
1161 amt = try posix.sendfile(out_fd, in_fd, offset, count, headers[i..], trls, flags);
1162 while (amt >= headers[i].len) {
1163 amt -= headers[i].len;
1164 i += 1;
1165 if (i >= headers.len) break :hdrs;
1166 }
1167 headers[i].base += amt;
1168 headers[i].len -= amt;
1169 }
1170 }
1171 if (count == 0) {
1172 var off: u64 = amt;
1173 while (true) {
1174 amt = try posix.sendfile(out_fd, in_fd, offset + off, 0, zero_iovec, zero_iovec, flags);
1175 if (amt == 0) break;
1176 off += amt;
1177 }
1178 } else {
1179 var off: u64 = amt;
1180 while (off < count) {
1181 amt = try posix.sendfile(out_fd, in_fd, offset + off, count - off, zero_iovec, trailers, flags);
1182 off += amt;
1183 }
1184 amt = @as(usize, @intCast(off - count));
1185 }
1186 var i: usize = 0;
1187 while (i < trailers.len) {
1188 while (amt >= trailers[i].len) {
1189 amt -= trailers[i].len;
1190 i += 1;
1191 if (i >= trailers.len) return;
1192 }
1193 trailers[i].base += amt;
1194 trailers[i].len -= amt;
1195 amt = try posix.writev(self.handle, trailers[i..]);
1196 }
1197}
1198
1199/// Deprecated in favor of `Reader`.1092/// Deprecated in favor of `Reader`.
1200pub const DeprecatedReader = io.GenericReader(File, ReadError, read);1093pub const DeprecatedReader = io.GenericReader(File, ReadError, read);
12011094
...@@ -1242,7 +1135,7 @@ pub const Reader = struct {...@@ -1242,7 +1135,7 @@ pub const Reader = struct {
1242 err: ?ReadError = null,1135 err: ?ReadError = null,
1243 mode: Reader.Mode = .positional,1136 mode: Reader.Mode = .positional,
1244 /// Tracks the true seek position in the file. To obtain the logical1137 /// Tracks the true seek position in the file. To obtain the logical
1245 /// position, subtract the buffer size from this value.1138 /// position, use `logicalPos`.
1246 pos: u64 = 0,1139 pos: u64 = 0,
1247 size: ?u64 = null,1140 size: ?u64 = null,
1248 size_err: ?GetEndPosError = null,1141 size_err: ?GetEndPosError = null,
...@@ -1335,14 +1228,12 @@ pub const Reader = struct {...@@ -1335,14 +1228,12 @@ pub const Reader = struct {
1335 pub fn seekBy(r: *Reader, offset: i64) Reader.SeekError!void {1228 pub fn seekBy(r: *Reader, offset: i64) Reader.SeekError!void {
1336 switch (r.mode) {1229 switch (r.mode) {
1337 .positional, .positional_reading => {1230 .positional, .positional_reading => {
1338 // TODO: make += operator allow any integer types1231 setPosAdjustingBuffer(r, @intCast(@as(i64, @intCast(r.pos)) + offset));
1339 r.pos = @intCast(@as(i64, @intCast(r.pos)) + offset);
1340 },1232 },
1341 .streaming, .streaming_reading => {1233 .streaming, .streaming_reading => {
1342 const seek_err = r.seek_err orelse e: {1234 const seek_err = r.seek_err orelse e: {
1343 if (posix.lseek_CUR(r.file.handle, offset)) |_| {1235 if (posix.lseek_CUR(r.file.handle, offset)) |_| {
1344 // TODO: make += operator allow any integer types1236 setPosAdjustingBuffer(r, @intCast(@as(i64, @intCast(r.pos)) + offset));
1345 r.pos = @intCast(@as(i64, @intCast(r.pos)) + offset);
1346 return;1237 return;
1347 } else |err| {1238 } else |err| {
1348 r.seek_err = err;1239 r.seek_err = err;
...@@ -1358,6 +1249,8 @@ pub const Reader = struct {...@@ -1358,6 +1249,8 @@ pub const Reader = struct {
1358 r.pos += n;1249 r.pos += n;
1359 remaining -= n;1250 remaining -= n;
1360 }1251 }
1252 r.interface.seek = 0;
1253 r.interface.end = 0;
1361 },1254 },
1362 .failure => return r.seek_err.?,1255 .failure => return r.seek_err.?,
1363 }1256 }
...@@ -1366,7 +1259,7 @@ pub const Reader = struct {...@@ -1366,7 +1259,7 @@ pub const Reader = struct {
1366 pub fn seekTo(r: *Reader, offset: u64) Reader.SeekError!void {1259 pub fn seekTo(r: *Reader, offset: u64) Reader.SeekError!void {
1367 switch (r.mode) {1260 switch (r.mode) {
1368 .positional, .positional_reading => {1261 .positional, .positional_reading => {
1369 r.pos = offset;1262 setPosAdjustingBuffer(r, offset);
1370 },1263 },
1371 .streaming, .streaming_reading => {1264 .streaming, .streaming_reading => {
1372 if (offset >= r.pos) return Reader.seekBy(r, @intCast(offset - r.pos));1265 if (offset >= r.pos) return Reader.seekBy(r, @intCast(offset - r.pos));
...@@ -1375,12 +1268,28 @@ pub const Reader = struct {...@@ -1375,12 +1268,28 @@ pub const Reader = struct {
1375 r.seek_err = err;1268 r.seek_err = err;
1376 return err;1269 return err;
1377 };1270 };
1378 r.pos = offset;1271 setPosAdjustingBuffer(r, offset);
1379 },1272 },
1380 .failure => return r.seek_err.?,1273 .failure => return r.seek_err.?,
1381 }1274 }
1382 }1275 }
13831276
1277 pub fn logicalPos(r: *const Reader) u64 {
1278 return r.pos - r.interface.bufferedLen();
1279 }
1280
1281 fn setPosAdjustingBuffer(r: *Reader, offset: u64) void {
1282 const logical_pos = logicalPos(r);
1283 if (offset < logical_pos or offset >= r.pos) {
1284 r.interface.seek = 0;
1285 r.interface.end = 0;
1286 r.pos = offset;
1287 } else {
1288 const logical_delta: usize = @intCast(offset - logical_pos);
1289 r.interface.seek += logical_delta;
1290 }
1291 }
1292
1384 /// Number of slices to store on the stack, when trying to send as many byte1293 /// Number of slices to store on the stack, when trying to send as many byte
1385 /// vectors through the underlying read calls as possible.1294 /// vectors through the underlying read calls as possible.
1386 const max_buffers_len = 16;1295 const max_buffers_len = 16;
...@@ -1526,7 +1435,7 @@ pub const Reader = struct {...@@ -1526,7 +1435,7 @@ pub const Reader = struct {
1526 }1435 }
1527 return 0;1436 return 0;
1528 };1437 };
1529 const n = @min(size - pos, std.math.maxInt(i64), @intFromEnum(limit));1438 const n = @min(size - pos, maxInt(i64), @intFromEnum(limit));
1530 file.seekBy(n) catch |err| {1439 file.seekBy(n) catch |err| {
1531 r.seek_err = err;1440 r.seek_err = err;
1532 return 0;1441 return 0;
...@@ -1645,7 +1554,10 @@ pub const Writer = struct {...@@ -1645,7 +1554,10 @@ pub const Writer = struct {
1645 return .{1554 return .{
1646 .vtable = &.{1555 .vtable = &.{
1647 .drain = drain,1556 .drain = drain,
1648 .sendFile = sendFile,1557 .sendFile = switch (builtin.zig_backend) {
1558 else => sendFile,
1559 .stage2_aarch64 => std.io.Writer.unimplementedSendFile,
1560 },
1649 },1561 },
1650 .buffer = buffer,1562 .buffer = buffer,
1651 };1563 };
...@@ -1715,7 +1627,6 @@ pub const Writer = struct {...@@ -1715,7 +1627,6 @@ pub const Writer = struct {
1715 const pattern = data[data.len - 1];1627 const pattern = data[data.len - 1];
1716 if (pattern.len == 0 or splat == 0) return 0;1628 if (pattern.len == 0 or splat == 0) return 0;
1717 const n = windows.WriteFile(handle, pattern, null) catch |err| {1629 const n = windows.WriteFile(handle, pattern, null) catch |err| {
1718 std.debug.print("windows write file failed3: {t}\n", .{err});
1719 w.err = err;1630 w.err = err;
1720 return error.WriteFailed;1631 return error.WriteFailed;
1721 };1632 };
...@@ -1817,18 +1728,141 @@ pub const Writer = struct {...@@ -1817,18 +1728,141 @@ pub const Writer = struct {
1817 file_reader: *Reader,1728 file_reader: *Reader,
1818 limit: std.io.Limit,1729 limit: std.io.Limit,
1819 ) std.io.Writer.FileError!usize {1730 ) std.io.Writer.FileError!usize {
1731 const reader_buffered = file_reader.interface.buffered();
1732 if (reader_buffered.len >= @intFromEnum(limit))
1733 return sendFileBuffered(io_w, file_reader, reader_buffered);
1734 const writer_buffered = io_w.buffered();
1735 const file_limit = @intFromEnum(limit) - reader_buffered.len;
1820 const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));1736 const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));
1821 const out_fd = w.file.handle;1737 const out_fd = w.file.handle;
1822 const in_fd = file_reader.file.handle;1738 const in_fd = file_reader.file.handle;
1823 // TODO try using copy_file_range on FreeBSD1739
1824 // TODO try using sendfile on macOS1740 if (file_reader.size) |size| {
1825 // TODO try using sendfile on FreeBSD1741 if (size - file_reader.pos == 0) {
1742 if (reader_buffered.len != 0) {
1743 return sendFileBuffered(io_w, file_reader, reader_buffered);
1744 } else {
1745 return error.EndOfStream;
1746 }
1747 }
1748 }
1749
1750 if (native_os == .freebsd and w.mode == .streaming) sf: {
1751 // Try using sendfile on FreeBSD.
1752 if (w.sendfile_err != null) break :sf;
1753 const offset = std.math.cast(std.c.off_t, file_reader.pos) orelse break :sf;
1754 var hdtr_data: std.c.sf_hdtr = undefined;
1755 var headers: [2]posix.iovec_const = undefined;
1756 var headers_i: u8 = 0;
1757 if (writer_buffered.len != 0) {
1758 headers[headers_i] = .{ .base = writer_buffered.ptr, .len = writer_buffered.len };
1759 headers_i += 1;
1760 }
1761 if (reader_buffered.len != 0) {
1762 headers[headers_i] = .{ .base = reader_buffered.ptr, .len = reader_buffered.len };
1763 headers_i += 1;
1764 }
1765 const hdtr: ?*std.c.sf_hdtr = if (headers_i == 0) null else b: {
1766 hdtr_data = .{
1767 .headers = &headers,
1768 .hdr_cnt = headers_i,
1769 .trailers = null,
1770 .trl_cnt = 0,
1771 };
1772 break :b &hdtr_data;
1773 };
1774 var sbytes: std.c.off_t = undefined;
1775 const nbytes: usize = @min(file_limit, maxInt(usize));
1776 const flags = 0;
1777 switch (posix.errno(std.c.sendfile(in_fd, out_fd, offset, nbytes, hdtr, &sbytes, flags))) {
1778 .SUCCESS, .INTR => {},
1779 .INVAL, .OPNOTSUPP, .NOTSOCK, .NOSYS => w.sendfile_err = error.UnsupportedOperation,
1780 .BADF => if (builtin.mode == .Debug) @panic("race condition") else {
1781 w.sendfile_err = error.Unexpected;
1782 },
1783 .FAULT => if (builtin.mode == .Debug) @panic("segmentation fault") else {
1784 w.sendfile_err = error.Unexpected;
1785 },
1786 .NOTCONN => w.sendfile_err = error.BrokenPipe,
1787 .AGAIN, .BUSY => if (sbytes == 0) {
1788 w.sendfile_err = error.WouldBlock;
1789 },
1790 .IO => w.sendfile_err = error.InputOutput,
1791 .PIPE => w.sendfile_err = error.BrokenPipe,
1792 .NOBUFS => w.sendfile_err = error.SystemResources,
1793 else => |err| w.sendfile_err = posix.unexpectedErrno(err),
1794 }
1795 if (sbytes == 0) {
1796 file_reader.size = file_reader.pos;
1797 return error.EndOfStream;
1798 }
1799 const consumed = io_w.consume(@intCast(sbytes));
1800 file_reader.seekTo(file_reader.pos + consumed) catch return error.ReadFailed;
1801 return consumed;
1802 }
1803
1804 if (native_os.isDarwin() and w.mode == .streaming) sf: {
1805 // Try using sendfile on macOS.
1806 if (w.sendfile_err != null) break :sf;
1807 const offset = std.math.cast(std.c.off_t, file_reader.pos) orelse break :sf;
1808 var hdtr_data: std.c.sf_hdtr = undefined;
1809 var headers: [2]posix.iovec_const = undefined;
1810 var headers_i: u8 = 0;
1811 if (writer_buffered.len != 0) {
1812 headers[headers_i] = .{ .base = writer_buffered.ptr, .len = writer_buffered.len };
1813 headers_i += 1;
1814 }
1815 if (reader_buffered.len != 0) {
1816 headers[headers_i] = .{ .base = reader_buffered.ptr, .len = reader_buffered.len };
1817 headers_i += 1;
1818 }
1819 const hdtr: ?*std.c.sf_hdtr = if (headers_i == 0) null else b: {
1820 hdtr_data = .{
1821 .headers = &headers,
1822 .hdr_cnt = headers_i,
1823 .trailers = null,
1824 .trl_cnt = 0,
1825 };
1826 break :b &hdtr_data;
1827 };
1828 const max_count = maxInt(i32); // Avoid EINVAL.
1829 var len: std.c.off_t = @min(file_limit, max_count);
1830 const flags = 0;
1831 switch (posix.errno(std.c.sendfile(in_fd, out_fd, offset, &len, hdtr, flags))) {
1832 .SUCCESS, .INTR => {},
1833 .OPNOTSUPP, .NOTSOCK, .NOSYS => w.sendfile_err = error.UnsupportedOperation,
1834 .BADF => if (builtin.mode == .Debug) @panic("race condition") else {
1835 w.sendfile_err = error.Unexpected;
1836 },
1837 .FAULT => if (builtin.mode == .Debug) @panic("segmentation fault") else {
1838 w.sendfile_err = error.Unexpected;
1839 },
1840 .INVAL => if (builtin.mode == .Debug) @panic("invalid API usage") else {
1841 w.sendfile_err = error.Unexpected;
1842 },
1843 .NOTCONN => w.sendfile_err = error.BrokenPipe,
1844 .AGAIN => if (len == 0) {
1845 w.sendfile_err = error.WouldBlock;
1846 },
1847 .IO => w.sendfile_err = error.InputOutput,
1848 .PIPE => w.sendfile_err = error.BrokenPipe,
1849 else => |err| w.sendfile_err = posix.unexpectedErrno(err),
1850 }
1851 if (len == 0) {
1852 file_reader.size = file_reader.pos;
1853 return error.EndOfStream;
1854 }
1855 const consumed = io_w.consume(@bitCast(len));
1856 file_reader.seekTo(file_reader.pos + consumed) catch return error.ReadFailed;
1857 return consumed;
1858 }
1859
1826 if (native_os == .linux and w.mode == .streaming) sf: {1860 if (native_os == .linux and w.mode == .streaming) sf: {
1827 // Try using sendfile on Linux.1861 // Try using sendfile on Linux.
1828 if (w.sendfile_err != null) break :sf;1862 if (w.sendfile_err != null) break :sf;
1829 // Linux sendfile does not support headers.1863 // Linux sendfile does not support headers.
1830 const buffered = limit.slice(file_reader.interface.buffer);1864 if (writer_buffered.len != 0 or reader_buffered.len != 0)
1831 if (io_w.end != 0 or buffered.len != 0) return drain(io_w, &.{buffered}, 1);1865 return sendFileBuffered(io_w, file_reader, reader_buffered);
1832 const max_count = 0x7ffff000; // Avoid EINVAL.1866 const max_count = 0x7ffff000; // Avoid EINVAL.
1833 var off: std.os.linux.off_t = undefined;1867 var off: std.os.linux.off_t = undefined;
1834 const off_ptr: ?*std.os.linux.off_t, const count: usize = switch (file_reader.mode) {1868 const off_ptr: ?*std.os.linux.off_t, const count: usize = switch (file_reader.mode) {
...@@ -1875,6 +1909,7 @@ pub const Writer = struct {...@@ -1875,6 +1909,7 @@ pub const Writer = struct {
1875 w.pos += n;1909 w.pos += n;
1876 return n;1910 return n;
1877 }1911 }
1912
1878 const copy_file_range = switch (native_os) {1913 const copy_file_range = switch (native_os) {
1879 .freebsd => std.os.freebsd.copy_file_range,1914 .freebsd => std.os.freebsd.copy_file_range,
1880 .linux => if (std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 })) std.os.linux.wrapped.copy_file_range else {},1915 .linux => if (std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 })) std.os.linux.wrapped.copy_file_range else {},
...@@ -1882,8 +1917,8 @@ pub const Writer = struct {...@@ -1882,8 +1917,8 @@ pub const Writer = struct {
1882 };1917 };
1883 if (@TypeOf(copy_file_range) != void) cfr: {1918 if (@TypeOf(copy_file_range) != void) cfr: {
1884 if (w.copy_file_range_err != null) break :cfr;1919 if (w.copy_file_range_err != null) break :cfr;
1885 const buffered = limit.slice(file_reader.interface.buffer);1920 if (writer_buffered.len != 0 or reader_buffered.len != 0)
1886 if (io_w.end != 0 or buffered.len != 0) return drain(io_w, &.{buffered}, 1);1921 return sendFileBuffered(io_w, file_reader, reader_buffered);
1887 var off_in: i64 = undefined;1922 var off_in: i64 = undefined;
1888 var off_out: i64 = undefined;1923 var off_out: i64 = undefined;
1889 const off_in_ptr: ?*i64 = switch (file_reader.mode) {1924 const off_in_ptr: ?*i64 = switch (file_reader.mode) {
...@@ -1922,6 +1957,9 @@ pub const Writer = struct {...@@ -1922,6 +1957,9 @@ pub const Writer = struct {
1922 if (file_reader.pos != 0) break :fcf;1957 if (file_reader.pos != 0) break :fcf;
1923 if (w.pos != 0) break :fcf;1958 if (w.pos != 0) break :fcf;
1924 if (limit != .unlimited) break :fcf;1959 if (limit != .unlimited) break :fcf;
1960 const size = file_reader.getSize() catch break :fcf;
1961 if (writer_buffered.len != 0 or reader_buffered.len != 0)
1962 return sendFileBuffered(io_w, file_reader, reader_buffered);
1925 const rc = std.c.fcopyfile(in_fd, out_fd, null, .{ .DATA = true });1963 const rc = std.c.fcopyfile(in_fd, out_fd, null, .{ .DATA = true });
1926 switch (posix.errno(rc)) {1964 switch (posix.errno(rc)) {
1927 .SUCCESS => {},1965 .SUCCESS => {},
...@@ -1942,15 +1980,24 @@ pub const Writer = struct {...@@ -1942,15 +1980,24 @@ pub const Writer = struct {
1942 return 0;1980 return 0;
1943 },1981 },
1944 }1982 }
1945 const n = if (file_reader.size) |size| size else @panic("TODO figure out how much copied");1983 file_reader.pos = size;
1946 file_reader.pos = n;1984 w.pos = size;
1947 w.pos = n;1985 return size;
1948 return n;
1949 }1986 }
19501987
1951 return error.Unimplemented;1988 return error.Unimplemented;
1952 }1989 }
19531990
1991 fn sendFileBuffered(
1992 io_w: *std.io.Writer,
1993 file_reader: *Reader,
1994 reader_buffered: []const u8,
1995 ) std.io.Writer.FileError!usize {
1996 const n = try drain(io_w, &.{reader_buffered}, 1);
1997 file_reader.seekTo(file_reader.pos + n) catch return error.ReadFailed;
1998 return n;
1999 }
2000
1954 pub fn seekTo(w: *Writer, offset: u64) SeekError!void {2001 pub fn seekTo(w: *Writer, offset: u64) SeekError!void {
1955 switch (w.mode) {2002 switch (w.mode) {
1956 .positional, .positional_reading => {2003 .positional, .positional_reading => {
...@@ -1979,7 +2026,19 @@ pub const Writer = struct {...@@ -1979,7 +2026,19 @@ pub const Writer = struct {
1979 /// along with other write failures.2026 /// along with other write failures.
1980 pub fn end(w: *Writer) EndError!void {2027 pub fn end(w: *Writer) EndError!void {
1981 try w.interface.flush();2028 try w.interface.flush();
1982 return w.file.setEndPos(w.pos);2029 switch (w.mode) {
2030 .positional,
2031 .positional_reading,
2032 => w.file.setEndPos(w.pos) catch |err| switch (err) {
2033 error.NonResizable => return,
2034 else => |e| return e,
2035 },
2036
2037 .streaming,
2038 .streaming_reading,
2039 .failure,
2040 => {},
2041 }
1983 }2042 }
1984};2043};
19852044
lib/std/fs/test.zig+57-29
...@@ -1499,32 +1499,18 @@ test "sendfile" {...@@ -1499,32 +1499,18 @@ test "sendfile" {
1499 const header2 = "second header\n";1499 const header2 = "second header\n";
1500 const trailer1 = "trailer1\n";1500 const trailer1 = "trailer1\n";
1501 const trailer2 = "second trailer\n";1501 const trailer2 = "second trailer\n";
1502 var hdtr = [_]posix.iovec_const{1502 var headers: [2][]const u8 = .{ header1, header2 };
1503 .{1503 var trailers: [2][]const u8 = .{ trailer1, trailer2 };
1504 .base = header1,
1505 .len = header1.len,
1506 },
1507 .{
1508 .base = header2,
1509 .len = header2.len,
1510 },
1511 .{
1512 .base = trailer1,
1513 .len = trailer1.len,
1514 },
1515 .{
1516 .base = trailer2,
1517 .len = trailer2.len,
1518 },
1519 };
15201504
1521 var written_buf: [100]u8 = undefined;1505 var written_buf: [100]u8 = undefined;
1522 try dest_file.writeFileAll(src_file, .{1506 var file_reader = src_file.reader(&.{});
1523 .in_offset = 1,1507 var fallback_buffer: [50]u8 = undefined;
1524 .in_len = 10,1508 var file_writer = dest_file.writer(&fallback_buffer);
1525 .headers_and_trailers = &hdtr,1509 try file_writer.interface.writeVecAll(&headers);
1526 .header_count = 2,1510 try file_reader.seekTo(1);
1527 });1511 try testing.expectEqual(10, try file_writer.interface.sendFileAll(&file_reader, .limited(10)));
1512 try file_writer.interface.writeVecAll(&trailers);
1513 try file_writer.interface.flush();
1528 const amt = try dest_file.preadAll(&written_buf, 0);1514 const amt = try dest_file.preadAll(&written_buf, 0);
1529 try testing.expectEqualStrings("header1\nsecond header\nine1\nsecontrailer1\nsecond trailer\n", written_buf[0..amt]);1515 try testing.expectEqualStrings("header1\nsecond header\nine1\nsecontrailer1\nsecond trailer\n", written_buf[0..amt]);
1530}1516}
...@@ -1595,9 +1581,10 @@ test "AtomicFile" {...@@ -1595,9 +1581,10 @@ test "AtomicFile" {
1595 ;1581 ;
15961582
1597 {1583 {
1598 var af = try ctx.dir.atomicFile(test_out_file, .{});1584 var buffer: [100]u8 = undefined;
1585 var af = try ctx.dir.atomicFile(test_out_file, .{ .write_buffer = &buffer });
1599 defer af.deinit();1586 defer af.deinit();
1600 try af.file.writeAll(test_content);1587 try af.file_writer.interface.writeAll(test_content);
1601 try af.finish();1588 try af.finish();
1602 }1589 }
1603 const content = try ctx.dir.readFileAlloc(allocator, test_out_file, 9999);1590 const content = try ctx.dir.readFileAlloc(allocator, test_out_file, 9999);
...@@ -2073,7 +2060,7 @@ test "invalid UTF-8/WTF-8 paths" {...@@ -2073,7 +2060,7 @@ test "invalid UTF-8/WTF-8 paths" {
2073}2060}
20742061
2075test "read file non vectored" {2062test "read file non vectored" {
2076 var tmp_dir = std.testing.tmpDir(.{});2063 var tmp_dir = testing.tmpDir(.{});
2077 defer tmp_dir.cleanup();2064 defer tmp_dir.cleanup();
20782065
2079 const contents = "hello, world!\n";2066 const contents = "hello, world!\n";
...@@ -2098,6 +2085,47 @@ test "read file non vectored" {...@@ -2098,6 +2085,47 @@ test "read file non vectored" {
2098 else => |e| return e,2085 else => |e| return e,
2099 };2086 };
2100 }2087 }
2101 try std.testing.expectEqualStrings(contents, w.buffered());2088 try testing.expectEqualStrings(contents, w.buffered());
2102 try std.testing.expectEqual(contents.len, i);2089 try testing.expectEqual(contents.len, i);
2090}
2091
2092test "seek keeping partial buffer" {
2093 var tmp_dir = testing.tmpDir(.{});
2094 defer tmp_dir.cleanup();
2095
2096 const contents = "0123456789";
2097
2098 const file = try tmp_dir.dir.createFile("input.txt", .{ .read = true });
2099 defer file.close();
2100 {
2101 var file_writer: std.fs.File.Writer = .init(file, &.{});
2102 try file_writer.interface.writeAll(contents);
2103 try file_writer.interface.flush();
2104 }
2105
2106 var read_buffer: [3]u8 = undefined;
2107 var file_reader: std.fs.File.Reader = .init(file, &read_buffer);
2108
2109 try testing.expectEqual(0, file_reader.logicalPos());
2110
2111 var buf: [4]u8 = undefined;
2112 try file_reader.interface.readSliceAll(&buf);
2113
2114 if (file_reader.interface.bufferedLen() != 3) {
2115 // Pass the test if the OS doesn't give us vectored reads.
2116 return;
2117 }
2118
2119 try testing.expectEqual(4, file_reader.logicalPos());
2120 try testing.expectEqual(7, file_reader.pos);
2121 try file_reader.seekTo(6);
2122 try testing.expectEqual(6, file_reader.logicalPos());
2123 try testing.expectEqual(7, file_reader.pos);
2124
2125 try testing.expectEqualStrings("0123", &buf);
2126
2127 const n = try file_reader.interface.readSliceShort(&buf);
2128 try testing.expectEqual(4, n);
2129
2130 try testing.expectEqualStrings("6789", &buf);
2103}2131}
lib/std/http/Server.zig+1-2
...@@ -129,11 +129,10 @@ pub const Request = struct {...@@ -129,11 +129,10 @@ pub const Request = struct {
129 pub const Compression = union(enum) {129 pub const Compression = union(enum) {
130 pub const DeflateDecompressor = std.compress.zlib.Decompressor(std.io.AnyReader);130 pub const DeflateDecompressor = std.compress.zlib.Decompressor(std.io.AnyReader);
131 pub const GzipDecompressor = std.compress.gzip.Decompressor(std.io.AnyReader);131 pub const GzipDecompressor = std.compress.gzip.Decompressor(std.io.AnyReader);
132 pub const ZstdDecompressor = std.compress.zstd.Decompressor(std.io.AnyReader);
133132
134 deflate: DeflateDecompressor,133 deflate: DeflateDecompressor,
135 gzip: GzipDecompressor,134 gzip: GzipDecompressor,
136 zstd: ZstdDecompressor,135 zstd: std.compress.zstd.Decompress,
137 none: void,136 none: void,
138 };137 };
139138
lib/std/json.zig-1
...@@ -69,7 +69,6 @@ pub const ArrayHashMap = @import("json/hashmap.zig").ArrayHashMap;...@@ -69,7 +69,6 @@ pub const ArrayHashMap = @import("json/hashmap.zig").ArrayHashMap;
69pub const Scanner = @import("json/Scanner.zig");69pub const Scanner = @import("json/Scanner.zig");
70pub const validate = Scanner.validate;70pub const validate = Scanner.validate;
71pub const Error = Scanner.Error;71pub const Error = Scanner.Error;
72pub const reader = Scanner.reader;
73pub const default_buffer_size = Scanner.default_buffer_size;72pub const default_buffer_size = Scanner.default_buffer_size;
74pub const Token = Scanner.Token;73pub const Token = Scanner.Token;
75pub const TokenType = Scanner.TokenType;74pub const TokenType = Scanner.TokenType;
lib/std/math.zig+55-38
...@@ -45,6 +45,7 @@ pub const rad_per_deg = 0.017453292519943295769236907684886127134428718885417254...@@ -45,6 +45,7 @@ pub const rad_per_deg = 0.017453292519943295769236907684886127134428718885417254
45/// 180.0/pi45/// 180.0/pi
46pub const deg_per_rad = 57.295779513082320876798154814105170332405472466564321549160243861;46pub const deg_per_rad = 57.295779513082320876798154814105170332405472466564321549160243861;
4747
48pub const Sign = enum(u1) { positive, negative };
48pub const FloatRepr = float.FloatRepr;49pub const FloatRepr = float.FloatRepr;
49pub const floatExponentBits = float.floatExponentBits;50pub const floatExponentBits = float.floatExponentBits;
50pub const floatMantissaBits = float.floatMantissaBits;51pub const floatMantissaBits = float.floatMantissaBits;
...@@ -594,27 +595,30 @@ pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T {...@@ -594,27 +595,30 @@ pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T {
594/// Shifts left. Overflowed bits are truncated.595/// Shifts left. Overflowed bits are truncated.
595/// A negative shift amount results in a right shift.596/// A negative shift amount results in a right shift.
596pub fn shl(comptime T: type, a: T, shift_amt: anytype) T {597pub fn shl(comptime T: type, a: T, shift_amt: anytype) T {
598 const is_shl = shift_amt >= 0;
597 const abs_shift_amt = @abs(shift_amt);599 const abs_shift_amt = @abs(shift_amt);
598600 const casted_shift_amt = casted_shift_amt: switch (@typeInfo(T)) {
599 const casted_shift_amt = blk: {601 .int => |info| {
600 if (@typeInfo(T) == .vector) {602 if (abs_shift_amt < info.bits) break :casted_shift_amt @as(
601 const C = @typeInfo(T).vector.child;603 Log2Int(T),
602 const len = @typeInfo(T).vector.len;604 @intCast(abs_shift_amt),
603 if (abs_shift_amt >= @typeInfo(C).int.bits) return @splat(0);605 );
604 break :blk @as(@Vector(len, Log2Int(C)), @splat(@as(Log2Int(C), @intCast(abs_shift_amt))));606 if (info.signedness == .unsigned or is_shl) return 0;
605 } else {607 return a >> (info.bits - 1);
606 if (abs_shift_amt >= @typeInfo(T).int.bits) return 0;608 },
607 break :blk @as(Log2Int(T), @intCast(abs_shift_amt));609 .vector => |info| {
608 }610 const Child = info.child;
611 const child_info = @typeInfo(Child).int;
612 if (abs_shift_amt < child_info.bits) break :casted_shift_amt @as(
613 @Vector(info.len, Log2Int(Child)),
614 @splat(@as(Log2Int(Child), @intCast(abs_shift_amt))),
615 );
616 if (child_info.signedness == .unsigned or is_shl) return @splat(0);
617 return a >> @splat(child_info.bits - 1);
618 },
619 else => comptime unreachable,
609 };620 };
610621 return if (is_shl) a << casted_shift_amt else a >> casted_shift_amt;
611 if (@TypeOf(shift_amt) == comptime_int or @typeInfo(@TypeOf(shift_amt)).int.signedness == .signed) {
612 if (shift_amt < 0) {
613 return a >> casted_shift_amt;
614 }
615 }
616
617 return a << casted_shift_amt;
618}622}
619623
620test shl {624test shl {
...@@ -629,32 +633,40 @@ test shl {...@@ -629,32 +633,40 @@ test shl {
629 try testing.expect(shl(@Vector(1, u32), @Vector(1, u32){42}, @as(usize, 1))[0] == @as(u32, 42) << 1);633 try testing.expect(shl(@Vector(1, u32), @Vector(1, u32){42}, @as(usize, 1))[0] == @as(u32, 42) << 1);
630 try testing.expect(shl(@Vector(1, u32), @Vector(1, u32){42}, @as(isize, -1))[0] == @as(u32, 42) >> 1);634 try testing.expect(shl(@Vector(1, u32), @Vector(1, u32){42}, @as(isize, -1))[0] == @as(u32, 42) >> 1);
631 try testing.expect(shl(@Vector(1, u32), @Vector(1, u32){42}, 33)[0] == 0);635 try testing.expect(shl(@Vector(1, u32), @Vector(1, u32){42}, 33)[0] == 0);
636
637 try testing.expect(shl(i8, -1, -100) == -1);
638 try testing.expect(shl(i8, -1, 100) == 0);
639 try testing.expect(@reduce(.And, shl(@Vector(2, i8), .{ -1, 1 }, -100) == @Vector(2, i8){ -1, 0 }));
640 try testing.expect(@reduce(.And, shl(@Vector(2, i8), .{ -1, 1 }, 100) == @Vector(2, i8){ 0, 0 }));
632}641}
633642
634/// Shifts right. Overflowed bits are truncated.643/// Shifts right. Overflowed bits are truncated.
635/// A negative shift amount results in a left shift.644/// A negative shift amount results in a left shift.
636pub fn shr(comptime T: type, a: T, shift_amt: anytype) T {645pub fn shr(comptime T: type, a: T, shift_amt: anytype) T {
646 const is_shl = shift_amt < 0;
637 const abs_shift_amt = @abs(shift_amt);647 const abs_shift_amt = @abs(shift_amt);
638648 const casted_shift_amt = casted_shift_amt: switch (@typeInfo(T)) {
639 const casted_shift_amt = blk: {649 .int => |info| {
640 if (@typeInfo(T) == .vector) {650 if (abs_shift_amt < info.bits) break :casted_shift_amt @as(
641 const C = @typeInfo(T).vector.child;651 Log2Int(T),
642 const len = @typeInfo(T).vector.len;652 @intCast(abs_shift_amt),
643 if (abs_shift_amt >= @typeInfo(C).int.bits) return @splat(0);653 );
644 break :blk @as(@Vector(len, Log2Int(C)), @splat(@as(Log2Int(C), @intCast(abs_shift_amt))));654 if (info.signedness == .unsigned or is_shl) return 0;
645 } else {655 return a >> (info.bits - 1);
646 if (abs_shift_amt >= @typeInfo(T).int.bits) return 0;656 },
647 break :blk @as(Log2Int(T), @intCast(abs_shift_amt));657 .vector => |info| {
648 }658 const Child = info.child;
659 const child_info = @typeInfo(Child).int;
660 if (abs_shift_amt < child_info.bits) break :casted_shift_amt @as(
661 @Vector(info.len, Log2Int(Child)),
662 @splat(@as(Log2Int(Child), @intCast(abs_shift_amt))),
663 );
664 if (child_info.signedness == .unsigned or is_shl) return @splat(0);
665 return a >> @splat(child_info.bits - 1);
666 },
667 else => comptime unreachable,
649 };668 };
650669 return if (is_shl) a << casted_shift_amt else a >> casted_shift_amt;
651 if (@TypeOf(shift_amt) == comptime_int or @typeInfo(@TypeOf(shift_amt)).int.signedness == .signed) {
652 if (shift_amt < 0) {
653 return a << casted_shift_amt;
654 }
655 }
656
657 return a >> casted_shift_amt;
658}670}
659671
660test shr {672test shr {
...@@ -669,6 +681,11 @@ test shr {...@@ -669,6 +681,11 @@ test shr {
669 try testing.expect(shr(@Vector(1, u32), @Vector(1, u32){42}, @as(usize, 1))[0] == @as(u32, 42) >> 1);681 try testing.expect(shr(@Vector(1, u32), @Vector(1, u32){42}, @as(usize, 1))[0] == @as(u32, 42) >> 1);
670 try testing.expect(shr(@Vector(1, u32), @Vector(1, u32){42}, @as(isize, -1))[0] == @as(u32, 42) << 1);682 try testing.expect(shr(@Vector(1, u32), @Vector(1, u32){42}, @as(isize, -1))[0] == @as(u32, 42) << 1);
671 try testing.expect(shr(@Vector(1, u32), @Vector(1, u32){42}, 33)[0] == 0);683 try testing.expect(shr(@Vector(1, u32), @Vector(1, u32){42}, 33)[0] == 0);
684
685 try testing.expect(shr(i8, -1, -100) == 0);
686 try testing.expect(shr(i8, -1, 100) == -1);
687 try testing.expect(@reduce(.And, shr(@Vector(2, i8), .{ -1, 1 }, -100) == @Vector(2, i8){ 0, 0 }));
688 try testing.expect(@reduce(.And, shr(@Vector(2, i8), .{ -1, 1 }, 100) == @Vector(2, i8){ -1, 0 }));
672}689}
673690
674/// Rotates right. Only unsigned values can be rotated. Negative shift691/// 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,7 +2774,6 @@ test "bitNotWrap more than two limbs" {
2774 // This test requires int sizes greater than 128 bits.2774 // This test requires int sizes greater than 128 bits.
2775 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO2775 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2776 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO2776 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
2777 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2778 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2777 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2779 // LLVM: unexpected runtime library name: __umodei42778 // LLVM: unexpected runtime library name: __umodei4
2780 if (builtin.zig_backend == .stage2_llvm and comptime builtin.target.cpu.arch.isWasm()) return error.SkipZigTest; // TODO2779 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,8 +4,6 @@ const assert = std.debug.assert;
4const expect = std.testing.expect;4const expect = std.testing.expect;
5const expectEqual = std.testing.expectEqual;5const expectEqual = std.testing.expectEqual;
66
7pub const Sign = enum(u1) { positive, negative };
8
9pub fn FloatRepr(comptime Float: type) type {7pub fn FloatRepr(comptime Float: type) type {
10 const fractional_bits = floatFractionalBits(Float);8 const fractional_bits = floatFractionalBits(Float);
11 const exponent_bits = floatExponentBits(Float);9 const exponent_bits = floatExponentBits(Float);
...@@ -14,7 +12,7 @@ pub fn FloatRepr(comptime Float: type) type {...@@ -14,7 +12,7 @@ pub fn FloatRepr(comptime Float: type) type {
1412
15 mantissa: StoredMantissa,13 mantissa: StoredMantissa,
16 exponent: BiasedExponent,14 exponent: BiasedExponent,
17 sign: Sign,15 sign: std.math.Sign,
1816
19 pub const StoredMantissa = @Type(.{ .int = .{17 pub const StoredMantissa = @Type(.{ .int = .{
20 .signedness = .unsigned,18 .signedness = .unsigned,
...@@ -69,7 +67,7 @@ pub fn FloatRepr(comptime Float: type) type {...@@ -69,7 +67,7 @@ pub fn FloatRepr(comptime Float: type) type {
6967
70 /// This currently truncates denormal values, which needs to be fixed before this can be used to68 /// This currently truncates denormal values, which needs to be fixed before this can be used to
71 /// produce a rounded value.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 if (normalized.exponent > BiasedExponent.max_normal.unbias()) return @bitCast(Repr{71 if (normalized.exponent > BiasedExponent.max_normal.unbias()) return @bitCast(Repr{
74 .mantissa = 0,72 .mantissa = 0,
75 .exponent = .infinite,73 .exponent = .infinite,
lib/std/math/log10.zig-1
...@@ -132,7 +132,6 @@ inline fn less_than_5(x: u32) u32 {...@@ -132,7 +132,6 @@ inline fn less_than_5(x: u32) u32 {
132test log10_int {132test log10_int {
133 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO133 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
134 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO134 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
136 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO135 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
137 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO136 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
138 if (builtin.zig_backend == .stage2_llvm and comptime builtin.target.cpu.arch.isWasm()) return error.SkipZigTest; // TODO137 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,6 +676,7 @@ test lessThan {
676676
677const eqlBytes_allowed = switch (builtin.zig_backend) {677const eqlBytes_allowed = switch (builtin.zig_backend) {
678 // These backends don't support vectors yet.678 // These backends don't support vectors yet.
679 .stage2_aarch64,
679 .stage2_powerpc,680 .stage2_powerpc,
680 .stage2_riscv64,681 .stage2_riscv64,
681 => false,682 => false,
...@@ -4482,7 +4483,7 @@ pub fn doNotOptimizeAway(val: anytype) void {...@@ -4482,7 +4483,7 @@ pub fn doNotOptimizeAway(val: anytype) void {
4482 );4483 );
4483 asm volatile (""4484 asm volatile (""
4484 :4485 :
4485 : [val2] "r" (val2),4486 : [_] "r" (val2),
4486 );4487 );
4487 } else doNotOptimizeAway(&val);4488 } else doNotOptimizeAway(&val);
4488 },4489 },
...@@ -4490,7 +4491,7 @@ pub fn doNotOptimizeAway(val: anytype) void {...@@ -4490,7 +4491,7 @@ pub fn doNotOptimizeAway(val: anytype) void {
4490 if ((t.float.bits == 32 or t.float.bits == 64) and builtin.zig_backend != .stage2_c) {4491 if ((t.float.bits == 32 or t.float.bits == 64) and builtin.zig_backend != .stage2_c) {
4491 asm volatile (""4492 asm volatile (""
4492 :4493 :
4493 : [val] "rm" (val),4494 : [_] "rm" (val),
4494 );4495 );
4495 } else doNotOptimizeAway(&val);4496 } else doNotOptimizeAway(&val);
4496 },4497 },
...@@ -4500,7 +4501,7 @@ pub fn doNotOptimizeAway(val: anytype) void {...@@ -4500,7 +4501,7 @@ pub fn doNotOptimizeAway(val: anytype) void {
4500 } else {4501 } else {
4501 asm volatile (""4502 asm volatile (""
4502 :4503 :
4503 : [val] "m" (val),4504 : [_] "m" (val),
4504 : .{ .memory = true });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,7 +503,6 @@ pub var elf_aux_maybe: ?[*]std.elf.Auxv = null;
503/// Whether an external or internal getauxval implementation is used.503/// Whether an external or internal getauxval implementation is used.
504const extern_getauxval = switch (builtin.zig_backend) {504const extern_getauxval = switch (builtin.zig_backend) {
505 // Calling extern functions is not yet supported with these backends505 // Calling extern functions is not yet supported with these backends
506 .stage2_aarch64,
507 .stage2_arm,506 .stage2_arm,
508 .stage2_powerpc,507 .stage2_powerpc,
509 .stage2_riscv64,508 .stage2_riscv64,
lib/std/posix.zig+24-295
...@@ -192,10 +192,27 @@ pub const iovec_const = extern struct {...@@ -192,10 +192,27 @@ pub const iovec_const = extern struct {
192 len: usize,192 len: usize,
193};193};
194194
195pub const ACCMODE = enum(u2) {195pub const ACCMODE = switch (native_os) {
196 RDONLY = 0,196 // POSIX has a note about the access mode values:
197 WRONLY = 1,197 //
198 RDWR = 2,198 // In historical implementations the value of O_RDONLY is zero. Because of
199 // that, it is not possible to detect the presence of O_RDONLY and another
200 // option. Future implementations should encode O_RDONLY and O_WRONLY as
201 // bit flags so that: O_RDONLY | O_WRONLY == O_RDWR
202 //
203 // In practice SerenityOS is the only system supported by Zig that
204 // implements this suggestion.
205 // https://github.com/SerenityOS/serenity/blob/4adc51fdf6af7d50679c48b39362e062f5a3b2cb/Kernel/API/POSIX/fcntl.h#L28-L30
206 .serenity => enum(u2) {
207 RDONLY = 1,
208 WRONLY = 2,
209 RDWR = 3,
210 },
211 else => enum(u2) {
212 RDONLY = 0,
213 WRONLY = 1,
214 RDWR = 2,
215 },
199};216};
200217
201pub const TCSA = enum(c_uint) {218pub const TCSA = enum(c_uint) {
...@@ -1035,6 +1052,7 @@ pub const TruncateError = error{...@@ -1035,6 +1052,7 @@ pub const TruncateError = error{
1035 FileBusy,1052 FileBusy,
1036 AccessDenied,1053 AccessDenied,
1037 PermissionDenied,1054 PermissionDenied,
1055 NonResizable,
1038} || UnexpectedError;1056} || UnexpectedError;
10391057
1040/// Length must be positive when treated as an i64.1058/// Length must be positive when treated as an i64.
...@@ -1074,7 +1092,7 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {...@@ -1074,7 +1092,7 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
1074 .PERM => return error.PermissionDenied,1092 .PERM => return error.PermissionDenied,
1075 .TXTBSY => return error.FileBusy,1093 .TXTBSY => return error.FileBusy,
1076 .BADF => unreachable, // Handle not open for writing1094 .BADF => unreachable, // Handle not open for writing
1077 .INVAL => unreachable, // Handle not open for writing, negative length, or non-resizable handle1095 .INVAL => return error.NonResizable,
1078 .NOTCAPABLE => return error.AccessDenied,1096 .NOTCAPABLE => return error.AccessDenied,
1079 else => |err| return unexpectedErrno(err),1097 else => |err| return unexpectedErrno(err),
1080 }1098 }
...@@ -1090,7 +1108,7 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {...@@ -1090,7 +1108,7 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
1090 .PERM => return error.PermissionDenied,1108 .PERM => return error.PermissionDenied,
1091 .TXTBSY => return error.FileBusy,1109 .TXTBSY => return error.FileBusy,
1092 .BADF => unreachable, // Handle not open for writing1110 .BADF => unreachable, // Handle not open for writing
1093 .INVAL => unreachable, // Handle not open for writing, negative length, or non-resizable handle1111 .INVAL => return error.NonResizable, // This is returned for /dev/null for example.
1094 else => |err| return unexpectedErrno(err),1112 else => |err| return unexpectedErrno(err),
1095 }1113 }
1096 }1114 }
...@@ -6326,295 +6344,6 @@ pub fn send(...@@ -6326,295 +6344,6 @@ pub fn send(
6326 };6344 };
6327}6345}
63286346
6329pub const SendFileError = PReadError || WriteError || SendError;
6330
6331/// Transfer data between file descriptors, with optional headers and trailers.
6332///
6333/// Returns the number of bytes written, which can be zero.
6334///
6335/// The `sendfile` call copies `in_len` bytes from one file descriptor to another. When possible,
6336/// this is done within the operating system kernel, which can provide better performance
6337/// characteristics than transferring data from kernel to user space and back, such as with
6338/// `read` and `write` calls. When `in_len` is `0`, it means to copy until the end of the input file has been
6339/// reached. Note, however, that partial writes are still possible in this case.
6340///
6341/// `in_fd` must be a file descriptor opened for reading, and `out_fd` must be a file descriptor
6342/// opened for writing. They may be any kind of file descriptor; however, if `in_fd` is not a regular
6343/// file system file, it may cause this function to fall back to calling `read` and `write`, in which case
6344/// atomicity guarantees no longer apply.
6345///
6346/// Copying begins reading at `in_offset`. The input file descriptor seek position is ignored and not updated.
6347/// If the output file descriptor has a seek position, it is updated as bytes are written. When
6348/// `in_offset` is past the end of the input file, it successfully reads 0 bytes.
6349///
6350/// `flags` has different meanings per operating system; refer to the respective man pages.
6351///
6352/// These systems support atomically sending everything, including headers and trailers:
6353/// * macOS
6354/// * FreeBSD
6355///
6356/// These systems support in-kernel data copying, but headers and trailers are not sent atomically:
6357/// * Linux
6358///
6359/// Other systems fall back to calling `read` / `write`.
6360///
6361/// Linux has a limit on how many bytes may be transferred in one `sendfile` call, which is `0x7ffff000`
6362/// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as
6363/// well as stuffing the errno codes into the last `4096` values. This is noted on the `sendfile` man page.
6364/// The limit on Darwin is `0x7fffffff`, trying to write more than that returns EINVAL.
6365/// The corresponding POSIX limit on this is `maxInt(isize)`.
6366pub fn sendfile(
6367 out_fd: fd_t,
6368 in_fd: fd_t,
6369 in_offset: u64,
6370 in_len: u64,
6371 headers: []const iovec_const,
6372 trailers: []const iovec_const,
6373 flags: u32,
6374) SendFileError!usize {
6375 var header_done = false;
6376 var total_written: usize = 0;
6377
6378 // Prevents EOVERFLOW.
6379 const size_t = std.meta.Int(.unsigned, @typeInfo(usize).int.bits - 1);
6380 const max_count = switch (native_os) {
6381 .linux => 0x7ffff000,
6382 .macos, .ios, .watchos, .tvos, .visionos => maxInt(i32),
6383 else => maxInt(size_t),
6384 };
6385
6386 switch (native_os) {
6387 .linux => sf: {
6388 if (headers.len != 0) {
6389 const amt = try writev(out_fd, headers);
6390 total_written += amt;
6391 if (amt < count_iovec_bytes(headers)) return total_written;
6392 header_done = true;
6393 }
6394
6395 // Here we match BSD behavior, making a zero count value send as many bytes as possible.
6396 const adjusted_count = if (in_len == 0) max_count else @min(in_len, max_count);
6397
6398 const sendfile_sym = if (lfs64_abi) system.sendfile64 else system.sendfile;
6399 while (true) {
6400 var offset: off_t = @bitCast(in_offset);
6401 const rc = sendfile_sym(out_fd, in_fd, &offset, adjusted_count);
6402 switch (errno(rc)) {
6403 .SUCCESS => {
6404 const amt: usize = @bitCast(rc);
6405 total_written += amt;
6406 if (in_len == 0 and amt == 0) {
6407 // We have detected EOF from `in_fd`.
6408 break;
6409 } else if (amt < in_len) {
6410 return total_written;
6411 } else {
6412 break;
6413 }
6414 },
6415
6416 .BADF => unreachable, // Always a race condition.
6417 .FAULT => unreachable, // Segmentation fault.
6418 .OVERFLOW => unreachable, // We avoid passing too large of a `count`.
6419 .NOTCONN => return error.BrokenPipe, // `out_fd` is an unconnected socket
6420
6421 .INVAL => {
6422 // EINVAL could be any of the following situations:
6423 // * Descriptor is not valid or locked
6424 // * an mmap(2)-like operation is not available for in_fd
6425 // * count is negative
6426 // * out_fd has the APPEND flag set
6427 // Because of the "mmap(2)-like operation" possibility, we fall back to doing read/write
6428 // manually.
6429 break :sf;
6430 },
6431 .AGAIN => return error.WouldBlock,
6432 .IO => return error.InputOutput,
6433 .PIPE => return error.BrokenPipe,
6434 .NOMEM => return error.SystemResources,
6435 .NXIO => return error.Unseekable,
6436 .SPIPE => return error.Unseekable,
6437 else => |err| {
6438 unexpectedErrno(err) catch {};
6439 break :sf;
6440 },
6441 }
6442 }
6443
6444 if (trailers.len != 0) {
6445 total_written += try writev(out_fd, trailers);
6446 }
6447
6448 return total_written;
6449 },
6450 .freebsd => sf: {
6451 var hdtr_data: std.c.sf_hdtr = undefined;
6452 var hdtr: ?*std.c.sf_hdtr = null;
6453 if (headers.len != 0 or trailers.len != 0) {
6454 // Here we carefully avoid `@intCast` by returning partial writes when
6455 // too many io vectors are provided.
6456 const hdr_cnt = cast(u31, headers.len) orelse maxInt(u31);
6457 if (headers.len > hdr_cnt) return writev(out_fd, headers);
6458
6459 const trl_cnt = cast(u31, trailers.len) orelse maxInt(u31);
6460
6461 hdtr_data = std.c.sf_hdtr{
6462 .headers = headers.ptr,
6463 .hdr_cnt = hdr_cnt,
6464 .trailers = trailers.ptr,
6465 .trl_cnt = trl_cnt,
6466 };
6467 hdtr = &hdtr_data;
6468 }
6469
6470 while (true) {
6471 var sbytes: off_t = undefined;
6472 const err = errno(system.sendfile(in_fd, out_fd, @bitCast(in_offset), @min(in_len, max_count), hdtr, &sbytes, flags));
6473 const amt: usize = @bitCast(sbytes);
6474 switch (err) {
6475 .SUCCESS => return amt,
6476
6477 .BADF => unreachable, // Always a race condition.
6478 .FAULT => unreachable, // Segmentation fault.
6479 .NOTCONN => return error.BrokenPipe, // `out_fd` is an unconnected socket
6480
6481 .INVAL, .OPNOTSUPP, .NOTSOCK, .NOSYS => {
6482 // EINVAL could be any of the following situations:
6483 // * The fd argument is not a regular file.
6484 // * The s argument is not a SOCK.STREAM type socket.
6485 // * The offset argument is negative.
6486 // Because of some of these possibilities, we fall back to doing read/write
6487 // manually, the same as ENOSYS.
6488 break :sf;
6489 },
6490
6491 .INTR => if (amt != 0) return amt else continue,
6492
6493 .AGAIN => if (amt != 0) {
6494 return amt;
6495 } else {
6496 return error.WouldBlock;
6497 },
6498
6499 .BUSY => if (amt != 0) {
6500 return amt;
6501 } else {
6502 return error.WouldBlock;
6503 },
6504
6505 .IO => return error.InputOutput,
6506 .NOBUFS => return error.SystemResources,
6507 .PIPE => return error.BrokenPipe,
6508
6509 else => {
6510 unexpectedErrno(err) catch {};
6511 if (amt != 0) {
6512 return amt;
6513 } else {
6514 break :sf;
6515 }
6516 },
6517 }
6518 }
6519 },
6520 .macos, .ios, .tvos, .watchos, .visionos => sf: {
6521 var hdtr_data: std.c.sf_hdtr = undefined;
6522 var hdtr: ?*std.c.sf_hdtr = null;
6523 if (headers.len != 0 or trailers.len != 0) {
6524 // Here we carefully avoid `@intCast` by returning partial writes when
6525 // too many io vectors are provided.
6526 const hdr_cnt = cast(u31, headers.len) orelse maxInt(u31);
6527 if (headers.len > hdr_cnt) return writev(out_fd, headers);
6528
6529 const trl_cnt = cast(u31, trailers.len) orelse maxInt(u31);
6530
6531 hdtr_data = std.c.sf_hdtr{
6532 .headers = headers.ptr,
6533 .hdr_cnt = hdr_cnt,
6534 .trailers = trailers.ptr,
6535 .trl_cnt = trl_cnt,
6536 };
6537 hdtr = &hdtr_data;
6538 }
6539
6540 while (true) {
6541 var sbytes: off_t = @min(in_len, max_count);
6542 const err = errno(system.sendfile(in_fd, out_fd, @bitCast(in_offset), &sbytes, hdtr, flags));
6543 const amt: usize = @bitCast(sbytes);
6544 switch (err) {
6545 .SUCCESS => return amt,
6546
6547 .BADF => unreachable, // Always a race condition.
6548 .FAULT => unreachable, // Segmentation fault.
6549 .INVAL => unreachable,
6550 .NOTCONN => return error.BrokenPipe, // `out_fd` is an unconnected socket
6551
6552 .OPNOTSUPP, .NOTSOCK, .NOSYS => break :sf,
6553
6554 .INTR => if (amt != 0) return amt else continue,
6555
6556 .AGAIN => if (amt != 0) {
6557 return amt;
6558 } else {
6559 return error.WouldBlock;
6560 },
6561
6562 .IO => return error.InputOutput,
6563 .PIPE => return error.BrokenPipe,
6564
6565 else => {
6566 unexpectedErrno(err) catch {};
6567 if (amt != 0) {
6568 return amt;
6569 } else {
6570 break :sf;
6571 }
6572 },
6573 }
6574 }
6575 },
6576 else => {}, // fall back to read/write
6577 }
6578
6579 if (headers.len != 0 and !header_done) {
6580 const amt = try writev(out_fd, headers);
6581 total_written += amt;
6582 if (amt < count_iovec_bytes(headers)) return total_written;
6583 }
6584
6585 rw: {
6586 var buf: [8 * 4096]u8 = undefined;
6587 // Here we match BSD behavior, making a zero count value send as many bytes as possible.
6588 const adjusted_count = if (in_len == 0) buf.len else @min(buf.len, in_len);
6589 const amt_read = try pread(in_fd, buf[0..adjusted_count], in_offset);
6590 if (amt_read == 0) {
6591 if (in_len == 0) {
6592 // We have detected EOF from `in_fd`.
6593 break :rw;
6594 } else {
6595 return total_written;
6596 }
6597 }
6598 const amt_written = try write(out_fd, buf[0..amt_read]);
6599 total_written += amt_written;
6600 if (amt_written < in_len or in_len == 0) return total_written;
6601 }
6602
6603 if (trailers.len != 0) {
6604 total_written += try writev(out_fd, trailers);
6605 }
6606
6607 return total_written;
6608}
6609
6610fn count_iovec_bytes(iovs: []const iovec_const) usize {
6611 var count: usize = 0;
6612 for (iovs) |iov| {
6613 count += iov.len;
6614 }
6615 return count;
6616}
6617
6618pub const CopyFileRangeError = error{6347pub const CopyFileRangeError = error{
6619 FileTooBig,6348 FileTooBig,
6620 InputOutput,6349 InputOutput,
lib/std/process/Child.zig+46-35
...@@ -14,6 +14,7 @@ const assert = std.debug.assert;...@@ -14,6 +14,7 @@ const assert = std.debug.assert;
14const native_os = builtin.os.tag;14const native_os = builtin.os.tag;
15const Allocator = std.mem.Allocator;15const Allocator = std.mem.Allocator;
16const ChildProcess = @This();16const ChildProcess = @This();
17const ArrayList = std.ArrayListUnmanaged;
1718
18pub const Id = switch (native_os) {19pub const Id = switch (native_os) {
19 .windows => windows.HANDLE,20 .windows => windows.HANDLE,
...@@ -348,19 +349,6 @@ pub const RunResult = struct {...@@ -348,19 +349,6 @@ pub const RunResult = struct {
348 stderr: []u8,349 stderr: []u8,
349};350};
350351
351fn writeFifoDataToArrayList(allocator: Allocator, list: *std.ArrayListUnmanaged(u8), fifo: *std.io.PollFifo) !void {
352 if (fifo.head != 0) fifo.realign();
353 if (list.capacity == 0) {
354 list.* = .{
355 .items = fifo.buf[0..fifo.count],
356 .capacity = fifo.buf.len,
357 };
358 fifo.* = std.io.PollFifo.init(fifo.allocator);
359 } else {
360 try list.appendSlice(allocator, fifo.buf[0..fifo.count]);
361 }
362}
363
364/// Collect the output from the process's stdout and stderr. Will return once all output352/// Collect the output from the process's stdout and stderr. Will return once all output
365/// has been collected. This does not mean that the process has ended. `wait` should still353/// has been collected. This does not mean that the process has ended. `wait` should still
366/// be called to wait for and clean up the process.354/// be called to wait for and clean up the process.
...@@ -370,28 +358,48 @@ pub fn collectOutput(...@@ -370,28 +358,48 @@ pub fn collectOutput(
370 child: ChildProcess,358 child: ChildProcess,
371 /// Used for `stdout` and `stderr`.359 /// Used for `stdout` and `stderr`.
372 allocator: Allocator,360 allocator: Allocator,
373 stdout: *std.ArrayListUnmanaged(u8),361 stdout: *ArrayList(u8),
374 stderr: *std.ArrayListUnmanaged(u8),362 stderr: *ArrayList(u8),
375 max_output_bytes: usize,363 max_output_bytes: usize,
376) !void {364) !void {
377 assert(child.stdout_behavior == .Pipe);365 assert(child.stdout_behavior == .Pipe);
378 assert(child.stderr_behavior == .Pipe);366 assert(child.stderr_behavior == .Pipe);
379367
380 var poller = std.io.poll(allocator, enum { stdout, stderr }, .{368 var poller = std.Io.poll(allocator, enum { stdout, stderr }, .{
381 .stdout = child.stdout.?,369 .stdout = child.stdout.?,
382 .stderr = child.stderr.?,370 .stderr = child.stderr.?,
383 });371 });
384 defer poller.deinit();372 defer poller.deinit();
385373
374 const stdout_r = poller.reader(.stdout);
375 stdout_r.buffer = stdout.allocatedSlice();
376 stdout_r.seek = 0;
377 stdout_r.end = stdout.items.len;
378
379 const stderr_r = poller.reader(.stderr);
380 stderr_r.buffer = stderr.allocatedSlice();
381 stderr_r.seek = 0;
382 stderr_r.end = stderr.items.len;
383
384 defer {
385 stdout.* = .{
386 .items = stdout_r.buffer[0..stdout_r.end],
387 .capacity = stdout_r.buffer.len,
388 };
389 stderr.* = .{
390 .items = stderr_r.buffer[0..stderr_r.end],
391 .capacity = stderr_r.buffer.len,
392 };
393 stdout_r.buffer = &.{};
394 stderr_r.buffer = &.{};
395 }
396
386 while (try poller.poll()) {397 while (try poller.poll()) {
387 if (poller.fifo(.stdout).count > max_output_bytes)398 if (stdout_r.bufferedLen() > max_output_bytes)
388 return error.StdoutStreamTooLong;399 return error.StdoutStreamTooLong;
389 if (poller.fifo(.stderr).count > max_output_bytes)400 if (stderr_r.bufferedLen() > max_output_bytes)
390 return error.StderrStreamTooLong;401 return error.StderrStreamTooLong;
391 }402 }
392
393 try writeFifoDataToArrayList(allocator, stdout, poller.fifo(.stdout));
394 try writeFifoDataToArrayList(allocator, stderr, poller.fifo(.stderr));
395}403}
396404
397pub const RunError = posix.GetCwdError || posix.ReadError || SpawnError || posix.PollError || error{405pub const RunError = posix.GetCwdError || posix.ReadError || SpawnError || posix.PollError || error{
...@@ -421,10 +429,10 @@ pub fn run(args: struct {...@@ -421,10 +429,10 @@ pub fn run(args: struct {
421 child.expand_arg0 = args.expand_arg0;429 child.expand_arg0 = args.expand_arg0;
422 child.progress_node = args.progress_node;430 child.progress_node = args.progress_node;
423431
424 var stdout: std.ArrayListUnmanaged(u8) = .empty;432 var stdout: ArrayList(u8) = .empty;
425 errdefer stdout.deinit(args.allocator);433 defer stdout.deinit(args.allocator);
426 var stderr: std.ArrayListUnmanaged(u8) = .empty;434 var stderr: ArrayList(u8) = .empty;
427 errdefer stderr.deinit(args.allocator);435 defer stderr.deinit(args.allocator);
428436
429 try child.spawn();437 try child.spawn();
430 errdefer {438 errdefer {
...@@ -432,7 +440,7 @@ pub fn run(args: struct {...@@ -432,7 +440,7 @@ pub fn run(args: struct {
432 }440 }
433 try child.collectOutput(args.allocator, &stdout, &stderr, args.max_output_bytes);441 try child.collectOutput(args.allocator, &stdout, &stderr, args.max_output_bytes);
434442
435 return RunResult{443 return .{
436 .stdout = try stdout.toOwnedSlice(args.allocator),444 .stdout = try stdout.toOwnedSlice(args.allocator),
437 .stderr = try stderr.toOwnedSlice(args.allocator),445 .stderr = try stderr.toOwnedSlice(args.allocator),
438 .term = try child.wait(),446 .term = try child.wait(),
...@@ -878,12 +886,12 @@ fn spawnWindows(self: *ChildProcess) SpawnError!void {...@@ -878,12 +886,12 @@ fn spawnWindows(self: *ChildProcess) SpawnError!void {
878 var cmd_line_cache = WindowsCommandLineCache.init(self.allocator, self.argv);886 var cmd_line_cache = WindowsCommandLineCache.init(self.allocator, self.argv);
879 defer cmd_line_cache.deinit();887 defer cmd_line_cache.deinit();
880888
881 var app_buf: std.ArrayListUnmanaged(u16) = .empty;889 var app_buf: ArrayList(u16) = .empty;
882 defer app_buf.deinit(self.allocator);890 defer app_buf.deinit(self.allocator);
883891
884 try app_buf.appendSlice(self.allocator, app_name_w);892 try app_buf.appendSlice(self.allocator, app_name_w);
885893
886 var dir_buf: std.ArrayListUnmanaged(u16) = .empty;894 var dir_buf: ArrayList(u16) = .empty;
887 defer dir_buf.deinit(self.allocator);895 defer dir_buf.deinit(self.allocator);
888896
889 if (cwd_path_w.len > 0) {897 if (cwd_path_w.len > 0) {
...@@ -1003,13 +1011,16 @@ fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn {...@@ -1003,13 +1011,16 @@ fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn {
1003}1011}
10041012
1005fn writeIntFd(fd: i32, value: ErrInt) !void {1013fn writeIntFd(fd: i32, value: ErrInt) !void {
1006 const file: File = .{ .handle = fd };1014 var buffer: [8]u8 = undefined;
1007 file.deprecatedWriter().writeInt(u64, @intCast(value), .little) catch return error.SystemResources;1015 var fw: std.fs.File.Writer = .initMode(.{ .handle = fd }, &buffer, .streaming);
1016 fw.interface.writeInt(u64, value, .little) catch unreachable;
1017 fw.interface.flush() catch return error.SystemResources;
1008}1018}
10091019
1010fn readIntFd(fd: i32) !ErrInt {1020fn readIntFd(fd: i32) !ErrInt {
1011 const file: File = .{ .handle = fd };1021 var buffer: [8]u8 = undefined;
1012 return @intCast(file.deprecatedReader().readInt(u64, .little) catch return error.SystemResources);1022 var fr: std.fs.File.Reader = .initMode(.{ .handle = fd }, &buffer, .streaming);
1023 return @intCast(fr.interface.takeInt(u64, .little) catch return error.SystemResources);
1013}1024}
10141025
1015const ErrInt = std.meta.Int(.unsigned, @sizeOf(anyerror) * 8);1026const ErrInt = std.meta.Int(.unsigned, @sizeOf(anyerror) * 8);
...@@ -1020,8 +1031,8 @@ const ErrInt = std.meta.Int(.unsigned, @sizeOf(anyerror) * 8);...@@ -1020,8 +1031,8 @@ const ErrInt = std.meta.Int(.unsigned, @sizeOf(anyerror) * 8);
1020/// Note: If the dir is the cwd, dir_buf should be empty (len = 0).1031/// Note: If the dir is the cwd, dir_buf should be empty (len = 0).
1021fn windowsCreateProcessPathExt(1032fn windowsCreateProcessPathExt(
1022 allocator: mem.Allocator,1033 allocator: mem.Allocator,
1023 dir_buf: *std.ArrayListUnmanaged(u16),1034 dir_buf: *ArrayList(u16),
1024 app_buf: *std.ArrayListUnmanaged(u16),1035 app_buf: *ArrayList(u16),
1025 pathext: [:0]const u16,1036 pathext: [:0]const u16,
1026 cmd_line_cache: *WindowsCommandLineCache,1037 cmd_line_cache: *WindowsCommandLineCache,
1027 envp_ptr: ?[*]u16,1038 envp_ptr: ?[*]u16,
...@@ -1504,7 +1515,7 @@ const WindowsCommandLineCache = struct {...@@ -1504,7 +1515,7 @@ const WindowsCommandLineCache = struct {
1504/// Returns the absolute path of `cmd.exe` within the Windows system directory.1515/// Returns the absolute path of `cmd.exe` within the Windows system directory.
1505/// The caller owns the returned slice.1516/// The caller owns the returned slice.
1506fn windowsCmdExePath(allocator: mem.Allocator) error{ OutOfMemory, Unexpected }![:0]u16 {1517fn windowsCmdExePath(allocator: mem.Allocator) error{ OutOfMemory, Unexpected }![:0]u16 {
1507 var buf = try std.ArrayListUnmanaged(u16).initCapacity(allocator, 128);1518 var buf = try ArrayList(u16).initCapacity(allocator, 128);
1508 errdefer buf.deinit(allocator);1519 errdefer buf.deinit(allocator);
1509 while (true) {1520 while (true) {
1510 const unused_slice = buf.unusedCapacitySlice();1521 const unused_slice = buf.unusedCapacitySlice();
lib/std/start.zig+5-54
...@@ -101,17 +101,11 @@ comptime {...@@ -101,17 +101,11 @@ comptime {
101// Simplified start code for stage2 until it supports more language features ///101// Simplified start code for stage2 until it supports more language features ///
102102
103fn main2() callconv(.c) c_int {103fn main2() callconv(.c) c_int {
104 root.main();104 return callMain();
105 return 0;
106}105}
107106
108fn _start2() callconv(.withStackAlign(.c, 1)) noreturn {107fn _start2() callconv(.withStackAlign(.c, 1)) noreturn {
109 callMain2();108 std.posix.exit(callMain());
110}
111
112fn callMain2() noreturn {
113 root.main();
114 exit2(0);
115}109}
116110
117fn spirvMain2() callconv(.kernel) void {111fn spirvMain2() callconv(.kernel) void {
...@@ -119,51 +113,7 @@ fn spirvMain2() callconv(.kernel) void {...@@ -119,51 +113,7 @@ fn spirvMain2() callconv(.kernel) void {
119}113}
120114
121fn wWinMainCRTStartup2() callconv(.c) noreturn {115fn wWinMainCRTStartup2() callconv(.c) noreturn {
122 root.main();116 std.posix.exit(callMain());
123 exit2(0);
124}
125
126fn exit2(code: usize) noreturn {
127 switch (native_os) {
128 .linux => switch (builtin.cpu.arch) {
129 .x86_64 => {
130 asm volatile ("syscall"
131 :
132 : [number] "{rax}" (231),
133 [arg1] "{rdi}" (code),
134 : .{ .rcx = true, .r11 = true, .memory = true });
135 },
136 .arm => {
137 asm volatile ("svc #0"
138 :
139 : [number] "{r7}" (1),
140 [arg1] "{r0}" (code),
141 : .{ .memory = true });
142 },
143 .aarch64 => {
144 asm volatile ("svc #0"
145 :
146 : [number] "{x8}" (93),
147 [arg1] "{x0}" (code),
148 : .{ .memory = true });
149 },
150 .sparc64 => {
151 asm volatile ("ta 0x6d"
152 :
153 : [number] "{g1}" (1),
154 [arg1] "{o0}" (code),
155 : .{ .o0 = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o6 = true, .o7 = true, .memory = true });
156 },
157 else => @compileError("TODO"),
158 },
159 // exits(0)
160 .plan9 => std.os.plan9.exits(null),
161 .windows => {
162 std.os.windows.ntdll.RtlExitUserProcess(@truncate(code));
163 },
164 else => @compileError("TODO"),
165 }
166 unreachable;
167}117}
168118
169////////////////////////////////////////////////////////////////////////////////119////////////////////////////////////////////////////////////////////////////////
...@@ -676,10 +626,11 @@ pub inline fn callMain() u8 {...@@ -676,10 +626,11 @@ pub inline fn callMain() u8 {
676626
677 const result = root.main() catch |err| {627 const result = root.main() catch |err| {
678 switch (builtin.zig_backend) {628 switch (builtin.zig_backend) {
629 .stage2_aarch64,
679 .stage2_powerpc,630 .stage2_powerpc,
680 .stage2_riscv64,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 return 1;634 return 1;
684 },635 },
685 else => {},636 else => {},
lib/std/tar.zig+283-329
...@@ -19,7 +19,7 @@ const std = @import("std");...@@ -19,7 +19,7 @@ const std = @import("std");
19const assert = std.debug.assert;19const assert = std.debug.assert;
20const testing = std.testing;20const testing = std.testing;
2121
22pub const writer = @import("tar/writer.zig").writer;22pub const Writer = @import("tar/Writer.zig");
2323
24/// Provide this to receive detailed error messages.24/// Provide this to receive detailed error messages.
25/// When this is provided, some errors which would otherwise be returned25/// When this is provided, some errors which would otherwise be returned
...@@ -293,28 +293,6 @@ fn nullStr(str: []const u8) []const u8 {...@@ -293,28 +293,6 @@ fn nullStr(str: []const u8) []const u8 {
293 return str;293 return str;
294}294}
295295
296/// Options for iterator.
297/// Buffers should be provided by the caller.
298pub const IteratorOptions = struct {
299 /// Use a buffer with length `std.fs.max_path_bytes` to match file system capabilities.
300 file_name_buffer: []u8,
301 /// Use a buffer with length `std.fs.max_path_bytes` to match file system capabilities.
302 link_name_buffer: []u8,
303 /// Collects error messages during unpacking
304 diagnostics: ?*Diagnostics = null,
305};
306
307/// Iterates over files in tar archive.
308/// `next` returns each file in tar archive.
309pub fn iterator(reader: anytype, options: IteratorOptions) Iterator(@TypeOf(reader)) {
310 return .{
311 .reader = reader,
312 .diagnostics = options.diagnostics,
313 .file_name_buffer = options.file_name_buffer,
314 .link_name_buffer = options.link_name_buffer,
315 };
316}
317
318/// Type of the file returned by iterator `next` method.296/// Type of the file returned by iterator `next` method.
319pub const FileKind = enum {297pub const FileKind = enum {
320 directory,298 directory,
...@@ -323,206 +301,192 @@ pub const FileKind = enum {...@@ -323,206 +301,192 @@ pub const FileKind = enum {
323};301};
324302
325/// Iterator over entries in the tar file represented by reader.303/// Iterator over entries in the tar file represented by reader.
326pub fn Iterator(comptime ReaderType: type) type {304pub const Iterator = struct {
327 return struct {305 reader: *std.Io.Reader,
328 reader: ReaderType,306 diagnostics: ?*Diagnostics = null,
329 diagnostics: ?*Diagnostics = null,
330
331 // buffers for heeader and file attributes
332 header_buffer: [Header.SIZE]u8 = undefined,
333 file_name_buffer: []u8,
334 link_name_buffer: []u8,
335
336 // bytes of padding to the end of the block
337 padding: usize = 0,
338 // not consumed bytes of file from last next iteration
339 unread_file_bytes: u64 = 0,
340
341 pub const File = struct {
342 name: []const u8, // name of file, symlink or directory
343 link_name: []const u8, // target name of symlink
344 size: u64 = 0, // size of the file in bytes
345 mode: u32 = 0,
346 kind: FileKind = .file,
347
348 unread_bytes: *u64,
349 parent_reader: ReaderType,
350
351 pub const Reader = std.io.GenericReader(File, ReaderType.Error, File.read);
352307
353 pub fn reader(self: File) Reader {308 // buffers for heeader and file attributes
354 return .{ .context = self };309 header_buffer: [Header.SIZE]u8 = undefined,
355 }310 file_name_buffer: []u8,
311 link_name_buffer: []u8,
356312
357 pub fn read(self: File, dest: []u8) ReaderType.Error!usize {313 // bytes of padding to the end of the block
358 const buf = dest[0..@min(dest.len, self.unread_bytes.*)];314 padding: usize = 0,
359 const n = try self.parent_reader.read(buf);315 // not consumed bytes of file from last next iteration
360 self.unread_bytes.* -= n;316 unread_file_bytes: u64 = 0,
361 return n;
362 }
363317
364 // Writes file content to writer.318 /// Options for iterator.
365 pub fn writeAll(self: File, out_writer: anytype) !void {319 /// Buffers should be provided by the caller.
366 var buffer: [4096]u8 = undefined;320 pub const Options = struct {
321 /// Use a buffer with length `std.fs.max_path_bytes` to match file system capabilities.
322 file_name_buffer: []u8,
323 /// Use a buffer with length `std.fs.max_path_bytes` to match file system capabilities.
324 link_name_buffer: []u8,
325 /// Collects error messages during unpacking
326 diagnostics: ?*Diagnostics = null,
327 };
367328
368 while (self.unread_bytes.* > 0) {329 /// Iterates over files in tar archive.
369 const buf = buffer[0..@min(buffer.len, self.unread_bytes.*)];330 /// `next` returns each file in tar archive.
370 try self.parent_reader.readNoEof(buf);331 pub fn init(reader: *std.Io.Reader, options: Options) Iterator {
371 try out_writer.writeAll(buf);332 return .{
372 self.unread_bytes.* -= buf.len;333 .reader = reader,
373 }334 .diagnostics = options.diagnostics,
374 }335 .file_name_buffer = options.file_name_buffer,
336 .link_name_buffer = options.link_name_buffer,
375 };337 };
338 }
376339
377 const Self = @This();340 pub const File = struct {
378341 name: []const u8, // name of file, symlink or directory
379 fn readHeader(self: *Self) !?Header {342 link_name: []const u8, // target name of symlink
380 if (self.padding > 0) {343 size: u64 = 0, // size of the file in bytes
381 try self.reader.skipBytes(self.padding, .{});344 mode: u32 = 0,
382 }345 kind: FileKind = .file,
383 const n = try self.reader.readAll(&self.header_buffer);346 };
384 if (n == 0) return null;
385 if (n < Header.SIZE) return error.UnexpectedEndOfStream;
386 const header = Header{ .bytes = self.header_buffer[0..Header.SIZE] };
387 if (try header.checkChksum() == 0) return null;
388 return header;
389 }
390347
391 fn readString(self: *Self, size: usize, buffer: []u8) ![]const u8 {348 fn readHeader(self: *Iterator) !?Header {
392 if (size > buffer.len) return error.TarInsufficientBuffer;349 if (self.padding > 0) {
393 const buf = buffer[0..size];350 try self.reader.discardAll(self.padding);
394 try self.reader.readNoEof(buf);
395 return nullStr(buf);
396 }351 }
352 const n = try self.reader.readSliceShort(&self.header_buffer);
353 if (n == 0) return null;
354 if (n < Header.SIZE) return error.UnexpectedEndOfStream;
355 const header = Header{ .bytes = self.header_buffer[0..Header.SIZE] };
356 if (try header.checkChksum() == 0) return null;
357 return header;
358 }
397359
398 fn newFile(self: *Self) File {360 fn readString(self: *Iterator, size: usize, buffer: []u8) ![]const u8 {
399 return .{361 if (size > buffer.len) return error.TarInsufficientBuffer;
400 .name = self.file_name_buffer[0..0],362 const buf = buffer[0..size];
401 .link_name = self.link_name_buffer[0..0],363 try self.reader.readSliceAll(buf);
402 .parent_reader = self.reader,364 return nullStr(buf);
403 .unread_bytes = &self.unread_file_bytes,365 }
404 };
405 }
406366
407 // Number of padding bytes in the last file block.367 fn newFile(self: *Iterator) File {
408 fn blockPadding(size: u64) usize {368 return .{
409 const block_rounded = std.mem.alignForward(u64, size, Header.SIZE); // size rounded to te block boundary369 .name = self.file_name_buffer[0..0],
410 return @intCast(block_rounded - size);370 .link_name = self.link_name_buffer[0..0],
411 }371 };
372 }
412373
413 /// Iterates through the tar archive as if it is a series of files.374 // Number of padding bytes in the last file block.
414 /// Internally, the tar format often uses entries (header with optional375 fn blockPadding(size: u64) usize {
415 /// content) to add meta data that describes the next file. These376 const block_rounded = std.mem.alignForward(u64, size, Header.SIZE); // size rounded to te block boundary
416 /// entries should not normally be visible to the outside. As such, this377 return @intCast(block_rounded - size);
417 /// loop iterates through one or more entries until it collects a all378 }
418 /// file attributes.
419 pub fn next(self: *Self) !?File {
420 if (self.unread_file_bytes > 0) {
421 // If file content was not consumed by caller
422 try self.reader.skipBytes(self.unread_file_bytes, .{});
423 self.unread_file_bytes = 0;
424 }
425 var file: File = self.newFile();
426
427 while (try self.readHeader()) |header| {
428 const kind = header.kind();
429 const size: u64 = try header.size();
430 self.padding = blockPadding(size);
431
432 switch (kind) {
433 // File types to return upstream
434 .directory, .normal, .symbolic_link => {
435 file.kind = switch (kind) {
436 .directory => .directory,
437 .normal => .file,
438 .symbolic_link => .sym_link,
439 else => unreachable,
440 };
441 file.mode = try header.mode();
442
443 // set file attributes if not already set by prefix/extended headers
444 if (file.size == 0) {
445 file.size = size;
446 }
447 if (file.link_name.len == 0) {
448 file.link_name = try header.linkName(self.link_name_buffer);
449 }
450 if (file.name.len == 0) {
451 file.name = try header.fullName(self.file_name_buffer);
452 }
453379
454 self.padding = blockPadding(file.size);380 /// Iterates through the tar archive as if it is a series of files.
455 self.unread_file_bytes = file.size;381 /// Internally, the tar format often uses entries (header with optional
456 return file;382 /// content) to add meta data that describes the next file. These
457 },383 /// entries should not normally be visible to the outside. As such, this
458 // Prefix header types384 /// loop iterates through one or more entries until it collects a all
459 .gnu_long_name => {385 /// file attributes.
460 file.name = try self.readString(@intCast(size), self.file_name_buffer);386 pub fn next(self: *Iterator) !?File {
461 },387 if (self.unread_file_bytes > 0) {
462 .gnu_long_link => {388 // If file content was not consumed by caller
463 file.link_name = try self.readString(@intCast(size), self.link_name_buffer);389 try self.reader.discardAll64(self.unread_file_bytes);
464 },390 self.unread_file_bytes = 0;
465 .extended_header => {391 }
466 // Use just attributes from last extended header.392 var file: File = self.newFile();
467 file = self.newFile();393
468394 while (try self.readHeader()) |header| {
469 var rdr = paxIterator(self.reader, @intCast(size));395 const kind = header.kind();
470 while (try rdr.next()) |attr| {396 const size: u64 = try header.size();
471 switch (attr.kind) {397 self.padding = blockPadding(size);
472 .path => {398
473 file.name = try attr.value(self.file_name_buffer);399 switch (kind) {
474 },400 // File types to return upstream
475 .linkpath => {401 .directory, .normal, .symbolic_link => {
476 file.link_name = try attr.value(self.link_name_buffer);402 file.kind = switch (kind) {
477 },403 .directory => .directory,
478 .size => {404 .normal => .file,
479 var buf: [pax_max_size_attr_len]u8 = undefined;405 .symbolic_link => .sym_link,
480 file.size = try std.fmt.parseInt(u64, try attr.value(&buf), 10);406 else => unreachable,
481 },407 };
482 }408 file.mode = try header.mode();
483 }409
484 },410 // set file attributes if not already set by prefix/extended headers
485 // Ignored header type411 if (file.size == 0) {
486 .global_extended_header => {412 file.size = size;
487 self.reader.skipBytes(size, .{}) catch return error.TarHeadersTooBig;413 }
488 },414 if (file.link_name.len == 0) {
489 // All other are unsupported header types415 file.link_name = try header.linkName(self.link_name_buffer);
490 else => {416 }
491 const d = self.diagnostics orelse return error.TarUnsupportedHeader;417 if (file.name.len == 0) {
492 try d.errors.append(d.allocator, .{ .unsupported_file_type = .{418 file.name = try header.fullName(self.file_name_buffer);
493 .file_name = try d.allocator.dupe(u8, header.name()),419 }
494 .file_type = kind,420
495 } });421 self.padding = blockPadding(file.size);
496 if (kind == .gnu_sparse) {422 self.unread_file_bytes = file.size;
497 try self.skipGnuSparseExtendedHeaders(header);423 return file;
424 },
425 // Prefix header types
426 .gnu_long_name => {
427 file.name = try self.readString(@intCast(size), self.file_name_buffer);
428 },
429 .gnu_long_link => {
430 file.link_name = try self.readString(@intCast(size), self.link_name_buffer);
431 },
432 .extended_header => {
433 // Use just attributes from last extended header.
434 file = self.newFile();
435
436 var rdr: PaxIterator = .{
437 .reader = self.reader,
438 .size = @intCast(size),
439 };
440 while (try rdr.next()) |attr| {
441 switch (attr.kind) {
442 .path => {
443 file.name = try attr.value(self.file_name_buffer);
444 },
445 .linkpath => {
446 file.link_name = try attr.value(self.link_name_buffer);
447 },
448 .size => {
449 var buf: [pax_max_size_attr_len]u8 = undefined;
450 file.size = try std.fmt.parseInt(u64, try attr.value(&buf), 10);
451 },
498 }452 }
499 self.reader.skipBytes(size, .{}) catch return error.TarHeadersTooBig;453 }
500 },454 },
501 }455 // Ignored header type
456 .global_extended_header => {
457 self.reader.discardAll64(size) catch return error.TarHeadersTooBig;
458 },
459 // All other are unsupported header types
460 else => {
461 const d = self.diagnostics orelse return error.TarUnsupportedHeader;
462 try d.errors.append(d.allocator, .{ .unsupported_file_type = .{
463 .file_name = try d.allocator.dupe(u8, header.name()),
464 .file_type = kind,
465 } });
466 if (kind == .gnu_sparse) {
467 try self.skipGnuSparseExtendedHeaders(header);
468 }
469 self.reader.discardAll64(size) catch return error.TarHeadersTooBig;
470 },
502 }471 }
503 return null;
504 }472 }
473 return null;
474 }
505475
506 fn skipGnuSparseExtendedHeaders(self: *Self, header: Header) !void {476 pub fn streamRemaining(it: *Iterator, file: File, w: *std.Io.Writer) std.Io.Reader.StreamError!void {
507 var is_extended = header.bytes[482] > 0;477 try it.reader.streamExact64(w, file.size);
508 while (is_extended) {478 it.unread_file_bytes = 0;
509 var buf: [Header.SIZE]u8 = undefined;479 }
510 const n = try self.reader.readAll(&buf);
511 if (n < Header.SIZE) return error.UnexpectedEndOfStream;
512 is_extended = buf[504] > 0;
513 }
514 }
515 };
516}
517480
518/// Pax attributes iterator.481 fn skipGnuSparseExtendedHeaders(self: *Iterator, header: Header) !void {
519/// Size is length of pax extended header in reader.482 var is_extended = header.bytes[482] > 0;
520fn paxIterator(reader: anytype, size: usize) PaxIterator(@TypeOf(reader)) {483 while (is_extended) {
521 return PaxIterator(@TypeOf(reader)){484 var buf: [Header.SIZE]u8 = undefined;
522 .reader = reader,485 try self.reader.readSliceAll(&buf);
523 .size = size,486 is_extended = buf[504] > 0;
524 };487 }
525}488 }
489};
526490
527const PaxAttributeKind = enum {491const PaxAttributeKind = enum {
528 path,492 path,
...@@ -533,108 +497,99 @@ const PaxAttributeKind = enum {...@@ -533,108 +497,99 @@ const PaxAttributeKind = enum {
533// maxInt(u64) has 20 chars, base 10 in practice we got 24 chars497// maxInt(u64) has 20 chars, base 10 in practice we got 24 chars
534const pax_max_size_attr_len = 64;498const pax_max_size_attr_len = 64;
535499
536fn PaxIterator(comptime ReaderType: type) type {500pub const PaxIterator = struct {
537 return struct {501 size: usize, // cumulative size of all pax attributes
538 size: usize, // cumulative size of all pax attributes502 reader: *std.Io.Reader,
539 reader: ReaderType,
540 // scratch buffer used for reading attribute length and keyword
541 scratch: [128]u8 = undefined,
542
543 const Self = @This();
544
545 const Attribute = struct {
546 kind: PaxAttributeKind,
547 len: usize, // length of the attribute value
548 reader: ReaderType, // reader positioned at value start
549
550 // Copies pax attribute value into destination buffer.
551 // Must be called with destination buffer of size at least Attribute.len.
552 pub fn value(self: Attribute, dst: []u8) ![]const u8 {
553 if (self.len > dst.len) return error.TarInsufficientBuffer;
554 // assert(self.len <= dst.len);
555 const buf = dst[0..self.len];
556 const n = try self.reader.readAll(buf);
557 if (n < self.len) return error.UnexpectedEndOfStream;
558 try validateAttributeEnding(self.reader);
559 if (hasNull(buf)) return error.PaxNullInValue;
560 return buf;
561 }
562 };
563503
564 // Iterates over pax attributes. Returns known only known attributes.504 const Self = @This();
565 // Caller has to call value in Attribute, to advance reader across value.
566 pub fn next(self: *Self) !?Attribute {
567 // Pax extended header consists of one or more attributes, each constructed as follows:
568 // "%d %s=%s\n", <length>, <keyword>, <value>
569 while (self.size > 0) {
570 const length_buf = try self.readUntil(' ');
571 const length = try std.fmt.parseInt(usize, length_buf, 10); // record length in bytes
572
573 const keyword = try self.readUntil('=');
574 if (hasNull(keyword)) return error.PaxNullInKeyword;
575
576 // calculate value_len
577 const value_start = length_buf.len + keyword.len + 2; // 2 separators
578 if (length < value_start + 1 or self.size < length) return error.UnexpectedEndOfStream;
579 const value_len = length - value_start - 1; // \n separator at end
580 self.size -= length;
581
582 const kind: PaxAttributeKind = if (eql(keyword, "path"))
583 .path
584 else if (eql(keyword, "linkpath"))
585 .linkpath
586 else if (eql(keyword, "size"))
587 .size
588 else {
589 try self.reader.skipBytes(value_len, .{});
590 try validateAttributeEnding(self.reader);
591 continue;
592 };
593 if (kind == .size and value_len > pax_max_size_attr_len) {
594 return error.PaxSizeAttrOverflow;
595 }
596 return Attribute{
597 .kind = kind,
598 .len = value_len,
599 .reader = self.reader,
600 };
601 }
602505
603 return null;506 const Attribute = struct {
507 kind: PaxAttributeKind,
508 len: usize, // length of the attribute value
509 reader: *std.Io.Reader, // reader positioned at value start
510
511 // Copies pax attribute value into destination buffer.
512 // Must be called with destination buffer of size at least Attribute.len.
513 pub fn value(self: Attribute, dst: []u8) ![]const u8 {
514 if (self.len > dst.len) return error.TarInsufficientBuffer;
515 // assert(self.len <= dst.len);
516 const buf = dst[0..self.len];
517 const n = try self.reader.readSliceShort(buf);
518 if (n < self.len) return error.UnexpectedEndOfStream;
519 try validateAttributeEnding(self.reader);
520 if (hasNull(buf)) return error.PaxNullInValue;
521 return buf;
604 }522 }
523 };
605524
606 fn readUntil(self: *Self, delimiter: u8) ![]const u8 {525 // Iterates over pax attributes. Returns known only known attributes.
607 var fbs = std.io.fixedBufferStream(&self.scratch);526 // Caller has to call value in Attribute, to advance reader across value.
608 try self.reader.streamUntilDelimiter(fbs.writer(), delimiter, null);527 pub fn next(self: *Self) !?Attribute {
609 return fbs.getWritten();528 // Pax extended header consists of one or more attributes, each constructed as follows:
529 // "%d %s=%s\n", <length>, <keyword>, <value>
530 while (self.size > 0) {
531 const length_buf = try self.reader.takeSentinel(' ');
532 const length = try std.fmt.parseInt(usize, length_buf, 10); // record length in bytes
533
534 const keyword = try self.reader.takeSentinel('=');
535 if (hasNull(keyword)) return error.PaxNullInKeyword;
536
537 // calculate value_len
538 const value_start = length_buf.len + keyword.len + 2; // 2 separators
539 if (length < value_start + 1 or self.size < length) return error.UnexpectedEndOfStream;
540 const value_len = length - value_start - 1; // \n separator at end
541 self.size -= length;
542
543 const kind: PaxAttributeKind = if (eql(keyword, "path"))
544 .path
545 else if (eql(keyword, "linkpath"))
546 .linkpath
547 else if (eql(keyword, "size"))
548 .size
549 else {
550 try self.reader.discardAll(value_len);
551 try validateAttributeEnding(self.reader);
552 continue;
553 };
554 if (kind == .size and value_len > pax_max_size_attr_len) {
555 return error.PaxSizeAttrOverflow;
556 }
557 return .{
558 .kind = kind,
559 .len = value_len,
560 .reader = self.reader,
561 };
610 }562 }
611563
612 fn eql(a: []const u8, b: []const u8) bool {564 return null;
613 return std.mem.eql(u8, a, b);565 }
614 }
615566
616 fn hasNull(str: []const u8) bool {567 fn eql(a: []const u8, b: []const u8) bool {
617 return (std.mem.indexOfScalar(u8, str, 0)) != null;568 return std.mem.eql(u8, a, b);
618 }569 }
619570
620 // Checks that each record ends with new line.571 fn hasNull(str: []const u8) bool {
621 fn validateAttributeEnding(reader: ReaderType) !void {572 return (std.mem.indexOfScalar(u8, str, 0)) != null;
622 if (try reader.readByte() != '\n') return error.PaxInvalidAttributeEnd;573 }
623 }574
624 };575 // Checks that each record ends with new line.
625}576 fn validateAttributeEnding(reader: *std.Io.Reader) !void {
577 if (try reader.takeByte() != '\n') return error.PaxInvalidAttributeEnd;
578 }
579};
626580
627/// Saves tar file content to the file systems.581/// Saves tar file content to the file systems.
628pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: PipeOptions) !void {582pub fn pipeToFileSystem(dir: std.fs.Dir, reader: *std.Io.Reader, options: PipeOptions) !void {
629 var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined;583 var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
630 var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined;584 var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
631 var iter = iterator(reader, .{585 var file_contents_buffer: [1024]u8 = undefined;
586 var it: Iterator = .init(reader, .{
632 .file_name_buffer = &file_name_buffer,587 .file_name_buffer = &file_name_buffer,
633 .link_name_buffer = &link_name_buffer,588 .link_name_buffer = &link_name_buffer,
634 .diagnostics = options.diagnostics,589 .diagnostics = options.diagnostics,
635 });590 });
636591
637 while (try iter.next()) |file| {592 while (try it.next()) |file| {
638 const file_name = stripComponents(file.name, options.strip_components);593 const file_name = stripComponents(file.name, options.strip_components);
639 if (file_name.len == 0 and file.kind != .directory) {594 if (file_name.len == 0 and file.kind != .directory) {
640 const d = options.diagnostics orelse return error.TarComponentsOutsideStrippedPrefix;595 const d = options.diagnostics orelse return error.TarComponentsOutsideStrippedPrefix;
...@@ -656,7 +611,9 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: PipeOptions)...@@ -656,7 +611,9 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: PipeOptions)
656 .file => {611 .file => {
657 if (createDirAndFile(dir, file_name, fileMode(file.mode, options))) |fs_file| {612 if (createDirAndFile(dir, file_name, fileMode(file.mode, options))) |fs_file| {
658 defer fs_file.close();613 defer fs_file.close();
659 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();
660 } else |err| {617 } else |err| {
661 const d = options.diagnostics orelse return err;618 const d = options.diagnostics orelse return err;
662 try d.errors.append(d.allocator, .{ .unable_to_create_file = .{619 try d.errors.append(d.allocator, .{ .unable_to_create_file = .{
...@@ -826,11 +783,14 @@ test PaxIterator {...@@ -826,11 +783,14 @@ test PaxIterator {
826 var buffer: [1024]u8 = undefined;783 var buffer: [1024]u8 = undefined;
827784
828 outer: for (cases) |case| {785 outer: for (cases) |case| {
829 var stream = std.io.fixedBufferStream(case.data);786 var reader: std.Io.Reader = .fixed(case.data);
830 var iter = paxIterator(stream.reader(), case.data.len);787 var it: PaxIterator = .{
788 .size = case.data.len,
789 .reader = &reader,
790 };
831791
832 var i: usize = 0;792 var i: usize = 0;
833 while (iter.next() catch |err| {793 while (it.next() catch |err| {
834 if (case.err) |e| {794 if (case.err) |e| {
835 try testing.expectEqual(e, err);795 try testing.expectEqual(e, err);
836 continue;796 continue;
...@@ -853,12 +813,6 @@ test PaxIterator {...@@ -853,12 +813,6 @@ test PaxIterator {
853 }813 }
854}814}
855815
856test {
857 _ = @import("tar/test.zig");
858 _ = @import("tar/writer.zig");
859 _ = Diagnostics;
860}
861
862test "header parse size" {816test "header parse size" {
863 const cases = [_]struct {817 const cases = [_]struct {
864 in: []const u8,818 in: []const u8,
...@@ -941,7 +895,7 @@ test "create file and symlink" {...@@ -941,7 +895,7 @@ test "create file and symlink" {
941 file.close();895 file.close();
942}896}
943897
944test iterator {898test Iterator {
945 // Example tar file is created from this tree structure:899 // Example tar file is created from this tree structure:
946 // $ tree example900 // $ tree example
947 // example901 // example
...@@ -962,19 +916,19 @@ test iterator {...@@ -962,19 +916,19 @@ test iterator {
962 // example/empty/916 // example/empty/
963917
964 const data = @embedFile("tar/testdata/example.tar");918 const data = @embedFile("tar/testdata/example.tar");
965 var fbs = std.io.fixedBufferStream(data);919 var reader: std.Io.Reader = .fixed(data);
966920
967 // User provided buffers to the iterator921 // User provided buffers to the iterator
968 var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined;922 var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
969 var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined;923 var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
970 // Create iterator924 // Create iterator
971 var iter = iterator(fbs.reader(), .{925 var it: Iterator = .init(&reader, .{
972 .file_name_buffer = &file_name_buffer,926 .file_name_buffer = &file_name_buffer,
973 .link_name_buffer = &link_name_buffer,927 .link_name_buffer = &link_name_buffer,
974 });928 });
975 // Iterate over files in example.tar929 // Iterate over files in example.tar
976 var file_no: usize = 0;930 var file_no: usize = 0;
977 while (try iter.next()) |file| : (file_no += 1) {931 while (try it.next()) |file| : (file_no += 1) {
978 switch (file.kind) {932 switch (file.kind) {
979 .directory => {933 .directory => {
980 switch (file_no) {934 switch (file_no) {
...@@ -987,10 +941,10 @@ test iterator {...@@ -987,10 +941,10 @@ test iterator {
987 },941 },
988 .file => {942 .file => {
989 try testing.expectEqualStrings("example/a/file", file.name);943 try testing.expectEqualStrings("example/a/file", file.name);
990 // Read file content
991 var buf: [16]u8 = undefined;944 var buf: [16]u8 = undefined;
992 const n = try file.reader().readAll(&buf);945 var w: std.Io.Writer = .fixed(&buf);
993 try testing.expectEqualStrings("content\n", buf[0..n]);946 try it.streamRemaining(file, &w);
947 try testing.expectEqualStrings("content\n", w.buffered());
994 },948 },
995 .sym_link => {949 .sym_link => {
996 try testing.expectEqualStrings("example/b/symlink", file.name);950 try testing.expectEqualStrings("example/b/symlink", file.name);
...@@ -1021,15 +975,14 @@ test pipeToFileSystem {...@@ -1021,15 +975,14 @@ test pipeToFileSystem {
1021 // example/empty/975 // example/empty/
1022976
1023 const data = @embedFile("tar/testdata/example.tar");977 const data = @embedFile("tar/testdata/example.tar");
1024 var fbs = std.io.fixedBufferStream(data);978 var reader: std.Io.Reader = .fixed(data);
1025 const reader = fbs.reader();
1026979
1027 var tmp = testing.tmpDir(.{ .no_follow = true });980 var tmp = testing.tmpDir(.{ .no_follow = true });
1028 defer tmp.cleanup();981 defer tmp.cleanup();
1029 const dir = tmp.dir;982 const dir = tmp.dir;
1030983
1031 // Save tar from `reader` to the file system `dir`984 // Save tar from reader to the file system `dir`
1032 pipeToFileSystem(dir, reader, .{985 pipeToFileSystem(dir, &reader, .{
1033 .mode_mode = .ignore,986 .mode_mode = .ignore,
1034 .strip_components = 1,987 .strip_components = 1,
1035 .exclude_empty_directories = true,988 .exclude_empty_directories = true,
...@@ -1053,8 +1006,7 @@ test pipeToFileSystem {...@@ -1053,8 +1006,7 @@ test pipeToFileSystem {
10531006
1054test "pipeToFileSystem root_dir" {1007test "pipeToFileSystem root_dir" {
1055 const data = @embedFile("tar/testdata/example.tar");1008 const data = @embedFile("tar/testdata/example.tar");
1056 var fbs = std.io.fixedBufferStream(data);1009 var reader: std.Io.Reader = .fixed(data);
1057 const reader = fbs.reader();
10581010
1059 // with strip_components = 11011 // with strip_components = 1
1060 {1012 {
...@@ -1063,7 +1015,7 @@ test "pipeToFileSystem root_dir" {...@@ -1063,7 +1015,7 @@ test "pipeToFileSystem root_dir" {
1063 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };1015 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
1064 defer diagnostics.deinit();1016 defer diagnostics.deinit();
10651017
1066 pipeToFileSystem(tmp.dir, reader, .{1018 pipeToFileSystem(tmp.dir, &reader, .{
1067 .strip_components = 1,1019 .strip_components = 1,
1068 .diagnostics = &diagnostics,1020 .diagnostics = &diagnostics,
1069 }) catch |err| {1021 }) catch |err| {
...@@ -1079,13 +1031,13 @@ test "pipeToFileSystem root_dir" {...@@ -1079,13 +1031,13 @@ test "pipeToFileSystem root_dir" {
10791031
1080 // with strip_components = 01032 // with strip_components = 0
1081 {1033 {
1082 fbs.reset();1034 reader = .fixed(data);
1083 var tmp = testing.tmpDir(.{ .no_follow = true });1035 var tmp = testing.tmpDir(.{ .no_follow = true });
1084 defer tmp.cleanup();1036 defer tmp.cleanup();
1085 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };1037 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
1086 defer diagnostics.deinit();1038 defer diagnostics.deinit();
10871039
1088 pipeToFileSystem(tmp.dir, reader, .{1040 pipeToFileSystem(tmp.dir, &reader, .{
1089 .strip_components = 0,1041 .strip_components = 0,
1090 .diagnostics = &diagnostics,1042 .diagnostics = &diagnostics,
1091 }) catch |err| {1043 }) catch |err| {
...@@ -1102,45 +1054,42 @@ test "pipeToFileSystem root_dir" {...@@ -1102,45 +1054,42 @@ test "pipeToFileSystem root_dir" {
11021054
1103test "findRoot with single file archive" {1055test "findRoot with single file archive" {
1104 const data = @embedFile("tar/testdata/22752.tar");1056 const data = @embedFile("tar/testdata/22752.tar");
1105 var fbs = std.io.fixedBufferStream(data);1057 var reader: std.Io.Reader = .fixed(data);
1106 const reader = fbs.reader();
11071058
1108 var tmp = testing.tmpDir(.{});1059 var tmp = testing.tmpDir(.{});
1109 defer tmp.cleanup();1060 defer tmp.cleanup();
11101061
1111 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };1062 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
1112 defer diagnostics.deinit();1063 defer diagnostics.deinit();
1113 try pipeToFileSystem(tmp.dir, reader, .{ .diagnostics = &diagnostics });1064 try pipeToFileSystem(tmp.dir, &reader, .{ .diagnostics = &diagnostics });
11141065
1115 try testing.expectEqualStrings("", diagnostics.root_dir);1066 try testing.expectEqualStrings("", diagnostics.root_dir);
1116}1067}
11171068
1118test "findRoot without explicit root dir" {1069test "findRoot without explicit root dir" {
1119 const data = @embedFile("tar/testdata/19820.tar");1070 const data = @embedFile("tar/testdata/19820.tar");
1120 var fbs = std.io.fixedBufferStream(data);1071 var reader: std.Io.Reader = .fixed(data);
1121 const reader = fbs.reader();
11221072
1123 var tmp = testing.tmpDir(.{});1073 var tmp = testing.tmpDir(.{});
1124 defer tmp.cleanup();1074 defer tmp.cleanup();
11251075
1126 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };1076 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
1127 defer diagnostics.deinit();1077 defer diagnostics.deinit();
1128 try pipeToFileSystem(tmp.dir, reader, .{ .diagnostics = &diagnostics });1078 try pipeToFileSystem(tmp.dir, &reader, .{ .diagnostics = &diagnostics });
11291079
1130 try testing.expectEqualStrings("root", diagnostics.root_dir);1080 try testing.expectEqualStrings("root", diagnostics.root_dir);
1131}1081}
11321082
1133test "pipeToFileSystem strip_components" {1083test "pipeToFileSystem strip_components" {
1134 const data = @embedFile("tar/testdata/example.tar");1084 const data = @embedFile("tar/testdata/example.tar");
1135 var fbs = std.io.fixedBufferStream(data);1085 var reader: std.Io.Reader = .fixed(data);
1136 const reader = fbs.reader();
11371086
1138 var tmp = testing.tmpDir(.{ .no_follow = true });1087 var tmp = testing.tmpDir(.{ .no_follow = true });
1139 defer tmp.cleanup();1088 defer tmp.cleanup();
1140 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };1089 var diagnostics: Diagnostics = .{ .allocator = testing.allocator };
1141 defer diagnostics.deinit();1090 defer diagnostics.deinit();
11421091
1143 pipeToFileSystem(tmp.dir, reader, .{1092 pipeToFileSystem(tmp.dir, &reader, .{
1144 .strip_components = 3,1093 .strip_components = 3,
1145 .diagnostics = &diagnostics,1094 .diagnostics = &diagnostics,
1146 }) catch |err| {1095 }) catch |err| {
...@@ -1194,13 +1143,12 @@ test "executable bit" {...@@ -1194,13 +1143,12 @@ test "executable bit" {
1194 const data = @embedFile("tar/testdata/example.tar");1143 const data = @embedFile("tar/testdata/example.tar");
11951144
1196 for ([_]PipeOptions.ModeMode{ .ignore, .executable_bit_only }) |opt| {1145 for ([_]PipeOptions.ModeMode{ .ignore, .executable_bit_only }) |opt| {
1197 var fbs = std.io.fixedBufferStream(data);1146 var reader: std.Io.Reader = .fixed(data);
1198 const reader = fbs.reader();
11991147
1200 var tmp = testing.tmpDir(.{ .no_follow = true });1148 var tmp = testing.tmpDir(.{ .no_follow = true });
1201 //defer tmp.cleanup();1149 //defer tmp.cleanup();
12021150
1203 pipeToFileSystem(tmp.dir, reader, .{1151 pipeToFileSystem(tmp.dir, &reader, .{
1204 .strip_components = 1,1152 .strip_components = 1,
1205 .exclude_empty_directories = true,1153 .exclude_empty_directories = true,
1206 .mode_mode = opt,1154 .mode_mode = opt,
...@@ -1226,3 +1174,9 @@ test "executable bit" {...@@ -1226,3 +1174,9 @@ test "executable bit" {
1226 }1174 }
1227 }1175 }
1228}1176}
1177
1178test {
1179 _ = @import("tar/test.zig");
1180 _ = Writer;
1181 _ = Diagnostics;
1182}
lib/std/tar/Writer.zig created+462
...@@ -0,0 +1,462 @@
1const std = @import("std");
2const assert = std.debug.assert;
3const testing = std.testing;
4const Writer = @This();
5
6const block_size = @sizeOf(Header);
7
8/// Options for writing file/dir/link. If left empty 0o664 is used for
9/// file mode and current time for mtime.
10pub const Options = struct {
11 /// File system permission mode.
12 mode: u32 = 0,
13 /// File system modification time.
14 mtime: u64 = 0,
15};
16
17underlying_writer: *std.Io.Writer,
18prefix: []const u8 = "",
19mtime_now: u64 = 0,
20
21const Error = error{
22 WriteFailed,
23 OctalOverflow,
24 NameTooLong,
25};
26
27/// Sets prefix for all other write* method paths.
28pub fn setRoot(w: *Writer, root: []const u8) Error!void {
29 if (root.len > 0)
30 try w.writeDir(root, .{});
31
32 w.prefix = root;
33}
34
35pub fn writeDir(w: *Writer, sub_path: []const u8, options: Options) Error!void {
36 try w.writeHeader(.directory, sub_path, "", 0, options);
37}
38
39pub const WriteFileError = std.Io.Writer.FileError || Error || std.fs.File.GetEndPosError;
40
41pub fn writeFile(
42 w: *Writer,
43 sub_path: []const u8,
44 file_reader: *std.fs.File.Reader,
45 stat_mtime: i128,
46) WriteFileError!void {
47 const size = try file_reader.getSize();
48 const mtime: u64 = @intCast(@divFloor(stat_mtime, std.time.ns_per_s));
49
50 var header: Header = .{};
51 try w.setPath(&header, sub_path);
52 try header.setSize(size);
53 try header.setMtime(mtime);
54 try header.updateChecksum();
55
56 try w.underlying_writer.writeAll(@ptrCast((&header)[0..1]));
57 _ = try w.underlying_writer.sendFileAll(file_reader, .unlimited);
58 try w.writePadding64(size);
59}
60
61pub const WriteFileStreamError = Error || std.Io.Reader.StreamError;
62
63/// Writes file reading file content from `reader`. Reads exactly `size` bytes
64/// from `reader`, or returns `error.EndOfStream`.
65pub fn writeFileStream(
66 w: *Writer,
67 sub_path: []const u8,
68 size: u64,
69 reader: *std.Io.Reader,
70 options: Options,
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);
75}
76
77/// Writes file using bytes buffer `content` for size and file content.
78pub fn writeFileBytes(w: *Writer, sub_path: []const u8, content: []const u8, options: Options) Error!void {
79 try w.writeHeader(.regular, sub_path, "", content.len, options);
80 try w.underlying_writer.writeAll(content);
81 try w.writePadding(content.len);
82}
83
84pub fn writeLink(w: *Writer, sub_path: []const u8, link_name: []const u8, options: Options) Error!void {
85 try w.writeHeader(.symbolic_link, sub_path, link_name, 0, options);
86}
87
88fn writeHeader(
89 w: *Writer,
90 typeflag: Header.FileType,
91 sub_path: []const u8,
92 link_name: []const u8,
93 size: u64,
94 options: Options,
95) Error!void {
96 var header = Header.init(typeflag);
97 try w.setPath(&header, sub_path);
98 try header.setSize(size);
99 try header.setMtime(options.mtime);
100 if (options.mode != 0)
101 try header.setMode(options.mode);
102 if (typeflag == .symbolic_link)
103 header.setLinkname(link_name) catch |err| switch (err) {
104 error.NameTooLong => try w.writeExtendedHeader(.gnu_long_link, &.{link_name}),
105 else => return err,
106 };
107 try header.write(w.underlying_writer);
108}
109
110/// Writes path in posix header, if don't fit (in name+prefix; 100+155
111/// bytes) writes it in gnu extended header.
112fn setPath(w: *Writer, header: *Header, sub_path: []const u8) Error!void {
113 header.setPath(w.prefix, sub_path) catch |err| switch (err) {
114 error.NameTooLong => {
115 // write extended header
116 const buffers: []const []const u8 = if (w.prefix.len == 0)
117 &.{sub_path}
118 else
119 &.{ w.prefix, "/", sub_path };
120 try w.writeExtendedHeader(.gnu_long_name, buffers);
121 },
122 else => return err,
123 };
124}
125
126/// Writes gnu extended header: gnu_long_name or gnu_long_link.
127fn writeExtendedHeader(w: *Writer, typeflag: Header.FileType, buffers: []const []const u8) Error!void {
128 var len: usize = 0;
129 for (buffers) |buf| len += buf.len;
130
131 var header: Header = .init(typeflag);
132 try header.setSize(len);
133 try header.write(w.underlying_writer);
134 for (buffers) |buf|
135 try w.underlying_writer.writeAll(buf);
136 try w.writePadding(len);
137}
138
139fn writePadding(w: *Writer, bytes: usize) std.Io.Writer.Error!void {
140 return writePaddingPos(w, bytes % block_size);
141}
142
143fn writePadding64(w: *Writer, bytes: u64) std.Io.Writer.Error!void {
144 return writePaddingPos(w, @intCast(bytes % block_size));
145}
146
147fn writePaddingPos(w: *Writer, pos: usize) std.Io.Writer.Error!void {
148 if (pos == 0) return;
149 try w.underlying_writer.splatByteAll(0, block_size - pos);
150}
151
152/// According to the specification, tar should finish with two zero blocks, but
153/// "reasonable system must not assume that such a block exists when reading an
154/// archive". Therefore, the Zig standard library recommends to not call this
155/// function.
156pub fn finishPedantically(w: *Writer) std.Io.Writer.Error!void {
157 try w.underlying_writer.splatByteAll(0, block_size * 2);
158}
159
160/// A struct that is exactly 512 bytes and matches tar file format. This is
161/// intended to be used for outputting tar files; for parsing there is
162/// `std.tar.Header`.
163pub const Header = extern struct {
164 // This struct was originally copied from
165 // https://github.com/mattnite/tar/blob/main/src/main.zig which is MIT
166 // licensed.
167 //
168 // The name, linkname, magic, uname, and gname are null-terminated character
169 // strings. All other fields are zero-filled octal numbers in ASCII. Each
170 // numeric field of width w contains w minus 1 digits, and a null.
171 // Reference: https://www.gnu.org/software/tar/manual/html_node/Standard.html
172 // POSIX header: byte offset
173 name: [100]u8 = [_]u8{0} ** 100, // 0
174 mode: [7:0]u8 = default_mode.file, // 100
175 uid: [7:0]u8 = [_:0]u8{0} ** 7, // unused 108
176 gid: [7:0]u8 = [_:0]u8{0} ** 7, // unused 116
177 size: [11:0]u8 = [_:0]u8{'0'} ** 11, // 124
178 mtime: [11:0]u8 = [_:0]u8{'0'} ** 11, // 136
179 checksum: [7:0]u8 = [_:0]u8{' '} ** 7, // 148
180 typeflag: FileType = .regular, // 156
181 linkname: [100]u8 = [_]u8{0} ** 100, // 157
182 magic: [6]u8 = [_]u8{ 'u', 's', 't', 'a', 'r', 0 }, // 257
183 version: [2]u8 = [_]u8{ '0', '0' }, // 263
184 uname: [32]u8 = [_]u8{0} ** 32, // unused 265
185 gname: [32]u8 = [_]u8{0} ** 32, // unused 297
186 devmajor: [7:0]u8 = [_:0]u8{0} ** 7, // unused 329
187 devminor: [7:0]u8 = [_:0]u8{0} ** 7, // unused 337
188 prefix: [155]u8 = [_]u8{0} ** 155, // 345
189 pad: [12]u8 = [_]u8{0} ** 12, // unused 500
190
191 pub const FileType = enum(u8) {
192 regular = '0',
193 symbolic_link = '2',
194 directory = '5',
195 gnu_long_name = 'L',
196 gnu_long_link = 'K',
197 };
198
199 const default_mode = struct {
200 const file = [_:0]u8{ '0', '0', '0', '0', '6', '6', '4' }; // 0o664
201 const dir = [_:0]u8{ '0', '0', '0', '0', '7', '7', '5' }; // 0o775
202 const sym_link = [_:0]u8{ '0', '0', '0', '0', '7', '7', '7' }; // 0o777
203 const other = [_:0]u8{ '0', '0', '0', '0', '0', '0', '0' }; // 0o000
204 };
205
206 pub fn init(typeflag: FileType) Header {
207 return .{
208 .typeflag = typeflag,
209 .mode = switch (typeflag) {
210 .directory => default_mode.dir,
211 .symbolic_link => default_mode.sym_link,
212 .regular => default_mode.file,
213 else => default_mode.other,
214 },
215 };
216 }
217
218 pub fn setSize(w: *Header, size: u64) error{OctalOverflow}!void {
219 try octal(&w.size, size);
220 }
221
222 fn octal(buf: []u8, value: u64) error{OctalOverflow}!void {
223 var remainder: u64 = value;
224 var pos: usize = buf.len;
225 while (remainder > 0 and pos > 0) {
226 pos -= 1;
227 const c: u8 = @as(u8, @intCast(remainder % 8)) + '0';
228 buf[pos] = c;
229 remainder /= 8;
230 if (pos == 0 and remainder > 0) return error.OctalOverflow;
231 }
232 }
233
234 pub fn setMode(w: *Header, mode: u32) error{OctalOverflow}!void {
235 try octal(&w.mode, mode);
236 }
237
238 // Integer number of seconds since January 1, 1970, 00:00 Coordinated Universal Time.
239 // mtime == 0 will use current time
240 pub fn setMtime(w: *Header, mtime: u64) error{OctalOverflow}!void {
241 try octal(&w.mtime, mtime);
242 }
243
244 pub fn updateChecksum(w: *Header) !void {
245 var checksum: usize = ' '; // other 7 w.checksum bytes are initialized to ' '
246 for (std.mem.asBytes(w)) |val|
247 checksum += val;
248 try octal(&w.checksum, checksum);
249 }
250
251 pub fn write(h: *Header, bw: *std.Io.Writer) error{ OctalOverflow, WriteFailed }!void {
252 try h.updateChecksum();
253 try bw.writeAll(std.mem.asBytes(h));
254 }
255
256 pub fn setLinkname(w: *Header, link: []const u8) !void {
257 if (link.len > w.linkname.len) return error.NameTooLong;
258 @memcpy(w.linkname[0..link.len], link);
259 }
260
261 pub fn setPath(w: *Header, prefix: []const u8, sub_path: []const u8) !void {
262 const max_prefix = w.prefix.len;
263 const max_name = w.name.len;
264 const sep = std.fs.path.sep_posix;
265
266 if (prefix.len + sub_path.len > max_name + max_prefix or prefix.len > max_prefix)
267 return error.NameTooLong;
268
269 // both fit into name
270 if (prefix.len > 0 and prefix.len + sub_path.len < max_name) {
271 @memcpy(w.name[0..prefix.len], prefix);
272 w.name[prefix.len] = sep;
273 @memcpy(w.name[prefix.len + 1 ..][0..sub_path.len], sub_path);
274 return;
275 }
276
277 // sub_path fits into name
278 // there is no prefix or prefix fits into prefix
279 if (sub_path.len <= max_name) {
280 @memcpy(w.name[0..sub_path.len], sub_path);
281 @memcpy(w.prefix[0..prefix.len], prefix);
282 return;
283 }
284
285 if (prefix.len > 0) {
286 @memcpy(w.prefix[0..prefix.len], prefix);
287 w.prefix[prefix.len] = sep;
288 }
289 const prefix_pos = if (prefix.len > 0) prefix.len + 1 else 0;
290
291 // add as much to prefix as you can, must split at /
292 const prefix_remaining = max_prefix - prefix_pos;
293 if (std.mem.lastIndexOf(u8, sub_path[0..@min(prefix_remaining, sub_path.len)], &.{'/'})) |sep_pos| {
294 @memcpy(w.prefix[prefix_pos..][0..sep_pos], sub_path[0..sep_pos]);
295 if ((sub_path.len - sep_pos - 1) > max_name) return error.NameTooLong;
296 @memcpy(w.name[0..][0 .. sub_path.len - sep_pos - 1], sub_path[sep_pos + 1 ..]);
297 return;
298 }
299
300 return error.NameTooLong;
301 }
302
303 comptime {
304 assert(@sizeOf(Header) == 512);
305 }
306
307 test "setPath" {
308 const cases = [_]struct {
309 in: []const []const u8,
310 out: []const []const u8,
311 }{
312 .{
313 .in = &.{ "", "123456789" },
314 .out = &.{ "", "123456789" },
315 },
316 // can fit into name
317 .{
318 .in = &.{ "prefix", "sub_path" },
319 .out = &.{ "", "prefix/sub_path" },
320 },
321 // no more both fits into name
322 .{
323 .in = &.{ "prefix", "0123456789/" ** 8 ++ "basename" },
324 .out = &.{ "prefix", "0123456789/" ** 8 ++ "basename" },
325 },
326 // put as much as you can into prefix the rest goes into name
327 .{
328 .in = &.{ "prefix", "0123456789/" ** 10 ++ "basename" },
329 .out = &.{ "prefix/" ++ "0123456789/" ** 9 ++ "0123456789", "basename" },
330 },
331
332 .{
333 .in = &.{ "prefix", "0123456789/" ** 15 ++ "basename" },
334 .out = &.{ "prefix/" ++ "0123456789/" ** 12 ++ "0123456789", "0123456789/0123456789/basename" },
335 },
336 .{
337 .in = &.{ "prefix", "0123456789/" ** 21 ++ "basename" },
338 .out = &.{ "prefix/" ++ "0123456789/" ** 12 ++ "0123456789", "0123456789/" ** 8 ++ "basename" },
339 },
340 .{
341 .in = &.{ "", "012345678/" ** 10 ++ "foo" },
342 .out = &.{ "012345678/" ** 9 ++ "012345678", "foo" },
343 },
344 };
345
346 for (cases) |case| {
347 var header = Header.init(.regular);
348 try header.setPath(case.in[0], case.in[1]);
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));
351 }
352
353 const error_cases = [_]struct {
354 in: []const []const u8,
355 }{
356 // basename can't fit into name (106 characters)
357 .{ .in = &.{ "zig", "test/cases/compile_errors/regression_test_2980_base_type_u32_is_not_type_checked_properly_when_assigning_a_value_within_a_struct.zig" } },
358 // cant fit into 255 + sep
359 .{ .in = &.{ "prefix", "0123456789/" ** 22 ++ "basename" } },
360 // can fit but sub_path can't be split (there is no separator)
361 .{ .in = &.{ "prefix", "0123456789" ** 10 ++ "a" } },
362 .{ .in = &.{ "prefix", "0123456789" ** 14 ++ "basename" } },
363 };
364
365 for (error_cases) |case| {
366 var header = Header.init(.regular);
367 try testing.expectError(
368 error.NameTooLong,
369 header.setPath(case.in[0], case.in[1]),
370 );
371 }
372 }
373};
374
375test {
376 _ = Header;
377}
378
379test "write files" {
380 const files = [_]struct {
381 path: []const u8,
382 content: []const u8,
383 }{
384 .{ .path = "foo", .content = "bar" },
385 .{ .path = "a12345678/" ** 10 ++ "foo", .content = "a" ** 511 },
386 .{ .path = "b12345678/" ** 24 ++ "foo", .content = "b" ** 512 },
387 .{ .path = "c12345678/" ** 25 ++ "foo", .content = "c" ** 513 },
388 .{ .path = "d12345678/" ** 51 ++ "foo", .content = "d" ** 1025 },
389 .{ .path = "e123456789" ** 11, .content = "e" },
390 };
391
392 var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
393 var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
394
395 // with root
396 {
397 const root = "root";
398
399 var output: std.Io.Writer.Allocating = .init(testing.allocator);
400 var w: Writer = .{ .underlying_writer = &output.writer };
401 defer output.deinit();
402 try w.setRoot(root);
403 for (files) |file|
404 try w.writeFileBytes(file.path, file.content, .{});
405
406 var input: std.Io.Reader = .fixed(output.getWritten());
407 var it: std.tar.Iterator = .init(&input, .{
408 .file_name_buffer = &file_name_buffer,
409 .link_name_buffer = &link_name_buffer,
410 });
411
412 // first entry is directory with prefix
413 {
414 const actual = (try it.next()).?;
415 try testing.expectEqualStrings(root, actual.name);
416 try testing.expectEqual(std.tar.FileKind.directory, actual.kind);
417 }
418
419 var i: usize = 0;
420 while (try it.next()) |actual| {
421 defer i += 1;
422 const expected = files[i];
423 try testing.expectEqualStrings(root, actual.name[0..root.len]);
424 try testing.expectEqual('/', actual.name[root.len..][0]);
425 try testing.expectEqualStrings(expected.path, actual.name[root.len + 1 ..]);
426
427 var content: std.Io.Writer.Allocating = .init(testing.allocator);
428 defer content.deinit();
429 try it.streamRemaining(actual, &content.writer);
430 try testing.expectEqualSlices(u8, expected.content, content.getWritten());
431 }
432 }
433 // without root
434 {
435 var output: std.Io.Writer.Allocating = .init(testing.allocator);
436 var w: Writer = .{ .underlying_writer = &output.writer };
437 defer output.deinit();
438 for (files) |file| {
439 var content: std.Io.Reader = .fixed(file.content);
440 try w.writeFileStream(file.path, file.content.len, &content, .{});
441 }
442
443 var input: std.Io.Reader = .fixed(output.getWritten());
444 var it: std.tar.Iterator = .init(&input, .{
445 .file_name_buffer = &file_name_buffer,
446 .link_name_buffer = &link_name_buffer,
447 });
448
449 var i: usize = 0;
450 while (try it.next()) |actual| {
451 defer i += 1;
452 const expected = files[i];
453 try testing.expectEqualStrings(expected.path, actual.name);
454
455 var content: std.Io.Writer.Allocating = .init(testing.allocator);
456 defer content.deinit();
457 try it.streamRemaining(actual, &content.writer);
458 try testing.expectEqualSlices(u8, expected.content, content.getWritten());
459 }
460 try w.finishPedantically();
461 }
462}
lib/std/tar/test.zig+173-177
...@@ -18,31 +18,72 @@ const Case = struct {...@@ -18,31 +18,72 @@ const Case = struct {
18 err: ?anyerror = null, // parsing should fail with this error18 err: ?anyerror = null, // parsing should fail with this error
19};19};
2020
21const cases = [_]Case{21const gnu_case: Case = .{
22 .{22 .data = @embedFile("testdata/gnu.tar"),
23 .data = @embedFile("testdata/gnu.tar"),23 .files = &[_]Case.File{
24 .files = &[_]Case.File{24 .{
25 .{25 .name = "small.txt",
26 .name = "small.txt",26 .size = 5,
27 .size = 5,27 .mode = 0o640,
28 .mode = 0o640,
29 },
30 .{
31 .name = "small2.txt",
32 .size = 11,
33 .mode = 0o640,
34 },
35 },28 },
36 .chksums = &[_][]const u8{29 .{
37 "e38b27eaccb4391bdec553a7f3ae6b2f",30 .name = "small2.txt",
38 "c65bd2e50a56a2138bf1716f2fd56fe9",31 .size = 11,
32 .mode = 0o640,
33 },
34 },
35 .chksums = &[_][]const u8{
36 "e38b27eaccb4391bdec553a7f3ae6b2f",
37 "c65bd2e50a56a2138bf1716f2fd56fe9",
38 },
39};
40
41const 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
52const 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
62const 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
75const fuzz1_case: Case = .{
76 .data = @embedFile("testdata/fuzz1.tar"),
77 .err = error.TarInsufficientBuffer,
78};
79
80test "run test cases" {
81 try testCase(gnu_case);
82 try testCase(.{
42 .data = @embedFile("testdata/sparse-formats.tar"),83 .data = @embedFile("testdata/sparse-formats.tar"),
43 .err = error.TarUnsupportedHeader,84 .err = error.TarUnsupportedHeader,
44 },85 });
45 .{86 try testCase(.{
46 .data = @embedFile("testdata/star.tar"),87 .data = @embedFile("testdata/star.tar"),
47 .files = &[_]Case.File{88 .files = &[_]Case.File{
48 .{89 .{
...@@ -60,8 +101,8 @@ const cases = [_]Case{...@@ -60,8 +101,8 @@ const cases = [_]Case{
60 "e38b27eaccb4391bdec553a7f3ae6b2f",101 "e38b27eaccb4391bdec553a7f3ae6b2f",
61 "c65bd2e50a56a2138bf1716f2fd56fe9",102 "c65bd2e50a56a2138bf1716f2fd56fe9",
62 },103 },
63 },104 });
64 .{105 try testCase(.{
65 .data = @embedFile("testdata/v7.tar"),106 .data = @embedFile("testdata/v7.tar"),
66 .files = &[_]Case.File{107 .files = &[_]Case.File{
67 .{108 .{
...@@ -79,8 +120,8 @@ const cases = [_]Case{...@@ -79,8 +120,8 @@ const cases = [_]Case{
79 "e38b27eaccb4391bdec553a7f3ae6b2f",120 "e38b27eaccb4391bdec553a7f3ae6b2f",
80 "c65bd2e50a56a2138bf1716f2fd56fe9",121 "c65bd2e50a56a2138bf1716f2fd56fe9",
81 },122 },
82 },123 });
83 .{124 try testCase(.{
84 .data = @embedFile("testdata/pax.tar"),125 .data = @embedFile("testdata/pax.tar"),
85 .files = &[_]Case.File{126 .files = &[_]Case.File{
86 .{127 .{
...@@ -99,13 +140,13 @@ const cases = [_]Case{...@@ -99,13 +140,13 @@ const cases = [_]Case{
99 .chksums = &[_][]const u8{140 .chksums = &[_][]const u8{
100 "3c382e8f5b6631aa2db52643912ffd4a",141 "3c382e8f5b6631aa2db52643912ffd4a",
101 },142 },
102 },143 });
103 .{144 try testCase(.{
104 // pax attribute don't end with \n145 // pax attribute don't end with \n
105 .data = @embedFile("testdata/pax-bad-hdr-file.tar"),146 .data = @embedFile("testdata/pax-bad-hdr-file.tar"),
106 .err = error.PaxInvalidAttributeEnd,147 .err = error.PaxInvalidAttributeEnd,
107 },148 });
108 .{149 try testCase(.{
109 // size is in pax attribute150 // size is in pax attribute
110 .data = @embedFile("testdata/pax-pos-size-file.tar"),151 .data = @embedFile("testdata/pax-pos-size-file.tar"),
111 .files = &[_]Case.File{152 .files = &[_]Case.File{
...@@ -119,8 +160,8 @@ const cases = [_]Case{...@@ -119,8 +160,8 @@ const cases = [_]Case{
119 .chksums = &[_][]const u8{160 .chksums = &[_][]const u8{
120 "0afb597b283fe61b5d4879669a350556",161 "0afb597b283fe61b5d4879669a350556",
121 },162 },
122 },163 });
123 .{164 try testCase(.{
124 // has pax records which we are not interested in165 // has pax records which we are not interested in
125 .data = @embedFile("testdata/pax-records.tar"),166 .data = @embedFile("testdata/pax-records.tar"),
126 .files = &[_]Case.File{167 .files = &[_]Case.File{
...@@ -128,8 +169,8 @@ const cases = [_]Case{...@@ -128,8 +169,8 @@ const cases = [_]Case{
128 .name = "file",169 .name = "file",
129 },170 },
130 },171 },
131 },172 });
132 .{173 try testCase(.{
133 // has global records which we are ignoring174 // has global records which we are ignoring
134 .data = @embedFile("testdata/pax-global-records.tar"),175 .data = @embedFile("testdata/pax-global-records.tar"),
135 .files = &[_]Case.File{176 .files = &[_]Case.File{
...@@ -146,8 +187,8 @@ const cases = [_]Case{...@@ -146,8 +187,8 @@ const cases = [_]Case{
146 .name = "file4",187 .name = "file4",
147 },188 },
148 },189 },
149 },190 });
150 .{191 try testCase(.{
151 .data = @embedFile("testdata/nil-uid.tar"),192 .data = @embedFile("testdata/nil-uid.tar"),
152 .files = &[_]Case.File{193 .files = &[_]Case.File{
153 .{194 .{
...@@ -160,8 +201,8 @@ const cases = [_]Case{...@@ -160,8 +201,8 @@ const cases = [_]Case{
160 .chksums = &[_][]const u8{201 .chksums = &[_][]const u8{
161 "08d504674115e77a67244beac19668f5",202 "08d504674115e77a67244beac19668f5",
162 },203 },
163 },204 });
164 .{205 try testCase(.{
165 // has xattrs and pax records which we are ignoring206 // has xattrs and pax records which we are ignoring
166 .data = @embedFile("testdata/xattrs.tar"),207 .data = @embedFile("testdata/xattrs.tar"),
167 .files = &[_]Case.File{208 .files = &[_]Case.File{
...@@ -182,23 +223,14 @@ const cases = [_]Case{...@@ -182,23 +223,14 @@ const cases = [_]Case{
182 "e38b27eaccb4391bdec553a7f3ae6b2f",223 "e38b27eaccb4391bdec553a7f3ae6b2f",
183 "c65bd2e50a56a2138bf1716f2fd56fe9",224 "c65bd2e50a56a2138bf1716f2fd56fe9",
184 },225 },
185 },226 });
186 .{227 try testCase(gnu_multi_headers_case);
187 .data = @embedFile("testdata/gnu-multi-hdrs.tar"),228 try testCase(.{
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 .{
197 // has gnu type D (directory) and S (sparse) blocks229 // has gnu type D (directory) and S (sparse) blocks
198 .data = @embedFile("testdata/gnu-incremental.tar"),230 .data = @embedFile("testdata/gnu-incremental.tar"),
199 .err = error.TarUnsupportedHeader,231 .err = error.TarUnsupportedHeader,
200 },232 });
201 .{233 try testCase(.{
202 // should use values only from last pax header234 // should use values only from last pax header
203 .data = @embedFile("testdata/pax-multi-hdrs.tar"),235 .data = @embedFile("testdata/pax-multi-hdrs.tar"),
204 .files = &[_]Case.File{236 .files = &[_]Case.File{
...@@ -208,8 +240,8 @@ const cases = [_]Case{...@@ -208,8 +240,8 @@ const cases = [_]Case{
208 .kind = .sym_link,240 .kind = .sym_link,
209 },241 },
210 },242 },
211 },243 });
212 .{244 try testCase(.{
213 .data = @embedFile("testdata/gnu-long-nul.tar"),245 .data = @embedFile("testdata/gnu-long-nul.tar"),
214 .files = &[_]Case.File{246 .files = &[_]Case.File{
215 .{247 .{
...@@ -217,8 +249,8 @@ const cases = [_]Case{...@@ -217,8 +249,8 @@ const cases = [_]Case{
217 .mode = 0o644,249 .mode = 0o644,
218 },250 },
219 },251 },
220 },252 });
221 .{253 try testCase(.{
222 .data = @embedFile("testdata/gnu-utf8.tar"),254 .data = @embedFile("testdata/gnu-utf8.tar"),
223 .files = &[_]Case.File{255 .files = &[_]Case.File{
224 .{256 .{
...@@ -226,8 +258,8 @@ const cases = [_]Case{...@@ -226,8 +258,8 @@ const cases = [_]Case{
226 .mode = 0o644,258 .mode = 0o644,
227 },259 },
228 },260 },
229 },261 });
230 .{262 try testCase(.{
231 .data = @embedFile("testdata/gnu-not-utf8.tar"),263 .data = @embedFile("testdata/gnu-not-utf8.tar"),
232 .files = &[_]Case.File{264 .files = &[_]Case.File{
233 .{265 .{
...@@ -235,33 +267,33 @@ const cases = [_]Case{...@@ -235,33 +267,33 @@ const cases = [_]Case{
235 .mode = 0o644,267 .mode = 0o644,
236 },268 },
237 },269 },
238 },270 });
239 .{271 try testCase(.{
240 // null in pax key272 // null in pax key
241 .data = @embedFile("testdata/pax-nul-xattrs.tar"),273 .data = @embedFile("testdata/pax-nul-xattrs.tar"),
242 .err = error.PaxNullInKeyword,274 .err = error.PaxNullInKeyword,
243 },275 });
244 .{276 try testCase(.{
245 .data = @embedFile("testdata/pax-nul-path.tar"),277 .data = @embedFile("testdata/pax-nul-path.tar"),
246 .err = error.PaxNullInValue,278 .err = error.PaxNullInValue,
247 },279 });
248 .{280 try testCase(.{
249 .data = @embedFile("testdata/neg-size.tar"),281 .data = @embedFile("testdata/neg-size.tar"),
250 .err = error.TarHeader,282 .err = error.TarHeader,
251 },283 });
252 .{284 try testCase(.{
253 .data = @embedFile("testdata/issue10968.tar"),285 .data = @embedFile("testdata/issue10968.tar"),
254 .err = error.TarHeader,286 .err = error.TarHeader,
255 },287 });
256 .{288 try testCase(.{
257 .data = @embedFile("testdata/issue11169.tar"),289 .data = @embedFile("testdata/issue11169.tar"),
258 .err = error.TarHeader,290 .err = error.TarHeader,
259 },291 });
260 .{292 try testCase(.{
261 .data = @embedFile("testdata/issue12435.tar"),293 .data = @embedFile("testdata/issue12435.tar"),
262 .err = error.TarHeaderChksum,294 .err = error.TarHeaderChksum,
263 },295 });
264 .{296 try testCase(.{
265 // has magic with space at end instead of null297 // has magic with space at end instead of null
266 .data = @embedFile("testdata/invalid-go17.tar"),298 .data = @embedFile("testdata/invalid-go17.tar"),
267 .files = &[_]Case.File{299 .files = &[_]Case.File{
...@@ -269,8 +301,8 @@ const cases = [_]Case{...@@ -269,8 +301,8 @@ const cases = [_]Case{
269 .name = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/foo",301 .name = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/foo",
270 },302 },
271 },303 },
272 },304 });
273 .{305 try testCase(.{
274 .data = @embedFile("testdata/ustar-file-devs.tar"),306 .data = @embedFile("testdata/ustar-file-devs.tar"),
275 .files = &[_]Case.File{307 .files = &[_]Case.File{
276 .{308 .{
...@@ -278,17 +310,9 @@ const cases = [_]Case{...@@ -278,17 +310,9 @@ const cases = [_]Case{
278 .mode = 0o644,310 .mode = 0o644,
279 },311 },
280 },312 },
281 },313 });
282 .{314 try testCase(trailing_slash_case);
283 .data = @embedFile("testdata/trailing-slash.tar"),315 try testCase(.{
284 .files = &[_]Case.File{
285 .{
286 .name = "123456789/" ** 30,
287 .kind = .directory,
288 },
289 },
290 },
291 .{
292 // Has size in gnu extended format. To represent size bigger than 8 GB.316 // Has size in gnu extended format. To represent size bigger than 8 GB.
293 .data = @embedFile("testdata/writer-big.tar"),317 .data = @embedFile("testdata/writer-big.tar"),
294 .files = &[_]Case.File{318 .files = &[_]Case.File{
...@@ -299,120 +323,92 @@ const cases = [_]Case{...@@ -299,120 +323,92 @@ const cases = [_]Case{
299 .mode = 0o640,323 .mode = 0o640,
300 },324 },
301 },325 },
302 },326 });
303 .{327 try testCase(writer_big_long_case);
304 // Size in gnu extended format, and name in pax attribute.328 try testCase(fuzz1_case);
305 .data = @embedFile("testdata/writer-big-long.tar"),329 try testCase(.{
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 .{
320 .data = @embedFile("testdata/fuzz2.tar"),330 .data = @embedFile("testdata/fuzz2.tar"),
321 .err = error.PaxSizeAttrOverflow,331 .err = error.PaxSizeAttrOverflow,
322 },332 });
323};333}
324
325// used in test to calculate file chksum
326const 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};
343334
344test "run test cases" {335fn testCase(case: Case) !void {
345 var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined;336 var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
346 var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined;337 var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
347338
348 for (cases) |case| {339 var br: std.io.Reader = .fixed(case.data);
349 var fsb = std.io.fixedBufferStream(case.data);340 var it: tar.Iterator = .init(&br, .{
350 var iter = tar.iterator(fsb.reader(), .{341 .file_name_buffer = &file_name_buffer,
351 .file_name_buffer = &file_name_buffer,342 .link_name_buffer = &link_name_buffer,
352 .link_name_buffer = &link_name_buffer,343 });
353 });344 var i: usize = 0;
354 var i: usize = 0;345 while (it.next() catch |err| {
355 while (iter.next() catch |err| {346 if (case.err) |e| {
356 if (case.err) |e| {347 try testing.expectEqual(e, err);
357 try testing.expectEqual(e, err);348 return;
358 continue;349 } else {
359 } else {350 return err;
360 return err;351 }
361 }352 }) |actual| : (i += 1) {
362 }) |actual| : (i += 1) {353 const expected = case.files[i];
363 const expected = case.files[i];354 try testing.expectEqualStrings(expected.name, actual.name);
364 try testing.expectEqualStrings(expected.name, actual.name);355 try testing.expectEqual(expected.size, actual.size);
365 try testing.expectEqual(expected.size, actual.size);356 try testing.expectEqual(expected.kind, actual.kind);
366 try testing.expectEqual(expected.kind, actual.kind);357 try testing.expectEqual(expected.mode, actual.mode);
367 try testing.expectEqual(expected.mode, actual.mode);358 try testing.expectEqualStrings(expected.link_name, actual.link_name);
368 try testing.expectEqualStrings(expected.link_name, actual.link_name);
369359
370 if (case.chksums.len > i) {360 if (case.chksums.len > i) {
371 var md5writer = Md5Writer{};361 var aw: std.Io.Writer.Allocating = .init(std.testing.allocator);
372 try actual.writeAll(&md5writer);362 defer aw.deinit();
373 const chksum = md5writer.chksum();363 try it.streamRemaining(actual, &aw.writer);
374 try testing.expectEqualStrings(case.chksums[i], &chksum);364 const chksum = std.fmt.bytesToHex(std.crypto.hash.Md5.hashResult(aw.getWritten()), .lower);
375 } else {365 try testing.expectEqualStrings(case.chksums[i], &chksum);
376 if (expected.truncated) {366 } else {
377 iter.unread_file_bytes = 0;367 if (expected.truncated) {
378 }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}
384374
385test "pax/gnu long names with small buffer" {375test "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
384fn testLongNameCase(case: Case) !void {
386 // should fail with insufficient buffer error385 // should fail with insufficient buffer error
387386
388 var min_file_name_buffer: [256]u8 = undefined;387 var min_file_name_buffer: [256]u8 = undefined;
389 var min_link_name_buffer: [100]u8 = undefined;388 var min_link_name_buffer: [100]u8 = undefined;
390 const long_name_cases = [_]Case{ cases[11], cases[25], cases[28] };
391389
392 for (long_name_cases) |case| {390 var br: std.io.Reader = .fixed(case.data);
393 var fsb = std.io.fixedBufferStream(case.data);391 var iter: tar.Iterator = .init(&br, .{
394 var iter = tar.iterator(fsb.reader(), .{392 .file_name_buffer = &min_file_name_buffer,
395 .file_name_buffer = &min_file_name_buffer,393 .link_name_buffer = &min_link_name_buffer,
396 .link_name_buffer = &min_link_name_buffer,394 });
397 });
398395
399 var iter_err: ?anyerror = null;396 var iter_err: ?anyerror = null;
400 while (iter.next() catch |err| brk: {397 while (iter.next() catch |err| brk: {
401 iter_err = err;398 iter_err = err;
402 break :brk null;399 break :brk null;
403 }) |_| {}400 }) |_| {}
404401
405 try testing.expect(iter_err != null);402 try testing.expect(iter_err != null);
406 try testing.expectEqual(error.TarInsufficientBuffer, iter_err.?);403 try testing.expectEqual(error.TarInsufficientBuffer, iter_err.?);
407 }
408}404}
409405
410test "insufficient buffer in Header name filed" {406test "insufficient buffer in Header name filed" {
411 var min_file_name_buffer: [9]u8 = undefined;407 var min_file_name_buffer: [9]u8 = undefined;
412 var min_link_name_buffer: [100]u8 = undefined;408 var min_link_name_buffer: [100]u8 = undefined;
413409
414 var fsb = std.io.fixedBufferStream(cases[0].data);410 var br: std.io.Reader = .fixed(gnu_case.data);
415 var iter = tar.iterator(fsb.reader(), .{411 var iter: tar.Iterator = .init(&br, .{
416 .file_name_buffer = &min_file_name_buffer,412 .file_name_buffer = &min_file_name_buffer,
417 .link_name_buffer = &min_link_name_buffer,413 .link_name_buffer = &min_link_name_buffer,
418 });414 });
...@@ -466,21 +462,21 @@ test "should not overwrite existing file" {...@@ -466,21 +462,21 @@ test "should not overwrite existing file" {
466 // This ensures that file is not overwritten.462 // This ensures that file is not overwritten.
467 //463 //
468 const data = @embedFile("testdata/overwrite_file.tar");464 const data = @embedFile("testdata/overwrite_file.tar");
469 var fsb = std.io.fixedBufferStream(data);465 var r: std.io.Reader = .fixed(data);
470466
471 // Unpack with strip_components = 1 should fail467 // Unpack with strip_components = 1 should fail
472 var root = std.testing.tmpDir(.{});468 var root = std.testing.tmpDir(.{});
473 defer root.cleanup();469 defer root.cleanup();
474 try testing.expectError(470 try testing.expectError(
475 error.PathAlreadyExists,471 error.PathAlreadyExists,
476 tar.pipeToFileSystem(root.dir, fsb.reader(), .{ .mode_mode = .ignore, .strip_components = 1 }),472 tar.pipeToFileSystem(root.dir, &r, .{ .mode_mode = .ignore, .strip_components = 1 }),
477 );473 );
478474
479 // Unpack with strip_components = 0 should pass475 // Unpack with strip_components = 0 should pass
480 fsb.reset();476 r = .fixed(data);
481 var root2 = std.testing.tmpDir(.{});477 var root2 = std.testing.tmpDir(.{});
482 defer root2.cleanup();478 defer root2.cleanup();
483 try tar.pipeToFileSystem(root2.dir, fsb.reader(), .{ .mode_mode = .ignore, .strip_components = 0 });479 try tar.pipeToFileSystem(root2.dir, &r, .{ .mode_mode = .ignore, .strip_components = 0 });
484}480}
485481
486test "case sensitivity" {482test "case sensitivity" {
...@@ -494,12 +490,12 @@ test "case sensitivity" {...@@ -494,12 +490,12 @@ test "case sensitivity" {
494 // 18089/alacritty/Darkermatrix.yml490 // 18089/alacritty/Darkermatrix.yml
495 //491 //
496 const data = @embedFile("testdata/18089.tar");492 const data = @embedFile("testdata/18089.tar");
497 var fsb = std.io.fixedBufferStream(data);493 var r: std.io.Reader = .fixed(data);
498494
499 var root = std.testing.tmpDir(.{});495 var root = std.testing.tmpDir(.{});
500 defer root.cleanup();496 defer root.cleanup();
501497
502 tar.pipeToFileSystem(root.dir, fsb.reader(), .{ .mode_mode = .ignore, .strip_components = 1 }) catch |err| {498 tar.pipeToFileSystem(root.dir, &r, .{ .mode_mode = .ignore, .strip_components = 1 }) catch |err| {
503 // on case insensitive fs we fail on overwrite existing file499 // on case insensitive fs we fail on overwrite existing file
504 try testing.expectEqual(error.PathAlreadyExists, err);500 try testing.expectEqual(error.PathAlreadyExists, err);
505 return;501 return;
lib/std/tar/writer.zig deleted-497
...@@ -1,497 +0,0 @@
1const std = @import("std");
2const assert = std.debug.assert;
3const testing = std.testing;
4
5/// Creates tar Writer which will write tar content to the `underlying_writer`.
6/// Use setRoot to nest all following entries under single root. If file don't
7/// fit into posix header (name+prefix: 100+155 bytes) gnu extented header will
8/// be used for long names. Options enables setting file premission mode and
9/// mtime. Default is to use current time for mtime and 0o664 for file mode.
10pub fn writer(underlying_writer: anytype) Writer(@TypeOf(underlying_writer)) {
11 return .{ .underlying_writer = underlying_writer };
12}
13
14pub fn Writer(comptime WriterType: type) type {
15 return struct {
16 const block_size = @sizeOf(Header);
17 const empty_block: [block_size]u8 = [_]u8{0} ** block_size;
18
19 /// Options for writing file/dir/link. If left empty 0o664 is used for
20 /// file mode and current time for mtime.
21 pub const Options = struct {
22 /// File system permission mode.
23 mode: u32 = 0,
24 /// File system modification time.
25 mtime: u64 = 0,
26 };
27 const Self = @This();
28
29 underlying_writer: WriterType,
30 prefix: []const u8 = "",
31 mtime_now: u64 = 0,
32
33 /// Sets prefix for all other write* method paths.
34 pub fn setRoot(self: *Self, root: []const u8) !void {
35 if (root.len > 0)
36 try self.writeDir(root, .{});
37
38 self.prefix = root;
39 }
40
41 /// Writes directory.
42 pub fn writeDir(self: *Self, sub_path: []const u8, opt: Options) !void {
43 try self.writeHeader(.directory, sub_path, "", 0, opt);
44 }
45
46 /// Writes file system file.
47 pub fn writeFile(self: *Self, sub_path: []const u8, file: std.fs.File) !void {
48 const stat = try file.stat();
49 const mtime: u64 = @intCast(@divFloor(stat.mtime, std.time.ns_per_s));
50
51 var header = Header{};
52 try self.setPath(&header, sub_path);
53 try header.setSize(stat.size);
54 try header.setMtime(mtime);
55 try header.write(self.underlying_writer);
56
57 try self.underlying_writer.writeFile(file);
58 try self.writePadding(stat.size);
59 }
60
61 /// Writes file reading file content from `reader`. Number of bytes in
62 /// reader must be equal to `size`.
63 pub fn writeFileStream(self: *Self, sub_path: []const u8, size: usize, reader: anytype, opt: Options) !void {
64 try self.writeHeader(.regular, sub_path, "", @intCast(size), opt);
65
66 var counting_reader = std.io.countingReader(reader);
67 var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init();
68 try fifo.pump(counting_reader.reader(), self.underlying_writer);
69 if (counting_reader.bytes_read != size) return error.WrongReaderSize;
70 try self.writePadding(size);
71 }
72
73 /// Writes file using bytes buffer `content` for size and file content.
74 pub fn writeFileBytes(self: *Self, sub_path: []const u8, content: []const u8, opt: Options) !void {
75 try self.writeHeader(.regular, sub_path, "", @intCast(content.len), opt);
76 try self.underlying_writer.writeAll(content);
77 try self.writePadding(content.len);
78 }
79
80 /// Writes symlink.
81 pub fn writeLink(self: *Self, sub_path: []const u8, link_name: []const u8, opt: Options) !void {
82 try self.writeHeader(.symbolic_link, sub_path, link_name, 0, opt);
83 }
84
85 /// Writes fs.Dir.WalkerEntry. Uses `mtime` from file system entry and
86 /// default for entry mode .
87 pub fn writeEntry(self: *Self, entry: std.fs.Dir.Walker.Entry) !void {
88 switch (entry.kind) {
89 .directory => {
90 try self.writeDir(entry.path, .{ .mtime = try entryMtime(entry) });
91 },
92 .file => {
93 var file = try entry.dir.openFile(entry.basename, .{});
94 defer file.close();
95 try self.writeFile(entry.path, file);
96 },
97 .sym_link => {
98 var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
99 const link_name = try entry.dir.readLink(entry.basename, &link_name_buffer);
100 try self.writeLink(entry.path, link_name, .{ .mtime = try entryMtime(entry) });
101 },
102 else => {
103 return error.UnsupportedWalkerEntryKind;
104 },
105 }
106 }
107
108 fn writeHeader(
109 self: *Self,
110 typeflag: Header.FileType,
111 sub_path: []const u8,
112 link_name: []const u8,
113 size: u64,
114 opt: Options,
115 ) !void {
116 var header = Header.init(typeflag);
117 try self.setPath(&header, sub_path);
118 try header.setSize(size);
119 try header.setMtime(if (opt.mtime != 0) opt.mtime else self.mtimeNow());
120 if (opt.mode != 0)
121 try header.setMode(opt.mode);
122 if (typeflag == .symbolic_link)
123 header.setLinkname(link_name) catch |err| switch (err) {
124 error.NameTooLong => try self.writeExtendedHeader(.gnu_long_link, &.{link_name}),
125 else => return err,
126 };
127 try header.write(self.underlying_writer);
128 }
129
130 fn mtimeNow(self: *Self) u64 {
131 if (self.mtime_now == 0)
132 self.mtime_now = @intCast(std.time.timestamp());
133 return self.mtime_now;
134 }
135
136 fn entryMtime(entry: std.fs.Dir.Walker.Entry) !u64 {
137 const stat = try entry.dir.statFile(entry.basename);
138 return @intCast(@divFloor(stat.mtime, std.time.ns_per_s));
139 }
140
141 /// Writes path in posix header, if don't fit (in name+prefix; 100+155
142 /// bytes) writes it in gnu extended header.
143 fn setPath(self: *Self, header: *Header, sub_path: []const u8) !void {
144 header.setPath(self.prefix, sub_path) catch |err| switch (err) {
145 error.NameTooLong => {
146 // write extended header
147 const buffers: []const []const u8 = if (self.prefix.len == 0)
148 &.{sub_path}
149 else
150 &.{ self.prefix, "/", sub_path };
151 try self.writeExtendedHeader(.gnu_long_name, buffers);
152 },
153 else => return err,
154 };
155 }
156
157 /// Writes gnu extended header: gnu_long_name or gnu_long_link.
158 fn writeExtendedHeader(self: *Self, typeflag: Header.FileType, buffers: []const []const u8) !void {
159 var len: usize = 0;
160 for (buffers) |buf|
161 len += buf.len;
162
163 var header = Header.init(typeflag);
164 try header.setSize(len);
165 try header.write(self.underlying_writer);
166 for (buffers) |buf|
167 try self.underlying_writer.writeAll(buf);
168 try self.writePadding(len);
169 }
170
171 fn writePadding(self: *Self, bytes: u64) !void {
172 const pos: usize = @intCast(bytes % block_size);
173 if (pos == 0) return;
174 try self.underlying_writer.writeAll(empty_block[pos..]);
175 }
176
177 /// Tar should finish with two zero blocks, but 'reasonable system must
178 /// not assume that such a block exists when reading an archive' (from
179 /// reference). In practice it is safe to skip this finish.
180 pub fn finish(self: *Self) !void {
181 try self.underlying_writer.writeAll(&empty_block);
182 try self.underlying_writer.writeAll(&empty_block);
183 }
184 };
185}
186
187/// A struct that is exactly 512 bytes and matches tar file format. This is
188/// intended to be used for outputting tar files; for parsing there is
189/// `std.tar.Header`.
190const Header = extern struct {
191 // This struct was originally copied from
192 // https://github.com/mattnite/tar/blob/main/src/main.zig which is MIT
193 // licensed.
194 //
195 // The name, linkname, magic, uname, and gname are null-terminated character
196 // strings. All other fields are zero-filled octal numbers in ASCII. Each
197 // numeric field of width w contains w minus 1 digits, and a null.
198 // Reference: https://www.gnu.org/software/tar/manual/html_node/Standard.html
199 // POSIX header: byte offset
200 name: [100]u8 = [_]u8{0} ** 100, // 0
201 mode: [7:0]u8 = default_mode.file, // 100
202 uid: [7:0]u8 = [_:0]u8{0} ** 7, // unused 108
203 gid: [7:0]u8 = [_:0]u8{0} ** 7, // unused 116
204 size: [11:0]u8 = [_:0]u8{'0'} ** 11, // 124
205 mtime: [11:0]u8 = [_:0]u8{'0'} ** 11, // 136
206 checksum: [7:0]u8 = [_:0]u8{' '} ** 7, // 148
207 typeflag: FileType = .regular, // 156
208 linkname: [100]u8 = [_]u8{0} ** 100, // 157
209 magic: [6]u8 = [_]u8{ 'u', 's', 't', 'a', 'r', 0 }, // 257
210 version: [2]u8 = [_]u8{ '0', '0' }, // 263
211 uname: [32]u8 = [_]u8{0} ** 32, // unused 265
212 gname: [32]u8 = [_]u8{0} ** 32, // unused 297
213 devmajor: [7:0]u8 = [_:0]u8{0} ** 7, // unused 329
214 devminor: [7:0]u8 = [_:0]u8{0} ** 7, // unused 337
215 prefix: [155]u8 = [_]u8{0} ** 155, // 345
216 pad: [12]u8 = [_]u8{0} ** 12, // unused 500
217
218 pub const FileType = enum(u8) {
219 regular = '0',
220 symbolic_link = '2',
221 directory = '5',
222 gnu_long_name = 'L',
223 gnu_long_link = 'K',
224 };
225
226 const default_mode = struct {
227 const file = [_:0]u8{ '0', '0', '0', '0', '6', '6', '4' }; // 0o664
228 const dir = [_:0]u8{ '0', '0', '0', '0', '7', '7', '5' }; // 0o775
229 const sym_link = [_:0]u8{ '0', '0', '0', '0', '7', '7', '7' }; // 0o777
230 const other = [_:0]u8{ '0', '0', '0', '0', '0', '0', '0' }; // 0o000
231 };
232
233 pub fn init(typeflag: FileType) Header {
234 return .{
235 .typeflag = typeflag,
236 .mode = switch (typeflag) {
237 .directory => default_mode.dir,
238 .symbolic_link => default_mode.sym_link,
239 .regular => default_mode.file,
240 else => default_mode.other,
241 },
242 };
243 }
244
245 pub fn setSize(self: *Header, size: u64) !void {
246 try octal(&self.size, size);
247 }
248
249 fn octal(buf: []u8, value: u64) !void {
250 var remainder: u64 = value;
251 var pos: usize = buf.len;
252 while (remainder > 0 and pos > 0) {
253 pos -= 1;
254 const c: u8 = @as(u8, @intCast(remainder % 8)) + '0';
255 buf[pos] = c;
256 remainder /= 8;
257 if (pos == 0 and remainder > 0) return error.OctalOverflow;
258 }
259 }
260
261 pub fn setMode(self: *Header, mode: u32) !void {
262 try octal(&self.mode, mode);
263 }
264
265 // Integer number of seconds since January 1, 1970, 00:00 Coordinated Universal Time.
266 // mtime == 0 will use current time
267 pub fn setMtime(self: *Header, mtime: u64) !void {
268 try octal(&self.mtime, mtime);
269 }
270
271 pub fn updateChecksum(self: *Header) !void {
272 var checksum: usize = ' '; // other 7 self.checksum bytes are initialized to ' '
273 for (std.mem.asBytes(self)) |val|
274 checksum += val;
275 try octal(&self.checksum, checksum);
276 }
277
278 pub fn write(self: *Header, output_writer: anytype) !void {
279 try self.updateChecksum();
280 try output_writer.writeAll(std.mem.asBytes(self));
281 }
282
283 pub fn setLinkname(self: *Header, link: []const u8) !void {
284 if (link.len > self.linkname.len) return error.NameTooLong;
285 @memcpy(self.linkname[0..link.len], link);
286 }
287
288 pub fn setPath(self: *Header, prefix: []const u8, sub_path: []const u8) !void {
289 const max_prefix = self.prefix.len;
290 const max_name = self.name.len;
291 const sep = std.fs.path.sep_posix;
292
293 if (prefix.len + sub_path.len > max_name + max_prefix or prefix.len > max_prefix)
294 return error.NameTooLong;
295
296 // both fit into name
297 if (prefix.len > 0 and prefix.len + sub_path.len < max_name) {
298 @memcpy(self.name[0..prefix.len], prefix);
299 self.name[prefix.len] = sep;
300 @memcpy(self.name[prefix.len + 1 ..][0..sub_path.len], sub_path);
301 return;
302 }
303
304 // sub_path fits into name
305 // there is no prefix or prefix fits into prefix
306 if (sub_path.len <= max_name) {
307 @memcpy(self.name[0..sub_path.len], sub_path);
308 @memcpy(self.prefix[0..prefix.len], prefix);
309 return;
310 }
311
312 if (prefix.len > 0) {
313 @memcpy(self.prefix[0..prefix.len], prefix);
314 self.prefix[prefix.len] = sep;
315 }
316 const prefix_pos = if (prefix.len > 0) prefix.len + 1 else 0;
317
318 // add as much to prefix as you can, must split at /
319 const prefix_remaining = max_prefix - prefix_pos;
320 if (std.mem.lastIndexOf(u8, sub_path[0..@min(prefix_remaining, sub_path.len)], &.{'/'})) |sep_pos| {
321 @memcpy(self.prefix[prefix_pos..][0..sep_pos], sub_path[0..sep_pos]);
322 if ((sub_path.len - sep_pos - 1) > max_name) return error.NameTooLong;
323 @memcpy(self.name[0..][0 .. sub_path.len - sep_pos - 1], sub_path[sep_pos + 1 ..]);
324 return;
325 }
326
327 return error.NameTooLong;
328 }
329
330 comptime {
331 assert(@sizeOf(Header) == 512);
332 }
333
334 test setPath {
335 const cases = [_]struct {
336 in: []const []const u8,
337 out: []const []const u8,
338 }{
339 .{
340 .in = &.{ "", "123456789" },
341 .out = &.{ "", "123456789" },
342 },
343 // can fit into name
344 .{
345 .in = &.{ "prefix", "sub_path" },
346 .out = &.{ "", "prefix/sub_path" },
347 },
348 // no more both fits into name
349 .{
350 .in = &.{ "prefix", "0123456789/" ** 8 ++ "basename" },
351 .out = &.{ "prefix", "0123456789/" ** 8 ++ "basename" },
352 },
353 // put as much as you can into prefix the rest goes into name
354 .{
355 .in = &.{ "prefix", "0123456789/" ** 10 ++ "basename" },
356 .out = &.{ "prefix/" ++ "0123456789/" ** 9 ++ "0123456789", "basename" },
357 },
358
359 .{
360 .in = &.{ "prefix", "0123456789/" ** 15 ++ "basename" },
361 .out = &.{ "prefix/" ++ "0123456789/" ** 12 ++ "0123456789", "0123456789/0123456789/basename" },
362 },
363 .{
364 .in = &.{ "prefix", "0123456789/" ** 21 ++ "basename" },
365 .out = &.{ "prefix/" ++ "0123456789/" ** 12 ++ "0123456789", "0123456789/" ** 8 ++ "basename" },
366 },
367 .{
368 .in = &.{ "", "012345678/" ** 10 ++ "foo" },
369 .out = &.{ "012345678/" ** 9 ++ "012345678", "foo" },
370 },
371 };
372
373 for (cases) |case| {
374 var header = Header.init(.regular);
375 try header.setPath(case.in[0], case.in[1]);
376 try testing.expectEqualStrings(case.out[0], str(&header.prefix));
377 try testing.expectEqualStrings(case.out[1], str(&header.name));
378 }
379
380 const error_cases = [_]struct {
381 in: []const []const u8,
382 }{
383 // basename can't fit into name (106 characters)
384 .{ .in = &.{ "zig", "test/cases/compile_errors/regression_test_2980_base_type_u32_is_not_type_checked_properly_when_assigning_a_value_within_a_struct.zig" } },
385 // cant fit into 255 + sep
386 .{ .in = &.{ "prefix", "0123456789/" ** 22 ++ "basename" } },
387 // can fit but sub_path can't be split (there is no separator)
388 .{ .in = &.{ "prefix", "0123456789" ** 10 ++ "a" } },
389 .{ .in = &.{ "prefix", "0123456789" ** 14 ++ "basename" } },
390 };
391
392 for (error_cases) |case| {
393 var header = Header.init(.regular);
394 try testing.expectError(
395 error.NameTooLong,
396 header.setPath(case.in[0], case.in[1]),
397 );
398 }
399 }
400
401 // Breaks string on first null character.
402 fn str(s: []const u8) []const u8 {
403 for (s, 0..) |c, i| {
404 if (c == 0) return s[0..i];
405 }
406 return s;
407 }
408};
409
410test {
411 _ = Header;
412}
413
414test "write files" {
415 const files = [_]struct {
416 path: []const u8,
417 content: []const u8,
418 }{
419 .{ .path = "foo", .content = "bar" },
420 .{ .path = "a12345678/" ** 10 ++ "foo", .content = "a" ** 511 },
421 .{ .path = "b12345678/" ** 24 ++ "foo", .content = "b" ** 512 },
422 .{ .path = "c12345678/" ** 25 ++ "foo", .content = "c" ** 513 },
423 .{ .path = "d12345678/" ** 51 ++ "foo", .content = "d" ** 1025 },
424 .{ .path = "e123456789" ** 11, .content = "e" },
425 };
426
427 var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
428 var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
429
430 // with root
431 {
432 const root = "root";
433
434 var output = std.ArrayList(u8).init(testing.allocator);
435 defer output.deinit();
436 var wrt = writer(output.writer());
437 try wrt.setRoot(root);
438 for (files) |file|
439 try wrt.writeFileBytes(file.path, file.content, .{});
440
441 var input = std.io.fixedBufferStream(output.items);
442 var iter = std.tar.iterator(
443 input.reader(),
444 .{ .file_name_buffer = &file_name_buffer, .link_name_buffer = &link_name_buffer },
445 );
446
447 // first entry is directory with prefix
448 {
449 const actual = (try iter.next()).?;
450 try testing.expectEqualStrings(root, actual.name);
451 try testing.expectEqual(std.tar.FileKind.directory, actual.kind);
452 }
453
454 var i: usize = 0;
455 while (try iter.next()) |actual| {
456 defer i += 1;
457 const expected = files[i];
458 try testing.expectEqualStrings(root, actual.name[0..root.len]);
459 try testing.expectEqual('/', actual.name[root.len..][0]);
460 try testing.expectEqualStrings(expected.path, actual.name[root.len + 1 ..]);
461
462 var content = std.ArrayList(u8).init(testing.allocator);
463 defer content.deinit();
464 try actual.writeAll(content.writer());
465 try testing.expectEqualSlices(u8, expected.content, content.items);
466 }
467 }
468 // without root
469 {
470 var output = std.ArrayList(u8).init(testing.allocator);
471 defer output.deinit();
472 var wrt = writer(output.writer());
473 for (files) |file| {
474 var content = std.io.fixedBufferStream(file.content);
475 try wrt.writeFileStream(file.path, file.content.len, content.reader(), .{});
476 }
477
478 var input = std.io.fixedBufferStream(output.items);
479 var iter = std.tar.iterator(
480 input.reader(),
481 .{ .file_name_buffer = &file_name_buffer, .link_name_buffer = &link_name_buffer },
482 );
483
484 var i: usize = 0;
485 while (try iter.next()) |actual| {
486 defer i += 1;
487 const expected = files[i];
488 try testing.expectEqualStrings(expected.path, actual.name);
489
490 var content = std.ArrayList(u8).init(testing.allocator);
491 defer content.deinit();
492 try actual.writeAll(content.writer());
493 try testing.expectEqualSlices(u8, expected.content, content.items);
494 }
495 try wrt.finish();
496 }
497}
lib/std/testing.zig+1
...@@ -33,6 +33,7 @@ pub var log_level = std.log.Level.warn;...@@ -33,6 +33,7 @@ pub var log_level = std.log.Level.warn;
3333
34// Disable printing in tests for simple backends.34// Disable printing in tests for simple backends.
35pub const backend_can_print = switch (builtin.zig_backend) {35pub const backend_can_print = switch (builtin.zig_backend) {
36 .stage2_aarch64,
36 .stage2_powerpc,37 .stage2_powerpc,
37 .stage2_riscv64,38 .stage2_riscv64,
38 .stage2_spirv,39 .stage2_spirv,
lib/std/zig.zig+30-9
...@@ -321,6 +321,27 @@ pub const BuildId = union(enum) {...@@ -321,6 +321,27 @@ pub const BuildId = union(enum) {
321 try std.testing.expectError(error.InvalidCharacter, parse("0xfoobbb"));321 try std.testing.expectError(error.InvalidCharacter, parse("0xfoobbb"));
322 try std.testing.expectError(error.InvalidBuildIdStyle, parse("yaddaxxx"));322 try std.testing.expectError(error.InvalidBuildIdStyle, parse("yaddaxxx"));
323 }323 }
324
325 pub fn format(id: BuildId, writer: *std.io.Writer) std.io.Writer.Error!void {
326 switch (id) {
327 .none, .fast, .uuid, .sha1, .md5 => {
328 try writer.writeAll(@tagName(id));
329 },
330 .hexstring => |hs| {
331 try writer.print("0x{x}", .{hs.toSlice()});
332 },
333 }
334 }
335
336 test format {
337 try std.testing.expectFmt("none", "{f}", .{@as(BuildId, .none)});
338 try std.testing.expectFmt("fast", "{f}", .{@as(BuildId, .fast)});
339 try std.testing.expectFmt("uuid", "{f}", .{@as(BuildId, .uuid)});
340 try std.testing.expectFmt("sha1", "{f}", .{@as(BuildId, .sha1)});
341 try std.testing.expectFmt("md5", "{f}", .{@as(BuildId, .md5)});
342 try std.testing.expectFmt("0x", "{f}", .{BuildId.initHexString("")});
343 try std.testing.expectFmt("0x1234cdef", "{f}", .{BuildId.initHexString("\x12\x34\xcd\xef")});
344 }
324};345};
325346
326pub const LtoMode = enum { none, full, thin };347pub const LtoMode = enum { none, full, thin };
...@@ -364,23 +385,23 @@ pub fn serializeCpuAlloc(ally: Allocator, cpu: std.Target.Cpu) Allocator.Error![...@@ -364,23 +385,23 @@ pub fn serializeCpuAlloc(ally: Allocator, cpu: std.Target.Cpu) Allocator.Error![
364/// Return a Formatter for a Zig identifier, escaping it with `@""` syntax if needed.385/// Return a Formatter for a Zig identifier, escaping it with `@""` syntax if needed.
365///386///
366/// See also `fmtIdFlags`.387/// See also `fmtIdFlags`.
367pub fn fmtId(bytes: []const u8) std.fmt.Formatter(FormatId, FormatId.render) {388pub fn fmtId(bytes: []const u8) FormatId {
368 return .{ .data = .{ .bytes = bytes, .flags = .{} } };389 return .{ .bytes = bytes, .flags = .{} };
369}390}
370391
371/// Return a Formatter for a Zig identifier, escaping it with `@""` syntax if needed.392/// Return a Formatter for a Zig identifier, escaping it with `@""` syntax if needed.
372///393///
373/// See also `fmtId`.394/// See also `fmtId`.
374pub fn fmtIdFlags(bytes: []const u8, flags: FormatId.Flags) std.fmt.Formatter(FormatId, FormatId.render) {395pub fn fmtIdFlags(bytes: []const u8, flags: FormatId.Flags) FormatId {
375 return .{ .data = .{ .bytes = bytes, .flags = flags } };396 return .{ .bytes = bytes, .flags = flags };
376}397}
377398
378pub fn fmtIdPU(bytes: []const u8) std.fmt.Formatter(FormatId, FormatId.render) {399pub fn fmtIdPU(bytes: []const u8) FormatId {
379 return .{ .data = .{ .bytes = bytes, .flags = .{ .allow_primitive = true, .allow_underscore = true } } };400 return .{ .bytes = bytes, .flags = .{ .allow_primitive = true, .allow_underscore = true } };
380}401}
381402
382pub fn fmtIdP(bytes: []const u8) std.fmt.Formatter(FormatId, FormatId.render) {403pub fn fmtIdP(bytes: []const u8) FormatId {
383 return .{ .data = .{ .bytes = bytes, .flags = .{ .allow_primitive = true } } };404 return .{ .bytes = bytes, .flags = .{ .allow_primitive = true } };
384}405}
385406
386test fmtId {407test fmtId {
...@@ -426,7 +447,7 @@ pub const FormatId = struct {...@@ -426,7 +447,7 @@ pub const FormatId = struct {
426 };447 };
427448
428 /// Print the string as a Zig identifier, escaping it with `@""` syntax if needed.449 /// Print the string as a Zig identifier, escaping it with `@""` syntax if needed.
429 fn render(ctx: FormatId, writer: *Writer) Writer.Error!void {450 pub fn format(ctx: FormatId, writer: *Writer) Writer.Error!void {
430 const bytes = ctx.bytes;451 const bytes = ctx.bytes;
431 if (isValidId(bytes) and452 if (isValidId(bytes) and
432 (ctx.flags.allow_primitive or !std.zig.isPrimitive(bytes)) and453 (ctx.flags.allow_primitive or !std.zig.isPrimitive(bytes)) and
src/Builtin.zig+2-2
...@@ -342,9 +342,9 @@ pub fn updateFileOnDisk(file: *File, comp: *Compilation) !void {...@@ -342,9 +342,9 @@ pub fn updateFileOnDisk(file: *File, comp: *Compilation) !void {
342 }342 }
343343
344 // `make_path` matters because the dir hasn't actually been created yet.344 // `make_path` matters because the dir hasn't actually been created yet.
345 var af = try root_dir.atomicFile(sub_path, .{ .make_path = true });345 var af = try root_dir.atomicFile(sub_path, .{ .make_path = true, .write_buffer = &.{} });
346 defer af.deinit();346 defer af.deinit();
347 try af.file.writeAll(file.source.?);347 try af.file_writer.interface.writeAll(file.source.?);
348 af.finish() catch |err| switch (err) {348 af.finish() catch |err| switch (err) {
349 error.AccessDenied => switch (builtin.os.tag) {349 error.AccessDenied => switch (builtin.os.tag) {
350 .windows => {350 .windows => {
src/Compilation.zig+166-149
...@@ -1816,10 +1816,12 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1816,10 +1816,12 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1816 if (options.skip_linker_dependencies) break :s .none;1816 if (options.skip_linker_dependencies) break :s .none;
1817 const want = options.want_compiler_rt orelse is_exe_or_dyn_lib;1817 const want = options.want_compiler_rt orelse is_exe_or_dyn_lib;
1818 if (!want) break :s .none;1818 if (!want) break :s .none;
1819 if (have_zcu) {1819 if (have_zcu and target_util.canBuildLibCompilerRt(target, use_llvm, build_options.have_llvm and use_llvm)) {
1820 if (output_mode == .Obj) break :s .zcu;1820 if (output_mode == .Obj) break :s .zcu;
1821 if (target.ofmt == .coff and target_util.zigBackend(target, use_llvm) == .stage2_x86_64)1821 if (switch (target_util.zigBackend(target, use_llvm)) {
1822 break :s if (is_exe_or_dyn_lib) .dyn_lib else .zcu;1822 else => false,
1823 .stage2_aarch64, .stage2_x86_64 => target.ofmt == .coff,
1824 }) break :s if (is_exe_or_dyn_lib) .dyn_lib else .zcu;
1823 }1825 }
1824 if (is_exe_or_dyn_lib) break :s .lib;1826 if (is_exe_or_dyn_lib) break :s .lib;
1825 break :s .obj;1827 break :s .obj;
...@@ -1850,11 +1852,11 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1850,11 +1852,11 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1850 // approach, since the ubsan runtime uses quite a lot of the standard library1852 // approach, since the ubsan runtime uses quite a lot of the standard library
1851 // and this reduces unnecessary bloat.1853 // and this reduces unnecessary bloat.
1852 const ubsan_rt_strat: RtStrat = s: {1854 const ubsan_rt_strat: RtStrat = s: {
1853 const can_build_ubsan_rt = target_util.canBuildLibUbsanRt(target);1855 const can_build_ubsan_rt = target_util.canBuildLibUbsanRt(target, use_llvm, build_options.have_llvm);
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);1856 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 if (!want_ubsan_rt) break :s .none;1857 if (!want_ubsan_rt) break :s .none;
1856 if (options.skip_linker_dependencies) break :s .none;1858 if (options.skip_linker_dependencies) break :s .none;
1857 if (have_zcu) break :s .zcu;1859 if (have_zcu and target_util.canBuildLibUbsanRt(target, use_llvm, build_options.have_llvm and use_llvm)) break :s .zcu;
1858 if (is_exe_or_dyn_lib) break :s .lib;1860 if (is_exe_or_dyn_lib) break :s .lib;
1859 break :s .obj;1861 break :s .obj;
1860 };1862 };
...@@ -3382,7 +3384,7 @@ pub fn saveState(comp: *Compilation) !void {...@@ -3382,7 +3384,7 @@ pub fn saveState(comp: *Compilation) !void {
33823384
3383 const gpa = comp.gpa;3385 const gpa = comp.gpa;
33843386
3385 var bufs = std.ArrayList(std.posix.iovec_const).init(gpa);3387 var bufs = std.ArrayList([]const u8).init(gpa);
3386 defer bufs.deinit();3388 defer bufs.deinit();
33873389
3388 var pt_headers = std.ArrayList(Header.PerThread).init(gpa);3390 var pt_headers = std.ArrayList(Header.PerThread).init(gpa);
...@@ -3421,50 +3423,50 @@ pub fn saveState(comp: *Compilation) !void {...@@ -3421,50 +3423,50 @@ pub fn saveState(comp: *Compilation) !void {
34213423
3422 try bufs.ensureTotalCapacityPrecise(14 + 8 * pt_headers.items.len);3424 try bufs.ensureTotalCapacityPrecise(14 + 8 * pt_headers.items.len);
3423 addBuf(&bufs, mem.asBytes(&header));3425 addBuf(&bufs, mem.asBytes(&header));
3424 addBuf(&bufs, mem.sliceAsBytes(pt_headers.items));3426 addBuf(&bufs, @ptrCast(pt_headers.items));
34253427
3426 addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.keys()));3428 addBuf(&bufs, @ptrCast(ip.src_hash_deps.keys()));
3427 addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.values()));3429 addBuf(&bufs, @ptrCast(ip.src_hash_deps.values()));
3428 addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.keys()));3430 addBuf(&bufs, @ptrCast(ip.nav_val_deps.keys()));
3429 addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.values()));3431 addBuf(&bufs, @ptrCast(ip.nav_val_deps.values()));
3430 addBuf(&bufs, mem.sliceAsBytes(ip.nav_ty_deps.keys()));3432 addBuf(&bufs, @ptrCast(ip.nav_ty_deps.keys()));
3431 addBuf(&bufs, mem.sliceAsBytes(ip.nav_ty_deps.values()));3433 addBuf(&bufs, @ptrCast(ip.nav_ty_deps.values()));
3432 addBuf(&bufs, mem.sliceAsBytes(ip.interned_deps.keys()));3434 addBuf(&bufs, @ptrCast(ip.interned_deps.keys()));
3433 addBuf(&bufs, mem.sliceAsBytes(ip.interned_deps.values()));3435 addBuf(&bufs, @ptrCast(ip.interned_deps.values()));
3434 addBuf(&bufs, mem.sliceAsBytes(ip.zon_file_deps.keys()));3436 addBuf(&bufs, @ptrCast(ip.zon_file_deps.keys()));
3435 addBuf(&bufs, mem.sliceAsBytes(ip.zon_file_deps.values()));3437 addBuf(&bufs, @ptrCast(ip.zon_file_deps.values()));
3436 addBuf(&bufs, mem.sliceAsBytes(ip.embed_file_deps.keys()));3438 addBuf(&bufs, @ptrCast(ip.embed_file_deps.keys()));
3437 addBuf(&bufs, mem.sliceAsBytes(ip.embed_file_deps.values()));3439 addBuf(&bufs, @ptrCast(ip.embed_file_deps.values()));
3438 addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.keys()));3440 addBuf(&bufs, @ptrCast(ip.namespace_deps.keys()));
3439 addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.values()));3441 addBuf(&bufs, @ptrCast(ip.namespace_deps.values()));
3440 addBuf(&bufs, mem.sliceAsBytes(ip.namespace_name_deps.keys()));3442 addBuf(&bufs, @ptrCast(ip.namespace_name_deps.keys()));
3441 addBuf(&bufs, mem.sliceAsBytes(ip.namespace_name_deps.values()));3443 addBuf(&bufs, @ptrCast(ip.namespace_name_deps.values()));
34423444
3443 addBuf(&bufs, mem.sliceAsBytes(ip.first_dependency.keys()));3445 addBuf(&bufs, @ptrCast(ip.first_dependency.keys()));
3444 addBuf(&bufs, mem.sliceAsBytes(ip.first_dependency.values()));3446 addBuf(&bufs, @ptrCast(ip.first_dependency.values()));
3445 addBuf(&bufs, mem.sliceAsBytes(ip.dep_entries.items));3447 addBuf(&bufs, @ptrCast(ip.dep_entries.items));
3446 addBuf(&bufs, mem.sliceAsBytes(ip.free_dep_entries.items));3448 addBuf(&bufs, @ptrCast(ip.free_dep_entries.items));
34473449
3448 for (ip.locals, pt_headers.items) |*local, pt_header| {3450 for (ip.locals, pt_headers.items) |*local, pt_header| {
3449 if (pt_header.intern_pool.limbs_len > 0) {3451 if (pt_header.intern_pool.limbs_len > 0) {
3450 addBuf(&bufs, mem.sliceAsBytes(local.shared.limbs.view().items(.@"0")[0..pt_header.intern_pool.limbs_len]));3452 addBuf(&bufs, @ptrCast(local.shared.limbs.view().items(.@"0")[0..pt_header.intern_pool.limbs_len]));
3451 }3453 }
3452 if (pt_header.intern_pool.extra_len > 0) {3454 if (pt_header.intern_pool.extra_len > 0) {
3453 addBuf(&bufs, mem.sliceAsBytes(local.shared.extra.view().items(.@"0")[0..pt_header.intern_pool.extra_len]));3455 addBuf(&bufs, @ptrCast(local.shared.extra.view().items(.@"0")[0..pt_header.intern_pool.extra_len]));
3454 }3456 }
3455 if (pt_header.intern_pool.items_len > 0) {3457 if (pt_header.intern_pool.items_len > 0) {
3456 addBuf(&bufs, mem.sliceAsBytes(local.shared.items.view().items(.data)[0..pt_header.intern_pool.items_len]));3458 addBuf(&bufs, @ptrCast(local.shared.items.view().items(.data)[0..pt_header.intern_pool.items_len]));
3457 addBuf(&bufs, mem.sliceAsBytes(local.shared.items.view().items(.tag)[0..pt_header.intern_pool.items_len]));3459 addBuf(&bufs, @ptrCast(local.shared.items.view().items(.tag)[0..pt_header.intern_pool.items_len]));
3458 }3460 }
3459 if (pt_header.intern_pool.string_bytes_len > 0) {3461 if (pt_header.intern_pool.string_bytes_len > 0) {
3460 addBuf(&bufs, local.shared.strings.view().items(.@"0")[0..pt_header.intern_pool.string_bytes_len]);3462 addBuf(&bufs, local.shared.strings.view().items(.@"0")[0..pt_header.intern_pool.string_bytes_len]);
3461 }3463 }
3462 if (pt_header.intern_pool.tracked_insts_len > 0) {3464 if (pt_header.intern_pool.tracked_insts_len > 0) {
3463 addBuf(&bufs, mem.sliceAsBytes(local.shared.tracked_insts.view().items(.@"0")[0..pt_header.intern_pool.tracked_insts_len]));3465 addBuf(&bufs, @ptrCast(local.shared.tracked_insts.view().items(.@"0")[0..pt_header.intern_pool.tracked_insts_len]));
3464 }3466 }
3465 if (pt_header.intern_pool.files_len > 0) {3467 if (pt_header.intern_pool.files_len > 0) {
3466 addBuf(&bufs, mem.sliceAsBytes(local.shared.files.view().items(.bin_digest)[0..pt_header.intern_pool.files_len]));3468 addBuf(&bufs, @ptrCast(local.shared.files.view().items(.bin_digest)[0..pt_header.intern_pool.files_len]));
3467 addBuf(&bufs, mem.sliceAsBytes(local.shared.files.view().items(.root_type)[0..pt_header.intern_pool.files_len]));3469 addBuf(&bufs, @ptrCast(local.shared.files.view().items(.root_type)[0..pt_header.intern_pool.files_len]));
3468 }3470 }
3469 }3471 }
34703472
...@@ -3482,95 +3484,95 @@ pub fn saveState(comp: *Compilation) !void {...@@ -3482,95 +3484,95 @@ pub fn saveState(comp: *Compilation) !void {
3482 try bufs.ensureUnusedCapacity(85);3484 try bufs.ensureUnusedCapacity(85);
3483 addBuf(&bufs, wasm.string_bytes.items);3485 addBuf(&bufs, wasm.string_bytes.items);
3484 // TODO make it well-defined memory layout3486 // TODO make it well-defined memory layout
3485 //addBuf(&bufs, mem.sliceAsBytes(wasm.objects.items));3487 //addBuf(&bufs, @ptrCast(wasm.objects.items));
3486 addBuf(&bufs, mem.sliceAsBytes(wasm.func_types.keys()));3488 addBuf(&bufs, @ptrCast(wasm.func_types.keys()));
3487 addBuf(&bufs, mem.sliceAsBytes(wasm.object_function_imports.keys()));3489 addBuf(&bufs, @ptrCast(wasm.object_function_imports.keys()));
3488 addBuf(&bufs, mem.sliceAsBytes(wasm.object_function_imports.values()));3490 addBuf(&bufs, @ptrCast(wasm.object_function_imports.values()));
3489 addBuf(&bufs, mem.sliceAsBytes(wasm.object_functions.items));3491 addBuf(&bufs, @ptrCast(wasm.object_functions.items));
3490 addBuf(&bufs, mem.sliceAsBytes(wasm.object_global_imports.keys()));3492 addBuf(&bufs, @ptrCast(wasm.object_global_imports.keys()));
3491 addBuf(&bufs, mem.sliceAsBytes(wasm.object_global_imports.values()));3493 addBuf(&bufs, @ptrCast(wasm.object_global_imports.values()));
3492 addBuf(&bufs, mem.sliceAsBytes(wasm.object_globals.items));3494 addBuf(&bufs, @ptrCast(wasm.object_globals.items));
3493 addBuf(&bufs, mem.sliceAsBytes(wasm.object_table_imports.keys()));3495 addBuf(&bufs, @ptrCast(wasm.object_table_imports.keys()));
3494 addBuf(&bufs, mem.sliceAsBytes(wasm.object_table_imports.values()));3496 addBuf(&bufs, @ptrCast(wasm.object_table_imports.values()));
3495 addBuf(&bufs, mem.sliceAsBytes(wasm.object_tables.items));3497 addBuf(&bufs, @ptrCast(wasm.object_tables.items));
3496 addBuf(&bufs, mem.sliceAsBytes(wasm.object_memory_imports.keys()));3498 addBuf(&bufs, @ptrCast(wasm.object_memory_imports.keys()));
3497 addBuf(&bufs, mem.sliceAsBytes(wasm.object_memory_imports.values()));3499 addBuf(&bufs, @ptrCast(wasm.object_memory_imports.values()));
3498 addBuf(&bufs, mem.sliceAsBytes(wasm.object_memories.items));3500 addBuf(&bufs, @ptrCast(wasm.object_memories.items));
3499 addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations.items(.tag)));3501 addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.tag)));
3500 addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations.items(.offset)));3502 addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.offset)));
3501 // TODO handle the union safety field3503 // TODO handle the union safety field
3502 //addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations.items(.pointee)));3504 //addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.pointee)));
3503 addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations.items(.addend)));3505 addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.addend)));
3504 addBuf(&bufs, mem.sliceAsBytes(wasm.object_init_funcs.items));3506 addBuf(&bufs, @ptrCast(wasm.object_init_funcs.items));
3505 addBuf(&bufs, mem.sliceAsBytes(wasm.object_data_segments.items));3507 addBuf(&bufs, @ptrCast(wasm.object_data_segments.items));
3506 addBuf(&bufs, mem.sliceAsBytes(wasm.object_datas.items));3508 addBuf(&bufs, @ptrCast(wasm.object_datas.items));
3507 addBuf(&bufs, mem.sliceAsBytes(wasm.object_data_imports.keys()));3509 addBuf(&bufs, @ptrCast(wasm.object_data_imports.keys()));
3508 addBuf(&bufs, mem.sliceAsBytes(wasm.object_data_imports.values()));3510 addBuf(&bufs, @ptrCast(wasm.object_data_imports.values()));
3509 addBuf(&bufs, mem.sliceAsBytes(wasm.object_custom_segments.keys()));3511 addBuf(&bufs, @ptrCast(wasm.object_custom_segments.keys()));
3510 addBuf(&bufs, mem.sliceAsBytes(wasm.object_custom_segments.values()));3512 addBuf(&bufs, @ptrCast(wasm.object_custom_segments.values()));
3511 // TODO make it well-defined memory layout3513 // TODO make it well-defined memory layout
3512 // addBuf(&bufs, mem.sliceAsBytes(wasm.object_comdats.items));3514 // addBuf(&bufs, @ptrCast(wasm.object_comdats.items));
3513 addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations_table.keys()));3515 addBuf(&bufs, @ptrCast(wasm.object_relocations_table.keys()));
3514 addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations_table.values()));3516 addBuf(&bufs, @ptrCast(wasm.object_relocations_table.values()));
3515 addBuf(&bufs, mem.sliceAsBytes(wasm.object_comdat_symbols.items(.kind)));3517 addBuf(&bufs, @ptrCast(wasm.object_comdat_symbols.items(.kind)));
3516 addBuf(&bufs, mem.sliceAsBytes(wasm.object_comdat_symbols.items(.index)));3518 addBuf(&bufs, @ptrCast(wasm.object_comdat_symbols.items(.index)));
3517 addBuf(&bufs, mem.sliceAsBytes(wasm.out_relocs.items(.tag)));3519 addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.tag)));
3518 addBuf(&bufs, mem.sliceAsBytes(wasm.out_relocs.items(.offset)));3520 addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.offset)));
3519 // TODO handle the union safety field3521 // TODO handle the union safety field
3520 //addBuf(&bufs, mem.sliceAsBytes(wasm.out_relocs.items(.pointee)));3522 //addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.pointee)));
3521 addBuf(&bufs, mem.sliceAsBytes(wasm.out_relocs.items(.addend)));3523 addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.addend)));
3522 addBuf(&bufs, mem.sliceAsBytes(wasm.uav_fixups.items));3524 addBuf(&bufs, @ptrCast(wasm.uav_fixups.items));
3523 addBuf(&bufs, mem.sliceAsBytes(wasm.nav_fixups.items));3525 addBuf(&bufs, @ptrCast(wasm.nav_fixups.items));
3524 addBuf(&bufs, mem.sliceAsBytes(wasm.func_table_fixups.items));3526 addBuf(&bufs, @ptrCast(wasm.func_table_fixups.items));
3525 if (is_obj) {3527 if (is_obj) {
3526 addBuf(&bufs, mem.sliceAsBytes(wasm.navs_obj.keys()));3528 addBuf(&bufs, @ptrCast(wasm.navs_obj.keys()));
3527 addBuf(&bufs, mem.sliceAsBytes(wasm.navs_obj.values()));3529 addBuf(&bufs, @ptrCast(wasm.navs_obj.values()));
3528 addBuf(&bufs, mem.sliceAsBytes(wasm.uavs_obj.keys()));3530 addBuf(&bufs, @ptrCast(wasm.uavs_obj.keys()));
3529 addBuf(&bufs, mem.sliceAsBytes(wasm.uavs_obj.values()));3531 addBuf(&bufs, @ptrCast(wasm.uavs_obj.values()));
3530 } else {3532 } else {
3531 addBuf(&bufs, mem.sliceAsBytes(wasm.navs_exe.keys()));3533 addBuf(&bufs, @ptrCast(wasm.navs_exe.keys()));
3532 addBuf(&bufs, mem.sliceAsBytes(wasm.navs_exe.values()));3534 addBuf(&bufs, @ptrCast(wasm.navs_exe.values()));
3533 addBuf(&bufs, mem.sliceAsBytes(wasm.uavs_exe.keys()));3535 addBuf(&bufs, @ptrCast(wasm.uavs_exe.keys()));
3534 addBuf(&bufs, mem.sliceAsBytes(wasm.uavs_exe.values()));3536 addBuf(&bufs, @ptrCast(wasm.uavs_exe.values()));
3535 }3537 }
3536 addBuf(&bufs, mem.sliceAsBytes(wasm.overaligned_uavs.keys()));3538 addBuf(&bufs, @ptrCast(wasm.overaligned_uavs.keys()));
3537 addBuf(&bufs, mem.sliceAsBytes(wasm.overaligned_uavs.values()));3539 addBuf(&bufs, @ptrCast(wasm.overaligned_uavs.values()));
3538 addBuf(&bufs, mem.sliceAsBytes(wasm.zcu_funcs.keys()));3540 addBuf(&bufs, @ptrCast(wasm.zcu_funcs.keys()));
3539 // TODO handle the union safety field3541 // TODO handle the union safety field
3540 // addBuf(&bufs, mem.sliceAsBytes(wasm.zcu_funcs.values()));3542 // addBuf(&bufs, @ptrCast(wasm.zcu_funcs.values()));
3541 addBuf(&bufs, mem.sliceAsBytes(wasm.nav_exports.keys()));3543 addBuf(&bufs, @ptrCast(wasm.nav_exports.keys()));
3542 addBuf(&bufs, mem.sliceAsBytes(wasm.nav_exports.values()));3544 addBuf(&bufs, @ptrCast(wasm.nav_exports.values()));
3543 addBuf(&bufs, mem.sliceAsBytes(wasm.uav_exports.keys()));3545 addBuf(&bufs, @ptrCast(wasm.uav_exports.keys()));
3544 addBuf(&bufs, mem.sliceAsBytes(wasm.uav_exports.values()));3546 addBuf(&bufs, @ptrCast(wasm.uav_exports.values()));
3545 addBuf(&bufs, mem.sliceAsBytes(wasm.imports.keys()));3547 addBuf(&bufs, @ptrCast(wasm.imports.keys()));
3546 addBuf(&bufs, mem.sliceAsBytes(wasm.missing_exports.keys()));3548 addBuf(&bufs, @ptrCast(wasm.missing_exports.keys()));
3547 addBuf(&bufs, mem.sliceAsBytes(wasm.function_exports.keys()));3549 addBuf(&bufs, @ptrCast(wasm.function_exports.keys()));
3548 addBuf(&bufs, mem.sliceAsBytes(wasm.function_exports.values()));3550 addBuf(&bufs, @ptrCast(wasm.function_exports.values()));
3549 addBuf(&bufs, mem.sliceAsBytes(wasm.hidden_function_exports.keys()));3551 addBuf(&bufs, @ptrCast(wasm.hidden_function_exports.keys()));
3550 addBuf(&bufs, mem.sliceAsBytes(wasm.hidden_function_exports.values()));3552 addBuf(&bufs, @ptrCast(wasm.hidden_function_exports.values()));
3551 addBuf(&bufs, mem.sliceAsBytes(wasm.global_exports.items));3553 addBuf(&bufs, @ptrCast(wasm.global_exports.items));
3552 addBuf(&bufs, mem.sliceAsBytes(wasm.functions.keys()));3554 addBuf(&bufs, @ptrCast(wasm.functions.keys()));
3553 addBuf(&bufs, mem.sliceAsBytes(wasm.function_imports.keys()));3555 addBuf(&bufs, @ptrCast(wasm.function_imports.keys()));
3554 addBuf(&bufs, mem.sliceAsBytes(wasm.function_imports.values()));3556 addBuf(&bufs, @ptrCast(wasm.function_imports.values()));
3555 addBuf(&bufs, mem.sliceAsBytes(wasm.data_imports.keys()));3557 addBuf(&bufs, @ptrCast(wasm.data_imports.keys()));
3556 addBuf(&bufs, mem.sliceAsBytes(wasm.data_imports.values()));3558 addBuf(&bufs, @ptrCast(wasm.data_imports.values()));
3557 addBuf(&bufs, mem.sliceAsBytes(wasm.data_segments.keys()));3559 addBuf(&bufs, @ptrCast(wasm.data_segments.keys()));
3558 addBuf(&bufs, mem.sliceAsBytes(wasm.globals.keys()));3560 addBuf(&bufs, @ptrCast(wasm.globals.keys()));
3559 addBuf(&bufs, mem.sliceAsBytes(wasm.global_imports.keys()));3561 addBuf(&bufs, @ptrCast(wasm.global_imports.keys()));
3560 addBuf(&bufs, mem.sliceAsBytes(wasm.global_imports.values()));3562 addBuf(&bufs, @ptrCast(wasm.global_imports.values()));
3561 addBuf(&bufs, mem.sliceAsBytes(wasm.tables.keys()));3563 addBuf(&bufs, @ptrCast(wasm.tables.keys()));
3562 addBuf(&bufs, mem.sliceAsBytes(wasm.table_imports.keys()));3564 addBuf(&bufs, @ptrCast(wasm.table_imports.keys()));
3563 addBuf(&bufs, mem.sliceAsBytes(wasm.table_imports.values()));3565 addBuf(&bufs, @ptrCast(wasm.table_imports.values()));
3564 addBuf(&bufs, mem.sliceAsBytes(wasm.zcu_indirect_function_set.keys()));3566 addBuf(&bufs, @ptrCast(wasm.zcu_indirect_function_set.keys()));
3565 addBuf(&bufs, mem.sliceAsBytes(wasm.object_indirect_function_import_set.keys()));3567 addBuf(&bufs, @ptrCast(wasm.object_indirect_function_import_set.keys()));
3566 addBuf(&bufs, mem.sliceAsBytes(wasm.object_indirect_function_set.keys()));3568 addBuf(&bufs, @ptrCast(wasm.object_indirect_function_set.keys()));
3567 addBuf(&bufs, mem.sliceAsBytes(wasm.mir_instructions.items(.tag)));3569 addBuf(&bufs, @ptrCast(wasm.mir_instructions.items(.tag)));
3568 // TODO handle the union safety field3570 // TODO handle the union safety field
3569 //addBuf(&bufs, mem.sliceAsBytes(wasm.mir_instructions.items(.data)));3571 //addBuf(&bufs, @ptrCast(wasm.mir_instructions.items(.data)));
3570 addBuf(&bufs, mem.sliceAsBytes(wasm.mir_extra.items));3572 addBuf(&bufs, @ptrCast(wasm.mir_extra.items));
3571 addBuf(&bufs, mem.sliceAsBytes(wasm.mir_locals.items));3573 addBuf(&bufs, @ptrCast(wasm.mir_locals.items));
3572 addBuf(&bufs, mem.sliceAsBytes(wasm.tag_name_bytes.items));3574 addBuf(&bufs, @ptrCast(wasm.tag_name_bytes.items));
3573 addBuf(&bufs, mem.sliceAsBytes(wasm.tag_name_offs.items));3575 addBuf(&bufs, @ptrCast(wasm.tag_name_offs.items));
35743576
3575 // TODO add as header fields3577 // TODO add as header fields
3576 // entry_resolution: FunctionImport.Resolution3578 // entry_resolution: FunctionImport.Resolution
...@@ -3596,16 +3598,16 @@ pub fn saveState(comp: *Compilation) !void {...@@ -3596,16 +3598,16 @@ pub fn saveState(comp: *Compilation) !void {
35963598
3597 // Using an atomic file prevents a crash or power failure from corrupting3599 // Using an atomic file prevents a crash or power failure from corrupting
3598 // the previous incremental compilation state.3600 // the previous incremental compilation state.
3599 var af = try lf.emit.root_dir.handle.atomicFile(basename, .{});3601 var write_buffer: [1024]u8 = undefined;
3602 var af = try lf.emit.root_dir.handle.atomicFile(basename, .{ .write_buffer = &write_buffer });
3600 defer af.deinit();3603 defer af.deinit();
3601 try af.file.pwritevAll(bufs.items, 0);3604 try af.file_writer.interface.writeVecAll(bufs.items);
3602 try af.finish();3605 try af.finish();
3603}3606}
36043607
3605fn addBuf(list: *std.ArrayList(std.posix.iovec_const), buf: []const u8) void {3608fn addBuf(list: *std.ArrayList([]const u8), buf: []const u8) void {
3606 // Even when len=0, the undefined pointer might cause EFAULT.
3607 if (buf.len == 0) return;3609 if (buf.len == 0) return;
3608 list.appendAssumeCapacity(.{ .base = buf.ptr, .len = buf.len });3610 list.appendAssumeCapacity(buf);
3609}3611}
36103612
3611/// This function is temporally single-threaded.3613/// This function is temporally single-threaded.
...@@ -4862,6 +4864,9 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {...@@ -4862,6 +4864,9 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {
4862 };4864 };
4863 defer tar_file.close();4865 defer tar_file.close();
48644866
4867 var buffer: [1024]u8 = undefined;
4868 var tar_file_writer = tar_file.writer(&buffer);
4869
4865 var seen_table: std.AutoArrayHashMapUnmanaged(*Package.Module, []const u8) = .empty;4870 var seen_table: std.AutoArrayHashMapUnmanaged(*Package.Module, []const u8) = .empty;
4866 defer seen_table.deinit(comp.gpa);4871 defer seen_table.deinit(comp.gpa);
48674872
...@@ -4871,32 +4876,45 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {...@@ -4871,32 +4876,45 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {
4871 var i: usize = 0;4876 var i: usize = 0;
4872 while (i < seen_table.count()) : (i += 1) {4877 while (i < seen_table.count()) : (i += 1) {
4873 const mod = seen_table.keys()[i];4878 const mod = seen_table.keys()[i];
4874 try comp.docsCopyModule(mod, seen_table.values()[i], tar_file);4879 try comp.docsCopyModule(mod, seen_table.values()[i], &tar_file_writer);
48754880
4876 const deps = mod.deps.values();4881 const deps = mod.deps.values();
4877 try seen_table.ensureUnusedCapacity(comp.gpa, deps.len);4882 try seen_table.ensureUnusedCapacity(comp.gpa, deps.len);
4878 for (deps) |dep| seen_table.putAssumeCapacity(dep, dep.fully_qualified_name);4883 for (deps) |dep| seen_table.putAssumeCapacity(dep, dep.fully_qualified_name);
4879 }4884 }
4885
4886 tar_file_writer.end() catch |err| {
4887 return comp.lockAndSetMiscFailure(
4888 .docs_copy,
4889 "unable to write '{f}/sources.tar': {t}",
4890 .{ docs_path, err },
4891 );
4892 };
4880}4893}
48814894
4882fn docsCopyModule(comp: *Compilation, module: *Package.Module, name: []const u8, tar_file: fs.File) !void {4895fn docsCopyModule(
4896 comp: *Compilation,
4897 module: *Package.Module,
4898 name: []const u8,
4899 tar_file_writer: *fs.File.Writer,
4900) !void {
4883 const root = module.root;4901 const root = module.root;
4884 var mod_dir = d: {4902 var mod_dir = d: {
4885 const root_dir, const sub_path = root.openInfo(comp.dirs);4903 const root_dir, const sub_path = root.openInfo(comp.dirs);
4886 break :d root_dir.openDir(sub_path, .{ .iterate = true });4904 break :d root_dir.openDir(sub_path, .{ .iterate = true });
4887 } catch |err| {4905 } catch |err| {
4888 return comp.lockAndSetMiscFailure(.docs_copy, "unable to open directory '{f}': {s}", .{4906 return comp.lockAndSetMiscFailure(.docs_copy, "unable to open directory '{f}': {t}", .{ root.fmt(comp), err });
4889 root.fmt(comp), @errorName(err),
4890 });
4891 };4907 };
4892 defer mod_dir.close();4908 defer mod_dir.close();
48934909
4894 var walker = try mod_dir.walk(comp.gpa);4910 var walker = try mod_dir.walk(comp.gpa);
4895 defer walker.deinit();4911 defer walker.deinit();
48964912
4897 var archiver = std.tar.writer(tar_file.deprecatedWriter().any());4913 var archiver: std.tar.Writer = .{ .underlying_writer = &tar_file_writer.interface };
4898 archiver.prefix = name;4914 archiver.prefix = name;
48994915
4916 var buffer: [1024]u8 = undefined;
4917
4900 while (try walker.next()) |entry| {4918 while (try walker.next()) |entry| {
4901 switch (entry.kind) {4919 switch (entry.kind) {
4902 .file => {4920 .file => {
...@@ -4907,14 +4925,17 @@ fn docsCopyModule(comp: *Compilation, module: *Package.Module, name: []const u8,...@@ -4907,14 +4925,17 @@ fn docsCopyModule(comp: *Compilation, module: *Package.Module, name: []const u8,
4907 else => continue,4925 else => continue,
4908 }4926 }
4909 var file = mod_dir.openFile(entry.path, .{}) catch |err| {4927 var file = mod_dir.openFile(entry.path, .{}) catch |err| {
4910 return comp.lockAndSetMiscFailure(.docs_copy, "unable to open '{f}{s}': {s}", .{4928 return comp.lockAndSetMiscFailure(.docs_copy, "unable to open {f}{s}: {t}", .{
4911 root.fmt(comp), entry.path, @errorName(err),4929 root.fmt(comp), entry.path, err,
4912 });4930 });
4913 };4931 };
4914 defer file.close();4932 defer file.close();
4915 archiver.writeFile(entry.path, file) catch |err| {4933 const stat = try file.stat();
4916 return comp.lockAndSetMiscFailure(.docs_copy, "unable to archive '{f}{s}': {s}", .{4934 var file_reader: fs.File.Reader = .initSize(file, &buffer, stat.size);
4917 root.fmt(comp), entry.path, @errorName(err),4935
4936 archiver.writeFile(entry.path, &file_reader, stat.mtime) catch |err| {
4937 return comp.lockAndSetMiscFailure(.docs_copy, "unable to archive {f}{s}: {t}", .{
4938 root.fmt(comp), entry.path, err,
4918 });4939 });
4919 };4940 };
4920 }4941 }
...@@ -4926,9 +4947,7 @@ fn workerDocsWasm(comp: *Compilation, parent_prog_node: std.Progress.Node) void...@@ -4926,9 +4947,7 @@ fn workerDocsWasm(comp: *Compilation, parent_prog_node: std.Progress.Node) void
49264947
4927 workerDocsWasmFallible(comp, prog_node) catch |err| switch (err) {4948 workerDocsWasmFallible(comp, prog_node) catch |err| switch (err) {
4928 error.SubCompilationFailed => return, // error reported already4949 error.SubCompilationFailed => return, // error reported already
4929 else => comp.lockAndSetMiscFailure(.docs_wasm, "unable to build autodocs: {s}", .{4950 else => comp.lockAndSetMiscFailure(.docs_wasm, "unable to build autodocs: {t}", .{err}),
4930 @errorName(err),
4931 }),
4932 };4951 };
4933}4952}
49344953
...@@ -6206,19 +6225,20 @@ fn spawnZigRc(...@@ -6206,19 +6225,20 @@ fn spawnZigRc(
6206 return comp.failWin32Resource(win32_resource, "unable to spawn {s} rc: {s}", .{ argv[0], @errorName(err) });6225 return comp.failWin32Resource(win32_resource, "unable to spawn {s} rc: {s}", .{ argv[0], @errorName(err) });
6207 };6226 };
62086227
6209 var poller = std.io.poll(comp.gpa, enum { stdout }, .{6228 var poller = std.Io.poll(comp.gpa, enum { stdout, stderr }, .{
6210 .stdout = child.stdout.?,6229 .stdout = child.stdout.?,
6230 .stderr = child.stderr.?,
6211 });6231 });
6212 defer poller.deinit();6232 defer poller.deinit();
62136233
6214 const stdout = poller.fifo(.stdout);6234 const stdout = poller.reader(.stdout);
62156235
6216 poll: while (true) {6236 poll: while (true) {
6217 while (stdout.readableLength() < @sizeOf(std.zig.Server.Message.Header)) if (!try poller.poll()) break :poll;6237 const MessageHeader = std.zig.Server.Message.Header;
6218 var header: std.zig.Server.Message.Header = undefined;6238 while (stdout.buffered().len < @sizeOf(MessageHeader)) if (!try poller.poll()) break :poll;
6219 assert(stdout.read(std.mem.asBytes(&header)) == @sizeOf(std.zig.Server.Message.Header));6239 const header = stdout.takeStruct(MessageHeader, .little) catch unreachable;
6220 while (stdout.readableLength() < header.bytes_len) if (!try poller.poll()) break :poll;6240 while (stdout.buffered().len < header.bytes_len) if (!try poller.poll()) break :poll;
6221 const body = stdout.readableSliceOfLen(header.bytes_len);6241 const body = stdout.take(header.bytes_len) catch unreachable;
62226242
6223 switch (header.tag) {6243 switch (header.tag) {
6224 // We expect exactly one ErrorBundle, and if any error_bundle header is6244 // We expect exactly one ErrorBundle, and if any error_bundle header is
...@@ -6241,13 +6261,10 @@ fn spawnZigRc(...@@ -6241,13 +6261,10 @@ fn spawnZigRc(
6241 },6261 },
6242 else => {}, // ignore other messages6262 else => {}, // ignore other messages
6243 }6263 }
6244
6245 stdout.discard(body.len);
6246 }6264 }
62476265
6248 // Just in case there's a failure that didn't send an ErrorBundle (e.g. an error return trace)6266 // Just in case there's a failure that didn't send an ErrorBundle (e.g. an error return trace)
6249 const stderr_reader = child.stderr.?.deprecatedReader();6267 const stderr = poller.reader(.stderr);
6250 const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024);
62516268
6252 const term = child.wait() catch |err| {6269 const term = child.wait() catch |err| {
6253 return comp.failWin32Resource(win32_resource, "unable to wait for {s} rc: {s}", .{ argv[0], @errorName(err) });6270 return comp.failWin32Resource(win32_resource, "unable to wait for {s} rc: {s}", .{ argv[0], @errorName(err) });
...@@ -6256,12 +6273,12 @@ fn spawnZigRc(...@@ -6256,12 +6273,12 @@ fn spawnZigRc(
6256 switch (term) {6273 switch (term) {
6257 .Exited => |code| {6274 .Exited => |code| {
6258 if (code != 0) {6275 if (code != 0) {
6259 log.err("zig rc failed with stderr:\n{s}", .{stderr});6276 log.err("zig rc failed with stderr:\n{s}", .{stderr.buffered()});
6260 return comp.failWin32Resource(win32_resource, "zig rc exited with code {d}", .{code});6277 return comp.failWin32Resource(win32_resource, "zig rc exited with code {d}", .{code});
6261 }6278 }
6262 },6279 },
6263 else => {6280 else => {
6264 log.err("zig rc terminated with stderr:\n{s}", .{stderr});6281 log.err("zig rc terminated with stderr:\n{s}", .{stderr.buffered()});
6265 return comp.failWin32Resource(win32_resource, "zig rc terminated unexpectedly", .{});6282 return comp.failWin32Resource(win32_resource, "zig rc terminated unexpectedly", .{});
6266 },6283 },
6267 }6284 }
src/InternPool.zig+10-4
...@@ -7556,12 +7556,18 @@ fn extraFuncCoerced(ip: *const InternPool, extra: Local.Extra, extra_index: u32)...@@ -7556,12 +7556,18 @@ fn extraFuncCoerced(ip: *const InternPool, extra: Local.Extra, extra_index: u32)
7556fn indexToKeyBigInt(ip: *const InternPool, tid: Zcu.PerThread.Id, limb_index: u32, positive: bool) Key {7556fn indexToKeyBigInt(ip: *const InternPool, tid: Zcu.PerThread.Id, limb_index: u32, positive: bool) Key {
7557 const limbs_items = ip.getLocalShared(tid).getLimbs().view().items(.@"0");7557 const limbs_items = ip.getLocalShared(tid).getLimbs().view().items(.@"0");
7558 const int: Int = @bitCast(limbs_items[limb_index..][0..Int.limbs_items_len].*);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 return .{ .int = .{7563 return .{ .int = .{
7560 .ty = int.ty,7564 .ty = int.ty,
7561 .storage = .{ .big_int = .{7565 .storage = if (big_int.toInt(u64)) |x|
7562 .limbs = limbs_items[limb_index + Int.limbs_items_len ..][0..int.limbs_len],7566 .{ .u64 = x }
7563 .positive = positive,7567 else |_| if (big_int.toInt(i64)) |x|
7564 } },7568 .{ .i64 = x }
7569 else |_|
7570 .{ .big_int = big_int },
7565 } };7571 } };
7566}7572}
75677573
src/Package/Fetch.zig+22-14
...@@ -1197,12 +1197,18 @@ fn unpackResource(...@@ -1197,12 +1197,18 @@ fn unpackResource(
1197 };1197 };
11981198
1199 switch (file_type) {1199 switch (file_type) {
1200 .tar => return try unpackTarball(f, tmp_directory.handle, resource.reader()),1200 .tar => {
1201 var adapter_buffer: [1024]u8 = undefined;
1202 var adapter = resource.reader().adaptToNewApi(&adapter_buffer);
1203 return unpackTarball(f, tmp_directory.handle, &adapter.new_interface);
1204 },
1201 .@"tar.gz" => {1205 .@"tar.gz" => {
1202 const reader = resource.reader();1206 const reader = resource.reader();
1203 var br = std.io.bufferedReaderSize(std.crypto.tls.max_ciphertext_record_len, reader);1207 var br = std.io.bufferedReaderSize(std.crypto.tls.max_ciphertext_record_len, reader);
1204 var dcp = std.compress.gzip.decompressor(br.reader());1208 var dcp = std.compress.gzip.decompressor(br.reader());
1205 return try unpackTarball(f, tmp_directory.handle, dcp.reader());1209 var adapter_buffer: [1024]u8 = undefined;
1210 var adapter = dcp.reader().adaptToNewApi(&adapter_buffer);
1211 return try unpackTarball(f, tmp_directory.handle, &adapter.new_interface);
1206 },1212 },
1207 .@"tar.xz" => {1213 .@"tar.xz" => {
1208 const gpa = f.arena.child_allocator;1214 const gpa = f.arena.child_allocator;
...@@ -1215,17 +1221,19 @@ fn unpackResource(...@@ -1215,17 +1221,19 @@ fn unpackResource(
1215 ));1221 ));
1216 };1222 };
1217 defer dcp.deinit();1223 defer dcp.deinit();
1218 return try unpackTarball(f, tmp_directory.handle, dcp.reader());1224 var adapter_buffer: [1024]u8 = undefined;
1225 var adapter = dcp.reader().adaptToNewApi(&adapter_buffer);
1226 return try unpackTarball(f, tmp_directory.handle, &adapter.new_interface);
1219 },1227 },
1220 .@"tar.zst" => {1228 .@"tar.zst" => {
1221 const window_size = std.compress.zstd.DecompressorOptions.default_window_buffer_len;1229 const window_size = std.compress.zstd.default_window_len;
1222 const window_buffer = try f.arena.allocator().create([window_size]u8);1230 const window_buffer = try f.arena.allocator().create([window_size]u8);
1223 const reader = resource.reader();1231 var adapter_buffer: [std.crypto.tls.max_ciphertext_record_len]u8 = undefined;
1224 var br = std.io.bufferedReaderSize(std.crypto.tls.max_ciphertext_record_len, reader);1232 var adapter = resource.reader().adaptToNewApi(&adapter_buffer);
1225 var dcp = std.compress.zstd.decompressor(br.reader(), .{1233 var decompress: std.compress.zstd.Decompress = .init(&adapter.new_interface, window_buffer, .{
1226 .window_buffer = window_buffer,1234 .verify_checksum = false,
1227 });1235 });
1228 return try unpackTarball(f, tmp_directory.handle, dcp.reader());1236 return try unpackTarball(f, tmp_directory.handle, &decompress.reader);
1229 },1237 },
1230 .git_pack => return unpackGitPack(f, tmp_directory.handle, &resource.git) catch |err| switch (err) {1238 .git_pack => return unpackGitPack(f, tmp_directory.handle, &resource.git) catch |err| switch (err) {
1231 error.FetchFailed => return error.FetchFailed,1239 error.FetchFailed => return error.FetchFailed,
...@@ -1239,7 +1247,7 @@ fn unpackResource(...@@ -1239,7 +1247,7 @@ fn unpackResource(
1239 }1247 }
1240}1248}
12411249
1242fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!UnpackResult {1250fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: *std.Io.Reader) RunError!UnpackResult {
1243 const eb = &f.error_bundle;1251 const eb = &f.error_bundle;
1244 const arena = f.arena.allocator();1252 const arena = f.arena.allocator();
12451253
...@@ -1250,10 +1258,10 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!UnpackRes...@@ -1250,10 +1258,10 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!UnpackRes
1250 .strip_components = 0,1258 .strip_components = 0,
1251 .mode_mode = .ignore,1259 .mode_mode = .ignore,
1252 .exclude_empty_directories = true,1260 .exclude_empty_directories = true,
1253 }) catch |err| return f.fail(f.location_tok, try eb.printString(1261 }) catch |err| return f.fail(
1254 "unable to unpack tarball to temporary directory: {s}",1262 f.location_tok,
1255 .{@errorName(err)},1263 try eb.printString("unable to unpack tarball to temporary directory: {t}", .{err}),
1256 ));1264 );
12571265
1258 var res: UnpackResult = .{ .root_dir = diagnostics.root_dir };1266 var res: UnpackResult = .{ .root_dir = diagnostics.root_dir };
1259 if (diagnostics.errors.items.len > 0) {1267 if (diagnostics.errors.items.len > 0) {
src/Package/Fetch/git.zig+60-5
...@@ -1281,7 +1281,7 @@ pub fn indexPack(allocator: Allocator, format: Oid.Format, pack: std.fs.File, in...@@ -1281,7 +1281,7 @@ pub fn indexPack(allocator: Allocator, format: Oid.Format, pack: std.fs.File, in
1281 }1281 }
1282 @memset(fan_out_table[fan_out_index..], count);1282 @memset(fan_out_table[fan_out_index..], count);
12831283
1284 var index_hashed_writer = std.compress.hashedWriter(index_writer, Oid.Hasher.init(format));1284 var index_hashed_writer = hashedWriter(index_writer, Oid.Hasher.init(format));
1285 const writer = index_hashed_writer.writer();1285 const writer = index_hashed_writer.writer();
1286 try writer.writeAll(IndexHeader.signature);1286 try writer.writeAll(IndexHeader.signature);
1287 try writer.writeInt(u32, IndexHeader.supported_version, .big);1287 try writer.writeInt(u32, IndexHeader.supported_version, .big);
...@@ -1331,7 +1331,7 @@ fn indexPackFirstPass(...@@ -1331,7 +1331,7 @@ fn indexPackFirstPass(
1331) !Oid {1331) !Oid {
1332 var pack_buffered_reader = std.io.bufferedReader(pack.deprecatedReader());1332 var pack_buffered_reader = std.io.bufferedReader(pack.deprecatedReader());
1333 var pack_counting_reader = std.io.countingReader(pack_buffered_reader.reader());1333 var pack_counting_reader = std.io.countingReader(pack_buffered_reader.reader());
1334 var pack_hashed_reader = std.compress.hashedReader(pack_counting_reader.reader(), Oid.Hasher.init(format));1334 var pack_hashed_reader = hashedReader(pack_counting_reader.reader(), Oid.Hasher.init(format));
1335 const pack_reader = pack_hashed_reader.reader();1335 const pack_reader = pack_hashed_reader.reader();
13361336
1337 const pack_header = try PackHeader.read(pack_reader);1337 const pack_header = try PackHeader.read(pack_reader);
...@@ -1339,13 +1339,13 @@ fn indexPackFirstPass(...@@ -1339,13 +1339,13 @@ fn indexPackFirstPass(
1339 var current_entry: u32 = 0;1339 var current_entry: u32 = 0;
1340 while (current_entry < pack_header.total_objects) : (current_entry += 1) {1340 while (current_entry < pack_header.total_objects) : (current_entry += 1) {
1341 const entry_offset = pack_counting_reader.bytes_read;1341 const entry_offset = pack_counting_reader.bytes_read;
1342 var entry_crc32_reader = std.compress.hashedReader(pack_reader, std.hash.Crc32.init());1342 var entry_crc32_reader = hashedReader(pack_reader, std.hash.Crc32.init());
1343 const entry_header = try EntryHeader.read(format, entry_crc32_reader.reader());1343 const entry_header = try EntryHeader.read(format, entry_crc32_reader.reader());
1344 switch (entry_header) {1344 switch (entry_header) {
1345 .commit, .tree, .blob, .tag => |object| {1345 .commit, .tree, .blob, .tag => |object| {
1346 var entry_decompress_stream = std.compress.zlib.decompressor(entry_crc32_reader.reader());1346 var entry_decompress_stream = std.compress.zlib.decompressor(entry_crc32_reader.reader());
1347 var entry_counting_reader = std.io.countingReader(entry_decompress_stream.reader());1347 var entry_counting_reader = std.io.countingReader(entry_decompress_stream.reader());
1348 var entry_hashed_writer = std.compress.hashedWriter(std.io.null_writer, Oid.Hasher.init(format));1348 var entry_hashed_writer = hashedWriter(std.io.null_writer, Oid.Hasher.init(format));
1349 const entry_writer = entry_hashed_writer.writer();1349 const entry_writer = entry_hashed_writer.writer();
1350 // The object header is not included in the pack data but is1350 // The object header is not included in the pack data but is
1351 // part of the object's ID1351 // part of the object's ID
...@@ -1432,7 +1432,7 @@ fn indexPackHashDelta(...@@ -1432,7 +1432,7 @@ fn indexPackHashDelta(
1432 const base_data = try resolveDeltaChain(allocator, format, pack, base_object, delta_offsets.items, cache);1432 const base_data = try resolveDeltaChain(allocator, format, pack, base_object, delta_offsets.items, cache);
14331433
1434 var entry_hasher: Oid.Hasher = .init(format);1434 var entry_hasher: Oid.Hasher = .init(format);
1435 var entry_hashed_writer = std.compress.hashedWriter(std.io.null_writer, &entry_hasher);1435 var entry_hashed_writer = hashedWriter(std.io.null_writer, &entry_hasher);
1436 try entry_hashed_writer.writer().print("{s} {}\x00", .{ @tagName(base_object.type), base_data.len });1436 try entry_hashed_writer.writer().print("{s} {}\x00", .{ @tagName(base_object.type), base_data.len });
1437 entry_hasher.update(base_data);1437 entry_hasher.update(base_data);
1438 return entry_hasher.finalResult();1438 return entry_hasher.finalResult();
...@@ -1703,3 +1703,58 @@ pub fn main() !void {...@@ -1703,3 +1703,58 @@ pub fn main() !void {
1703 std.debug.print("Diagnostic: {}\n", .{err});1703 std.debug.print("Diagnostic: {}\n", .{err});
1704 }1704 }
1705}1705}
1706
1707/// Deprecated
1708fn hashedReader(reader: anytype, hasher: anytype) HashedReader(@TypeOf(reader), @TypeOf(hasher)) {
1709 return .{ .child_reader = reader, .hasher = hasher };
1710}
1711
1712/// Deprecated
1713fn HashedReader(ReaderType: type, HasherType: type) type {
1714 return struct {
1715 child_reader: ReaderType,
1716 hasher: HasherType,
1717
1718 pub const Error = ReaderType.Error;
1719 pub const Reader = std.io.GenericReader(*@This(), Error, read);
1720
1721 pub fn read(self: *@This(), buf: []u8) Error!usize {
1722 const amt = try self.child_reader.read(buf);
1723 self.hasher.update(buf[0..amt]);
1724 return amt;
1725 }
1726
1727 pub fn reader(self: *@This()) Reader {
1728 return .{ .context = self };
1729 }
1730 };
1731}
1732
1733/// Deprecated
1734pub fn HashedWriter(WriterType: type, HasherType: type) type {
1735 return struct {
1736 child_writer: WriterType,
1737 hasher: HasherType,
1738
1739 pub const Error = WriterType.Error;
1740 pub const Writer = std.io.GenericWriter(*@This(), Error, write);
1741
1742 pub fn write(self: *@This(), buf: []const u8) Error!usize {
1743 const amt = try self.child_writer.write(buf);
1744 self.hasher.update(buf[0..amt]);
1745 return amt;
1746 }
1747
1748 pub fn writer(self: *@This()) Writer {
1749 return .{ .context = self };
1750 }
1751 };
1752}
1753
1754/// Deprecated
1755pub fn hashedWriter(
1756 writer: anytype,
1757 hasher: anytype,
1758) HashedWriter(@TypeOf(writer), @TypeOf(hasher)) {
1759 return .{ .child_writer = writer, .hasher = hasher };
1760}
src/Package/Module.zig+1-1
...@@ -250,7 +250,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {...@@ -250,7 +250,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
250 };250 };
251251
252 const stack_check = b: {252 const stack_check = b: {
253 if (!target_util.supportsStackProbing(target)) {253 if (!target_util.supportsStackProbing(target, zig_backend)) {
254 if (options.inherited.stack_check == true)254 if (options.inherited.stack_check == true)
255 return error.StackCheckUnsupportedByTarget;255 return error.StackCheckUnsupportedByTarget;
256 break :b false;256 break :b false;
src/Sema.zig+19-12
...@@ -16522,7 +16522,7 @@ fn zirAsm(...@@ -16522,7 +16522,7 @@ fn zirAsm(
16522 break :empty try sema.structInitEmpty(block, clobbers_ty, src, src);16522 break :empty try sema.structInitEmpty(block, clobbers_ty, src, src);
16523 } else try sema.resolveInst(extra.data.clobbers); // Already coerced by AstGen.16523 } else try sema.resolveInst(extra.data.clobbers); // Already coerced by AstGen.
16524 const clobbers_val = try sema.resolveConstDefinedValue(block, src, clobbers, .{ .simple = .clobber });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;
1652616526
16527 const gpa = sema.gpa;16527 const gpa = sema.gpa;
16528 try sema.air_extra.ensureUnusedCapacity(gpa, needed_capacity);16528 try sema.air_extra.ensureUnusedCapacity(gpa, needed_capacity);
...@@ -16562,7 +16562,8 @@ fn zirAsm(...@@ -16562,7 +16562,8 @@ fn zirAsm(
16562 {16562 {
16563 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());16563 const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
16564 @memcpy(buffer[0..asm_source.len], asm_source);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 return asm_air;16568 return asm_air;
16568}16569}
...@@ -22482,11 +22483,18 @@ fn ptrCastFull(...@@ -22482,11 +22483,18 @@ fn ptrCastFull(
22482 .slice => {},22483 .slice => {},
22483 .many, .c, .one => break :len null,22484 .many, .c, .one => break :len null,
22484 }22485 }
22485 // `null` means the operand is a runtime-known slice (so the length is runtime-known).22486 // A `null` length means the operand is a runtime-known slice (so the length is runtime-known).
22486 const opt_src_len: ?u64 = switch (src_info.flags.size) {22487 // `src_elem_type` is different from `src_info.child` if the latter is an array, to ensure we ignore sentinels.
22487 .one => 1,22488 const src_elem_ty: Type, const opt_src_len: ?u64 = switch (src_info.flags.size) {
22488 .slice => src_len: {22489 .one => src: {
22489 const operand_val = try sema.resolveValue(operand) orelse break :src_len null;22490 const true_child: Type = .fromInterned(src_info.child);
22491 break :src switch (true_child.zigTypeTag(zcu)) {
22492 .array => .{ true_child.childType(zcu), true_child.arrayLen(zcu) },
22493 else => .{ true_child, 1 },
22494 };
22495 },
22496 .slice => src: {
22497 const operand_val = try sema.resolveValue(operand) orelse break :src .{ .fromInterned(src_info.child), null };
22490 if (operand_val.isUndef(zcu)) break :len .undef;22498 if (operand_val.isUndef(zcu)) break :len .undef;
22491 const slice_val = switch (operand_ty.zigTypeTag(zcu)) {22499 const slice_val = switch (operand_ty.zigTypeTag(zcu)) {
22492 .optional => operand_val.optionalValue(zcu) orelse break :len .undef,22500 .optional => operand_val.optionalValue(zcu) orelse break :len .undef,
...@@ -22495,14 +22503,13 @@ fn ptrCastFull(...@@ -22495,14 +22503,13 @@ fn ptrCastFull(
22495 };22503 };
22496 const slice_len_resolved = try sema.resolveLazyValue(.fromInterned(zcu.intern_pool.sliceLen(slice_val.toIntern())));22504 const slice_len_resolved = try sema.resolveLazyValue(.fromInterned(zcu.intern_pool.sliceLen(slice_val.toIntern())));
22497 if (slice_len_resolved.isUndef(zcu)) break :len .undef;22505 if (slice_len_resolved.isUndef(zcu)) break :len .undef;
22498 break :src_len slice_len_resolved.toUnsignedInt(zcu);22506 break :src .{ .fromInterned(src_info.child), slice_len_resolved.toUnsignedInt(zcu) };
22499 },22507 },
22500 .many, .c => {22508 .many, .c => {
22501 return sema.fail(block, src, "cannot infer length of slice from {s}", .{pointerSizeString(src_info.flags.size)});22509 return sema.fail(block, src, "cannot infer length of slice from {s}", .{pointerSizeString(src_info.flags.size)});
22502 },22510 },
22503 };22511 };
22504 const dest_elem_ty: Type = .fromInterned(dest_info.child);22512 const dest_elem_ty: Type = .fromInterned(dest_info.child);
22505 const src_elem_ty: Type = .fromInterned(src_info.child);
22506 if (dest_elem_ty.toIntern() == src_elem_ty.toIntern()) {22513 if (dest_elem_ty.toIntern() == src_elem_ty.toIntern()) {
22507 break :len if (opt_src_len) |l| .{ .constant = l } else .equal_runtime_src_slice;22514 break :len if (opt_src_len) |l| .{ .constant = l } else .equal_runtime_src_slice;
22508 }22515 }
...@@ -22518,7 +22525,7 @@ fn ptrCastFull(...@@ -22518,7 +22525,7 @@ fn ptrCastFull(
22518 const bytes = src_len * src_elem_size;22525 const bytes = src_len * src_elem_size;
22519 const dest_len = std.math.divExact(u64, bytes, dest_elem_size) catch switch (src_info.flags.size) {22526 const dest_len = std.math.divExact(u64, bytes, dest_elem_size) catch switch (src_info.flags.size) {
22520 .slice => return sema.fail(block, src, "slice length '{d}' does not divide exactly into destination elements", .{src_len}),22527 .slice => return sema.fail(block, src, "slice length '{d}' does not divide exactly into destination elements", .{src_len}),
22521 .one => return sema.fail(block, src, "type '{f}' does not divide exactly into destination elements", .{src_elem_ty.fmt(pt)}),22528 .one => return sema.fail(block, src, "type '{f}' does not divide exactly into destination elements", .{Type.fromInterned(src_info.child).fmt(pt)}),
22522 else => unreachable,22529 else => unreachable,
22523 };22530 };
22524 break :len .{ .constant = dest_len };22531 break :len .{ .constant = dest_len };
...@@ -24846,7 +24853,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins...@@ -24846,7 +24853,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
24846 },24853 },
24847 .@"packed" => {24854 .@"packed" => {
24848 const byte_offset = std.math.divExact(u32, @abs(@as(i32, actual_parent_ptr_info.packed_offset.bit_offset) +24855 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) -24856 (if (zcu.typeToStruct(parent_ty)) |struct_obj| zcu.structPackedFieldBitOffset(struct_obj, field_index) else 0) -
24850 actual_field_ptr_info.packed_offset.bit_offset), 8) catch24857 actual_field_ptr_info.packed_offset.bit_offset), 8) catch
24851 return sema.fail(block, inst_src, "pointer bit-offset mismatch", .{});24858 return sema.fail(block, inst_src, "pointer bit-offset mismatch", .{});
24852 actual_parent_ptr_info.flags.alignment = actual_field_ptr_info.flags.alignment.minStrict(if (byte_offset > 0)24859 actual_parent_ptr_info.flags.alignment = actual_field_ptr_info.flags.alignment.minStrict(if (byte_offset > 0)
...@@ -24873,7 +24880,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins...@@ -24873,7 +24880,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
24873 // Logic lifted from type computation above - I'm just assuming it's correct.24880 // Logic lifted from type computation above - I'm just assuming it's correct.
24874 // `catch unreachable` since error case handled above.24881 // `catch unreachable` since error case handled above.
24875 const byte_offset = std.math.divExact(u32, @abs(@as(i32, actual_parent_ptr_info.packed_offset.bit_offset) +24882 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) -24883 zcu.structPackedFieldBitOffset(zcu.typeToStruct(parent_ty).?, field_index) -
24877 actual_field_ptr_info.packed_offset.bit_offset), 8) catch unreachable;24884 actual_field_ptr_info.packed_offset.bit_offset), 8) catch unreachable;
24878 const parent_ptr_val = try sema.ptrSubtract(block, field_ptr_src, field_ptr_val, byte_offset, actual_parent_ptr_ty);24885 const parent_ptr_val = try sema.ptrSubtract(block, field_ptr_src, field_ptr_val, byte_offset, actual_parent_ptr_ty);
24879 break :result Air.internedToRef(parent_ptr_val.toIntern());24886 break :result Air.internedToRef(parent_ptr_val.toIntern());
src/Type.zig+1-1
...@@ -4166,7 +4166,7 @@ pub const generic_poison: Type = .{ .ip_index = .generic_poison_type };...@@ -4166,7 +4166,7 @@ pub const generic_poison: Type = .{ .ip_index = .generic_poison_type };
4166pub fn smallestUnsignedBits(max: u64) u16 {4166pub fn smallestUnsignedBits(max: u64) u16 {
4167 return switch (max) {4167 return switch (max) {
4168 0 => 0,4168 0 => 0,
4169 else => 1 + std.math.log2_int(u64, max),4169 else => @as(u16, 1) + std.math.log2_int(u64, max),
4170 };4170 };
4171}4171}
41724172
src/Zcu.zig+24-5
...@@ -3891,6 +3891,29 @@ pub fn typeToPackedStruct(zcu: *const Zcu, ty: Type) ?InternPool.LoadedStructTyp...@@ -3891,6 +3891,29 @@ pub fn typeToPackedStruct(zcu: *const Zcu, ty: Type) ?InternPool.LoadedStructTyp
3891 return s;3891 return s;
3892}3892}
38933893
3894/// https://github.com/ziglang/zig/issues/17178 explored storing these bit offsets
3895/// into the packed struct InternPool data rather than computing this on the
3896/// fly, however it was found to perform worse when measured on real world
3897/// projects.
3898pub fn structPackedFieldBitOffset(
3899 zcu: *Zcu,
3900 struct_type: InternPool.LoadedStructType,
3901 field_index: u32,
3902) u16 {
3903 const ip = &zcu.intern_pool;
3904 assert(struct_type.layout == .@"packed");
3905 assert(struct_type.haveLayout(ip));
3906 var bit_sum: u64 = 0;
3907 for (0..struct_type.field_types.len) |i| {
3908 if (i == field_index) {
3909 return @intCast(bit_sum);
3910 }
3911 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
3912 bit_sum += field_ty.bitSize(zcu);
3913 }
3914 unreachable; // index out of bounds
3915}
3916
3894pub fn typeToUnion(zcu: *const Zcu, ty: Type) ?InternPool.LoadedUnionType {3917pub fn typeToUnion(zcu: *const Zcu, ty: Type) ?InternPool.LoadedUnionType {
3895 if (ty.ip_index == .none) return null;3918 if (ty.ip_index == .none) return null;
3896 const ip = &zcu.intern_pool;3919 const ip = &zcu.intern_pool;
...@@ -4436,11 +4459,7 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu...@@ -4436,11 +4459,7 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu
4436 else => false,4459 else => false,
4437 },4460 },
4438 .stage2_aarch64 => switch (cc) {4461 .stage2_aarch64 => switch (cc) {
4439 .aarch64_aapcs,4462 .aarch64_aapcs, .aarch64_aapcs_darwin, .naked => true,
4440 .aarch64_aapcs_darwin,
4441 .aarch64_aapcs_win,
4442 => |opts| opts.incoming_stack_alignment == null,
4443 .naked => true,
4444 else => false,4463 else => false,
4445 },4464 },
4446 .stage2_x86 => switch (cc) {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,30 +3737,6 @@ pub fn intBitsForValue(pt: Zcu.PerThread, val: Value, sign: bool) u16 {
3737 }3737 }
3738}3738}
37393739
3740/// https://github.com/ziglang/zig/issues/17178 explored storing these bit offsets
3741/// into the packed struct InternPool data rather than computing this on the
3742/// fly, however it was found to perform worse when measured on real world
3743/// projects.
3744pub fn structPackedFieldBitOffset(
3745 pt: Zcu.PerThread,
3746 struct_type: InternPool.LoadedStructType,
3747 field_index: u32,
3748) u16 {
3749 const zcu = pt.zcu;
3750 const ip = &zcu.intern_pool;
3751 assert(struct_type.layout == .@"packed");
3752 assert(struct_type.haveLayout(ip));
3753 var bit_sum: u64 = 0;
3754 for (0..struct_type.field_types.len) |i| {
3755 if (i == field_index) {
3756 return @intCast(bit_sum);
3757 }
3758 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
3759 bit_sum += field_ty.bitSize(zcu);
3760 }
3761 unreachable; // index out of bounds
3762}
3763
3764pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Error!Type {3740pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Error!Type {
3765 const zcu = pt.zcu;3741 const zcu = pt.zcu;
3766 const ip = &zcu.intern_pool;3742 const ip = &zcu.intern_pool;
...@@ -4381,8 +4357,11 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e...@@ -4381,8 +4357,11 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e
4381 try air.legalize(pt, features);4357 try air.legalize(pt, features);
4382 }4358 }
43834359
4384 var liveness: Air.Liveness = try .analyze(zcu, air.*, ip);4360 var liveness: ?Air.Liveness = if (codegen.wantsLiveness(pt, nav))
4385 defer liveness.deinit(gpa);4361 try .analyze(zcu, air.*, ip)
4362 else
4363 null;
4364 defer if (liveness) |*l| l.deinit(gpa);
43864365
4387 if (build_options.enable_debug_extensions and comp.verbose_air) {4366 if (build_options.enable_debug_extensions and comp.verbose_air) {
4388 const stderr = std.debug.lockStderrWriter(&.{});4367 const stderr = std.debug.lockStderrWriter(&.{});
...@@ -4392,12 +4371,12 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e...@@ -4392,12 +4371,12 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e
4392 stderr.print("# End Function AIR: {f}\n\n", .{fqn.fmt(ip)}) catch {};4371 stderr.print("# End Function AIR: {f}\n\n", .{fqn.fmt(ip)}) catch {};
4393 }4372 }
43944373
4395 if (std.debug.runtime_safety) {4374 if (std.debug.runtime_safety) verify_liveness: {
4396 var verify: Air.Liveness.Verify = .{4375 var verify: Air.Liveness.Verify = .{
4397 .gpa = gpa,4376 .gpa = gpa,
4398 .zcu = zcu,4377 .zcu = zcu,
4399 .air = air.*,4378 .air = air.*,
4400 .liveness = liveness,4379 .liveness = liveness orelse break :verify_liveness,
4401 .intern_pool = ip,4380 .intern_pool = ip,
4402 };4381 };
4403 defer verify.deinit();4382 defer verify.deinit();
src/arch/aarch64/bits.zig deleted-2063
...@@ -1,2063 +0,0 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const testing = std.testing;
5
6/// Disjoint sets of registers. Every register must belong to
7/// exactly one register class.
8pub const RegisterClass = enum {
9 general_purpose,
10 stack_pointer,
11 floating_point,
12};
13
14/// Registers in the AArch64 instruction set
15pub const Register = enum(u8) {
16 // zig fmt: off
17 // 64-bit general-purpose registers
18 x0, x1, x2, x3, x4, x5, x6, x7,
19 x8, x9, x10, x11, x12, x13, x14, x15,
20 x16, x17, x18, x19, x20, x21, x22, x23,
21 x24, x25, x26, x27, x28, x29, x30, xzr,
22
23 // 32-bit general-purpose registers
24 w0, w1, w2, w3, w4, w5, w6, w7,
25 w8, w9, w10, w11, w12, w13, w14, w15,
26 w16, w17, w18, w19, w20, w21, w22, w23,
27 w24, w25, w26, w27, w28, w29, w30, wzr,
28
29 // Stack pointer
30 sp, wsp,
31
32 // 128-bit floating-point registers
33 q0, q1, q2, q3, q4, q5, q6, q7,
34 q8, q9, q10, q11, q12, q13, q14, q15,
35 q16, q17, q18, q19, q20, q21, q22, q23,
36 q24, q25, q26, q27, q28, q29, q30, q31,
37
38 // 64-bit floating-point registers
39 d0, d1, d2, d3, d4, d5, d6, d7,
40 d8, d9, d10, d11, d12, d13, d14, d15,
41 d16, d17, d18, d19, d20, d21, d22, d23,
42 d24, d25, d26, d27, d28, d29, d30, d31,
43
44 // 32-bit floating-point registers
45 s0, s1, s2, s3, s4, s5, s6, s7,
46 s8, s9, s10, s11, s12, s13, s14, s15,
47 s16, s17, s18, s19, s20, s21, s22, s23,
48 s24, s25, s26, s27, s28, s29, s30, s31,
49
50 // 16-bit floating-point registers
51 h0, h1, h2, h3, h4, h5, h6, h7,
52 h8, h9, h10, h11, h12, h13, h14, h15,
53 h16, h17, h18, h19, h20, h21, h22, h23,
54 h24, h25, h26, h27, h28, h29, h30, h31,
55
56 // 8-bit floating-point registers
57 b0, b1, b2, b3, b4, b5, b6, b7,
58 b8, b9, b10, b11, b12, b13, b14, b15,
59 b16, b17, b18, b19, b20, b21, b22, b23,
60 b24, b25, b26, b27, b28, b29, b30, b31,
61 // zig fmt: on
62
63 pub fn class(self: Register) RegisterClass {
64 return switch (@intFromEnum(self)) {
65 @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => .general_purpose,
66 @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => .general_purpose,
67
68 @intFromEnum(Register.sp) => .stack_pointer,
69 @intFromEnum(Register.wsp) => .stack_pointer,
70
71 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => .floating_point,
72 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => .floating_point,
73 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => .floating_point,
74 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => .floating_point,
75 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => .floating_point,
76 else => unreachable,
77 };
78 }
79
80 pub fn id(self: Register) u6 {
81 return switch (@intFromEnum(self)) {
82 @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.x0))),
83 @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.w0))),
84
85 @intFromEnum(Register.sp) => 32,
86 @intFromEnum(Register.wsp) => 32,
87
88 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.q0) + 33)),
89 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.d0) + 33)),
90 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.s0) + 33)),
91 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.h0) + 33)),
92 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.b0) + 33)),
93 else => unreachable,
94 };
95 }
96
97 pub fn enc(self: Register) u5 {
98 return switch (@intFromEnum(self)) {
99 @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.x0))),
100 @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.w0))),
101
102 @intFromEnum(Register.sp) => 31,
103 @intFromEnum(Register.wsp) => 31,
104
105 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.q0))),
106 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.d0))),
107 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.s0))),
108 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.h0))),
109 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.b0))),
110 else => unreachable,
111 };
112 }
113
114 /// Returns the bit-width of the register.
115 pub fn size(self: Register) u8 {
116 return switch (@intFromEnum(self)) {
117 @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => 64,
118 @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => 32,
119
120 @intFromEnum(Register.sp) => 64,
121 @intFromEnum(Register.wsp) => 32,
122
123 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => 128,
124 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => 64,
125 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => 32,
126 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => 16,
127 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => 8,
128 else => unreachable,
129 };
130 }
131
132 /// Convert from a general-purpose register to its 64 bit alias.
133 pub fn toX(self: Register) Register {
134 return switch (@intFromEnum(self)) {
135 @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => @as(
136 Register,
137 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.x0) + @intFromEnum(Register.x0)),
138 ),
139 @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => @as(
140 Register,
141 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.w0) + @intFromEnum(Register.x0)),
142 ),
143 else => unreachable,
144 };
145 }
146
147 /// Convert from a general-purpose register to its 32 bit alias.
148 pub fn toW(self: Register) Register {
149 return switch (@intFromEnum(self)) {
150 @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => @as(
151 Register,
152 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.x0) + @intFromEnum(Register.w0)),
153 ),
154 @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => @as(
155 Register,
156 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.w0) + @intFromEnum(Register.w0)),
157 ),
158 else => unreachable,
159 };
160 }
161
162 /// Convert from a floating-point register to its 128 bit alias.
163 pub fn toQ(self: Register) Register {
164 return switch (@intFromEnum(self)) {
165 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(
166 Register,
167 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.q0)),
168 ),
169 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(
170 Register,
171 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.q0)),
172 ),
173 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(
174 Register,
175 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.q0)),
176 ),
177 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(
178 Register,
179 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.q0)),
180 ),
181 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(
182 Register,
183 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.q0)),
184 ),
185 else => unreachable,
186 };
187 }
188
189 /// Convert from a floating-point register to its 64 bit alias.
190 pub fn toD(self: Register) Register {
191 return switch (@intFromEnum(self)) {
192 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(
193 Register,
194 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.d0)),
195 ),
196 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(
197 Register,
198 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.d0)),
199 ),
200 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(
201 Register,
202 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.d0)),
203 ),
204 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(
205 Register,
206 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.d0)),
207 ),
208 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(
209 Register,
210 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.d0)),
211 ),
212 else => unreachable,
213 };
214 }
215
216 /// Convert from a floating-point register to its 32 bit alias.
217 pub fn toS(self: Register) Register {
218 return switch (@intFromEnum(self)) {
219 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(
220 Register,
221 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.s0)),
222 ),
223 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(
224 Register,
225 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.s0)),
226 ),
227 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(
228 Register,
229 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.s0)),
230 ),
231 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(
232 Register,
233 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.s0)),
234 ),
235 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(
236 Register,
237 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.s0)),
238 ),
239 else => unreachable,
240 };
241 }
242
243 /// Convert from a floating-point register to its 16 bit alias.
244 pub fn toH(self: Register) Register {
245 return switch (@intFromEnum(self)) {
246 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(
247 Register,
248 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.h0)),
249 ),
250 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(
251 Register,
252 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.h0)),
253 ),
254 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(
255 Register,
256 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.h0)),
257 ),
258 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(
259 Register,
260 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.h0)),
261 ),
262 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(
263 Register,
264 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.h0)),
265 ),
266 else => unreachable,
267 };
268 }
269
270 /// Convert from a floating-point register to its 8 bit alias.
271 pub fn toB(self: Register) Register {
272 return switch (@intFromEnum(self)) {
273 @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(
274 Register,
275 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.b0)),
276 ),
277 @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(
278 Register,
279 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.b0)),
280 ),
281 @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(
282 Register,
283 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.b0)),
284 ),
285 @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(
286 Register,
287 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.b0)),
288 ),
289 @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(
290 Register,
291 @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.b0)),
292 ),
293 else => unreachable,
294 };
295 }
296
297 pub fn dwarfNum(self: Register) u5 {
298 return self.enc();
299 }
300};
301
302test "Register.enc" {
303 try testing.expectEqual(@as(u5, 0), Register.x0.enc());
304 try testing.expectEqual(@as(u5, 0), Register.w0.enc());
305
306 try testing.expectEqual(@as(u5, 31), Register.xzr.enc());
307 try testing.expectEqual(@as(u5, 31), Register.wzr.enc());
308
309 try testing.expectEqual(@as(u5, 31), Register.sp.enc());
310 try testing.expectEqual(@as(u5, 31), Register.sp.enc());
311}
312
313test "Register.size" {
314 try testing.expectEqual(@as(u8, 64), Register.x19.size());
315 try testing.expectEqual(@as(u8, 32), Register.w3.size());
316}
317
318test "Register.toX/toW" {
319 try testing.expectEqual(Register.x0, Register.w0.toX());
320 try testing.expectEqual(Register.x0, Register.x0.toX());
321
322 try testing.expectEqual(Register.w3, Register.w3.toW());
323 try testing.expectEqual(Register.w3, Register.x3.toW());
324}
325
326/// Represents an instruction in the AArch64 instruction set
327pub const Instruction = union(enum) {
328 move_wide_immediate: packed struct {
329 rd: u5,
330 imm16: u16,
331 hw: u2,
332 fixed: u6 = 0b100101,
333 opc: u2,
334 sf: u1,
335 },
336 pc_relative_address: packed struct {
337 rd: u5,
338 immhi: u19,
339 fixed: u5 = 0b10000,
340 immlo: u2,
341 op: u1,
342 },
343 load_store_register: packed struct {
344 rt: u5,
345 rn: u5,
346 offset: u12,
347 opc: u2,
348 op1: u2,
349 v: u1,
350 fixed: u3 = 0b111,
351 size: u2,
352 },
353 load_store_register_pair: packed struct {
354 rt1: u5,
355 rn: u5,
356 rt2: u5,
357 imm7: u7,
358 load: u1,
359 encoding: u2,
360 fixed: u5 = 0b101_0_0,
361 opc: u2,
362 },
363 load_literal: packed struct {
364 rt: u5,
365 imm19: u19,
366 fixed: u6 = 0b011_0_00,
367 opc: u2,
368 },
369 exception_generation: packed struct {
370 ll: u2,
371 op2: u3,
372 imm16: u16,
373 opc: u3,
374 fixed: u8 = 0b1101_0100,
375 },
376 unconditional_branch_register: packed struct {
377 op4: u5,
378 rn: u5,
379 op3: u6,
380 op2: u5,
381 opc: u4,
382 fixed: u7 = 0b1101_011,
383 },
384 unconditional_branch_immediate: packed struct {
385 imm26: u26,
386 fixed: u5 = 0b00101,
387 op: u1,
388 },
389 no_operation: packed struct {
390 fixed: u32 = 0b1101010100_0_00_011_0010_0000_000_11111,
391 },
392 logical_shifted_register: packed struct {
393 rd: u5,
394 rn: u5,
395 imm6: u6,
396 rm: u5,
397 n: u1,
398 shift: u2,
399 fixed: u5 = 0b01010,
400 opc: u2,
401 sf: u1,
402 },
403 add_subtract_immediate: packed struct {
404 rd: u5,
405 rn: u5,
406 imm12: u12,
407 sh: u1,
408 fixed: u6 = 0b100010,
409 s: u1,
410 op: u1,
411 sf: u1,
412 },
413 logical_immediate: packed struct {
414 rd: u5,
415 rn: u5,
416 imms: u6,
417 immr: u6,
418 n: u1,
419 fixed: u6 = 0b100100,
420 opc: u2,
421 sf: u1,
422 },
423 bitfield: packed struct {
424 rd: u5,
425 rn: u5,
426 imms: u6,
427 immr: u6,
428 n: u1,
429 fixed: u6 = 0b100110,
430 opc: u2,
431 sf: u1,
432 },
433 add_subtract_shifted_register: packed struct {
434 rd: u5,
435 rn: u5,
436 imm6: u6,
437 rm: u5,
438 fixed_1: u1 = 0b0,
439 shift: u2,
440 fixed_2: u5 = 0b01011,
441 s: u1,
442 op: u1,
443 sf: u1,
444 },
445 add_subtract_extended_register: packed struct {
446 rd: u5,
447 rn: u5,
448 imm3: u3,
449 option: u3,
450 rm: u5,
451 fixed: u8 = 0b01011_00_1,
452 s: u1,
453 op: u1,
454 sf: u1,
455 },
456 conditional_branch: struct {
457 cond: u4,
458 o0: u1,
459 imm19: u19,
460 o1: u1,
461 fixed: u7 = 0b0101010,
462 },
463 compare_and_branch: struct {
464 rt: u5,
465 imm19: u19,
466 op: u1,
467 fixed: u6 = 0b011010,
468 sf: u1,
469 },
470 conditional_select: struct {
471 rd: u5,
472 rn: u5,
473 op2: u2,
474 cond: u4,
475 rm: u5,
476 fixed: u8 = 0b11010100,
477 s: u1,
478 op: u1,
479 sf: u1,
480 },
481 data_processing_3_source: packed struct {
482 rd: u5,
483 rn: u5,
484 ra: u5,
485 o0: u1,
486 rm: u5,
487 op31: u3,
488 fixed: u5 = 0b11011,
489 op54: u2,
490 sf: u1,
491 },
492 data_processing_2_source: packed struct {
493 rd: u5,
494 rn: u5,
495 opcode: u6,
496 rm: u5,
497 fixed_1: u8 = 0b11010110,
498 s: u1,
499 fixed_2: u1 = 0b0,
500 sf: u1,
501 },
502
503 pub const Condition = enum(u4) {
504 /// Integer: Equal
505 /// Floating point: Equal
506 eq,
507 /// Integer: Not equal
508 /// Floating point: Not equal or unordered
509 ne,
510 /// Integer: Carry set
511 /// Floating point: Greater than, equal, or unordered
512 cs,
513 /// Integer: Carry clear
514 /// Floating point: Less than
515 cc,
516 /// Integer: Minus, negative
517 /// Floating point: Less than
518 mi,
519 /// Integer: Plus, positive or zero
520 /// Floating point: Greater than, equal, or unordered
521 pl,
522 /// Integer: Overflow
523 /// Floating point: Unordered
524 vs,
525 /// Integer: No overflow
526 /// Floating point: Ordered
527 vc,
528 /// Integer: Unsigned higher
529 /// Floating point: Greater than, or unordered
530 hi,
531 /// Integer: Unsigned lower or same
532 /// Floating point: Less than or equal
533 ls,
534 /// Integer: Signed greater than or equal
535 /// Floating point: Greater than or equal
536 ge,
537 /// Integer: Signed less than
538 /// Floating point: Less than, or unordered
539 lt,
540 /// Integer: Signed greater than
541 /// Floating point: Greater than
542 gt,
543 /// Integer: Signed less than or equal
544 /// Floating point: Less than, equal, or unordered
545 le,
546 /// Integer: Always
547 /// Floating point: Always
548 al,
549 /// Integer: Always
550 /// Floating point: Always
551 nv,
552
553 /// Converts a std.math.CompareOperator into a condition flag,
554 /// i.e. returns the condition that is true iff the result of the
555 /// comparison is true. Assumes signed comparison
556 pub fn fromCompareOperatorSigned(op: std.math.CompareOperator) Condition {
557 return switch (op) {
558 .gte => .ge,
559 .gt => .gt,
560 .neq => .ne,
561 .lt => .lt,
562 .lte => .le,
563 .eq => .eq,
564 };
565 }
566
567 /// Converts a std.math.CompareOperator into a condition flag,
568 /// i.e. returns the condition that is true iff the result of the
569 /// comparison is true. Assumes unsigned comparison
570 pub fn fromCompareOperatorUnsigned(op: std.math.CompareOperator) Condition {
571 return switch (op) {
572 .gte => .cs,
573 .gt => .hi,
574 .neq => .ne,
575 .lt => .cc,
576 .lte => .ls,
577 .eq => .eq,
578 };
579 }
580
581 /// Returns the condition which is true iff the given condition is
582 /// false (if such a condition exists)
583 pub fn negate(cond: Condition) Condition {
584 return switch (cond) {
585 .eq => .ne,
586 .ne => .eq,
587 .cs => .cc,
588 .cc => .cs,
589 .mi => .pl,
590 .pl => .mi,
591 .vs => .vc,
592 .vc => .vs,
593 .hi => .ls,
594 .ls => .hi,
595 .ge => .lt,
596 .lt => .ge,
597 .gt => .le,
598 .le => .gt,
599 .al => unreachable,
600 .nv => unreachable,
601 };
602 }
603 };
604
605 pub fn toU32(self: Instruction) u32 {
606 return switch (self) {
607 .move_wide_immediate => |v| @as(u32, @bitCast(v)),
608 .pc_relative_address => |v| @as(u32, @bitCast(v)),
609 .load_store_register => |v| @as(u32, @bitCast(v)),
610 .load_store_register_pair => |v| @as(u32, @bitCast(v)),
611 .load_literal => |v| @as(u32, @bitCast(v)),
612 .exception_generation => |v| @as(u32, @bitCast(v)),
613 .unconditional_branch_register => |v| @as(u32, @bitCast(v)),
614 .unconditional_branch_immediate => |v| @as(u32, @bitCast(v)),
615 .no_operation => |v| @as(u32, @bitCast(v)),
616 .logical_shifted_register => |v| @as(u32, @bitCast(v)),
617 .add_subtract_immediate => |v| @as(u32, @bitCast(v)),
618 .logical_immediate => |v| @as(u32, @bitCast(v)),
619 .bitfield => |v| @as(u32, @bitCast(v)),
620 .add_subtract_shifted_register => |v| @as(u32, @bitCast(v)),
621 .add_subtract_extended_register => |v| @as(u32, @bitCast(v)),
622 // TODO once packed structs work, this can be refactored
623 .conditional_branch => |v| @as(u32, v.cond) | (@as(u32, v.o0) << 4) | (@as(u32, v.imm19) << 5) | (@as(u32, v.o1) << 24) | (@as(u32, v.fixed) << 25),
624 .compare_and_branch => |v| @as(u32, v.rt) | (@as(u32, v.imm19) << 5) | (@as(u32, v.op) << 24) | (@as(u32, v.fixed) << 25) | (@as(u32, v.sf) << 31),
625 .conditional_select => |v| @as(u32, v.rd) | @as(u32, v.rn) << 5 | @as(u32, v.op2) << 10 | @as(u32, v.cond) << 12 | @as(u32, v.rm) << 16 | @as(u32, v.fixed) << 21 | @as(u32, v.s) << 29 | @as(u32, v.op) << 30 | @as(u32, v.sf) << 31,
626 .data_processing_3_source => |v| @as(u32, @bitCast(v)),
627 .data_processing_2_source => |v| @as(u32, @bitCast(v)),
628 };
629 }
630
631 fn moveWideImmediate(
632 opc: u2,
633 rd: Register,
634 imm16: u16,
635 shift: u6,
636 ) Instruction {
637 assert(shift % 16 == 0);
638 assert(!(rd.size() == 32 and shift > 16));
639 assert(!(rd.size() == 64 and shift > 48));
640
641 return Instruction{
642 .move_wide_immediate = .{
643 .rd = rd.enc(),
644 .imm16 = imm16,
645 .hw = @as(u2, @intCast(shift / 16)),
646 .opc = opc,
647 .sf = switch (rd.size()) {
648 32 => 0,
649 64 => 1,
650 else => unreachable, // unexpected register size
651 },
652 },
653 };
654 }
655
656 fn pcRelativeAddress(rd: Register, imm21: i21, op: u1) Instruction {
657 assert(rd.size() == 64);
658 const imm21_u = @as(u21, @bitCast(imm21));
659 return Instruction{
660 .pc_relative_address = .{
661 .rd = rd.enc(),
662 .immlo = @as(u2, @truncate(imm21_u)),
663 .immhi = @as(u19, @truncate(imm21_u >> 2)),
664 .op = op,
665 },
666 };
667 }
668
669 pub const LoadStoreOffsetImmediate = union(enum) {
670 post_index: i9,
671 pre_index: i9,
672 unsigned: u12,
673 };
674
675 pub const LoadStoreOffsetRegister = struct {
676 rm: u5,
677 shift: union(enum) {
678 uxtw: u2,
679 lsl: u2,
680 sxtw: u2,
681 sxtx: u2,
682 },
683 };
684
685 /// Represents the offset operand of a load or store instruction.
686 /// Data can be loaded from memory with either an immediate offset
687 /// or an offset that is stored in some register.
688 pub const LoadStoreOffset = union(enum) {
689 immediate: LoadStoreOffsetImmediate,
690 register: LoadStoreOffsetRegister,
691
692 pub const none = LoadStoreOffset{
693 .immediate = .{ .unsigned = 0 },
694 };
695
696 pub fn toU12(self: LoadStoreOffset) u12 {
697 return switch (self) {
698 .immediate => |imm_type| switch (imm_type) {
699 .post_index => |v| (@as(u12, @intCast(@as(u9, @bitCast(v)))) << 2) + 1,
700 .pre_index => |v| (@as(u12, @intCast(@as(u9, @bitCast(v)))) << 2) + 3,
701 .unsigned => |v| v,
702 },
703 .register => |r| switch (r.shift) {
704 .uxtw => |v| (@as(u12, @intCast(r.rm)) << 6) + (@as(u12, @intCast(v)) << 2) + 16 + 2050,
705 .lsl => |v| (@as(u12, @intCast(r.rm)) << 6) + (@as(u12, @intCast(v)) << 2) + 24 + 2050,
706 .sxtw => |v| (@as(u12, @intCast(r.rm)) << 6) + (@as(u12, @intCast(v)) << 2) + 48 + 2050,
707 .sxtx => |v| (@as(u12, @intCast(r.rm)) << 6) + (@as(u12, @intCast(v)) << 2) + 56 + 2050,
708 },
709 };
710 }
711
712 pub fn imm(offset: u12) LoadStoreOffset {
713 return .{
714 .immediate = .{ .unsigned = offset },
715 };
716 }
717
718 pub fn imm_post_index(offset: i9) LoadStoreOffset {
719 return .{
720 .immediate = .{ .post_index = offset },
721 };
722 }
723
724 pub fn imm_pre_index(offset: i9) LoadStoreOffset {
725 return .{
726 .immediate = .{ .pre_index = offset },
727 };
728 }
729
730 pub fn reg(rm: Register) LoadStoreOffset {
731 return .{
732 .register = .{
733 .rm = rm.enc(),
734 .shift = .{
735 .lsl = 0,
736 },
737 },
738 };
739 }
740
741 pub fn reg_uxtw(rm: Register, shift: u2) LoadStoreOffset {
742 assert(rm.size() == 32 and (shift == 0 or shift == 2));
743 return .{
744 .register = .{
745 .rm = rm.enc(),
746 .shift = .{
747 .uxtw = shift,
748 },
749 },
750 };
751 }
752
753 pub fn reg_lsl(rm: Register, shift: u2) LoadStoreOffset {
754 assert(rm.size() == 64 and (shift == 0 or shift == 3));
755 return .{
756 .register = .{
757 .rm = rm.enc(),
758 .shift = .{
759 .lsl = shift,
760 },
761 },
762 };
763 }
764
765 pub fn reg_sxtw(rm: Register, shift: u2) LoadStoreOffset {
766 assert(rm.size() == 32 and (shift == 0 or shift == 2));
767 return .{
768 .register = .{
769 .rm = rm.enc(),
770 .shift = .{
771 .sxtw = shift,
772 },
773 },
774 };
775 }
776
777 pub fn reg_sxtx(rm: Register, shift: u2) LoadStoreOffset {
778 assert(rm.size() == 64 and (shift == 0 or shift == 3));
779 return .{
780 .register = .{
781 .rm = rm.enc(),
782 .shift = .{
783 .sxtx = shift,
784 },
785 },
786 };
787 }
788 };
789
790 /// Which kind of load/store to perform
791 const LoadStoreVariant = enum {
792 /// 32 bits or 64 bits
793 str,
794 /// 8 bits, zero-extended
795 strb,
796 /// 16 bits, zero-extended
797 strh,
798 /// 32 bits or 64 bits
799 ldr,
800 /// 8 bits, zero-extended
801 ldrb,
802 /// 16 bits, zero-extended
803 ldrh,
804 /// 8 bits, sign extended
805 ldrsb,
806 /// 16 bits, sign extended
807 ldrsh,
808 /// 32 bits, sign extended
809 ldrsw,
810 };
811
812 fn loadStoreRegister(
813 rt: Register,
814 rn: Register,
815 offset: LoadStoreOffset,
816 variant: LoadStoreVariant,
817 ) Instruction {
818 assert(rn.size() == 64);
819 assert(rn.id() != Register.xzr.id());
820
821 const off = offset.toU12();
822
823 const op1: u2 = blk: {
824 switch (offset) {
825 .immediate => |imm| switch (imm) {
826 .unsigned => break :blk 0b01,
827 else => {},
828 },
829 else => {},
830 }
831 break :blk 0b00;
832 };
833
834 const opc: u2 = blk: {
835 switch (variant) {
836 .ldr, .ldrh, .ldrb => break :blk 0b01,
837 .str, .strh, .strb => break :blk 0b00,
838 .ldrsb,
839 .ldrsh,
840 => switch (rt.size()) {
841 32 => break :blk 0b11,
842 64 => break :blk 0b10,
843 else => unreachable, // unexpected register size
844 },
845 .ldrsw => break :blk 0b10,
846 }
847 };
848
849 const size: u2 = blk: {
850 switch (variant) {
851 .ldr, .str => switch (rt.size()) {
852 32 => break :blk 0b10,
853 64 => break :blk 0b11,
854 else => unreachable, // unexpected register size
855 },
856 .ldrsw => break :blk 0b10,
857 .ldrh, .ldrsh, .strh => break :blk 0b01,
858 .ldrb, .ldrsb, .strb => break :blk 0b00,
859 }
860 };
861
862 return Instruction{
863 .load_store_register = .{
864 .rt = rt.enc(),
865 .rn = rn.enc(),
866 .offset = off,
867 .opc = opc,
868 .op1 = op1,
869 .v = 0,
870 .size = size,
871 },
872 };
873 }
874
875 fn loadStoreRegisterPair(
876 rt1: Register,
877 rt2: Register,
878 rn: Register,
879 offset: i9,
880 encoding: u2,
881 load: bool,
882 ) Instruction {
883 assert(rn.size() == 64);
884 assert(rn.id() != Register.xzr.id());
885
886 switch (rt1.size()) {
887 32 => {
888 assert(-256 <= offset and offset <= 252);
889 const imm7 = @as(u7, @truncate(@as(u9, @bitCast(offset >> 2))));
890 return Instruction{
891 .load_store_register_pair = .{
892 .rt1 = rt1.enc(),
893 .rn = rn.enc(),
894 .rt2 = rt2.enc(),
895 .imm7 = imm7,
896 .load = @intFromBool(load),
897 .encoding = encoding,
898 .opc = 0b00,
899 },
900 };
901 },
902 64 => {
903 assert(-512 <= offset and offset <= 504);
904 const imm7 = @as(u7, @truncate(@as(u9, @bitCast(offset >> 3))));
905 return Instruction{
906 .load_store_register_pair = .{
907 .rt1 = rt1.enc(),
908 .rn = rn.enc(),
909 .rt2 = rt2.enc(),
910 .imm7 = imm7,
911 .load = @intFromBool(load),
912 .encoding = encoding,
913 .opc = 0b10,
914 },
915 };
916 },
917 else => unreachable, // unexpected register size
918 }
919 }
920
921 fn loadLiteral(rt: Register, imm19: u19) Instruction {
922 return Instruction{
923 .load_literal = .{
924 .rt = rt.enc(),
925 .imm19 = imm19,
926 .opc = switch (rt.size()) {
927 32 => 0b00,
928 64 => 0b01,
929 else => unreachable, // unexpected register size
930 },
931 },
932 };
933 }
934
935 fn exceptionGeneration(
936 opc: u3,
937 op2: u3,
938 ll: u2,
939 imm16: u16,
940 ) Instruction {
941 return Instruction{
942 .exception_generation = .{
943 .ll = ll,
944 .op2 = op2,
945 .imm16 = imm16,
946 .opc = opc,
947 },
948 };
949 }
950
951 fn unconditionalBranchRegister(
952 opc: u4,
953 op2: u5,
954 op3: u6,
955 rn: Register,
956 op4: u5,
957 ) Instruction {
958 assert(rn.size() == 64);
959
960 return Instruction{
961 .unconditional_branch_register = .{
962 .op4 = op4,
963 .rn = rn.enc(),
964 .op3 = op3,
965 .op2 = op2,
966 .opc = opc,
967 },
968 };
969 }
970
971 fn unconditionalBranchImmediate(
972 op: u1,
973 offset: i28,
974 ) Instruction {
975 return Instruction{
976 .unconditional_branch_immediate = .{
977 .imm26 = @as(u26, @bitCast(@as(i26, @intCast(offset >> 2)))),
978 .op = op,
979 },
980 };
981 }
982
983 pub const LogicalShiftedRegisterShift = enum(u2) { lsl, lsr, asr, ror };
984
985 fn logicalShiftedRegister(
986 opc: u2,
987 n: u1,
988 rd: Register,
989 rn: Register,
990 rm: Register,
991 shift: LogicalShiftedRegisterShift,
992 amount: u6,
993 ) Instruction {
994 assert(rd.size() == rn.size());
995 assert(rd.size() == rm.size());
996 if (rd.size() == 32) assert(amount < 32);
997
998 return Instruction{
999 .logical_shifted_register = .{
1000 .rd = rd.enc(),
1001 .rn = rn.enc(),
1002 .imm6 = amount,
1003 .rm = rm.enc(),
1004 .n = n,
1005 .shift = @intFromEnum(shift),
1006 .opc = opc,
1007 .sf = switch (rd.size()) {
1008 32 => 0b0,
1009 64 => 0b1,
1010 else => unreachable,
1011 },
1012 },
1013 };
1014 }
1015
1016 fn addSubtractImmediate(
1017 op: u1,
1018 s: u1,
1019 rd: Register,
1020 rn: Register,
1021 imm12: u12,
1022 shift: bool,
1023 ) Instruction {
1024 assert(rd.size() == rn.size());
1025 assert(rn.id() != Register.xzr.id());
1026
1027 return Instruction{
1028 .add_subtract_immediate = .{
1029 .rd = rd.enc(),
1030 .rn = rn.enc(),
1031 .imm12 = imm12,
1032 .sh = @intFromBool(shift),
1033 .s = s,
1034 .op = op,
1035 .sf = switch (rd.size()) {
1036 32 => 0b0,
1037 64 => 0b1,
1038 else => unreachable, // unexpected register size
1039 },
1040 },
1041 };
1042 }
1043
1044 fn logicalImmediate(
1045 opc: u2,
1046 rd: Register,
1047 rn: Register,
1048 imms: u6,
1049 immr: u6,
1050 n: u1,
1051 ) Instruction {
1052 assert(rd.size() == rn.size());
1053 assert(!(rd.size() == 32 and n != 0));
1054
1055 return Instruction{
1056 .logical_immediate = .{
1057 .rd = rd.enc(),
1058 .rn = rn.enc(),
1059 .imms = imms,
1060 .immr = immr,
1061 .n = n,
1062 .opc = opc,
1063 .sf = switch (rd.size()) {
1064 32 => 0b0,
1065 64 => 0b1,
1066 else => unreachable, // unexpected register size
1067 },
1068 },
1069 };
1070 }
1071
1072 fn initBitfield(
1073 opc: u2,
1074 n: u1,
1075 rd: Register,
1076 rn: Register,
1077 immr: u6,
1078 imms: u6,
1079 ) Instruction {
1080 assert(rd.size() == rn.size());
1081 assert(!(rd.size() == 64 and n != 1));
1082 assert(!(rd.size() == 32 and (n != 0 or immr >> 5 != 0 or immr >> 5 != 0)));
1083
1084 return Instruction{
1085 .bitfield = .{
1086 .rd = rd.enc(),
1087 .rn = rn.enc(),
1088 .imms = imms,
1089 .immr = immr,
1090 .n = n,
1091 .opc = opc,
1092 .sf = switch (rd.size()) {
1093 32 => 0b0,
1094 64 => 0b1,
1095 else => unreachable, // unexpected register size
1096 },
1097 },
1098 };
1099 }
1100
1101 pub const AddSubtractShiftedRegisterShift = enum(u2) { lsl, lsr, asr, _ };
1102
1103 fn addSubtractShiftedRegister(
1104 op: u1,
1105 s: u1,
1106 shift: AddSubtractShiftedRegisterShift,
1107 rd: Register,
1108 rn: Register,
1109 rm: Register,
1110 imm6: u6,
1111 ) Instruction {
1112 assert(rd.size() == rn.size());
1113 assert(rd.size() == rm.size());
1114
1115 return Instruction{
1116 .add_subtract_shifted_register = .{
1117 .rd = rd.enc(),
1118 .rn = rn.enc(),
1119 .imm6 = imm6,
1120 .rm = rm.enc(),
1121 .shift = @intFromEnum(shift),
1122 .s = s,
1123 .op = op,
1124 .sf = switch (rd.size()) {
1125 32 => 0b0,
1126 64 => 0b1,
1127 else => unreachable, // unexpected register size
1128 },
1129 },
1130 };
1131 }
1132
1133 pub const AddSubtractExtendedRegisterOption = enum(u3) {
1134 uxtb,
1135 uxth,
1136 uxtw,
1137 uxtx, // serves also as lsl
1138 sxtb,
1139 sxth,
1140 sxtw,
1141 sxtx,
1142 };
1143
1144 fn addSubtractExtendedRegister(
1145 op: u1,
1146 s: u1,
1147 rd: Register,
1148 rn: Register,
1149 rm: Register,
1150 extend: AddSubtractExtendedRegisterOption,
1151 imm3: u3,
1152 ) Instruction {
1153 return Instruction{
1154 .add_subtract_extended_register = .{
1155 .rd = rd.enc(),
1156 .rn = rn.enc(),
1157 .imm3 = imm3,
1158 .option = @intFromEnum(extend),
1159 .rm = rm.enc(),
1160 .s = s,
1161 .op = op,
1162 .sf = switch (rd.size()) {
1163 32 => 0b0,
1164 64 => 0b1,
1165 else => unreachable, // unexpected register size
1166 },
1167 },
1168 };
1169 }
1170
1171 fn conditionalBranch(
1172 o0: u1,
1173 o1: u1,
1174 cond: Condition,
1175 offset: i21,
1176 ) Instruction {
1177 assert(offset & 0b11 == 0b00);
1178
1179 return Instruction{
1180 .conditional_branch = .{
1181 .cond = @intFromEnum(cond),
1182 .o0 = o0,
1183 .imm19 = @as(u19, @bitCast(@as(i19, @intCast(offset >> 2)))),
1184 .o1 = o1,
1185 },
1186 };
1187 }
1188
1189 fn compareAndBranch(
1190 op: u1,
1191 rt: Register,
1192 offset: i21,
1193 ) Instruction {
1194 assert(offset & 0b11 == 0b00);
1195
1196 return Instruction{
1197 .compare_and_branch = .{
1198 .rt = rt.enc(),
1199 .imm19 = @as(u19, @bitCast(@as(i19, @intCast(offset >> 2)))),
1200 .op = op,
1201 .sf = switch (rt.size()) {
1202 32 => 0b0,
1203 64 => 0b1,
1204 else => unreachable, // unexpected register size
1205 },
1206 },
1207 };
1208 }
1209
1210 fn conditionalSelect(
1211 op2: u2,
1212 op: u1,
1213 s: u1,
1214 rd: Register,
1215 rn: Register,
1216 rm: Register,
1217 cond: Condition,
1218 ) Instruction {
1219 assert(rd.size() == rn.size());
1220 assert(rd.size() == rm.size());
1221
1222 return Instruction{
1223 .conditional_select = .{
1224 .rd = rd.enc(),
1225 .rn = rn.enc(),
1226 .op2 = op2,
1227 .cond = @intFromEnum(cond),
1228 .rm = rm.enc(),
1229 .s = s,
1230 .op = op,
1231 .sf = switch (rd.size()) {
1232 32 => 0b0,
1233 64 => 0b1,
1234 else => unreachable, // unexpected register size
1235 },
1236 },
1237 };
1238 }
1239
1240 fn dataProcessing3Source(
1241 op54: u2,
1242 op31: u3,
1243 o0: u1,
1244 rd: Register,
1245 rn: Register,
1246 rm: Register,
1247 ra: Register,
1248 ) Instruction {
1249 return Instruction{
1250 .data_processing_3_source = .{
1251 .rd = rd.enc(),
1252 .rn = rn.enc(),
1253 .ra = ra.enc(),
1254 .o0 = o0,
1255 .rm = rm.enc(),
1256 .op31 = op31,
1257 .op54 = op54,
1258 .sf = switch (rd.size()) {
1259 32 => 0b0,
1260 64 => 0b1,
1261 else => unreachable, // unexpected register size
1262 },
1263 },
1264 };
1265 }
1266
1267 fn dataProcessing2Source(
1268 s: u1,
1269 opcode: u6,
1270 rd: Register,
1271 rn: Register,
1272 rm: Register,
1273 ) Instruction {
1274 assert(rd.size() == rn.size());
1275 assert(rd.size() == rm.size());
1276
1277 return Instruction{
1278 .data_processing_2_source = .{
1279 .rd = rd.enc(),
1280 .rn = rn.enc(),
1281 .opcode = opcode,
1282 .rm = rm.enc(),
1283 .s = s,
1284 .sf = switch (rd.size()) {
1285 32 => 0b0,
1286 64 => 0b1,
1287 else => unreachable, // unexpected register size
1288 },
1289 },
1290 };
1291 }
1292
1293 // Helper functions for assembly syntax functions
1294
1295 // Move wide (immediate)
1296
1297 pub fn movn(rd: Register, imm16: u16, shift: u6) Instruction {
1298 return moveWideImmediate(0b00, rd, imm16, shift);
1299 }
1300
1301 pub fn movz(rd: Register, imm16: u16, shift: u6) Instruction {
1302 return moveWideImmediate(0b10, rd, imm16, shift);
1303 }
1304
1305 pub fn movk(rd: Register, imm16: u16, shift: u6) Instruction {
1306 return moveWideImmediate(0b11, rd, imm16, shift);
1307 }
1308
1309 // PC relative address
1310
1311 pub fn adr(rd: Register, imm21: i21) Instruction {
1312 return pcRelativeAddress(rd, imm21, 0b0);
1313 }
1314
1315 pub fn adrp(rd: Register, imm21: i21) Instruction {
1316 return pcRelativeAddress(rd, imm21, 0b1);
1317 }
1318
1319 // Load or store register
1320
1321 pub fn ldrLiteral(rt: Register, literal: u19) Instruction {
1322 return loadLiteral(rt, literal);
1323 }
1324
1325 pub fn ldr(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1326 return loadStoreRegister(rt, rn, offset, .ldr);
1327 }
1328
1329 pub fn ldrh(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1330 return loadStoreRegister(rt, rn, offset, .ldrh);
1331 }
1332
1333 pub fn ldrb(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1334 return loadStoreRegister(rt, rn, offset, .ldrb);
1335 }
1336
1337 pub fn ldrsb(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1338 return loadStoreRegister(rt, rn, offset, .ldrsb);
1339 }
1340
1341 pub fn ldrsh(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1342 return loadStoreRegister(rt, rn, offset, .ldrsh);
1343 }
1344
1345 pub fn ldrsw(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1346 return loadStoreRegister(rt, rn, offset, .ldrsw);
1347 }
1348
1349 pub fn str(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1350 return loadStoreRegister(rt, rn, offset, .str);
1351 }
1352
1353 pub fn strh(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1354 return loadStoreRegister(rt, rn, offset, .strh);
1355 }
1356
1357 pub fn strb(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
1358 return loadStoreRegister(rt, rn, offset, .strb);
1359 }
1360
1361 // Load or store pair of registers
1362
1363 pub const LoadStorePairOffset = struct {
1364 encoding: enum(u2) {
1365 post_index = 0b01,
1366 signed = 0b10,
1367 pre_index = 0b11,
1368 },
1369 offset: i9,
1370
1371 pub fn none() LoadStorePairOffset {
1372 return .{ .encoding = .signed, .offset = 0 };
1373 }
1374
1375 pub fn post_index(imm: i9) LoadStorePairOffset {
1376 return .{ .encoding = .post_index, .offset = imm };
1377 }
1378
1379 pub fn pre_index(imm: i9) LoadStorePairOffset {
1380 return .{ .encoding = .pre_index, .offset = imm };
1381 }
1382
1383 pub fn signed(imm: i9) LoadStorePairOffset {
1384 return .{ .encoding = .signed, .offset = imm };
1385 }
1386 };
1387
1388 pub fn ldp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction {
1389 return loadStoreRegisterPair(rt1, rt2, rn, offset.offset, @intFromEnum(offset.encoding), true);
1390 }
1391
1392 pub fn ldnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction {
1393 return loadStoreRegisterPair(rt1, rt2, rn, offset, 0, true);
1394 }
1395
1396 pub fn stp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction {
1397 return loadStoreRegisterPair(rt1, rt2, rn, offset.offset, @intFromEnum(offset.encoding), false);
1398 }
1399
1400 pub fn stnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction {
1401 return loadStoreRegisterPair(rt1, rt2, rn, offset, 0, false);
1402 }
1403
1404 // Exception generation
1405
1406 pub fn svc(imm16: u16) Instruction {
1407 return exceptionGeneration(0b000, 0b000, 0b01, imm16);
1408 }
1409
1410 pub fn hvc(imm16: u16) Instruction {
1411 return exceptionGeneration(0b000, 0b000, 0b10, imm16);
1412 }
1413
1414 pub fn smc(imm16: u16) Instruction {
1415 return exceptionGeneration(0b000, 0b000, 0b11, imm16);
1416 }
1417
1418 pub fn brk(imm16: u16) Instruction {
1419 return exceptionGeneration(0b001, 0b000, 0b00, imm16);
1420 }
1421
1422 pub fn hlt(imm16: u16) Instruction {
1423 return exceptionGeneration(0b010, 0b000, 0b00, imm16);
1424 }
1425
1426 // Unconditional branch (register)
1427
1428 pub fn br(rn: Register) Instruction {
1429 return unconditionalBranchRegister(0b0000, 0b11111, 0b000000, rn, 0b00000);
1430 }
1431
1432 pub fn blr(rn: Register) Instruction {
1433 return unconditionalBranchRegister(0b0001, 0b11111, 0b000000, rn, 0b00000);
1434 }
1435
1436 pub fn ret(rn: ?Register) Instruction {
1437 return unconditionalBranchRegister(0b0010, 0b11111, 0b000000, rn orelse .x30, 0b00000);
1438 }
1439
1440 // Unconditional branch (immediate)
1441
1442 pub fn b(offset: i28) Instruction {
1443 return unconditionalBranchImmediate(0, offset);
1444 }
1445
1446 pub fn bl(offset: i28) Instruction {
1447 return unconditionalBranchImmediate(1, offset);
1448 }
1449
1450 // Nop
1451
1452 pub fn nop() Instruction {
1453 return Instruction{ .no_operation = .{} };
1454 }
1455
1456 // Logical (shifted register)
1457
1458 pub fn andShiftedRegister(
1459 rd: Register,
1460 rn: Register,
1461 rm: Register,
1462 shift: LogicalShiftedRegisterShift,
1463 amount: u6,
1464 ) Instruction {
1465 return logicalShiftedRegister(0b00, 0b0, rd, rn, rm, shift, amount);
1466 }
1467
1468 pub fn bicShiftedRegister(
1469 rd: Register,
1470 rn: Register,
1471 rm: Register,
1472 shift: LogicalShiftedRegisterShift,
1473 amount: u6,
1474 ) Instruction {
1475 return logicalShiftedRegister(0b00, 0b1, rd, rn, rm, shift, amount);
1476 }
1477
1478 pub fn orrShiftedRegister(
1479 rd: Register,
1480 rn: Register,
1481 rm: Register,
1482 shift: LogicalShiftedRegisterShift,
1483 amount: u6,
1484 ) Instruction {
1485 return logicalShiftedRegister(0b01, 0b0, rd, rn, rm, shift, amount);
1486 }
1487
1488 pub fn ornShiftedRegister(
1489 rd: Register,
1490 rn: Register,
1491 rm: Register,
1492 shift: LogicalShiftedRegisterShift,
1493 amount: u6,
1494 ) Instruction {
1495 return logicalShiftedRegister(0b01, 0b1, rd, rn, rm, shift, amount);
1496 }
1497
1498 pub fn eorShiftedRegister(
1499 rd: Register,
1500 rn: Register,
1501 rm: Register,
1502 shift: LogicalShiftedRegisterShift,
1503 amount: u6,
1504 ) Instruction {
1505 return logicalShiftedRegister(0b10, 0b0, rd, rn, rm, shift, amount);
1506 }
1507
1508 pub fn eonShiftedRegister(
1509 rd: Register,
1510 rn: Register,
1511 rm: Register,
1512 shift: LogicalShiftedRegisterShift,
1513 amount: u6,
1514 ) Instruction {
1515 return logicalShiftedRegister(0b10, 0b1, rd, rn, rm, shift, amount);
1516 }
1517
1518 pub fn andsShiftedRegister(
1519 rd: Register,
1520 rn: Register,
1521 rm: Register,
1522 shift: LogicalShiftedRegisterShift,
1523 amount: u6,
1524 ) Instruction {
1525 return logicalShiftedRegister(0b11, 0b0, rd, rn, rm, shift, amount);
1526 }
1527
1528 pub fn bicsShiftedRegister(
1529 rd: Register,
1530 rn: Register,
1531 rm: Register,
1532 shift: LogicalShiftedRegisterShift,
1533 amount: u6,
1534 ) Instruction {
1535 return logicalShiftedRegister(0b11, 0b1, rd, rn, rm, shift, amount);
1536 }
1537
1538 // Add/subtract (immediate)
1539
1540 pub fn add(rd: Register, rn: Register, imm: u12, shift: bool) Instruction {
1541 return addSubtractImmediate(0b0, 0b0, rd, rn, imm, shift);
1542 }
1543
1544 pub fn adds(rd: Register, rn: Register, imm: u12, shift: bool) Instruction {
1545 return addSubtractImmediate(0b0, 0b1, rd, rn, imm, shift);
1546 }
1547
1548 pub fn sub(rd: Register, rn: Register, imm: u12, shift: bool) Instruction {
1549 return addSubtractImmediate(0b1, 0b0, rd, rn, imm, shift);
1550 }
1551
1552 pub fn subs(rd: Register, rn: Register, imm: u12, shift: bool) Instruction {
1553 return addSubtractImmediate(0b1, 0b1, rd, rn, imm, shift);
1554 }
1555
1556 // Logical (immediate)
1557
1558 pub fn andImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction {
1559 return logicalImmediate(0b00, rd, rn, imms, immr, n);
1560 }
1561
1562 pub fn orrImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction {
1563 return logicalImmediate(0b01, rd, rn, imms, immr, n);
1564 }
1565
1566 pub fn eorImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction {
1567 return logicalImmediate(0b10, rd, rn, imms, immr, n);
1568 }
1569
1570 pub fn andsImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction {
1571 return logicalImmediate(0b11, rd, rn, imms, immr, n);
1572 }
1573
1574 // Bitfield
1575
1576 pub fn sbfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction {
1577 const n: u1 = switch (rd.size()) {
1578 32 => 0b0,
1579 64 => 0b1,
1580 else => unreachable, // unexpected register size
1581 };
1582 return initBitfield(0b00, n, rd, rn, immr, imms);
1583 }
1584
1585 pub fn bfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction {
1586 const n: u1 = switch (rd.size()) {
1587 32 => 0b0,
1588 64 => 0b1,
1589 else => unreachable, // unexpected register size
1590 };
1591 return initBitfield(0b01, n, rd, rn, immr, imms);
1592 }
1593
1594 pub fn ubfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction {
1595 const n: u1 = switch (rd.size()) {
1596 32 => 0b0,
1597 64 => 0b1,
1598 else => unreachable, // unexpected register size
1599 };
1600 return initBitfield(0b10, n, rd, rn, immr, imms);
1601 }
1602
1603 pub fn asrImmediate(rd: Register, rn: Register, shift: u6) Instruction {
1604 const imms = @as(u6, @intCast(rd.size() - 1));
1605 return sbfm(rd, rn, shift, imms);
1606 }
1607
1608 pub fn sbfx(rd: Register, rn: Register, lsb: u6, width: u7) Instruction {
1609 return sbfm(rd, rn, lsb, @as(u6, @intCast(lsb + width - 1)));
1610 }
1611
1612 pub fn sxtb(rd: Register, rn: Register) Instruction {
1613 return sbfm(rd, rn, 0, 7);
1614 }
1615
1616 pub fn sxth(rd: Register, rn: Register) Instruction {
1617 return sbfm(rd, rn, 0, 15);
1618 }
1619
1620 pub fn sxtw(rd: Register, rn: Register) Instruction {
1621 assert(rd.size() == 64);
1622 return sbfm(rd, rn, 0, 31);
1623 }
1624
1625 pub fn lslImmediate(rd: Register, rn: Register, shift: u6) Instruction {
1626 const size = @as(u6, @intCast(rd.size() - 1));
1627 return ubfm(rd, rn, size - shift + 1, size - shift);
1628 }
1629
1630 pub fn lsrImmediate(rd: Register, rn: Register, shift: u6) Instruction {
1631 const imms = @as(u6, @intCast(rd.size() - 1));
1632 return ubfm(rd, rn, shift, imms);
1633 }
1634
1635 pub fn ubfx(rd: Register, rn: Register, lsb: u6, width: u7) Instruction {
1636 return ubfm(rd, rn, lsb, @as(u6, @intCast(lsb + width - 1)));
1637 }
1638
1639 pub fn uxtb(rd: Register, rn: Register) Instruction {
1640 return ubfm(rd, rn, 0, 7);
1641 }
1642
1643 pub fn uxth(rd: Register, rn: Register) Instruction {
1644 return ubfm(rd, rn, 0, 15);
1645 }
1646
1647 // Add/subtract (shifted register)
1648
1649 pub fn addShiftedRegister(
1650 rd: Register,
1651 rn: Register,
1652 rm: Register,
1653 shift: AddSubtractShiftedRegisterShift,
1654 imm6: u6,
1655 ) Instruction {
1656 return addSubtractShiftedRegister(0b0, 0b0, shift, rd, rn, rm, imm6);
1657 }
1658
1659 pub fn addsShiftedRegister(
1660 rd: Register,
1661 rn: Register,
1662 rm: Register,
1663 shift: AddSubtractShiftedRegisterShift,
1664 imm6: u6,
1665 ) Instruction {
1666 return addSubtractShiftedRegister(0b0, 0b1, shift, rd, rn, rm, imm6);
1667 }
1668
1669 pub fn subShiftedRegister(
1670 rd: Register,
1671 rn: Register,
1672 rm: Register,
1673 shift: AddSubtractShiftedRegisterShift,
1674 imm6: u6,
1675 ) Instruction {
1676 return addSubtractShiftedRegister(0b1, 0b0, shift, rd, rn, rm, imm6);
1677 }
1678
1679 pub fn subsShiftedRegister(
1680 rd: Register,
1681 rn: Register,
1682 rm: Register,
1683 shift: AddSubtractShiftedRegisterShift,
1684 imm6: u6,
1685 ) Instruction {
1686 return addSubtractShiftedRegister(0b1, 0b1, shift, rd, rn, rm, imm6);
1687 }
1688
1689 // Add/subtract (extended register)
1690
1691 pub fn addExtendedRegister(
1692 rd: Register,
1693 rn: Register,
1694 rm: Register,
1695 extend: AddSubtractExtendedRegisterOption,
1696 imm3: u3,
1697 ) Instruction {
1698 return addSubtractExtendedRegister(0b0, 0b0, rd, rn, rm, extend, imm3);
1699 }
1700
1701 pub fn addsExtendedRegister(
1702 rd: Register,
1703 rn: Register,
1704 rm: Register,
1705 extend: AddSubtractExtendedRegisterOption,
1706 imm3: u3,
1707 ) Instruction {
1708 return addSubtractExtendedRegister(0b0, 0b1, rd, rn, rm, extend, imm3);
1709 }
1710
1711 pub fn subExtendedRegister(
1712 rd: Register,
1713 rn: Register,
1714 rm: Register,
1715 extend: AddSubtractExtendedRegisterOption,
1716 imm3: u3,
1717 ) Instruction {
1718 return addSubtractExtendedRegister(0b1, 0b0, rd, rn, rm, extend, imm3);
1719 }
1720
1721 pub fn subsExtendedRegister(
1722 rd: Register,
1723 rn: Register,
1724 rm: Register,
1725 extend: AddSubtractExtendedRegisterOption,
1726 imm3: u3,
1727 ) Instruction {
1728 return addSubtractExtendedRegister(0b1, 0b1, rd, rn, rm, extend, imm3);
1729 }
1730
1731 // Conditional branch
1732
1733 pub fn bCond(cond: Condition, offset: i21) Instruction {
1734 return conditionalBranch(0b0, 0b0, cond, offset);
1735 }
1736
1737 // Compare and branch
1738
1739 pub fn cbz(rt: Register, offset: i21) Instruction {
1740 return compareAndBranch(0b0, rt, offset);
1741 }
1742
1743 pub fn cbnz(rt: Register, offset: i21) Instruction {
1744 return compareAndBranch(0b1, rt, offset);
1745 }
1746
1747 // Conditional select
1748
1749 pub fn csel(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction {
1750 return conditionalSelect(0b00, 0b0, 0b0, rd, rn, rm, cond);
1751 }
1752
1753 pub fn csinc(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction {
1754 return conditionalSelect(0b01, 0b0, 0b0, rd, rn, rm, cond);
1755 }
1756
1757 pub fn csinv(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction {
1758 return conditionalSelect(0b00, 0b1, 0b0, rd, rn, rm, cond);
1759 }
1760
1761 pub fn csneg(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction {
1762 return conditionalSelect(0b01, 0b1, 0b0, rd, rn, rm, cond);
1763 }
1764
1765 // Data processing (3 source)
1766
1767 pub fn madd(rd: Register, rn: Register, rm: Register, ra: Register) Instruction {
1768 return dataProcessing3Source(0b00, 0b000, 0b0, rd, rn, rm, ra);
1769 }
1770
1771 pub fn smaddl(rd: Register, rn: Register, rm: Register, ra: Register) Instruction {
1772 assert(rd.size() == 64 and rn.size() == 32 and rm.size() == 32 and ra.size() == 64);
1773 return dataProcessing3Source(0b00, 0b001, 0b0, rd, rn, rm, ra);
1774 }
1775
1776 pub fn umaddl(rd: Register, rn: Register, rm: Register, ra: Register) Instruction {
1777 assert(rd.size() == 64 and rn.size() == 32 and rm.size() == 32 and ra.size() == 64);
1778 return dataProcessing3Source(0b00, 0b101, 0b0, rd, rn, rm, ra);
1779 }
1780
1781 pub fn msub(rd: Register, rn: Register, rm: Register, ra: Register) Instruction {
1782 return dataProcessing3Source(0b00, 0b000, 0b1, rd, rn, rm, ra);
1783 }
1784
1785 pub fn mul(rd: Register, rn: Register, rm: Register) Instruction {
1786 return madd(rd, rn, rm, .xzr);
1787 }
1788
1789 pub fn smull(rd: Register, rn: Register, rm: Register) Instruction {
1790 return smaddl(rd, rn, rm, .xzr);
1791 }
1792
1793 pub fn smulh(rd: Register, rn: Register, rm: Register) Instruction {
1794 assert(rd.size() == 64);
1795 return dataProcessing3Source(0b00, 0b010, 0b0, rd, rn, rm, .xzr);
1796 }
1797
1798 pub fn umull(rd: Register, rn: Register, rm: Register) Instruction {
1799 return umaddl(rd, rn, rm, .xzr);
1800 }
1801
1802 pub fn umulh(rd: Register, rn: Register, rm: Register) Instruction {
1803 assert(rd.size() == 64);
1804 return dataProcessing3Source(0b00, 0b110, 0b0, rd, rn, rm, .xzr);
1805 }
1806
1807 pub fn mneg(rd: Register, rn: Register, rm: Register) Instruction {
1808 return msub(rd, rn, rm, .xzr);
1809 }
1810
1811 // Data processing (2 source)
1812
1813 pub fn udiv(rd: Register, rn: Register, rm: Register) Instruction {
1814 return dataProcessing2Source(0b0, 0b000010, rd, rn, rm);
1815 }
1816
1817 pub fn sdiv(rd: Register, rn: Register, rm: Register) Instruction {
1818 return dataProcessing2Source(0b0, 0b000011, rd, rn, rm);
1819 }
1820
1821 pub fn lslv(rd: Register, rn: Register, rm: Register) Instruction {
1822 return dataProcessing2Source(0b0, 0b001000, rd, rn, rm);
1823 }
1824
1825 pub fn lsrv(rd: Register, rn: Register, rm: Register) Instruction {
1826 return dataProcessing2Source(0b0, 0b001001, rd, rn, rm);
1827 }
1828
1829 pub fn asrv(rd: Register, rn: Register, rm: Register) Instruction {
1830 return dataProcessing2Source(0b0, 0b001010, rd, rn, rm);
1831 }
1832
1833 pub const asrRegister = asrv;
1834 pub const lslRegister = lslv;
1835 pub const lsrRegister = lsrv;
1836};
1837
1838test {
1839 testing.refAllDecls(@This());
1840}
1841
1842test "serialize instructions" {
1843 const Testcase = struct {
1844 inst: Instruction,
1845 expected: u32,
1846 };
1847
1848 const testcases = [_]Testcase{
1849 .{ // orr x0, xzr, x1
1850 .inst = Instruction.orrShiftedRegister(.x0, .xzr, .x1, .lsl, 0),
1851 .expected = 0b1_01_01010_00_0_00001_000000_11111_00000,
1852 },
1853 .{ // orn x0, xzr, x1
1854 .inst = Instruction.ornShiftedRegister(.x0, .xzr, .x1, .lsl, 0),
1855 .expected = 0b1_01_01010_00_1_00001_000000_11111_00000,
1856 },
1857 .{ // movz x1, #4
1858 .inst = Instruction.movz(.x1, 4, 0),
1859 .expected = 0b1_10_100101_00_0000000000000100_00001,
1860 },
1861 .{ // movz x1, #4, lsl 16
1862 .inst = Instruction.movz(.x1, 4, 16),
1863 .expected = 0b1_10_100101_01_0000000000000100_00001,
1864 },
1865 .{ // movz x1, #4, lsl 32
1866 .inst = Instruction.movz(.x1, 4, 32),
1867 .expected = 0b1_10_100101_10_0000000000000100_00001,
1868 },
1869 .{ // movz x1, #4, lsl 48
1870 .inst = Instruction.movz(.x1, 4, 48),
1871 .expected = 0b1_10_100101_11_0000000000000100_00001,
1872 },
1873 .{ // movz w1, #4
1874 .inst = Instruction.movz(.w1, 4, 0),
1875 .expected = 0b0_10_100101_00_0000000000000100_00001,
1876 },
1877 .{ // movz w1, #4, lsl 16
1878 .inst = Instruction.movz(.w1, 4, 16),
1879 .expected = 0b0_10_100101_01_0000000000000100_00001,
1880 },
1881 .{ // svc #0
1882 .inst = Instruction.svc(0),
1883 .expected = 0b1101_0100_000_0000000000000000_00001,
1884 },
1885 .{ // svc #0x80 ; typical on Darwin
1886 .inst = Instruction.svc(0x80),
1887 .expected = 0b1101_0100_000_0000000010000000_00001,
1888 },
1889 .{ // ret
1890 .inst = Instruction.ret(null),
1891 .expected = 0b1101_011_00_10_11111_0000_00_11110_00000,
1892 },
1893 .{ // bl #0x10
1894 .inst = Instruction.bl(0x10),
1895 .expected = 0b1_00101_00_0000_0000_0000_0000_0000_0100,
1896 },
1897 .{ // ldr x2, [x1]
1898 .inst = Instruction.ldr(.x2, .x1, Instruction.LoadStoreOffset.none),
1899 .expected = 0b11_111_0_01_01_000000000000_00001_00010,
1900 },
1901 .{ // ldr x2, [x1, #1]!
1902 .inst = Instruction.ldr(.x2, .x1, Instruction.LoadStoreOffset.imm_pre_index(1)),
1903 .expected = 0b11_111_0_00_01_0_000000001_11_00001_00010,
1904 },
1905 .{ // ldr x2, [x1], #-1
1906 .inst = Instruction.ldr(.x2, .x1, Instruction.LoadStoreOffset.imm_post_index(-1)),
1907 .expected = 0b11_111_0_00_01_0_111111111_01_00001_00010,
1908 },
1909 .{ // ldr x2, [x1], (x3)
1910 .inst = Instruction.ldr(.x2, .x1, Instruction.LoadStoreOffset.reg(.x3)),
1911 .expected = 0b11_111_0_00_01_1_00011_011_0_10_00001_00010,
1912 },
1913 .{ // ldr x2, label
1914 .inst = Instruction.ldrLiteral(.x2, 0x1),
1915 .expected = 0b01_011_0_00_0000000000000000001_00010,
1916 },
1917 .{ // ldrh x7, [x4], #0xaa
1918 .inst = Instruction.ldrh(.x7, .x4, Instruction.LoadStoreOffset.imm_post_index(0xaa)),
1919 .expected = 0b01_111_0_00_01_0_010101010_01_00100_00111,
1920 },
1921 .{ // ldrb x9, [x15, #0xff]!
1922 .inst = Instruction.ldrb(.x9, .x15, Instruction.LoadStoreOffset.imm_pre_index(0xff)),
1923 .expected = 0b00_111_0_00_01_0_011111111_11_01111_01001,
1924 },
1925 .{ // str x2, [x1]
1926 .inst = Instruction.str(.x2, .x1, Instruction.LoadStoreOffset.none),
1927 .expected = 0b11_111_0_01_00_000000000000_00001_00010,
1928 },
1929 .{ // str x2, [x1], (x3)
1930 .inst = Instruction.str(.x2, .x1, Instruction.LoadStoreOffset.reg(.x3)),
1931 .expected = 0b11_111_0_00_00_1_00011_011_0_10_00001_00010,
1932 },
1933 .{ // strh w0, [x1]
1934 .inst = Instruction.strh(.w0, .x1, Instruction.LoadStoreOffset.none),
1935 .expected = 0b01_111_0_01_00_000000000000_00001_00000,
1936 },
1937 .{ // strb w8, [x9]
1938 .inst = Instruction.strb(.w8, .x9, Instruction.LoadStoreOffset.none),
1939 .expected = 0b00_111_0_01_00_000000000000_01001_01000,
1940 },
1941 .{ // adr x2, #0x8
1942 .inst = Instruction.adr(.x2, 0x8),
1943 .expected = 0b0_00_10000_0000000000000000010_00010,
1944 },
1945 .{ // adr x2, -#0x8
1946 .inst = Instruction.adr(.x2, -0x8),
1947 .expected = 0b0_00_10000_1111111111111111110_00010,
1948 },
1949 .{ // adrp x2, #0x8
1950 .inst = Instruction.adrp(.x2, 0x8),
1951 .expected = 0b1_00_10000_0000000000000000010_00010,
1952 },
1953 .{ // adrp x2, -#0x8
1954 .inst = Instruction.adrp(.x2, -0x8),
1955 .expected = 0b1_00_10000_1111111111111111110_00010,
1956 },
1957 .{ // stp x1, x2, [sp, #8]
1958 .inst = Instruction.stp(.x1, .x2, .sp, Instruction.LoadStorePairOffset.signed(8)),
1959 .expected = 0b10_101_0_010_0_0000001_00010_11111_00001,
1960 },
1961 .{ // ldp x1, x2, [sp, #8]
1962 .inst = Instruction.ldp(.x1, .x2, .sp, Instruction.LoadStorePairOffset.signed(8)),
1963 .expected = 0b10_101_0_010_1_0000001_00010_11111_00001,
1964 },
1965 .{ // stp x1, x2, [sp, #-16]!
1966 .inst = Instruction.stp(.x1, .x2, .sp, Instruction.LoadStorePairOffset.pre_index(-16)),
1967 .expected = 0b10_101_0_011_0_1111110_00010_11111_00001,
1968 },
1969 .{ // ldp x1, x2, [sp], #16
1970 .inst = Instruction.ldp(.x1, .x2, .sp, Instruction.LoadStorePairOffset.post_index(16)),
1971 .expected = 0b10_101_0_001_1_0000010_00010_11111_00001,
1972 },
1973 .{ // and x0, x4, x2
1974 .inst = Instruction.andShiftedRegister(.x0, .x4, .x2, .lsl, 0),
1975 .expected = 0b1_00_01010_00_0_00010_000000_00100_00000,
1976 },
1977 .{ // and x0, x4, x2, lsl #0x8
1978 .inst = Instruction.andShiftedRegister(.x0, .x4, .x2, .lsl, 0x8),
1979 .expected = 0b1_00_01010_00_0_00010_001000_00100_00000,
1980 },
1981 .{ // add x0, x10, #10
1982 .inst = Instruction.add(.x0, .x10, 10, false),
1983 .expected = 0b1_0_0_100010_0_0000_0000_1010_01010_00000,
1984 },
1985 .{ // subs x0, x5, #11, lsl #12
1986 .inst = Instruction.subs(.x0, .x5, 11, true),
1987 .expected = 0b1_1_1_100010_1_0000_0000_1011_00101_00000,
1988 },
1989 .{ // b.hi #-4
1990 .inst = Instruction.bCond(.hi, -4),
1991 .expected = 0b0101010_0_1111111111111111111_0_1000,
1992 },
1993 .{ // cbz x10, #40
1994 .inst = Instruction.cbz(.x10, 40),
1995 .expected = 0b1_011010_0_0000000000000001010_01010,
1996 },
1997 .{ // add x0, x1, x2, lsl #5
1998 .inst = Instruction.addShiftedRegister(.x0, .x1, .x2, .lsl, 5),
1999 .expected = 0b1_0_0_01011_00_0_00010_000101_00001_00000,
2000 },
2001 .{ // csinc x1, x2, x4, eq
2002 .inst = Instruction.csinc(.x1, .x2, .x4, .eq),
2003 .expected = 0b1_0_0_11010100_00100_0000_0_1_00010_00001,
2004 },
2005 .{ // mul x1, x4, x9
2006 .inst = Instruction.mul(.x1, .x4, .x9),
2007 .expected = 0b1_00_11011_000_01001_0_11111_00100_00001,
2008 },
2009 .{ // eor x3, x5, #1
2010 .inst = Instruction.eorImmediate(.x3, .x5, 0b000000, 0b000000, 0b1),
2011 .expected = 0b1_10_100100_1_000000_000000_00101_00011,
2012 },
2013 .{ // lslv x6, x9, x10
2014 .inst = Instruction.lslv(.x6, .x9, .x10),
2015 .expected = 0b1_0_0_11010110_01010_0010_00_01001_00110,
2016 },
2017 .{ // lsl x4, x2, #42
2018 .inst = Instruction.lslImmediate(.x4, .x2, 42),
2019 .expected = 0b1_10_100110_1_010110_010101_00010_00100,
2020 },
2021 .{ // lsl x4, x2, #63
2022 .inst = Instruction.lslImmediate(.x4, .x2, 63),
2023 .expected = 0b1_10_100110_1_000001_000000_00010_00100,
2024 },
2025 .{ // lsr x4, x2, #42
2026 .inst = Instruction.lsrImmediate(.x4, .x2, 42),
2027 .expected = 0b1_10_100110_1_101010_111111_00010_00100,
2028 },
2029 .{ // lsr x4, x2, #63
2030 .inst = Instruction.lsrImmediate(.x4, .x2, 63),
2031 .expected = 0b1_10_100110_1_111111_111111_00010_00100,
2032 },
2033 .{ // umull x0, w0, w1
2034 .inst = Instruction.umull(.x0, .w0, .w1),
2035 .expected = 0b1_00_11011_1_01_00001_0_11111_00000_00000,
2036 },
2037 .{ // smull x0, w0, w1
2038 .inst = Instruction.smull(.x0, .w0, .w1),
2039 .expected = 0b1_00_11011_0_01_00001_0_11111_00000_00000,
2040 },
2041 .{ // tst x0, #0xffffffff00000000
2042 .inst = Instruction.andsImmediate(.xzr, .x0, 0b011111, 0b100000, 0b1),
2043 .expected = 0b1_11_100100_1_100000_011111_00000_11111,
2044 },
2045 .{ // umulh x0, x1, x2
2046 .inst = Instruction.umulh(.x0, .x1, .x2),
2047 .expected = 0b1_00_11011_1_10_00010_0_11111_00001_00000,
2048 },
2049 .{ // smulh x0, x1, x2
2050 .inst = Instruction.smulh(.x0, .x1, .x2),
2051 .expected = 0b1_00_11011_0_10_00010_0_11111_00001_00000,
2052 },
2053 .{ // adds x0, x1, x2, sxtx
2054 .inst = Instruction.addsExtendedRegister(.x0, .x1, .x2, .sxtx, 0),
2055 .expected = 0b1_0_1_01011_00_1_00010_111_000_00001_00000,
2056 },
2057 };
2058
2059 for (testcases) |case| {
2060 const actual = case.inst.toU32();
2061 try testing.expectEqual(case.expected, actual);
2062 }
2063}
src/arch/riscv64/CodeGen.zig+5-5
...@@ -744,7 +744,7 @@ pub fn generate(...@@ -744,7 +744,7 @@ pub fn generate(
744 src_loc: Zcu.LazySrcLoc,744 src_loc: Zcu.LazySrcLoc,
745 func_index: InternPool.Index,745 func_index: InternPool.Index,
746 air: *const Air,746 air: *const Air,
747 liveness: *const Air.Liveness,747 liveness: *const ?Air.Liveness,
748) CodeGenError!Mir {748) CodeGenError!Mir {
749 const zcu = pt.zcu;749 const zcu = pt.zcu;
750 const gpa = zcu.gpa;750 const gpa = zcu.gpa;
...@@ -767,7 +767,7 @@ pub fn generate(...@@ -767,7 +767,7 @@ pub fn generate(
767 .pt = pt,767 .pt = pt,
768 .mod = mod,768 .mod = mod,
769 .bin_file = bin_file,769 .bin_file = bin_file,
770 .liveness = liveness.*,770 .liveness = liveness.*.?,
771 .target = &mod.resolved_target.result,771 .target = &mod.resolved_target.result,
772 .owner = .{ .nav_index = func.owner_nav },772 .owner = .{ .nav_index = func.owner_nav },
773 .args = undefined, // populated after `resolveCallingConventionValues`773 .args = undefined, // populated after `resolveCallingConventionValues`
...@@ -4584,7 +4584,7 @@ fn structFieldPtr(func: *Func, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde...@@ -4584,7 +4584,7 @@ fn structFieldPtr(func: *Func, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
4584 const field_offset: i32 = switch (container_ty.containerLayout(zcu)) {4584 const field_offset: i32 = switch (container_ty.containerLayout(zcu)) {
4585 .auto, .@"extern" => @intCast(container_ty.structFieldOffset(index, zcu)),4585 .auto, .@"extern" => @intCast(container_ty.structFieldOffset(index, zcu)),
4586 .@"packed" => @divExact(@as(i32, ptr_container_ty.ptrInfo(zcu).packed_offset.bit_offset) +4586 .@"packed" => @divExact(@as(i32, ptr_container_ty.ptrInfo(zcu).packed_offset.bit_offset) +
4587 (if (zcu.typeToStruct(container_ty)) |struct_obj| pt.structPackedFieldBitOffset(struct_obj, index) else 0) -4587 (if (zcu.typeToStruct(container_ty)) |struct_obj| zcu.structPackedFieldBitOffset(struct_obj, index) else 0) -
4588 ptr_field_ty.ptrInfo(zcu).packed_offset.bit_offset, 8),4588 ptr_field_ty.ptrInfo(zcu).packed_offset.bit_offset, 8),
4589 };4589 };
45904590
...@@ -4615,7 +4615,7 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void {...@@ -4615,7 +4615,7 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void {
4615 const field_off: u32 = switch (struct_ty.containerLayout(zcu)) {4615 const field_off: u32 = switch (struct_ty.containerLayout(zcu)) {
4616 .auto, .@"extern" => @intCast(struct_ty.structFieldOffset(index, zcu) * 8),4616 .auto, .@"extern" => @intCast(struct_ty.structFieldOffset(index, zcu) * 8),
4617 .@"packed" => if (zcu.typeToStruct(struct_ty)) |struct_type|4617 .@"packed" => if (zcu.typeToStruct(struct_ty)) |struct_type|
4618 pt.structPackedFieldBitOffset(struct_type, index)4618 zcu.structPackedFieldBitOffset(struct_type, index)
4619 else4619 else
4620 0,4620 0,
4621 };4621 };
...@@ -8059,7 +8059,7 @@ fn airAggregateInit(func: *Func, inst: Air.Inst.Index) !void {...@@ -8059,7 +8059,7 @@ fn airAggregateInit(func: *Func, inst: Air.Inst.Index) !void {
80598059
8060 const elem_abi_size: u32 = @intCast(elem_ty.abiSize(zcu));8060 const elem_abi_size: u32 = @intCast(elem_ty.abiSize(zcu));
8061 const elem_abi_bits = elem_abi_size * 8;8061 const elem_abi_bits = elem_abi_size * 8;
8062 const elem_off = pt.structPackedFieldBitOffset(struct_obj, elem_i);8062 const elem_off = zcu.structPackedFieldBitOffset(struct_obj, elem_i);
8063 const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size);8063 const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size);
8064 const elem_bit_off = elem_off % elem_abi_bits;8064 const elem_bit_off = elem_off % elem_abi_bits;
8065 const elem_mcv = try func.resolveInst(elem);8065 const elem_mcv = try func.resolveInst(elem);
src/arch/sparc64/CodeGen.zig+2-2
...@@ -267,7 +267,7 @@ pub fn generate(...@@ -267,7 +267,7 @@ pub fn generate(
267 src_loc: Zcu.LazySrcLoc,267 src_loc: Zcu.LazySrcLoc,
268 func_index: InternPool.Index,268 func_index: InternPool.Index,
269 air: *const Air,269 air: *const Air,
270 liveness: *const Air.Liveness,270 liveness: *const ?Air.Liveness,
271) CodeGenError!Mir {271) CodeGenError!Mir {
272 const zcu = pt.zcu;272 const zcu = pt.zcu;
273 const gpa = zcu.gpa;273 const gpa = zcu.gpa;
...@@ -288,7 +288,7 @@ pub fn generate(...@@ -288,7 +288,7 @@ pub fn generate(
288 .gpa = gpa,288 .gpa = gpa,
289 .pt = pt,289 .pt = pt,
290 .air = air.*,290 .air = air.*,
291 .liveness = liveness.*,291 .liveness = liveness.*.?,
292 .target = target,292 .target = target,
293 .bin_file = lf,293 .bin_file = lf,
294 .func_index = func_index,294 .func_index = func_index,
src/arch/wasm/CodeGen.zig+14-17
...@@ -1173,7 +1173,7 @@ pub fn generate(...@@ -1173,7 +1173,7 @@ pub fn generate(
1173 src_loc: Zcu.LazySrcLoc,1173 src_loc: Zcu.LazySrcLoc,
1174 func_index: InternPool.Index,1174 func_index: InternPool.Index,
1175 air: *const Air,1175 air: *const Air,
1176 liveness: *const Air.Liveness,1176 liveness: *const ?Air.Liveness,
1177) Error!Mir {1177) Error!Mir {
1178 _ = src_loc;1178 _ = src_loc;
1179 _ = bin_file;1179 _ = bin_file;
...@@ -1194,7 +1194,7 @@ pub fn generate(...@@ -1194,7 +1194,7 @@ pub fn generate(
1194 .gpa = gpa,1194 .gpa = gpa,
1195 .pt = pt,1195 .pt = pt,
1196 .air = air.*,1196 .air = air.*,
1197 .liveness = liveness.*,1197 .liveness = liveness.*.?,
1198 .owner_nav = cg.owner_nav,1198 .owner_nav = cg.owner_nav,
1199 .target = target,1199 .target = target,
1200 .ptr_size = switch (target.cpu.arch) {1200 .ptr_size = switch (target.cpu.arch) {
...@@ -1886,8 +1886,10 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -1886,8 +1886,10 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1886 .call_never_tail => cg.airCall(inst, .never_tail),1886 .call_never_tail => cg.airCall(inst, .never_tail),
1887 .call_never_inline => cg.airCall(inst, .never_inline),1887 .call_never_inline => cg.airCall(inst, .never_inline),
18881888
1889 .is_err => cg.airIsErr(inst, .i32_ne),1889 .is_err => cg.airIsErr(inst, .i32_ne, .value),
1890 .is_non_err => cg.airIsErr(inst, .i32_eq),1890 .is_non_err => cg.airIsErr(inst, .i32_eq, .value),
1891 .is_err_ptr => cg.airIsErr(inst, .i32_ne, .ptr),
1892 .is_non_err_ptr => cg.airIsErr(inst, .i32_eq, .ptr),
18911893
1892 .is_null => cg.airIsNull(inst, .i32_eq, .value),1894 .is_null => cg.airIsNull(inst, .i32_eq, .value),
1893 .is_non_null => cg.airIsNull(inst, .i32_ne, .value),1895 .is_non_null => cg.airIsNull(inst, .i32_ne, .value),
...@@ -1970,8 +1972,6 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -1970,8 +1972,6 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1970 .runtime_nav_ptr => cg.airRuntimeNavPtr(inst),1972 .runtime_nav_ptr => cg.airRuntimeNavPtr(inst),
19711973
1972 .assembly,1974 .assembly,
1973 .is_err_ptr,
1974 .is_non_err_ptr,
19751975
1976 .err_return_trace,1976 .err_return_trace,
1977 .set_err_return_trace,1977 .set_err_return_trace,
...@@ -3776,7 +3776,7 @@ fn structFieldPtr(...@@ -3776,7 +3776,7 @@ fn structFieldPtr(
3776 break :offset @as(u32, 0);3776 break :offset @as(u32, 0);
3777 }3777 }
3778 const struct_type = zcu.typeToStruct(struct_ty).?;3778 const struct_type = zcu.typeToStruct(struct_ty).?;
3779 break :offset @divExact(pt.structPackedFieldBitOffset(struct_type, index) + struct_ptr_ty_info.packed_offset.bit_offset, 8);3779 break :offset @divExact(zcu.structPackedFieldBitOffset(struct_type, index) + struct_ptr_ty_info.packed_offset.bit_offset, 8);
3780 },3780 },
3781 .@"union" => 0,3781 .@"union" => 0,
3782 else => unreachable,3782 else => unreachable,
...@@ -3812,7 +3812,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -3812,7 +3812,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
3812 .@"packed" => switch (struct_ty.zigTypeTag(zcu)) {3812 .@"packed" => switch (struct_ty.zigTypeTag(zcu)) {
3813 .@"struct" => result: {3813 .@"struct" => result: {
3814 const packed_struct = zcu.typeToPackedStruct(struct_ty).?;3814 const packed_struct = zcu.typeToPackedStruct(struct_ty).?;
3815 const offset = pt.structPackedFieldBitOffset(packed_struct, field_index);3815 const offset = zcu.structPackedFieldBitOffset(packed_struct, field_index);
3816 const backing_ty = Type.fromInterned(packed_struct.backingIntTypeUnordered(ip));3816 const backing_ty = Type.fromInterned(packed_struct.backingIntTypeUnordered(ip));
3817 const host_bits = backing_ty.intInfo(zcu).bits;3817 const host_bits = backing_ty.intInfo(zcu).bits;
38183818
...@@ -4105,7 +4105,7 @@ fn airSwitchDispatch(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -4105,7 +4105,7 @@ fn airSwitchDispatch(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
4105 return cg.finishAir(inst, .none, &.{br.operand});4105 return cg.finishAir(inst, .none, &.{br.operand});
4106}4106}
41074107
4108fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode) InnerError!void {4108fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode, op_kind: enum { value, ptr }) InnerError!void {
4109 const zcu = cg.pt.zcu;4109 const zcu = cg.pt.zcu;
4110 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;4110 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
4111 const operand = try cg.resolveInst(un_op);4111 const operand = try cg.resolveInst(un_op);
...@@ -4122,7 +4122,7 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode) InnerEr...@@ -4122,7 +4122,7 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode) InnerEr
4122 }4122 }
41234123
4124 try cg.emitWValue(operand);4124 try cg.emitWValue(operand);
4125 if (pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {4125 if (op_kind == .ptr or pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4126 try cg.addMemArg(.i32_load16_u, .{4126 try cg.addMemArg(.i32_load16_u, .{
4127 .offset = operand.offset() + @as(u32, @intCast(errUnionErrorOffset(pl_ty, zcu))),4127 .offset = operand.offset() + @as(u32, @intCast(errUnionErrorOffset(pl_ty, zcu))),
4128 .alignment = @intCast(Type.anyerror.abiAlignment(zcu).toByteUnits().?),4128 .alignment = @intCast(Type.anyerror.abiAlignment(zcu).toByteUnits().?),
...@@ -5696,7 +5696,7 @@ fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5696,7 +5696,7 @@ fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5696 .auto, .@"extern" => parent_ty.structFieldOffset(field_index, zcu),5696 .auto, .@"extern" => parent_ty.structFieldOffset(field_index, zcu),
5697 .@"packed" => offset: {5697 .@"packed" => offset: {
5698 const parent_ptr_offset = parent_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset;5698 const parent_ptr_offset = parent_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset;
5699 const field_offset = if (zcu.typeToStruct(parent_ty)) |loaded_struct| pt.structPackedFieldBitOffset(loaded_struct, field_index) else 0;5699 const field_offset = if (zcu.typeToStruct(parent_ty)) |loaded_struct| zcu.structPackedFieldBitOffset(loaded_struct, field_index) else 0;
5700 const field_ptr_offset = field_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset;5700 const field_ptr_offset = field_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset;
5701 break :offset @divExact(parent_ptr_offset + field_offset - field_ptr_offset, 8);5701 break :offset @divExact(parent_ptr_offset + field_offset - field_ptr_offset, 8);
5702 },5702 },
...@@ -6462,9 +6462,6 @@ fn lowerTry(...@@ -6462,9 +6462,6 @@ fn lowerTry(
6462 operand_is_ptr: bool,6462 operand_is_ptr: bool,
6463) InnerError!WValue {6463) InnerError!WValue {
6464 const zcu = cg.pt.zcu;6464 const zcu = cg.pt.zcu;
6465 if (operand_is_ptr) {
6466 return cg.fail("TODO: lowerTry for pointers", .{});
6467 }
64686465
6469 const pl_ty = err_union_ty.errorUnionPayload(zcu);6466 const pl_ty = err_union_ty.errorUnionPayload(zcu);
6470 const pl_has_bits = pl_ty.hasRuntimeBitsIgnoreComptime(zcu);6467 const pl_has_bits = pl_ty.hasRuntimeBitsIgnoreComptime(zcu);
...@@ -6475,7 +6472,7 @@ fn lowerTry(...@@ -6475,7 +6472,7 @@ fn lowerTry(
64756472
6476 // check if the error tag is set for the error union.6473 // check if the error tag is set for the error union.
6477 try cg.emitWValue(err_union);6474 try cg.emitWValue(err_union);
6478 if (pl_has_bits) {6475 if (pl_has_bits or operand_is_ptr) {
6479 const err_offset: u32 = @intCast(errUnionErrorOffset(pl_ty, zcu));6476 const err_offset: u32 = @intCast(errUnionErrorOffset(pl_ty, zcu));
6480 try cg.addMemArg(.i32_load16_u, .{6477 try cg.addMemArg(.i32_load16_u, .{
6481 .offset = err_union.offset() + err_offset,6478 .offset = err_union.offset() + err_offset,
...@@ -6497,12 +6494,12 @@ fn lowerTry(...@@ -6497,12 +6494,12 @@ fn lowerTry(
6497 }6494 }
64986495
6499 // if we reach here it means error was not set, and we want the payload6496 // if we reach here it means error was not set, and we want the payload
6500 if (!pl_has_bits) {6497 if (!pl_has_bits and !operand_is_ptr) {
6501 return .none;6498 return .none;
6502 }6499 }
65036500
6504 const pl_offset: u32 = @intCast(errUnionPayloadOffset(pl_ty, zcu));6501 const pl_offset: u32 = @intCast(errUnionPayloadOffset(pl_ty, zcu));
6505 if (isByRef(pl_ty, zcu, cg.target)) {6502 if (operand_is_ptr or isByRef(pl_ty, zcu, cg.target)) {
6506 return buildPointerOffset(cg, err_union, pl_offset, .new);6503 return buildPointerOffset(cg, err_union, pl_offset, .new);
6507 }6504 }
6508 const payload = try cg.load(err_union, pl_ty, pl_offset);6505 const payload = try cg.load(err_union, pl_ty, pl_offset);
src/arch/x86_64/CodeGen.zig+53-55
...@@ -878,7 +878,7 @@ pub fn generate(...@@ -878,7 +878,7 @@ pub fn generate(
878 src_loc: Zcu.LazySrcLoc,878 src_loc: Zcu.LazySrcLoc,
879 func_index: InternPool.Index,879 func_index: InternPool.Index,
880 air: *const Air,880 air: *const Air,
881 liveness: *const Air.Liveness,881 liveness: *const ?Air.Liveness,
882) codegen.CodeGenError!Mir {882) codegen.CodeGenError!Mir {
883 _ = bin_file;883 _ = bin_file;
884 const zcu = pt.zcu;884 const zcu = pt.zcu;
...@@ -894,7 +894,7 @@ pub fn generate(...@@ -894,7 +894,7 @@ pub fn generate(
894 .gpa = gpa,894 .gpa = gpa,
895 .pt = pt,895 .pt = pt,
896 .air = air.*,896 .air = air.*,
897 .liveness = liveness.*,897 .liveness = liveness.*.?,
898 .target = &mod.resolved_target.result,898 .target = &mod.resolved_target.result,
899 .mod = mod,899 .mod = mod,
900 .owner = .{ .nav_index = func.owner_nav },900 .owner = .{ .nav_index = func.owner_nav },
...@@ -1103,11 +1103,7 @@ const FormatAirData = struct {...@@ -1103,11 +1103,7 @@ const FormatAirData = struct {
1103 inst: Air.Inst.Index,1103 inst: Air.Inst.Index,
1104};1104};
1105fn formatAir(data: FormatAirData, w: *std.io.Writer) Writer.Error!void {1105fn formatAir(data: FormatAirData, w: *std.io.Writer) Writer.Error!void {
1106 // not acceptable implementation because it ignores `w`:1106 data.self.air.writeInst(w, data.inst, data.self.pt, data.self.liveness);
1107 //data.self.air.dumpInst(data.inst, data.self.pt, data.self.liveness);
1108 _ = data;
1109 _ = w;
1110 @panic("TODO: unimplemented");
1111}1107}
1112fn fmtAir(self: *CodeGen, inst: Air.Inst.Index) std.fmt.Formatter(FormatAirData, formatAir) {1108fn fmtAir(self: *CodeGen, inst: Air.Inst.Index) std.fmt.Formatter(FormatAirData, formatAir) {
1113 return .{ .data = .{ .self = self, .inst = inst } };1109 return .{ .data = .{ .self = self, .inst = inst } };
...@@ -100674,11 +100670,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -100674,11 +100670,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
100674 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;100670 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
100675 const struct_field = cg.air.extraData(Air.StructField, ty_pl.payload).data;100671 const struct_field = cg.air.extraData(Air.StructField, ty_pl.payload).data;
100676 var ops = try cg.tempsFromOperands(inst, .{struct_field.struct_operand});100672 var ops = try cg.tempsFromOperands(inst, .{struct_field.struct_operand});
100677 try ops[0].toOffset(cg.fieldOffset(100673 try ops[0].toOffset(@intCast(codegen.fieldOffset(
100678 cg.typeOf(struct_field.struct_operand),100674 cg.typeOf(struct_field.struct_operand),
100679 ty_pl.ty.toType(),100675 ty_pl.ty.toType(),
100680 struct_field.field_index,100676 struct_field.field_index,
100681 ), cg);100677 zcu,
100678 )), cg);
100682 try ops[0].finish(inst, &.{struct_field.struct_operand}, &ops, cg);100679 try ops[0].finish(inst, &.{struct_field.struct_operand}, &ops, cg);
100683 },100680 },
100684 .struct_field_ptr_index_0,100681 .struct_field_ptr_index_0,
...@@ -100688,7 +100685,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -100688,7 +100685,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
100688 => |air_tag| {100685 => |air_tag| {
100689 const ty_op = air_datas[@intFromEnum(inst)].ty_op;100686 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
100690 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});100687 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
100691 try ops[0].toOffset(cg.fieldOffset(100688 try ops[0].toOffset(@intCast(codegen.fieldOffset(
100692 cg.typeOf(ty_op.operand),100689 cg.typeOf(ty_op.operand),
100693 ty_op.ty.toType(),100690 ty_op.ty.toType(),
100694 switch (air_tag) {100691 switch (air_tag) {
...@@ -100698,7 +100695,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -100698,7 +100695,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
100698 .struct_field_ptr_index_2 => 2,100695 .struct_field_ptr_index_2 => 2,
100699 .struct_field_ptr_index_3 => 3,100696 .struct_field_ptr_index_3 => 3,
100700 },100697 },
100701 ), cg);100698 zcu,
100699 )), cg);
100702 try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);100700 try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
100703 },100701 },
100704 .struct_field_val => {100702 .struct_field_val => {
...@@ -168108,11 +168106,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -168108,11 +168106,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
168108 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;168106 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
168109 const field_parent_ptr = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;168107 const field_parent_ptr = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
168110 var ops = try cg.tempsFromOperands(inst, .{field_parent_ptr.field_ptr});168108 var ops = try cg.tempsFromOperands(inst, .{field_parent_ptr.field_ptr});
168111 try ops[0].toOffset(-cg.fieldOffset(168109 try ops[0].toOffset(-@as(i32, @intCast(codegen.fieldOffset(
168112 ty_pl.ty.toType(),168110 ty_pl.ty.toType(),
168113 cg.typeOf(field_parent_ptr.field_ptr),168111 cg.typeOf(field_parent_ptr.field_ptr),
168114 field_parent_ptr.field_index,168112 field_parent_ptr.field_index,
168115 ), cg);168113 zcu,
168114 ))), cg);
168116 try ops[0].finish(inst, &.{field_parent_ptr.field_ptr}, &ops, cg);168115 try ops[0].finish(inst, &.{field_parent_ptr.field_ptr}, &ops, cg);
168117 },168116 },
168118 .wasm_memory_size, .wasm_memory_grow => unreachable,168117 .wasm_memory_size, .wasm_memory_grow => unreachable,
...@@ -168138,7 +168137,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -168138,7 +168137,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
168138 .unused,168137 .unused,
168139 .unused,168138 .unused,
168140 },168139 },
168141 .dst_temps = .{ .{ .cc = .b }, .unused },168140 .dst_temps = .{ .{ .cc = .be }, .unused },
168142 .clobbers = .{ .eflags = true },168141 .clobbers = .{ .eflags = true },
168143 .each = .{ .once = &.{168142 .each = .{ .once = &.{
168144 .{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ },168143 .{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ },
...@@ -168162,7 +168161,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -168162,7 +168161,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
168162 .unused,168161 .unused,
168163 .unused,168162 .unused,
168164 },168163 },
168165 .dst_temps = .{ .{ .cc = .b }, .unused },168164 .dst_temps = .{ .{ .cc = .be }, .unused },
168166 .clobbers = .{ .eflags = true },168165 .clobbers = .{ .eflags = true },
168167 .each = .{ .once = &.{168166 .each = .{ .once = &.{
168168 .{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ },168167 .{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ },
...@@ -168186,7 +168185,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -168186,7 +168185,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
168186 .unused,168185 .unused,
168187 .unused,168186 .unused,
168188 },168187 },
168189 .dst_temps = .{ .{ .cc = .b }, .unused },168188 .dst_temps = .{ .{ .cc = .be }, .unused },
168190 .clobbers = .{ .eflags = true },168189 .clobbers = .{ .eflags = true },
168191 .each = .{ .once = &.{168190 .each = .{ .once = &.{
168192 .{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ },168191 .{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ },
...@@ -174809,18 +174808,6 @@ fn airStore(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void {...@@ -174809,18 +174808,6 @@ fn airStore(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void {
174809 return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none });174808 return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none });
174810}174809}
174811174810
174812fn fieldOffset(self: *CodeGen, ptr_agg_ty: Type, ptr_field_ty: Type, field_index: u32) i32 {
174813 const pt = self.pt;
174814 const zcu = pt.zcu;
174815 const agg_ty = ptr_agg_ty.childType(zcu);
174816 return switch (agg_ty.containerLayout(zcu)) {
174817 .auto, .@"extern" => @intCast(agg_ty.structFieldOffset(field_index, zcu)),
174818 .@"packed" => @divExact(@as(i32, ptr_agg_ty.ptrInfo(zcu).packed_offset.bit_offset) +
174819 (if (zcu.typeToStruct(agg_ty)) |loaded_struct| pt.structPackedFieldBitOffset(loaded_struct, field_index) else 0) -
174820 ptr_field_ty.ptrInfo(zcu).packed_offset.bit_offset, 8),
174821 };
174822}
174823
174824fn genUnOp(self: *CodeGen, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: Air.Inst.Ref) !MCValue {174811fn genUnOp(self: *CodeGen, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: Air.Inst.Ref) !MCValue {
174825 const pt = self.pt;174812 const pt = self.pt;
174826 const zcu = pt.zcu;174813 const zcu = pt.zcu;
...@@ -179309,10 +179296,13 @@ fn lowerSwitchBr(...@@ -179309,10 +179296,13 @@ fn lowerSwitchBr(
179309 } else undefined;179296 } else undefined;
179310 const table_start: u31 = @intCast(cg.mir_table.items.len);179297 const table_start: u31 = @intCast(cg.mir_table.items.len);
179311 {179298 {
179312 const condition_index_reg = if (condition_index.isRegister())179299 const condition_index_reg = condition_index_reg: {
179313 condition_index.getReg().?179300 if (condition_index.isRegister()) {
179314 else179301 const condition_index_reg = condition_index.getReg().?;
179315 try cg.copyToTmpRegister(.usize, condition_index);179302 if (condition_index_reg.isClass(.general_purpose)) break :condition_index_reg condition_index_reg;
179303 }
179304 break :condition_index_reg try cg.copyToTmpRegister(.usize, condition_index);
179305 };
179316 const condition_index_lock = cg.register_manager.lockReg(condition_index_reg);179306 const condition_index_lock = cg.register_manager.lockReg(condition_index_reg);
179317 defer if (condition_index_lock) |lock| cg.register_manager.unlockReg(lock);179307 defer if (condition_index_lock) |lock| cg.register_manager.unlockReg(lock);
179318 try cg.truncateRegister(condition_ty, condition_index_reg);179308 try cg.truncateRegister(condition_ty, condition_index_reg);
...@@ -184575,7 +184565,7 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -184575,7 +184565,7 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void {
184575 }184565 }
184576 const elem_abi_size: u32 = @intCast(elem_ty.abiSize(zcu));184566 const elem_abi_size: u32 = @intCast(elem_ty.abiSize(zcu));
184577 const elem_abi_bits = elem_abi_size * 8;184567 const elem_abi_bits = elem_abi_size * 8;
184578 const elem_off = pt.structPackedFieldBitOffset(loaded_struct, elem_i);184568 const elem_off = zcu.structPackedFieldBitOffset(loaded_struct, elem_i);
184579 const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size);184569 const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size);
184580 const elem_bit_off = elem_off % elem_abi_bits;184570 const elem_bit_off = elem_off % elem_abi_bits;
184581 const elem_mcv = try self.resolveInst(elem);184571 const elem_mcv = try self.resolveInst(elem);
...@@ -185625,21 +185615,19 @@ fn resolveCallingConventionValues(...@@ -185625,21 +185615,19 @@ fn resolveCallingConventionValues(
185625fn fail(cg: *CodeGen, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {185615fn fail(cg: *CodeGen, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {
185626 @branchHint(.cold);185616 @branchHint(.cold);
185627 const zcu = cg.pt.zcu;185617 const zcu = cg.pt.zcu;
185628 switch (cg.owner) {185618 return switch (cg.owner) {
185629 .nav_index => |i| return zcu.codegenFail(i, format, args),185619 .nav_index => |i| zcu.codegenFail(i, format, args),
185630 .lazy_sym => |s| return zcu.codegenFailType(s.ty, format, args),185620 .lazy_sym => |s| zcu.codegenFailType(s.ty, format, args),
185631 }185621 };
185632 return error.CodegenFail;
185633}185622}
185634185623
185635fn failMsg(cg: *CodeGen, msg: *Zcu.ErrorMsg) error{ OutOfMemory, CodegenFail } {185624fn failMsg(cg: *CodeGen, msg: *Zcu.ErrorMsg) error{ OutOfMemory, CodegenFail } {
185636 @branchHint(.cold);185625 @branchHint(.cold);
185637 const zcu = cg.pt.zcu;185626 const zcu = cg.pt.zcu;
185638 switch (cg.owner) {185627 return switch (cg.owner) {
185639 .nav_index => |i| return zcu.codegenFailMsg(i, msg),185628 .nav_index => |i| zcu.codegenFailMsg(i, msg),
185640 .lazy_sym => |s| return zcu.codegenFailTypeMsg(s.ty, msg),185629 .lazy_sym => |s| zcu.codegenFailTypeMsg(s.ty, msg),
185641 }185630 };
185642 return error.CodegenFail;
185643}185631}
185644185632
185645fn parseRegName(name: []const u8) ?Register {185633fn parseRegName(name: []const u8) ?Register {
...@@ -191932,18 +191920,15 @@ const Select = struct {...@@ -191932,18 +191920,15 @@ const Select = struct {
191932 error.InvalidInstruction => {191920 error.InvalidInstruction => {
191933 const fixes = @tagName(mir_tag[0]);191921 const fixes = @tagName(mir_tag[0]);
191934 const fixes_blank = std.mem.indexOfScalar(u8, fixes, '_').?;191922 const fixes_blank = std.mem.indexOfScalar(u8, fixes, '_').?;
191935 return s.cg.fail(191923 return s.cg.fail("invalid instruction: '{s}{s}{s} {s} {s} {s} {s}'", .{
191936 "invalid instruction: '{s}{s}{s} {s} {s} {s} {s}'",191924 fixes[0..fixes_blank],
191937 .{191925 @tagName(mir_tag[1]),
191938 fixes[0..fixes_blank],191926 fixes[fixes_blank + 1 ..],
191939 @tagName(mir_tag[1]),191927 @tagName(mir_ops[0]),
191940 fixes[fixes_blank + 1 ..],191928 @tagName(mir_ops[1]),
191941 @tagName(mir_ops[0]),191929 @tagName(mir_ops[2]),
191942 @tagName(mir_ops[1]),191930 @tagName(mir_ops[3]),
191943 @tagName(mir_ops[2]),191931 });
191944 @tagName(mir_ops[3]),
191945 },
191946 );
191947 },191932 },
191948 else => |e| return e,191933 else => |e| return e,
191949 };191934 };
...@@ -194435,6 +194420,18 @@ fn select(...@@ -194435,6 +194420,18 @@ fn select(
194435 while (true) for (pattern.src[0..src_temps.len], src_temps) |src_pattern, *src_temp| {194420 while (true) for (pattern.src[0..src_temps.len], src_temps) |src_pattern, *src_temp| {
194436 if (try src_pattern.convert(src_temp, cg)) break;194421 if (try src_pattern.convert(src_temp, cg)) break;
194437 } else break;194422 } else break;
194423 var src_locks: [s_src_temps.len][2]?RegisterLock = @splat(@splat(null));
194424 for (src_locks[0..src_temps.len], src_temps) |*locks, src_temp| {
194425 const regs: [2]Register = switch (src_temp.tracking(cg).short) {
194426 else => continue,
194427 .register => |reg| .{ reg, .none },
194428 .register_pair => |regs| regs,
194429 };
194430 for (regs, locks) |reg, *lock| {
194431 if (reg == .none) continue;
194432 lock.* = cg.register_manager.lockRegIndex(RegisterManager.indexOfRegIntoTracked(reg) orelse continue);
194433 }
194434 }
194438 @memcpy(s_src_temps[0..src_temps.len], src_temps);194435 @memcpy(s_src_temps[0..src_temps.len], src_temps);
194439 std.mem.swap(Temp, &s_src_temps[pattern.commute[0]], &s_src_temps[pattern.commute[1]]);194436 std.mem.swap(Temp, &s_src_temps[pattern.commute[0]], &s_src_temps[pattern.commute[1]]);
194440194437
...@@ -194453,6 +194450,7 @@ fn select(...@@ -194453,6 +194450,7 @@ fn select(
194453 }194450 }
194454 assert(s.top == 0);194451 assert(s.top == 0);
194455194452
194453 for (src_locks) |locks| for (locks) |lock| if (lock) |reg| cg.register_manager.unlockReg(reg);
194456 for (tmp_locks) |locks| for (locks) |lock| if (lock) |reg| cg.register_manager.unlockReg(reg);194454 for (tmp_locks) |locks| for (locks) |lock| if (lock) |reg| cg.register_manager.unlockReg(reg);
194457 for (dst_locks) |locks| for (locks) |lock| if (lock) |reg| cg.register_manager.unlockReg(reg);194455 for (dst_locks) |locks| for (locks) |lock| if (lock) |reg| cg.register_manager.unlockReg(reg);
194458 caller_preserved: {194456 caller_preserved: {
src/arch/x86_64/Emit.zig+6-5
...@@ -168,11 +168,12 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -168,11 +168,12 @@ pub fn emitMir(emit: *Emit) Error!void {
168 else if (emit.bin_file.cast(.macho)) |macho_file|168 else if (emit.bin_file.cast(.macho)) |macho_file|
169 macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, emit.pt, lazy_sym) catch |err|169 macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, emit.pt, lazy_sym) catch |err|
170 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})170 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})
171 else if (emit.bin_file.cast(.coff)) |coff_file| sym_index: {171 else if (emit.bin_file.cast(.coff)) |coff_file|
172 const atom = coff_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym) catch |err|172 if (coff_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym)) |atom|
173 return emit.fail("{s} creating lazy symbol", .{@errorName(err)});173 coff_file.getAtom(atom).getSymbolIndex().?
174 break :sym_index coff_file.getAtom(atom).getSymbolIndex().?;174 else |err|
175 } else if (emit.bin_file.cast(.plan9)) |p9_file|175 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})
176 else if (emit.bin_file.cast(.plan9)) |p9_file|
176 p9_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym) catch |err|177 p9_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym) catch |err|
177 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})178 return emit.fail("{s} creating lazy symbol", .{@errorName(err)})
178 else179 else
src/codegen.zig+48-13
...@@ -22,6 +22,8 @@ const Zir = std.zig.Zir;...@@ -22,6 +22,8 @@ const Zir = std.zig.Zir;
22const Alignment = InternPool.Alignment;22const Alignment = InternPool.Alignment;
23const dev = @import("dev.zig");23const dev = @import("dev.zig");
2424
25pub const aarch64 = @import("codegen/aarch64.zig");
26
25pub const CodeGenError = GenerateSymbolError || error{27pub const CodeGenError = GenerateSymbolError || error{
26 /// Indicates the error is already stored in Zcu `failed_codegen`.28 /// Indicates the error is already stored in Zcu `failed_codegen`.
27 CodegenFail,29 CodegenFail,
...@@ -48,7 +50,7 @@ fn devFeatureForBackend(backend: std.builtin.CompilerBackend) dev.Feature {...@@ -48,7 +50,7 @@ fn devFeatureForBackend(backend: std.builtin.CompilerBackend) dev.Feature {
48fn importBackend(comptime backend: std.builtin.CompilerBackend) type {50fn importBackend(comptime backend: std.builtin.CompilerBackend) type {
49 return switch (backend) {51 return switch (backend) {
50 .other, .stage1 => unreachable,52 .other, .stage1 => unreachable,
51 .stage2_aarch64 => unreachable,53 .stage2_aarch64 => aarch64,
52 .stage2_arm => unreachable,54 .stage2_arm => unreachable,
53 .stage2_c => @import("codegen/c.zig"),55 .stage2_c => @import("codegen/c.zig"),
54 .stage2_llvm => @import("codegen/llvm.zig"),56 .stage2_llvm => @import("codegen/llvm.zig"),
...@@ -71,6 +73,7 @@ pub fn legalizeFeatures(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) ?*co...@@ -71,6 +73,7 @@ pub fn legalizeFeatures(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) ?*co
71 .stage2_c,73 .stage2_c,
72 .stage2_wasm,74 .stage2_wasm,
73 .stage2_x86_64,75 .stage2_x86_64,
76 .stage2_aarch64,
74 .stage2_x86,77 .stage2_x86,
75 .stage2_riscv64,78 .stage2_riscv64,
76 .stage2_sparc64,79 .stage2_sparc64,
...@@ -82,20 +85,29 @@ pub fn legalizeFeatures(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) ?*co...@@ -82,20 +85,29 @@ pub fn legalizeFeatures(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) ?*co
82 }85 }
83}86}
8487
88pub fn wantsLiveness(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) bool {
89 const zcu = pt.zcu;
90 const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;
91 return switch (target_util.zigBackend(target, zcu.comp.config.use_llvm)) {
92 else => true,
93 .stage2_aarch64 => false,
94 };
95}
96
85/// Every code generation backend has a different MIR representation. However, we want to pass97/// Every code generation backend has a different MIR representation. However, we want to pass
86/// MIR from codegen to the linker *regardless* of which backend is in use. So, we use this: a98/// MIR from codegen to the linker *regardless* of which backend is in use. So, we use this: a
87/// union of all MIR types. The active tag is known from the backend in use; see `AnyMir.tag`.99/// union of all MIR types. The active tag is known from the backend in use; see `AnyMir.tag`.
88pub const AnyMir = union {100pub const AnyMir = union {
89 riscv64: @import("arch/riscv64/Mir.zig"),101 aarch64: if (dev.env.supports(.aarch64_backend)) @import("codegen/aarch64/Mir.zig") else noreturn,
90 sparc64: @import("arch/sparc64/Mir.zig"),102 riscv64: if (dev.env.supports(.riscv64_backend)) @import("arch/riscv64/Mir.zig") else noreturn,
91 x86_64: @import("arch/x86_64/Mir.zig"),103 sparc64: if (dev.env.supports(.sparc64_backend)) @import("arch/sparc64/Mir.zig") else noreturn,
92 wasm: @import("arch/wasm/Mir.zig"),104 x86_64: if (dev.env.supports(.x86_64_backend)) @import("arch/x86_64/Mir.zig") else noreturn,
93 c: @import("codegen/c.zig").Mir,105 wasm: if (dev.env.supports(.wasm_backend)) @import("arch/wasm/Mir.zig") else noreturn,
106 c: if (dev.env.supports(.c_backend)) @import("codegen/c.zig").Mir else noreturn,
94107
95 pub inline fn tag(comptime backend: std.builtin.CompilerBackend) []const u8 {108 pub inline fn tag(comptime backend: std.builtin.CompilerBackend) []const u8 {
96 return switch (backend) {109 return switch (backend) {
97 .stage2_aarch64 => "aarch64",110 .stage2_aarch64 => "aarch64",
98 .stage2_arm => "arm",
99 .stage2_riscv64 => "riscv64",111 .stage2_riscv64 => "riscv64",
100 .stage2_sparc64 => "sparc64",112 .stage2_sparc64 => "sparc64",
101 .stage2_x86_64 => "x86_64",113 .stage2_x86_64 => "x86_64",
...@@ -110,7 +122,8 @@ pub const AnyMir = union {...@@ -110,7 +122,8 @@ pub const AnyMir = union {
110 const backend = target_util.zigBackend(&zcu.root_mod.resolved_target.result, zcu.comp.config.use_llvm);122 const backend = target_util.zigBackend(&zcu.root_mod.resolved_target.result, zcu.comp.config.use_llvm);
111 switch (backend) {123 switch (backend) {
112 else => unreachable,124 else => unreachable,
113 inline .stage2_riscv64,125 inline .stage2_aarch64,
126 .stage2_riscv64,
114 .stage2_sparc64,127 .stage2_sparc64,
115 .stage2_x86_64,128 .stage2_x86_64,
116 .stage2_wasm,129 .stage2_wasm,
...@@ -131,14 +144,15 @@ pub fn generateFunction(...@@ -131,14 +144,15 @@ pub fn generateFunction(
131 src_loc: Zcu.LazySrcLoc,144 src_loc: Zcu.LazySrcLoc,
132 func_index: InternPool.Index,145 func_index: InternPool.Index,
133 air: *const Air,146 air: *const Air,
134 liveness: *const Air.Liveness,147 liveness: *const ?Air.Liveness,
135) CodeGenError!AnyMir {148) CodeGenError!AnyMir {
136 const zcu = pt.zcu;149 const zcu = pt.zcu;
137 const func = zcu.funcInfo(func_index);150 const func = zcu.funcInfo(func_index);
138 const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result;151 const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result;
139 switch (target_util.zigBackend(target, false)) {152 switch (target_util.zigBackend(target, false)) {
140 else => unreachable,153 else => unreachable,
141 inline .stage2_riscv64,154 inline .stage2_aarch64,
155 .stage2_riscv64,
142 .stage2_sparc64,156 .stage2_sparc64,
143 .stage2_x86_64,157 .stage2_x86_64,
144 .stage2_wasm,158 .stage2_wasm,
...@@ -173,7 +187,8 @@ pub fn emitFunction(...@@ -173,7 +187,8 @@ pub fn emitFunction(
173 const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result;187 const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result;
174 switch (target_util.zigBackend(target, zcu.comp.config.use_llvm)) {188 switch (target_util.zigBackend(target, zcu.comp.config.use_llvm)) {
175 else => unreachable,189 else => unreachable,
176 inline .stage2_riscv64,190 inline .stage2_aarch64,
191 .stage2_riscv64,
177 .stage2_sparc64,192 .stage2_sparc64,
178 .stage2_x86_64,193 .stage2_x86_64,
179 => |backend| {194 => |backend| {
...@@ -420,7 +435,7 @@ pub fn generateSymbol(...@@ -420,7 +435,7 @@ pub fn generateSymbol(
420 const int_tag_ty = ty.intTagType(zcu);435 const int_tag_ty = ty.intTagType(zcu);
421 try generateSymbol(bin_file, pt, src_loc, try pt.getCoerced(Value.fromInterned(enum_tag.int), int_tag_ty), code, reloc_parent);436 try generateSymbol(bin_file, pt, src_loc, try pt.getCoerced(Value.fromInterned(enum_tag.int), int_tag_ty), code, reloc_parent);
422 },437 },
423 .float => |float| switch (float.storage) {438 .float => |float| storage: switch (float.storage) {
424 .f16 => |f16_val| writeFloat(f16, f16_val, target, endian, try code.addManyAsArray(gpa, 2)),439 .f16 => |f16_val| writeFloat(f16, f16_val, target, endian, try code.addManyAsArray(gpa, 2)),
425 .f32 => |f32_val| writeFloat(f32, f32_val, target, endian, try code.addManyAsArray(gpa, 4)),440 .f32 => |f32_val| writeFloat(f32, f32_val, target, endian, try code.addManyAsArray(gpa, 4)),
426 .f64 => |f64_val| writeFloat(f64, f64_val, target, endian, try code.addManyAsArray(gpa, 8)),441 .f64 => |f64_val| writeFloat(f64, f64_val, target, endian, try code.addManyAsArray(gpa, 8)),
...@@ -429,7 +444,13 @@ pub fn generateSymbol(...@@ -429,7 +444,13 @@ pub fn generateSymbol(
429 const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow;444 const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow;
430 try code.appendNTimes(gpa, 0, abi_size - 10);445 try code.appendNTimes(gpa, 0, abi_size - 10);
431 },446 },
432 .f128 => |f128_val| writeFloat(f128, f128_val, target, endian, try code.addManyAsArray(gpa, 16)),447 .f128 => |f128_val| switch (Type.fromInterned(float.ty).floatBits(target)) {
448 else => unreachable,
449 16 => continue :storage .{ .f16 = @floatCast(f128_val) },
450 32 => continue :storage .{ .f32 = @floatCast(f128_val) },
451 64 => continue :storage .{ .f64 = @floatCast(f128_val) },
452 128 => writeFloat(f128, f128_val, target, endian, try code.addManyAsArray(gpa, 16)),
453 },
433 },454 },
434 .ptr => try lowerPtr(bin_file, pt, src_loc, val.toIntern(), code, reloc_parent, 0),455 .ptr => try lowerPtr(bin_file, pt, src_loc, val.toIntern(), code, reloc_parent, 0),
435 .slice => |slice| {456 .slice => |slice| {
...@@ -1218,3 +1239,17 @@ pub fn errUnionErrorOffset(payload_ty: Type, zcu: *Zcu) u64 {...@@ -1218,3 +1239,17 @@ pub fn errUnionErrorOffset(payload_ty: Type, zcu: *Zcu) u64 {
1218 return 0;1239 return 0;
1219 }1240 }
1220}1241}
1242
1243pub fn fieldOffset(ptr_agg_ty: Type, ptr_field_ty: Type, field_index: u32, zcu: *Zcu) u64 {
1244 const agg_ty = ptr_agg_ty.childType(zcu);
1245 return switch (agg_ty.containerLayout(zcu)) {
1246 .auto, .@"extern" => agg_ty.structFieldOffset(field_index, zcu),
1247 .@"packed" => @divExact(@as(u64, ptr_agg_ty.ptrInfo(zcu).packed_offset.bit_offset) +
1248 (if (zcu.typeToPackedStruct(agg_ty)) |loaded_struct| zcu.structPackedFieldBitOffset(loaded_struct, field_index) else 0) -
1249 ptr_field_ty.ptrInfo(zcu).packed_offset.bit_offset, 8),
1250 };
1251}
1252
1253test {
1254 _ = aarch64;
1255}
src/codegen/aarch64.zig created+205
...@@ -0,0 +1,205 @@
1pub const abi = @import("aarch64/abi.zig");
2pub const Assemble = @import("aarch64/Assemble.zig");
3pub const Disassemble = @import("aarch64/Disassemble.zig");
4pub const encoding = @import("aarch64/encoding.zig");
5pub const Mir = @import("aarch64/Mir.zig");
6pub const Select = @import("aarch64/Select.zig");
7
8pub fn legalizeFeatures(_: *const std.Target) ?*Air.Legalize.Features {
9 return null;
10}
11
12pub fn generate(
13 _: *link.File,
14 pt: Zcu.PerThread,
15 _: Zcu.LazySrcLoc,
16 func_index: InternPool.Index,
17 air: *const Air,
18 liveness: *const ?Air.Liveness,
19) !Mir {
20 const zcu = pt.zcu;
21 const gpa = zcu.gpa;
22 const ip = &zcu.intern_pool;
23 const func = zcu.funcInfo(func_index);
24 const func_zir = func.zir_body_inst.resolveFull(ip).?;
25 const file = zcu.fileByIndex(func_zir.file);
26 const named_params_len = file.zir.?.getParamBody(func_zir.inst).len;
27 const func_type = ip.indexToKey(func.ty).func_type;
28 assert(liveness.* == null);
29
30 const mod = zcu.navFileScope(func.owner_nav).mod.?;
31 var isel: Select = .{
32 .pt = pt,
33 .target = &mod.resolved_target.result,
34 .air = air.*,
35 .nav_index = zcu.funcInfo(func_index).owner_nav,
36
37 .def_order = .empty,
38 .blocks = .empty,
39 .loops = .empty,
40 .active_loops = .empty,
41 .loop_live = .{
42 .set = .empty,
43 .list = .empty,
44 },
45 .dom_start = 0,
46 .dom_len = 0,
47 .dom = .empty,
48
49 .saved_registers = comptime .initEmpty(),
50 .instructions = .empty,
51 .literals = .empty,
52 .nav_relocs = .empty,
53 .uav_relocs = .empty,
54 .lazy_relocs = .empty,
55 .global_relocs = .empty,
56 .literal_relocs = .empty,
57
58 .returns = false,
59 .va_list = undefined,
60 .stack_size = 0,
61 .stack_align = .@"16",
62
63 .live_registers = comptime .initFill(.free),
64 .live_values = .empty,
65 .values = .empty,
66 };
67 defer isel.deinit();
68 const is_sysv = !isel.target.os.tag.isDarwin() and isel.target.os.tag != .windows;
69 const is_sysv_var_args = is_sysv and func_type.is_var_args;
70
71 const air_main_body = air.getMainBody();
72 var param_it: Select.CallAbiIterator = .init;
73 const air_args = for (air_main_body, 0..) |air_inst_index, body_index| {
74 if (air.instructions.items(.tag)[@intFromEnum(air_inst_index)] != .arg) break air_main_body[0..body_index];
75 const arg = air.instructions.items(.data)[@intFromEnum(air_inst_index)].arg;
76 const param_ty = arg.ty.toType();
77 const param_vi = param_vi: {
78 if (arg.zir_param_index >= named_params_len) {
79 assert(func_type.is_var_args);
80 if (!is_sysv) break :param_vi try param_it.nonSysvVarArg(&isel, param_ty);
81 }
82 break :param_vi try param_it.param(&isel, param_ty);
83 };
84 tracking_log.debug("${d} <- %{d}", .{ @intFromEnum(param_vi.?), @intFromEnum(air_inst_index) });
85 try isel.live_values.putNoClobber(gpa, air_inst_index, param_vi.?);
86 } else unreachable;
87
88 const saved_gra_start = if (mod.strip) param_it.ngrn else Select.CallAbiIterator.ngrn_start;
89 const saved_gra_end = if (is_sysv_var_args) Select.CallAbiIterator.ngrn_end else param_it.ngrn;
90 const saved_gra_len = @intFromEnum(saved_gra_end) - @intFromEnum(saved_gra_start);
91
92 const saved_vra_start = if (mod.strip) param_it.nsrn else Select.CallAbiIterator.nsrn_start;
93 const saved_vra_end = if (is_sysv_var_args) Select.CallAbiIterator.nsrn_end else param_it.nsrn;
94 const saved_vra_len = @intFromEnum(saved_vra_end) - @intFromEnum(saved_vra_start);
95
96 const frame_record = 2;
97 const named_stack_args: Select.Value.Indirect = .{
98 .base = .fp,
99 .offset = 8 * std.mem.alignForward(u7, frame_record + saved_gra_len, 2),
100 };
101 const stack_var_args = named_stack_args.withOffset(param_it.nsaa);
102 const gr_top = named_stack_args;
103 const vr_top: Select.Value.Indirect = .{ .base = .fp, .offset = 0 };
104 isel.va_list = if (is_sysv) .{ .sysv = .{
105 .__stack = stack_var_args,
106 .__gr_top = gr_top,
107 .__vr_top = vr_top,
108 .__gr_offs = @as(i32, @intFromEnum(Select.CallAbiIterator.ngrn_end) - @intFromEnum(param_it.ngrn)) * -8,
109 .__vr_offs = @as(i32, @intFromEnum(Select.CallAbiIterator.nsrn_end) - @intFromEnum(param_it.nsrn)) * -16,
110 } } else .{ .other = stack_var_args };
111
112 // translate arg locations from caller-based to callee-based
113 for (air_args) |air_inst_index| {
114 assert(air.instructions.items(.tag)[@intFromEnum(air_inst_index)] == .arg);
115 const arg_vi = isel.live_values.get(air_inst_index).?;
116 const passed_vi = switch (arg_vi.parent(&isel)) {
117 .unallocated, .stack_slot => arg_vi,
118 .value, .constant => unreachable,
119 .address => |address_vi| address_vi,
120 };
121 switch (passed_vi.parent(&isel)) {
122 .unallocated => if (!mod.strip) {
123 var part_it = passed_vi.parts(&isel);
124 const first_passed_part_vi = part_it.next().?;
125 const hint_ra = first_passed_part_vi.hint(&isel).?;
126 passed_vi.setParent(&isel, .{ .stack_slot = if (hint_ra.isVector())
127 vr_top.withOffset(@as(i8, -16) * (@intFromEnum(saved_vra_end) - @intFromEnum(hint_ra)))
128 else
129 gr_top.withOffset(@as(i8, -8) * (@intFromEnum(saved_gra_end) - @intFromEnum(hint_ra))) });
130 },
131 .stack_slot => |stack_slot| {
132 assert(stack_slot.base == .sp);
133 passed_vi.changeStackSlot(&isel, named_stack_args.withOffset(stack_slot.offset));
134 },
135 .address, .value, .constant => unreachable,
136 }
137 }
138
139 ret: {
140 var ret_it: Select.CallAbiIterator = .init;
141 const ret_vi = try ret_it.ret(&isel, .fromInterned(func_type.return_type)) orelse break :ret;
142 tracking_log.debug("${d} <- %main", .{@intFromEnum(ret_vi)});
143 try isel.live_values.putNoClobber(gpa, Select.Block.main, ret_vi);
144 }
145
146 assert(!(try isel.blocks.getOrPut(gpa, Select.Block.main)).found_existing);
147 try isel.analyze(air_main_body);
148 try isel.finishAnalysis();
149 isel.verify(false);
150
151 isel.blocks.values()[0] = .{
152 .live_registers = isel.live_registers,
153 .target_label = @intCast(isel.instructions.items.len),
154 };
155 try isel.body(air_main_body);
156 if (isel.live_values.fetchRemove(Select.Block.main)) |ret_vi| {
157 switch (ret_vi.value.parent(&isel)) {
158 .unallocated, .stack_slot => {},
159 .value, .constant => unreachable,
160 .address => |address_vi| try address_vi.liveIn(
161 &isel,
162 address_vi.hint(&isel).?,
163 comptime &.initFill(.free),
164 ),
165 }
166 ret_vi.value.deref(&isel);
167 }
168 isel.verify(true);
169
170 const prologue = isel.instructions.items.len;
171 const epilogue = try isel.layout(param_it, is_sysv_var_args, saved_gra_len, saved_vra_len, mod);
172
173 const instructions = try isel.instructions.toOwnedSlice(gpa);
174 var mir: Mir = .{
175 .prologue = instructions[prologue..epilogue],
176 .body = instructions[0..prologue],
177 .epilogue = instructions[epilogue..],
178 .literals = &.{},
179 .nav_relocs = &.{},
180 .uav_relocs = &.{},
181 .lazy_relocs = &.{},
182 .global_relocs = &.{},
183 .literal_relocs = &.{},
184 };
185 errdefer mir.deinit(gpa);
186 mir.literals = try isel.literals.toOwnedSlice(gpa);
187 mir.nav_relocs = try isel.nav_relocs.toOwnedSlice(gpa);
188 mir.uav_relocs = try isel.uav_relocs.toOwnedSlice(gpa);
189 mir.lazy_relocs = try isel.lazy_relocs.toOwnedSlice(gpa);
190 mir.global_relocs = try isel.global_relocs.toOwnedSlice(gpa);
191 mir.literal_relocs = try isel.literal_relocs.toOwnedSlice(gpa);
192 return mir;
193}
194
195test {
196 _ = Assemble;
197}
198
199const Air = @import("../Air.zig");
200const assert = std.debug.assert;
201const InternPool = @import("../InternPool.zig");
202const link = @import("../link.zig");
203const std = @import("std");
204const tracking_log = std.log.scoped(.tracking);
205const Zcu = @import("../Zcu.zig");
src/codegen/aarch64/Assemble.zig created+1682
...@@ -0,0 +1,1682 @@
1source: [*:0]const u8,
2operands: std.StringHashMapUnmanaged(Operand),
3
4pub const Operand = union(enum) {
5 register: aarch64.encoding.Register,
6};
7
8pub fn nextInstruction(as: *Assemble) !?Instruction {
9 @setEvalBranchQuota(42_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 switch (source_token.len) {
16 0 => return null,
17 else => switch (source_token[0]) {
18 else => break original_source,
19 '\n', ';' => {},
20 },
21 }
22 };
23 log.debug(
24 \\.
25 \\=========================
26 \\= Assembling "{f}"
27 \\=========================
28 \\
29 , .{std.zig.fmtString(std.mem.span(original_source))});
30 inline for (instructions) |instruction| {
31 next_pattern: {
32 as.source = original_source;
33 var symbols: Symbols: {
34 const symbols = @typeInfo(@TypeOf(instruction.symbols)).@"struct".fields;
35 var symbol_fields: [symbols.len]std.builtin.Type.StructField = undefined;
36 for (&symbol_fields, symbols) |*symbol_field, symbol| symbol_field.* = .{
37 .name = symbol.name,
38 .type = zonCast(SymbolSpec, @field(instruction.symbols, symbol.name), .{}).Storage(),
39 .default_value_ptr = null,
40 .is_comptime = false,
41 .alignment = 0,
42 };
43 break :Symbols @Type(.{ .@"struct" = .{
44 .layout = .auto,
45 .fields = &symbol_fields,
46 .decls = &.{},
47 .is_tuple = false,
48 } });
49 } = undefined;
50 comptime var pattern_as: Assemble = .{ .source = instruction.pattern, .operands = undefined };
51 inline while (true) {
52 const pattern_token = comptime pattern_as.nextToken(&ct_token_buf, .{ .placeholders = true }) catch |err|
53 @compileError(@errorName(err) ++ " while parsing '" ++ instruction.pattern ++ "'");
54 const source_token = try as.nextToken(&token_buf, .{ .operands = true });
55 log.debug("\"{f}\" -> \"{f}\"", .{
56 std.zig.fmtString(pattern_token),
57 std.zig.fmtString(source_token),
58 });
59 if (pattern_token.len == 0) {
60 switch (source_token.len) {
61 0 => {},
62 else => switch (source_token[0]) {
63 else => break :next_pattern,
64 '\n', ';' => {},
65 },
66 }
67 const encode = @field(Instruction, @tagName(instruction.encode[0]));
68 const Encode = @TypeOf(encode);
69 var args: std.meta.ArgsTuple(Encode) = undefined;
70 inline for (&args, @typeInfo(Encode).@"fn".params, 1..instruction.encode.len) |*arg, param, encode_index|
71 arg.* = zonCast(param.type.?, instruction.encode[encode_index], symbols);
72 return @call(.auto, encode, args);
73 } else if (pattern_token[0] == '<') {
74 const symbol_name = comptime pattern_token[1 .. std.mem.indexOfScalarPos(u8, pattern_token, 1, '|') orelse
75 pattern_token.len - 1];
76 const symbol = &@field(symbols, symbol_name);
77 symbol.* = zonCast(SymbolSpec, @field(instruction.symbols, symbol_name), .{}).parse(source_token) orelse break :next_pattern;
78 log.debug("{s} = {any}", .{ symbol_name, symbol.* });
79 } else if (!toUpperEqlAssertUpper(source_token, pattern_token)) break :next_pattern;
80 }
81 }
82 log.debug("'{s}' not matched...", .{instruction.pattern});
83 }
84 as.source = original_source;
85 log.debug("Nothing matched!\n", .{});
86 return error.InvalidSyntax;
87}
88
89fn zonCast(comptime Result: type, zon_value: anytype, symbols: anytype) Result {
90 const ZonValue = @TypeOf(zon_value);
91 const Symbols = @TypeOf(symbols);
92 switch (@typeInfo(ZonValue)) {
93 .void, .bool, .int, .float, .pointer, .comptime_float, .comptime_int, .@"enum" => return zon_value,
94 .@"struct" => |zon_struct| switch (@typeInfo(Result)) {
95 .@"struct" => |result_struct| {
96 comptime var used_zon_fields = 0;
97 var result: Result = undefined;
98 inline for (result_struct.fields) |result_field| @field(result, result_field.name) = if (@hasField(ZonValue, result_field.name)) result: {
99 used_zon_fields += 1;
100 break :result zonCast(@FieldType(Result, result_field.name), @field(zon_value, result_field.name), symbols);
101 } else result_field.defaultValue() orelse @compileError(std.fmt.comptimePrint("missing zon field '{s}': {} <- {any}", .{ result_field.name, Result, zon_value }));
102 if (used_zon_fields != zon_struct.fields.len) @compileError(std.fmt.comptimePrint("unused zon field: {} <- {any}", .{ Result, zon_value }));
103 return result;
104 },
105 .@"union" => {
106 if (zon_struct.fields.len != 1) @compileError(std.fmt.comptimePrint("{} <- {any}", .{ Result, zon_value }));
107 const field_name = zon_struct.fields[0].name;
108 return @unionInit(
109 Result,
110 field_name,
111 zonCast(@FieldType(Result, field_name), @field(zon_value, field_name), symbols),
112 );
113 },
114 else => @compileError(std.fmt.comptimePrint("unsupported zon type: {} <- {any}", .{ Result, zon_value })),
115 },
116 .enum_literal => if (@hasField(Symbols, @tagName(zon_value))) {
117 const symbol = @field(symbols, @tagName(zon_value));
118 const Symbol = @TypeOf(symbol);
119 switch (@typeInfo(Result)) {
120 .@"enum" => switch (@typeInfo(Symbol)) {
121 .int => |symbol_int| {
122 var buf: [
123 std.fmt.count("{d}", .{switch (symbol_int.signedness) {
124 .signed => std.math.minInt(Symbol),
125 .unsigned => std.math.maxInt(Symbol),
126 }})
127 ]u8 = undefined;
128 return std.meta.stringToEnum(Result, std.fmt.bufPrint(&buf, "{d}", .{symbol}) catch unreachable).?;
129 },
130 else => return symbol,
131 },
132 else => return symbol,
133 }
134 } else return if (@hasDecl(Result, @tagName(zon_value))) @field(Result, @tagName(zon_value)) else zon_value,
135 else => @compileError(std.fmt.comptimePrint("unsupported zon type: {} <- {any}", .{ Result, zon_value })),
136 }
137}
138
139fn toUpperEqlAssertUpper(lhs: []const u8, rhs: []const u8) bool {
140 if (lhs.len != rhs.len) return false;
141 for (lhs, rhs) |l, r| {
142 assert(!std.ascii.isLower(r));
143 if (std.ascii.toUpper(l) != r) return false;
144 }
145 return true;
146}
147
148const token_buf_len = "v31.b[15]".len;
149fn nextToken(as: *Assemble, buf: *[token_buf_len]u8, comptime opts: struct {
150 operands: bool = false,
151 placeholders: bool = false,
152}) ![]const u8 {
153 const invalid_syntax: u8 = 1;
154 while (true) c: switch (as.source[0]) {
155 0 => return as.source[0..0],
156 '\t', '\n' + 1...'\r', ' ' => as.source = as.source[1..],
157 '\n', '!', '#', ',', ';', '[', ']' => {
158 defer as.source = as.source[1..];
159 return as.source[0..1];
160 },
161 '%' => if (opts.operands) {
162 if (as.source[1] != '[') continue :c invalid_syntax;
163 const name_start: usize = 2;
164 var index = name_start;
165 while (switch (as.source[index]) {
166 else => true,
167 ':', ']' => false,
168 }) index += 1;
169 const operand = as.operands.get(as.source[name_start..index]) orelse continue :c invalid_syntax;
170 const modifier = modifier: switch (as.source[index]) {
171 else => unreachable,
172 ':' => {
173 index += 1;
174 const modifier_start = index;
175 while (switch (as.source[index]) {
176 else => true,
177 ']' => false,
178 }) index += 1;
179 break :modifier as.source[modifier_start..index];
180 },
181 ']' => "",
182 };
183 assert(as.source[index] == ']');
184 const modified_operand: Operand = if (std.mem.eql(u8, modifier, ""))
185 operand
186 else if (std.mem.eql(u8, modifier, "w")) switch (operand) {
187 .register => |reg| .{ .register = reg.alias.w() },
188 } else if (std.mem.eql(u8, modifier, "x")) switch (operand) {
189 .register => |reg| .{ .register = reg.alias.x() },
190 } else if (std.mem.eql(u8, modifier, "b")) switch (operand) {
191 .register => |reg| .{ .register = reg.alias.b() },
192 } else if (std.mem.eql(u8, modifier, "h")) switch (operand) {
193 .register => |reg| .{ .register = reg.alias.h() },
194 } else if (std.mem.eql(u8, modifier, "s")) switch (operand) {
195 .register => |reg| .{ .register = reg.alias.s() },
196 } else if (std.mem.eql(u8, modifier, "d")) switch (operand) {
197 .register => |reg| .{ .register = reg.alias.d() },
198 } else if (std.mem.eql(u8, modifier, "q")) switch (operand) {
199 .register => |reg| .{ .register = reg.alias.q() },
200 } else if (std.mem.eql(u8, modifier, "Z")) switch (operand) {
201 .register => |reg| .{ .register = reg.alias.z() },
202 } else continue :c invalid_syntax;
203 switch (modified_operand) {
204 .register => |reg| {
205 as.source = as.source[index + 1 ..];
206 return std.fmt.bufPrint(buf, "{f}", .{reg.fmt()}) catch unreachable;
207 },
208 }
209 } else continue :c invalid_syntax,
210 '-', '0'...'9', 'A'...'Z', '_', 'a'...'z' => {
211 var index: usize = 1;
212 while (switch (as.source[index]) {
213 '0'...'9', 'A'...'Z', '_', 'a'...'z' => true,
214 else => false,
215 }) index += 1;
216 defer as.source = as.source[index..];
217 return as.source[0..index];
218 },
219 '<' => if (opts.placeholders) {
220 var index: usize = 1;
221 while (switch (as.source[index]) {
222 0 => return error.UnterminatedPlaceholder,
223 '>' => false,
224 else => true,
225 }) index += 1;
226 defer as.source = as.source[index + 1 ..];
227 return as.source[0 .. index + 1];
228 } else continue :c invalid_syntax,
229 else => {
230 if (!@inComptime()) log.debug("invalid token \"{f}\"", .{std.zig.fmtString(std.mem.span(as.source))});
231 return error.InvalidSyntax;
232 },
233 };
234}
235
236const SymbolSpec = union(enum) {
237 reg: struct { format: aarch64.encoding.Register.Format, allow_sp: bool = false },
238 systemreg,
239 imm: struct {
240 type: std.builtin.Type.Int,
241 multiple_of: comptime_int = 1,
242 max_valid: ?comptime_int = null,
243 },
244 extend: struct { size: aarch64.encoding.Register.IntegerSize },
245 shift: struct { allow_ror: bool = true },
246 barrier: struct { only_sy: bool = false },
247
248 fn Storage(comptime spec: SymbolSpec) type {
249 return switch (spec) {
250 .reg => aarch64.encoding.Register,
251 .systemreg => aarch64.encoding.Register.System,
252 .imm => |imm| @Type(.{ .int = imm.type }),
253 .extend => Instruction.DataProcessingRegister.AddSubtractExtendedRegister.Option,
254 .shift => Instruction.DataProcessingRegister.Shift.Op,
255 .barrier => Instruction.BranchExceptionGeneratingSystem.Barriers.Option,
256 };
257 }
258
259 fn parse(comptime spec: SymbolSpec, token: []const u8) ?Storage(spec) {
260 const Result = Storage(spec);
261 switch (spec) {
262 .reg => |reg_spec| {
263 const reg = Result.parse(token) orelse {
264 log.debug("invalid register: \"{f}\"", .{std.zig.fmtString(token)});
265 return null;
266 };
267 if (reg.format.integer != reg_spec.format.integer) {
268 log.debug("invalid register size: \"{f}\"", .{std.zig.fmtString(token)});
269 return null;
270 }
271 if (reg.alias == if (reg_spec.allow_sp) .zr else .sp) {
272 log.debug("invalid register usage: \"{f}\"", .{std.zig.fmtString(token)});
273 return null;
274 }
275 return reg;
276 },
277 .systemreg => {
278 const systemreg = Result.parse(token) orelse {
279 log.debug("invalid system register: \"{f}\"", .{std.zig.fmtString(token)});
280 return null;
281 };
282 assert(systemreg.op0 >= 2);
283 return systemreg;
284 },
285 .imm => |imm_spec| {
286 const imm = std.fmt.parseInt(Result, token, 0) catch {
287 log.debug("invalid immediate: \"{f}\"", .{std.zig.fmtString(token)});
288 return null;
289 };
290 if (@rem(imm, imm_spec.multiple_of) != 0) {
291 log.debug("invalid immediate usage: \"{f}\"", .{std.zig.fmtString(token)});
292 return null;
293 }
294 if (imm_spec.max_valid) |max_valid| if (imm > max_valid) {
295 log.debug("out of range immediate: \"{f}\"", .{std.zig.fmtString(token)});
296 return null;
297 };
298 return imm;
299 },
300 .extend => |extend_spec| {
301 const Option = Instruction.DataProcessingRegister.AddSubtractExtendedRegister.Option;
302 var buf: [
303 max_len: {
304 var max_len = 0;
305 for (@typeInfo(Option).@"enum".fields) |field| max_len = @max(max_len, field.name.len);
306 break :max_len max_len;
307 } + 1
308 ]u8 = undefined;
309 const extend = std.meta.stringToEnum(Option, std.ascii.lowerString(
310 &buf,
311 token[0..@min(token.len, buf.len)],
312 )) orelse {
313 log.debug("invalid extend: \"{f}\"", .{std.zig.fmtString(token)});
314 return null;
315 };
316 if (extend.sf() != extend_spec.size) {
317 log.debug("invalid extend: \"{f}\"", .{std.zig.fmtString(token)});
318 return null;
319 }
320 return extend;
321 },
322 .shift => |shift_spec| {
323 const ShiftOp = Instruction.DataProcessingRegister.Shift.Op;
324 var buf: [
325 max_len: {
326 var max_len = 0;
327 for (@typeInfo(ShiftOp).@"enum".fields) |field| max_len = @max(max_len, field.name.len);
328 break :max_len max_len;
329 } + 1
330 ]u8 = undefined;
331 const shift = std.meta.stringToEnum(ShiftOp, std.ascii.lowerString(
332 &buf,
333 token[0..@min(token.len, buf.len)],
334 )) orelse {
335 log.debug("invalid shift: \"{f}\"", .{std.zig.fmtString(token)});
336 return null;
337 };
338 if (!shift_spec.allow_ror and shift == .ror) {
339 log.debug("invalid shift usage: \"{f}\"", .{std.zig.fmtString(token)});
340 return null;
341 }
342 return shift;
343 },
344 .barrier => |barrier_spec| {
345 const Option = Instruction.BranchExceptionGeneratingSystem.Barriers.Option;
346 var buf: [
347 max_len: {
348 var max_len = 0;
349 for (@typeInfo(Option).@"enum".fields) |field| max_len = @max(max_len, field.name.len);
350 break :max_len max_len;
351 } + 1
352 ]u8 = undefined;
353 const barrier = std.meta.stringToEnum(Option, std.ascii.lowerString(
354 &buf,
355 token[0..@min(token.len, buf.len)],
356 )) orelse {
357 log.debug("invalid barrier: \"{f}\"", .{std.zig.fmtString(token)});
358 return null;
359 };
360 if (barrier_spec.only_sy and barrier != .sy) {
361 log.debug("invalid barrier: \"{f}\"", .{std.zig.fmtString(token)});
362 return null;
363 }
364 return barrier;
365 },
366 }
367 }
368};
369
370test "add sub" {
371 var as: Assemble = .{
372 .source =
373 \\ add w0, w0, w1
374 \\ add w2, w3, w4
375 \\ add wsp, w5, w6
376 \\ add w7, wsp, w8
377 \\ add wsp, wsp, w9
378 \\ add w10, w10, wzr
379 \\ add w11, w12, wzr
380 \\ add wsp, w13, wzr
381 \\ add w14, wsp, wzr
382 \\ add wsp, wsp, wzr
383 \\
384 \\ add x0, x0, x1
385 \\ add x2, x3, x4
386 \\ add sp, x5, x6
387 \\ add x7, sp, x8
388 \\ add sp, sp, x9
389 \\ add x10, x10, xzr
390 \\ add x11, x12, xzr
391 \\ add sp, x13, xzr
392 \\ add x14, sp, xzr
393 \\ add sp, sp, xzr
394 \\
395 \\ add w0, w0, w1
396 \\ add w2, w3, w4, uxtb #0
397 \\ add wsp, w5, w6, uxth #1
398 \\ add w7, wsp, w8, uxtw #0
399 \\ add wsp, wsp, w9, uxtw #2
400 \\ add w10, w10, wzr, uxtw #3
401 \\ add w11, w12, wzr, sxtb #4
402 \\ add wsp, w13, wzr, sxth #0
403 \\ add w14, wsp, wzr, sxtw #1
404 \\ add wsp, wsp, wzr, sxtw #2
405 \\
406 \\ add x0, x0, x1
407 \\ add x2, x3, w4, uxtb #0
408 \\ add sp, x5, w6, uxth #1
409 \\ add x7, sp, w8, uxtw #2
410 \\ add sp, sp, x9, uxtx #0
411 \\ add x10, x10, xzr, uxtx #3
412 \\ add x11, x12, wzr, sxtb #4
413 \\ add sp, x13, wzr, sxth #0
414 \\ add x14, sp, wzr, sxtw #1
415 \\ add sp, sp, xzr, sxtx #2
416 \\
417 \\ add w0, w0, #0
418 \\ add w0, w1, #1, lsl #0
419 \\ add wsp, w2, #2, lsl #12
420 \\ add w3, wsp, #3, lsl #0
421 \\ add wsp, wsp, #4095, lsl #12
422 \\ add w0, w1, #0
423 \\ add w2, w3, #0, lsl #0
424 \\ add w4, wsp, #0
425 \\ add w5, wsp, #0, lsl #0
426 \\ add wsp, w6, #0
427 \\ add wsp, w7, #0, lsl #0
428 \\ add wsp, wsp, #0
429 \\ add wsp, wsp, #0, lsl #0
430 \\
431 \\ add x0, x0, #0
432 \\ add x0, x1, #1, lsl #0
433 \\ add sp, x2, #2, lsl #12
434 \\ add x3, sp, #3, lsl #0
435 \\ add sp, sp, #4095, lsl #12
436 \\ add x0, x1, #0
437 \\ add x2, x3, #0, lsl #0
438 \\ add x4, sp, #0
439 \\ add x5, sp, #0, lsl #0
440 \\ add sp, x6, #0
441 \\ add sp, x7, #0, lsl #0
442 \\ add sp, sp, #0
443 \\ add sp, sp, #0, lsl #0
444 \\
445 \\ add w0, w0, w0
446 \\ add w1, w1, w2, lsl #0
447 \\ add w3, w4, w5, lsl #1
448 \\ add w6, w6, wzr, lsl #31
449 \\ add w7, wzr, w8, lsr #0
450 \\ add w9, wzr, wzr, lsr #30
451 \\ add wzr, w10, w11, lsr #31
452 \\ add wzr, w12, wzr, asr #0x0
453 \\ add wzr, wzr, w13, asr #0x10
454 \\ add wzr, wzr, wzr, asr #0x1f
455 \\
456 \\ add x0, x0, x0
457 \\ add x1, x1, x2, lsl #0
458 \\ add x3, x4, x5, lsl #1
459 \\ add x6, x6, xzr, lsl #63
460 \\ add x7, xzr, x8, lsr #0
461 \\ add x9, xzr, xzr, lsr #62
462 \\ add xzr, x10, x11, lsr #63
463 \\ add xzr, x12, xzr, asr #0x0
464 \\ add xzr, xzr, x13, asr #0x1F
465 \\ add xzr, xzr, xzr, asr #0x3f
466 \\
467 \\ sub w0, w0, w1
468 \\ sub w2, w3, w4
469 \\ sub wsp, w5, w6
470 \\ sub w7, wsp, w8
471 \\ sub wsp, wsp, w9
472 \\ sub w10, w10, wzr
473 \\ sub w11, w12, wzr
474 \\ sub wsp, w13, wzr
475 \\ sub w14, wsp, wzr
476 \\ sub wsp, wsp, wzr
477 \\
478 \\ sub x0, x0, x1
479 \\ sub x2, x3, x4
480 \\ sub sp, x5, x6
481 \\ sub x7, sp, x8
482 \\ sub sp, sp, x9
483 \\ sub x10, x10, xzr
484 \\ sub x11, x12, xzr
485 \\ sub sp, x13, xzr
486 \\ sub x14, sp, xzr
487 \\ sub sp, sp, xzr
488 \\
489 \\ sub w0, w0, w1
490 \\ sub w2, w3, w4, uxtb #0
491 \\ sub wsp, w5, w6, uxth #1
492 \\ sub w7, wsp, w8, uxtw #0
493 \\ sub wsp, wsp, w9, uxtw #2
494 \\ sub w10, w10, wzr, uxtw #3
495 \\ sub w11, w12, wzr, sxtb #4
496 \\ sub wsp, w13, wzr, sxth #0
497 \\ sub w14, wsp, wzr, sxtw #1
498 \\ sub wsp, wsp, wzr, sxtw #2
499 \\
500 \\ sub x0, x0, x1
501 \\ sub x2, x3, w4, uxtb #0
502 \\ sub sp, x5, w6, uxth #1
503 \\ sub x7, sp, w8, uxtw #2
504 \\ sub sp, sp, x9, uxtx #0
505 \\ sub x10, x10, xzr, uxtx #3
506 \\ sub x11, x12, wzr, sxtb #4
507 \\ sub sp, x13, wzr, sxth #0
508 \\ sub x14, sp, wzr, sxtw #1
509 \\ sub sp, sp, xzr, sxtx #2
510 \\
511 \\ sub w0, w0, #0
512 \\ sub w0, w1, #1, lsl #0
513 \\ sub wsp, w2, #2, lsl #12
514 \\ sub w3, wsp, #3, lsl #0
515 \\ sub wsp, wsp, #4095, lsl #12
516 \\ sub w0, w1, #0
517 \\ sub w2, w3, #0, lsl #0
518 \\ sub w4, wsp, #0
519 \\ sub w5, wsp, #0, lsl #0
520 \\ sub wsp, w6, #0
521 \\ sub wsp, w7, #0, lsl #0
522 \\ sub wsp, wsp, #0
523 \\ sub wsp, wsp, #0, lsl #0
524 \\
525 \\ sub x0, x0, #0
526 \\ sub x0, x1, #1, lsl #0
527 \\ sub sp, x2, #2, lsl #12
528 \\ sub x3, sp, #3, lsl #0
529 \\ sub sp, sp, #4095, lsl #12
530 \\ sub x0, x1, #0
531 \\ sub x2, x3, #0, lsl #0
532 \\ sub x4, sp, #0
533 \\ sub x5, sp, #0, lsl #0
534 \\ sub sp, x6, #0
535 \\ sub sp, x7, #0, lsl #0
536 \\ sub sp, sp, #0
537 \\ sub sp, sp, #0, lsl #0
538 \\
539 \\ sub w0, w0, w0
540 \\ sub w1, w1, w2, lsl #0
541 \\ sub w3, w4, w5, lsl #1
542 \\ sub w6, w6, wzr, lsl #31
543 \\ sub w7, wzr, w8, lsr #0
544 \\ sub w9, wzr, wzr, lsr #30
545 \\ sub wzr, w10, w11, lsr #31
546 \\ sub wzr, w12, wzr, asr #0x0
547 \\ sub wzr, wzr, w13, asr #0x10
548 \\ sub wzr, wzr, wzr, asr #0x1f
549 \\
550 \\ sub x0, x0, x0
551 \\ sub x1, x1, x2, lsl #0
552 \\ sub x3, x4, x5, lsl #1
553 \\ sub x6, x6, xzr, lsl #63
554 \\ sub x7, xzr, x8, lsr #0
555 \\ sub x9, xzr, xzr, lsr #62
556 \\ sub xzr, x10, x11, lsr #63
557 \\ sub xzr, x12, xzr, asr #0x0
558 \\ sub xzr, xzr, x13, asr #0x1F
559 \\ sub xzr, xzr, xzr, asr #0x3f
560 \\
561 \\ neg w0, w0
562 \\ neg w1, w2, lsl #0
563 \\ neg w3, wzr, lsl #7
564 \\ neg wzr, w4, lsr #14
565 \\ neg wzr, wzr, asr #21
566 \\
567 \\ neg x0, x0
568 \\ neg x1, x2, lsl #0
569 \\ neg x3, xzr, lsl #11
570 \\ neg xzr, x4, lsr #22
571 \\ neg xzr, xzr, asr #33
572 ,
573 .operands = .empty,
574 };
575
576 try std.testing.expectFmt("add w0, w0, w1", "{f}", .{(try as.nextInstruction()).?});
577 try std.testing.expectFmt("add w2, w3, w4", "{f}", .{(try as.nextInstruction()).?});
578 try std.testing.expectFmt("add wsp, w5, w6", "{f}", .{(try as.nextInstruction()).?});
579 try std.testing.expectFmt("add w7, wsp, w8", "{f}", .{(try as.nextInstruction()).?});
580 try std.testing.expectFmt("add wsp, wsp, w9", "{f}", .{(try as.nextInstruction()).?});
581 try std.testing.expectFmt("add w10, w10, wzr", "{f}", .{(try as.nextInstruction()).?});
582 try std.testing.expectFmt("add w11, w12, wzr", "{f}", .{(try as.nextInstruction()).?});
583 try std.testing.expectFmt("add wsp, w13, wzr", "{f}", .{(try as.nextInstruction()).?});
584 try std.testing.expectFmt("add w14, wsp, wzr", "{f}", .{(try as.nextInstruction()).?});
585 try std.testing.expectFmt("add wsp, wsp, wzr", "{f}", .{(try as.nextInstruction()).?});
586
587 try std.testing.expectFmt("add x0, x0, x1", "{f}", .{(try as.nextInstruction()).?});
588 try std.testing.expectFmt("add x2, x3, x4", "{f}", .{(try as.nextInstruction()).?});
589 try std.testing.expectFmt("add sp, x5, x6", "{f}", .{(try as.nextInstruction()).?});
590 try std.testing.expectFmt("add x7, sp, x8", "{f}", .{(try as.nextInstruction()).?});
591 try std.testing.expectFmt("add sp, sp, x9", "{f}", .{(try as.nextInstruction()).?});
592 try std.testing.expectFmt("add x10, x10, xzr", "{f}", .{(try as.nextInstruction()).?});
593 try std.testing.expectFmt("add x11, x12, xzr", "{f}", .{(try as.nextInstruction()).?});
594 try std.testing.expectFmt("add sp, x13, xzr", "{f}", .{(try as.nextInstruction()).?});
595 try std.testing.expectFmt("add x14, sp, xzr", "{f}", .{(try as.nextInstruction()).?});
596 try std.testing.expectFmt("add sp, sp, xzr", "{f}", .{(try as.nextInstruction()).?});
597
598 try std.testing.expectFmt("add w0, w0, w1", "{f}", .{(try as.nextInstruction()).?});
599 try std.testing.expectFmt("add w2, w3, w4, uxtb #0", "{f}", .{(try as.nextInstruction()).?});
600 try std.testing.expectFmt("add wsp, w5, w6, uxth #1", "{f}", .{(try as.nextInstruction()).?});
601 try std.testing.expectFmt("add w7, wsp, w8", "{f}", .{(try as.nextInstruction()).?});
602 try std.testing.expectFmt("add wsp, wsp, w9, uxtw #2", "{f}", .{(try as.nextInstruction()).?});
603 try std.testing.expectFmt("add w10, w10, wzr, uxtw #3", "{f}", .{(try as.nextInstruction()).?});
604 try std.testing.expectFmt("add w11, w12, wzr, sxtb #4", "{f}", .{(try as.nextInstruction()).?});
605 try std.testing.expectFmt("add wsp, w13, wzr, sxth #0", "{f}", .{(try as.nextInstruction()).?});
606 try std.testing.expectFmt("add w14, wsp, wzr, sxtw #1", "{f}", .{(try as.nextInstruction()).?});
607 try std.testing.expectFmt("add wsp, wsp, wzr, sxtw #2", "{f}", .{(try as.nextInstruction()).?});
608
609 try std.testing.expectFmt("add x0, x0, x1", "{f}", .{(try as.nextInstruction()).?});
610 try std.testing.expectFmt("add x2, x3, w4, uxtb #0", "{f}", .{(try as.nextInstruction()).?});
611 try std.testing.expectFmt("add sp, x5, w6, uxth #1", "{f}", .{(try as.nextInstruction()).?});
612 try std.testing.expectFmt("add x7, sp, w8, uxtw #2", "{f}", .{(try as.nextInstruction()).?});
613 try std.testing.expectFmt("add sp, sp, x9", "{f}", .{(try as.nextInstruction()).?});
614 try std.testing.expectFmt("add x10, x10, xzr, uxtx #3", "{f}", .{(try as.nextInstruction()).?});
615 try std.testing.expectFmt("add x11, x12, wzr, sxtb #4", "{f}", .{(try as.nextInstruction()).?});
616 try std.testing.expectFmt("add sp, x13, wzr, sxth #0", "{f}", .{(try as.nextInstruction()).?});
617 try std.testing.expectFmt("add x14, sp, wzr, sxtw #1", "{f}", .{(try as.nextInstruction()).?});
618 try std.testing.expectFmt("add sp, sp, xzr, sxtx #2", "{f}", .{(try as.nextInstruction()).?});
619
620 try std.testing.expectFmt("add w0, w0, #0x0", "{f}", .{(try as.nextInstruction()).?});
621 try std.testing.expectFmt("add w0, w1, #0x1", "{f}", .{(try as.nextInstruction()).?});
622 try std.testing.expectFmt("add wsp, w2, #0x2, lsl #12", "{f}", .{(try as.nextInstruction()).?});
623 try std.testing.expectFmt("add w3, wsp, #0x3", "{f}", .{(try as.nextInstruction()).?});
624 try std.testing.expectFmt("add wsp, wsp, #0xfff, lsl #12", "{f}", .{(try as.nextInstruction()).?});
625 try std.testing.expectFmt("add w0, w1, #0x0", "{f}", .{(try as.nextInstruction()).?});
626 try std.testing.expectFmt("add w2, w3, #0x0", "{f}", .{(try as.nextInstruction()).?});
627 try std.testing.expectFmt("mov w4, wsp", "{f}", .{(try as.nextInstruction()).?});
628 try std.testing.expectFmt("mov w5, wsp", "{f}", .{(try as.nextInstruction()).?});
629 try std.testing.expectFmt("mov wsp, w6", "{f}", .{(try as.nextInstruction()).?});
630 try std.testing.expectFmt("mov wsp, w7", "{f}", .{(try as.nextInstruction()).?});
631 try std.testing.expectFmt("mov wsp, wsp", "{f}", .{(try as.nextInstruction()).?});
632 try std.testing.expectFmt("mov wsp, wsp", "{f}", .{(try as.nextInstruction()).?});
633
634 try std.testing.expectFmt("add x0, x0, #0x0", "{f}", .{(try as.nextInstruction()).?});
635 try std.testing.expectFmt("add x0, x1, #0x1", "{f}", .{(try as.nextInstruction()).?});
636 try std.testing.expectFmt("add sp, x2, #0x2, lsl #12", "{f}", .{(try as.nextInstruction()).?});
637 try std.testing.expectFmt("add x3, sp, #0x3", "{f}", .{(try as.nextInstruction()).?});
638 try std.testing.expectFmt("add sp, sp, #0xfff, lsl #12", "{f}", .{(try as.nextInstruction()).?});
639 try std.testing.expectFmt("add x0, x1, #0x0", "{f}", .{(try as.nextInstruction()).?});
640 try std.testing.expectFmt("add x2, x3, #0x0", "{f}", .{(try as.nextInstruction()).?});
641 try std.testing.expectFmt("mov x4, sp", "{f}", .{(try as.nextInstruction()).?});
642 try std.testing.expectFmt("mov x5, sp", "{f}", .{(try as.nextInstruction()).?});
643 try std.testing.expectFmt("mov sp, x6", "{f}", .{(try as.nextInstruction()).?});
644 try std.testing.expectFmt("mov sp, x7", "{f}", .{(try as.nextInstruction()).?});
645 try std.testing.expectFmt("mov sp, sp", "{f}", .{(try as.nextInstruction()).?});
646 try std.testing.expectFmt("mov sp, sp", "{f}", .{(try as.nextInstruction()).?});
647
648 try std.testing.expectFmt("add w0, w0, w0", "{f}", .{(try as.nextInstruction()).?});
649 try std.testing.expectFmt("add w1, w1, w2", "{f}", .{(try as.nextInstruction()).?});
650 try std.testing.expectFmt("add w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
651 try std.testing.expectFmt("add w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?});
652 try std.testing.expectFmt("add w7, wzr, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
653 try std.testing.expectFmt("add w9, wzr, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?});
654 try std.testing.expectFmt("add wzr, w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?});
655 try std.testing.expectFmt("add wzr, w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
656 try std.testing.expectFmt("add wzr, wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?});
657 try std.testing.expectFmt("add wzr, wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?});
658
659 try std.testing.expectFmt("add x0, x0, x0", "{f}", .{(try as.nextInstruction()).?});
660 try std.testing.expectFmt("add x1, x1, x2", "{f}", .{(try as.nextInstruction()).?});
661 try std.testing.expectFmt("add x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
662 try std.testing.expectFmt("add x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?});
663 try std.testing.expectFmt("add x7, xzr, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
664 try std.testing.expectFmt("add x9, xzr, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?});
665 try std.testing.expectFmt("add xzr, x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?});
666 try std.testing.expectFmt("add xzr, x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
667 try std.testing.expectFmt("add xzr, xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?});
668 try std.testing.expectFmt("add xzr, xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?});
669
670 try std.testing.expectFmt("sub w0, w0, w1", "{f}", .{(try as.nextInstruction()).?});
671 try std.testing.expectFmt("sub w2, w3, w4", "{f}", .{(try as.nextInstruction()).?});
672 try std.testing.expectFmt("sub wsp, w5, w6", "{f}", .{(try as.nextInstruction()).?});
673 try std.testing.expectFmt("sub w7, wsp, w8", "{f}", .{(try as.nextInstruction()).?});
674 try std.testing.expectFmt("sub wsp, wsp, w9", "{f}", .{(try as.nextInstruction()).?});
675 try std.testing.expectFmt("sub w10, w10, wzr", "{f}", .{(try as.nextInstruction()).?});
676 try std.testing.expectFmt("sub w11, w12, wzr", "{f}", .{(try as.nextInstruction()).?});
677 try std.testing.expectFmt("sub wsp, w13, wzr", "{f}", .{(try as.nextInstruction()).?});
678 try std.testing.expectFmt("sub w14, wsp, wzr", "{f}", .{(try as.nextInstruction()).?});
679 try std.testing.expectFmt("sub wsp, wsp, wzr", "{f}", .{(try as.nextInstruction()).?});
680
681 try std.testing.expectFmt("sub x0, x0, x1", "{f}", .{(try as.nextInstruction()).?});
682 try std.testing.expectFmt("sub x2, x3, x4", "{f}", .{(try as.nextInstruction()).?});
683 try std.testing.expectFmt("sub sp, x5, x6", "{f}", .{(try as.nextInstruction()).?});
684 try std.testing.expectFmt("sub x7, sp, x8", "{f}", .{(try as.nextInstruction()).?});
685 try std.testing.expectFmt("sub sp, sp, x9", "{f}", .{(try as.nextInstruction()).?});
686 try std.testing.expectFmt("sub x10, x10, xzr", "{f}", .{(try as.nextInstruction()).?});
687 try std.testing.expectFmt("sub x11, x12, xzr", "{f}", .{(try as.nextInstruction()).?});
688 try std.testing.expectFmt("sub sp, x13, xzr", "{f}", .{(try as.nextInstruction()).?});
689 try std.testing.expectFmt("sub x14, sp, xzr", "{f}", .{(try as.nextInstruction()).?});
690 try std.testing.expectFmt("sub sp, sp, xzr", "{f}", .{(try as.nextInstruction()).?});
691
692 try std.testing.expectFmt("sub w0, w0, w1", "{f}", .{(try as.nextInstruction()).?});
693 try std.testing.expectFmt("sub w2, w3, w4, uxtb #0", "{f}", .{(try as.nextInstruction()).?});
694 try std.testing.expectFmt("sub wsp, w5, w6, uxth #1", "{f}", .{(try as.nextInstruction()).?});
695 try std.testing.expectFmt("sub w7, wsp, w8", "{f}", .{(try as.nextInstruction()).?});
696 try std.testing.expectFmt("sub wsp, wsp, w9, uxtw #2", "{f}", .{(try as.nextInstruction()).?});
697 try std.testing.expectFmt("sub w10, w10, wzr, uxtw #3", "{f}", .{(try as.nextInstruction()).?});
698 try std.testing.expectFmt("sub w11, w12, wzr, sxtb #4", "{f}", .{(try as.nextInstruction()).?});
699 try std.testing.expectFmt("sub wsp, w13, wzr, sxth #0", "{f}", .{(try as.nextInstruction()).?});
700 try std.testing.expectFmt("sub w14, wsp, wzr, sxtw #1", "{f}", .{(try as.nextInstruction()).?});
701 try std.testing.expectFmt("sub wsp, wsp, wzr, sxtw #2", "{f}", .{(try as.nextInstruction()).?});
702
703 try std.testing.expectFmt("sub x0, x0, x1", "{f}", .{(try as.nextInstruction()).?});
704 try std.testing.expectFmt("sub x2, x3, w4, uxtb #0", "{f}", .{(try as.nextInstruction()).?});
705 try std.testing.expectFmt("sub sp, x5, w6, uxth #1", "{f}", .{(try as.nextInstruction()).?});
706 try std.testing.expectFmt("sub x7, sp, w8, uxtw #2", "{f}", .{(try as.nextInstruction()).?});
707 try std.testing.expectFmt("sub sp, sp, x9", "{f}", .{(try as.nextInstruction()).?});
708 try std.testing.expectFmt("sub x10, x10, xzr, uxtx #3", "{f}", .{(try as.nextInstruction()).?});
709 try std.testing.expectFmt("sub x11, x12, wzr, sxtb #4", "{f}", .{(try as.nextInstruction()).?});
710 try std.testing.expectFmt("sub sp, x13, wzr, sxth #0", "{f}", .{(try as.nextInstruction()).?});
711 try std.testing.expectFmt("sub x14, sp, wzr, sxtw #1", "{f}", .{(try as.nextInstruction()).?});
712 try std.testing.expectFmt("sub sp, sp, xzr, sxtx #2", "{f}", .{(try as.nextInstruction()).?});
713
714 try std.testing.expectFmt("sub w0, w0, #0x0", "{f}", .{(try as.nextInstruction()).?});
715 try std.testing.expectFmt("sub w0, w1, #0x1", "{f}", .{(try as.nextInstruction()).?});
716 try std.testing.expectFmt("sub wsp, w2, #0x2, lsl #12", "{f}", .{(try as.nextInstruction()).?});
717 try std.testing.expectFmt("sub w3, wsp, #0x3", "{f}", .{(try as.nextInstruction()).?});
718 try std.testing.expectFmt("sub wsp, wsp, #0xfff, lsl #12", "{f}", .{(try as.nextInstruction()).?});
719 try std.testing.expectFmt("sub w0, w1, #0x0", "{f}", .{(try as.nextInstruction()).?});
720 try std.testing.expectFmt("sub w2, w3, #0x0", "{f}", .{(try as.nextInstruction()).?});
721 try std.testing.expectFmt("sub w4, wsp, #0x0", "{f}", .{(try as.nextInstruction()).?});
722 try std.testing.expectFmt("sub w5, wsp, #0x0", "{f}", .{(try as.nextInstruction()).?});
723 try std.testing.expectFmt("sub wsp, w6, #0x0", "{f}", .{(try as.nextInstruction()).?});
724 try std.testing.expectFmt("sub wsp, w7, #0x0", "{f}", .{(try as.nextInstruction()).?});
725 try std.testing.expectFmt("sub wsp, wsp, #0x0", "{f}", .{(try as.nextInstruction()).?});
726 try std.testing.expectFmt("sub wsp, wsp, #0x0", "{f}", .{(try as.nextInstruction()).?});
727
728 try std.testing.expectFmt("sub x0, x0, #0x0", "{f}", .{(try as.nextInstruction()).?});
729 try std.testing.expectFmt("sub x0, x1, #0x1", "{f}", .{(try as.nextInstruction()).?});
730 try std.testing.expectFmt("sub sp, x2, #0x2, lsl #12", "{f}", .{(try as.nextInstruction()).?});
731 try std.testing.expectFmt("sub x3, sp, #0x3", "{f}", .{(try as.nextInstruction()).?});
732 try std.testing.expectFmt("sub sp, sp, #0xfff, lsl #12", "{f}", .{(try as.nextInstruction()).?});
733 try std.testing.expectFmt("sub x0, x1, #0x0", "{f}", .{(try as.nextInstruction()).?});
734 try std.testing.expectFmt("sub x2, x3, #0x0", "{f}", .{(try as.nextInstruction()).?});
735 try std.testing.expectFmt("sub x4, sp, #0x0", "{f}", .{(try as.nextInstruction()).?});
736 try std.testing.expectFmt("sub x5, sp, #0x0", "{f}", .{(try as.nextInstruction()).?});
737 try std.testing.expectFmt("sub sp, x6, #0x0", "{f}", .{(try as.nextInstruction()).?});
738 try std.testing.expectFmt("sub sp, x7, #0x0", "{f}", .{(try as.nextInstruction()).?});
739 try std.testing.expectFmt("sub sp, sp, #0x0", "{f}", .{(try as.nextInstruction()).?});
740 try std.testing.expectFmt("sub sp, sp, #0x0", "{f}", .{(try as.nextInstruction()).?});
741
742 try std.testing.expectFmt("sub w0, w0, w0", "{f}", .{(try as.nextInstruction()).?});
743 try std.testing.expectFmt("sub w1, w1, w2", "{f}", .{(try as.nextInstruction()).?});
744 try std.testing.expectFmt("sub w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
745 try std.testing.expectFmt("sub w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?});
746 try std.testing.expectFmt("neg w7, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
747 try std.testing.expectFmt("neg w9, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?});
748 try std.testing.expectFmt("sub wzr, w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?});
749 try std.testing.expectFmt("sub wzr, w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
750 try std.testing.expectFmt("neg wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?});
751 try std.testing.expectFmt("neg wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?});
752
753 try std.testing.expectFmt("sub x0, x0, x0", "{f}", .{(try as.nextInstruction()).?});
754 try std.testing.expectFmt("sub x1, x1, x2", "{f}", .{(try as.nextInstruction()).?});
755 try std.testing.expectFmt("sub x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
756 try std.testing.expectFmt("sub x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?});
757 try std.testing.expectFmt("neg x7, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
758 try std.testing.expectFmt("neg x9, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?});
759 try std.testing.expectFmt("sub xzr, x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?});
760 try std.testing.expectFmt("sub xzr, x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
761 try std.testing.expectFmt("neg xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?});
762 try std.testing.expectFmt("neg xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?});
763
764 try std.testing.expectFmt("neg w0, w0", "{f}", .{(try as.nextInstruction()).?});
765 try std.testing.expectFmt("neg w1, w2", "{f}", .{(try as.nextInstruction()).?});
766 try std.testing.expectFmt("neg w3, wzr, lsl #7", "{f}", .{(try as.nextInstruction()).?});
767 try std.testing.expectFmt("neg wzr, w4, lsr #14", "{f}", .{(try as.nextInstruction()).?});
768 try std.testing.expectFmt("neg wzr, wzr, asr #21", "{f}", .{(try as.nextInstruction()).?});
769
770 try std.testing.expectFmt("neg x0, x0", "{f}", .{(try as.nextInstruction()).?});
771 try std.testing.expectFmt("neg x1, x2", "{f}", .{(try as.nextInstruction()).?});
772 try std.testing.expectFmt("neg x3, xzr, lsl #11", "{f}", .{(try as.nextInstruction()).?});
773 try std.testing.expectFmt("neg xzr, x4, lsr #22", "{f}", .{(try as.nextInstruction()).?});
774 try std.testing.expectFmt("neg xzr, xzr, asr #33", "{f}", .{(try as.nextInstruction()).?});
775
776 try std.testing.expect(null == try as.nextInstruction());
777}
778test "bitfield" {
779 var as: Assemble = .{
780 .source =
781 \\sbfm w0, w0, #0, #31
782 \\sbfm w0, w0, #31, #0
783 \\
784 \\sbfm x0, x0, #0, #63
785 \\sbfm x0, x0, #63, #0
786 \\
787 \\bfm w0, w0, #0, #31
788 \\bfm w0, w0, #31, #0
789 \\
790 \\bfm x0, x0, #0, #63
791 \\bfm x0, x0, #63, #0
792 \\
793 \\ubfm w0, w0, #0, #31
794 \\ubfm w0, w0, #31, #0
795 \\
796 \\ubfm x0, x0, #0, #63
797 \\ubfm x0, x0, #63, #0
798 ,
799 .operands = .empty,
800 };
801
802 try std.testing.expectFmt("sbfm w0, w0, #0, #31", "{f}", .{(try as.nextInstruction()).?});
803 try std.testing.expectFmt("sbfm w0, w0, #31, #0", "{f}", .{(try as.nextInstruction()).?});
804
805 try std.testing.expectFmt("sbfm x0, x0, #0, #63", "{f}", .{(try as.nextInstruction()).?});
806 try std.testing.expectFmt("sbfm x0, x0, #63, #0", "{f}", .{(try as.nextInstruction()).?});
807
808 try std.testing.expectFmt("bfm w0, w0, #0, #31", "{f}", .{(try as.nextInstruction()).?});
809 try std.testing.expectFmt("bfm w0, w0, #31, #0", "{f}", .{(try as.nextInstruction()).?});
810
811 try std.testing.expectFmt("bfm x0, x0, #0, #63", "{f}", .{(try as.nextInstruction()).?});
812 try std.testing.expectFmt("bfm x0, x0, #63, #0", "{f}", .{(try as.nextInstruction()).?});
813
814 try std.testing.expectFmt("ubfm w0, w0, #0, #31", "{f}", .{(try as.nextInstruction()).?});
815 try std.testing.expectFmt("ubfm w0, w0, #31, #0", "{f}", .{(try as.nextInstruction()).?});
816
817 try std.testing.expectFmt("ubfm x0, x0, #0, #63", "{f}", .{(try as.nextInstruction()).?});
818 try std.testing.expectFmt("ubfm x0, x0, #63, #0", "{f}", .{(try as.nextInstruction()).?});
819
820 try std.testing.expect(null == try as.nextInstruction());
821}
822test "branch register" {
823 var as: Assemble = .{
824 .source =
825 \\ret
826 \\br x30
827 \\blr x30
828 \\ret x30
829 \\br x29
830 \\blr x29
831 \\ret x29
832 \\br x2
833 \\blr x1
834 \\ret x0
835 ,
836 .operands = .empty,
837 };
838
839 try std.testing.expectFmt("ret", "{f}", .{(try as.nextInstruction()).?});
840 try std.testing.expectFmt("br x30", "{f}", .{(try as.nextInstruction()).?});
841 try std.testing.expectFmt("blr x30", "{f}", .{(try as.nextInstruction()).?});
842 try std.testing.expectFmt("ret", "{f}", .{(try as.nextInstruction()).?});
843 try std.testing.expectFmt("br x29", "{f}", .{(try as.nextInstruction()).?});
844 try std.testing.expectFmt("blr x29", "{f}", .{(try as.nextInstruction()).?});
845 try std.testing.expectFmt("ret x29", "{f}", .{(try as.nextInstruction()).?});
846 try std.testing.expectFmt("br x2", "{f}", .{(try as.nextInstruction()).?});
847 try std.testing.expectFmt("blr x1", "{f}", .{(try as.nextInstruction()).?});
848 try std.testing.expectFmt("ret x0", "{f}", .{(try as.nextInstruction()).?});
849
850 try std.testing.expect(null == try as.nextInstruction());
851}
852test "exception generating" {
853 var as: Assemble = .{
854 .source =
855 \\SVC #0
856 \\HVC #0x1
857 \\SMC #0o15
858 \\BRK #42
859 \\HLT #0x42
860 \\TCANCEL #123
861 \\DCPS1 #1234
862 \\DCPS2 #12345
863 \\DCPS3 #65535
864 \\DCPS3 #0x0
865 \\DCPS2 #0
866 \\DCPS1
867 ,
868 .operands = .empty,
869 };
870
871 try std.testing.expectFmt("svc #0", "{f}", .{(try as.nextInstruction()).?});
872 try std.testing.expectFmt("hvc #0x1", "{f}", .{(try as.nextInstruction()).?});
873 try std.testing.expectFmt("smc #0xd", "{f}", .{(try as.nextInstruction()).?});
874 try std.testing.expectFmt("brk #0x2a", "{f}", .{(try as.nextInstruction()).?});
875 try std.testing.expectFmt("hlt #0x42", "{f}", .{(try as.nextInstruction()).?});
876 try std.testing.expectFmt("tcancel #0x7b", "{f}", .{(try as.nextInstruction()).?});
877 try std.testing.expectFmt("dcps1 #0x4d2", "{f}", .{(try as.nextInstruction()).?});
878 try std.testing.expectFmt("dcps2 #0x3039", "{f}", .{(try as.nextInstruction()).?});
879 try std.testing.expectFmt("dcps3 #0xffff", "{f}", .{(try as.nextInstruction()).?});
880 try std.testing.expectFmt("dcps3", "{f}", .{(try as.nextInstruction()).?});
881 try std.testing.expectFmt("dcps2", "{f}", .{(try as.nextInstruction()).?});
882 try std.testing.expectFmt("dcps1", "{f}", .{(try as.nextInstruction()).?});
883
884 try std.testing.expect(null == try as.nextInstruction());
885}
886test "extract" {
887 var as: Assemble = .{
888 .source =
889 \\extr W0, W1, W2, #0
890 \\extr W3, W3, W4, #1
891 \\extr W5, W5, W5, #31
892 \\
893 \\extr X0, X1, X2, #0
894 \\extr X3, X3, X4, #1
895 \\extr X5, X5, X5, #63
896 ,
897 .operands = .empty,
898 };
899
900 try std.testing.expectFmt("extr w0, w1, w2, #0", "{f}", .{(try as.nextInstruction()).?});
901 try std.testing.expectFmt("extr w3, w3, w4, #1", "{f}", .{(try as.nextInstruction()).?});
902 try std.testing.expectFmt("extr w5, w5, w5, #31", "{f}", .{(try as.nextInstruction()).?});
903
904 try std.testing.expectFmt("extr x0, x1, x2, #0", "{f}", .{(try as.nextInstruction()).?});
905 try std.testing.expectFmt("extr x3, x3, x4, #1", "{f}", .{(try as.nextInstruction()).?});
906 try std.testing.expectFmt("extr x5, x5, x5, #63", "{f}", .{(try as.nextInstruction()).?});
907
908 try std.testing.expect(null == try as.nextInstruction());
909}
910test "hints" {
911 var as: Assemble = .{
912 .source =
913 \\NOP
914 \\hint #0
915 \\YiElD
916 \\Hint #0x1
917 \\WfE
918 \\hInt #02
919 \\wFi
920 \\hiNt #0b11
921 \\sEv
922 \\hinT #4
923 \\sevl
924 \\HINT #0b101
925 \\hint #0x7F
926 ,
927 .operands = .empty,
928 };
929
930 try std.testing.expectFmt("nop", "{f}", .{(try as.nextInstruction()).?});
931 try std.testing.expectFmt("nop", "{f}", .{(try as.nextInstruction()).?});
932 try std.testing.expectFmt("yield", "{f}", .{(try as.nextInstruction()).?});
933 try std.testing.expectFmt("yield", "{f}", .{(try as.nextInstruction()).?});
934 try std.testing.expectFmt("wfe", "{f}", .{(try as.nextInstruction()).?});
935 try std.testing.expectFmt("wfe", "{f}", .{(try as.nextInstruction()).?});
936 try std.testing.expectFmt("wfi", "{f}", .{(try as.nextInstruction()).?});
937 try std.testing.expectFmt("wfi", "{f}", .{(try as.nextInstruction()).?});
938 try std.testing.expectFmt("sev", "{f}", .{(try as.nextInstruction()).?});
939 try std.testing.expectFmt("sev", "{f}", .{(try as.nextInstruction()).?});
940 try std.testing.expectFmt("sevl", "{f}", .{(try as.nextInstruction()).?});
941 try std.testing.expectFmt("sevl", "{f}", .{(try as.nextInstruction()).?});
942 try std.testing.expectFmt("hint #0x7f", "{f}", .{(try as.nextInstruction()).?});
943
944 try std.testing.expect(null == try as.nextInstruction());
945}
946test "load store" {
947 var as: Assemble = .{
948 .source =
949 \\ LDP w0, w1, [x2], #-256
950 \\ LDP w3, w4, [x5], #0
951 \\ LDP w6, w7, [sp], #252
952 \\ LDP w0, w1, [x2, #-0x100]!
953 \\ LDP w3, w4, [x5, #0]!
954 \\ LDP w6, w7, [sp, #0xfc]!
955 \\ LDP w0, w1, [x2, #-256]
956 \\ LDP w3, w4, [x5]
957 \\ LDP w6, w7, [x8, #0]
958 \\ LDP w9, w10, [sp, #252]
959 \\
960 \\ LDP x0, x1, [x2], #-512
961 \\ LDP x3, x4, [x5], #0
962 \\ LDP x6, x7, [sp], #504
963 \\ LDP x0, x1, [x2, #-0x200]!
964 \\ LDP x3, x4, [x5, #0]!
965 \\ LDP x6, x7, [sp, #0x1f8]!
966 \\ LDP x0, x1, [x2, #-512]
967 \\ LDP x3, x4, [x5]
968 \\ LDP x6, x7, [x8, #0]
969 \\ LDP x9, x10, [sp, #504]
970 \\
971 \\ LDR w0, [x1], #-256
972 \\ LDR w2, [x3], #0
973 \\ LDR w4, [sp], #255
974 \\ LDR w0, [x1, #-0x100]!
975 \\ LDR w2, [x3, #0]!
976 \\ LDR w4, [sp, #0xff]!
977 \\ LDR w0, [x1, #0]
978 \\ LDR w2, [x3]
979 \\ LDR w4, [sp, #16380]
980 \\
981 \\ LDR x0, [x1], #-256
982 \\ LDR x2, [x3], #0
983 \\ LDR x4, [sp], #255
984 \\ LDR x0, [x1, #-0x100]!
985 \\ LDR x2, [x3, #0]!
986 \\ LDR x4, [sp, #0xff]!
987 \\ LDR x0, [x1, #0]
988 \\ LDR x2, [x3]
989 \\ LDR x4, [sp, #32760]
990 \\
991 \\ STP w0, w1, [x2], #-256
992 \\ STP w3, w4, [x5], #0
993 \\ STP w6, w7, [sp], #252
994 \\ STP w0, w1, [x2, #-0x100]!
995 \\ STP w3, w4, [x5, #0]!
996 \\ STP w6, w7, [sp, #0xfc]!
997 \\ STP w0, w1, [x2, #-256]
998 \\ STP w3, w4, [x5]
999 \\ STP w6, w7, [x8, #0]
1000 \\ STP w9, w10, [sp, #252]
1001 \\
1002 \\ STP x0, x1, [x2], #-512
1003 \\ STP x3, x4, [x5], #0
1004 \\ STP x6, x7, [sp], #504
1005 \\ STP x0, x1, [x2, #-0x200]!
1006 \\ STP x3, x4, [x5, #0]!
1007 \\ STP x6, x7, [sp, #0x1f8]!
1008 \\ STP x0, x1, [x2, #-512]
1009 \\ STP x3, x4, [x5]
1010 \\ STP x6, x7, [x8, #0]
1011 \\ STP x9, x10, [sp, #504]
1012 \\
1013 \\ STR w0, [x1], #-256
1014 \\ STR w2, [x3], #0
1015 \\ STR w4, [sp], #255
1016 \\ STR w0, [x1, #-0x100]!
1017 \\ STR w2, [x3, #0]!
1018 \\ STR w4, [sp, #0xff]!
1019 \\ STR w0, [x1, #0]
1020 \\ STR w2, [x3]
1021 \\ STR w4, [sp, #16380]
1022 \\
1023 \\ STR x0, [x1], #-256
1024 \\ STR x2, [x3], #0
1025 \\ STR x4, [sp], #255
1026 \\ STR x0, [x1, #-0x100]!
1027 \\ STR x2, [x3, #0]!
1028 \\ STR x4, [sp, #0xff]!
1029 \\ STR x0, [x1, #0]
1030 \\ STR x2, [x3]
1031 \\ STR x4, [sp, #32760]
1032 ,
1033 .operands = .empty,
1034 };
1035
1036 try std.testing.expectFmt("ldp w0, w1, [x2], #-0x100", "{f}", .{(try as.nextInstruction()).?});
1037 try std.testing.expectFmt("ldp w3, w4, [x5], #0x0", "{f}", .{(try as.nextInstruction()).?});
1038 try std.testing.expectFmt("ldp w6, w7, [sp], #0xfc", "{f}", .{(try as.nextInstruction()).?});
1039 try std.testing.expectFmt("ldp w0, w1, [x2, #-0x100]!", "{f}", .{(try as.nextInstruction()).?});
1040 try std.testing.expectFmt("ldp w3, w4, [x5, #0x0]!", "{f}", .{(try as.nextInstruction()).?});
1041 try std.testing.expectFmt("ldp w6, w7, [sp, #0xfc]!", "{f}", .{(try as.nextInstruction()).?});
1042 try std.testing.expectFmt("ldp w0, w1, [x2, #-0x100]", "{f}", .{(try as.nextInstruction()).?});
1043 try std.testing.expectFmt("ldp w3, w4, [x5]", "{f}", .{(try as.nextInstruction()).?});
1044 try std.testing.expectFmt("ldp w6, w7, [x8]", "{f}", .{(try as.nextInstruction()).?});
1045 try std.testing.expectFmt("ldp w9, w10, [sp, #0xfc]", "{f}", .{(try as.nextInstruction()).?});
1046
1047 try std.testing.expectFmt("ldp x0, x1, [x2], #-0x200", "{f}", .{(try as.nextInstruction()).?});
1048 try std.testing.expectFmt("ldp x3, x4, [x5], #0x0", "{f}", .{(try as.nextInstruction()).?});
1049 try std.testing.expectFmt("ldp x6, x7, [sp], #0x1f8", "{f}", .{(try as.nextInstruction()).?});
1050 try std.testing.expectFmt("ldp x0, x1, [x2, #-0x200]!", "{f}", .{(try as.nextInstruction()).?});
1051 try std.testing.expectFmt("ldp x3, x4, [x5, #0x0]!", "{f}", .{(try as.nextInstruction()).?});
1052 try std.testing.expectFmt("ldp x6, x7, [sp, #0x1f8]!", "{f}", .{(try as.nextInstruction()).?});
1053 try std.testing.expectFmt("ldp x0, x1, [x2, #-0x200]", "{f}", .{(try as.nextInstruction()).?});
1054 try std.testing.expectFmt("ldp x3, x4, [x5]", "{f}", .{(try as.nextInstruction()).?});
1055 try std.testing.expectFmt("ldp x6, x7, [x8]", "{f}", .{(try as.nextInstruction()).?});
1056 try std.testing.expectFmt("ldp x9, x10, [sp, #0x1f8]", "{f}", .{(try as.nextInstruction()).?});
1057
1058 try std.testing.expectFmt("ldr w0, [x1], #-0x100", "{f}", .{(try as.nextInstruction()).?});
1059 try std.testing.expectFmt("ldr w2, [x3], #0x0", "{f}", .{(try as.nextInstruction()).?});
1060 try std.testing.expectFmt("ldr w4, [sp], #0xff", "{f}", .{(try as.nextInstruction()).?});
1061 try std.testing.expectFmt("ldr w0, [x1, #-0x100]!", "{f}", .{(try as.nextInstruction()).?});
1062 try std.testing.expectFmt("ldr w2, [x3, #0x0]!", "{f}", .{(try as.nextInstruction()).?});
1063 try std.testing.expectFmt("ldr w4, [sp, #0xff]!", "{f}", .{(try as.nextInstruction()).?});
1064 try std.testing.expectFmt("ldr w0, [x1]", "{f}", .{(try as.nextInstruction()).?});
1065 try std.testing.expectFmt("ldr w2, [x3]", "{f}", .{(try as.nextInstruction()).?});
1066 try std.testing.expectFmt("ldr w4, [sp, #0x3ffc]", "{f}", .{(try as.nextInstruction()).?});
1067
1068 try std.testing.expectFmt("ldr x0, [x1], #-0x100", "{f}", .{(try as.nextInstruction()).?});
1069 try std.testing.expectFmt("ldr x2, [x3], #0x0", "{f}", .{(try as.nextInstruction()).?});
1070 try std.testing.expectFmt("ldr x4, [sp], #0xff", "{f}", .{(try as.nextInstruction()).?});
1071 try std.testing.expectFmt("ldr x0, [x1, #-0x100]!", "{f}", .{(try as.nextInstruction()).?});
1072 try std.testing.expectFmt("ldr x2, [x3, #0x0]!", "{f}", .{(try as.nextInstruction()).?});
1073 try std.testing.expectFmt("ldr x4, [sp, #0xff]!", "{f}", .{(try as.nextInstruction()).?});
1074 try std.testing.expectFmt("ldr x0, [x1]", "{f}", .{(try as.nextInstruction()).?});
1075 try std.testing.expectFmt("ldr x2, [x3]", "{f}", .{(try as.nextInstruction()).?});
1076 try std.testing.expectFmt("ldr x4, [sp, #0x7ff8]", "{f}", .{(try as.nextInstruction()).?});
1077
1078 try std.testing.expectFmt("stp w0, w1, [x2], #-0x100", "{f}", .{(try as.nextInstruction()).?});
1079 try std.testing.expectFmt("stp w3, w4, [x5], #0x0", "{f}", .{(try as.nextInstruction()).?});
1080 try std.testing.expectFmt("stp w6, w7, [sp], #0xfc", "{f}", .{(try as.nextInstruction()).?});
1081 try std.testing.expectFmt("stp w0, w1, [x2, #-0x100]!", "{f}", .{(try as.nextInstruction()).?});
1082 try std.testing.expectFmt("stp w3, w4, [x5, #0x0]!", "{f}", .{(try as.nextInstruction()).?});
1083 try std.testing.expectFmt("stp w6, w7, [sp, #0xfc]!", "{f}", .{(try as.nextInstruction()).?});
1084 try std.testing.expectFmt("stp w0, w1, [x2, #-0x100]", "{f}", .{(try as.nextInstruction()).?});
1085 try std.testing.expectFmt("stp w3, w4, [x5]", "{f}", .{(try as.nextInstruction()).?});
1086 try std.testing.expectFmt("stp w6, w7, [x8]", "{f}", .{(try as.nextInstruction()).?});
1087 try std.testing.expectFmt("stp w9, w10, [sp, #0xfc]", "{f}", .{(try as.nextInstruction()).?});
1088
1089 try std.testing.expectFmt("stp x0, x1, [x2], #-0x200", "{f}", .{(try as.nextInstruction()).?});
1090 try std.testing.expectFmt("stp x3, x4, [x5], #0x0", "{f}", .{(try as.nextInstruction()).?});
1091 try std.testing.expectFmt("stp x6, x7, [sp], #0x1f8", "{f}", .{(try as.nextInstruction()).?});
1092 try std.testing.expectFmt("stp x0, x1, [x2, #-0x200]!", "{f}", .{(try as.nextInstruction()).?});
1093 try std.testing.expectFmt("stp x3, x4, [x5, #0x0]!", "{f}", .{(try as.nextInstruction()).?});
1094 try std.testing.expectFmt("stp x6, x7, [sp, #0x1f8]!", "{f}", .{(try as.nextInstruction()).?});
1095 try std.testing.expectFmt("stp x0, x1, [x2, #-0x200]", "{f}", .{(try as.nextInstruction()).?});
1096 try std.testing.expectFmt("stp x3, x4, [x5]", "{f}", .{(try as.nextInstruction()).?});
1097 try std.testing.expectFmt("stp x6, x7, [x8]", "{f}", .{(try as.nextInstruction()).?});
1098 try std.testing.expectFmt("stp x9, x10, [sp, #0x1f8]", "{f}", .{(try as.nextInstruction()).?});
1099
1100 try std.testing.expectFmt("str w0, [x1], #-0x100", "{f}", .{(try as.nextInstruction()).?});
1101 try std.testing.expectFmt("str w2, [x3], #0x0", "{f}", .{(try as.nextInstruction()).?});
1102 try std.testing.expectFmt("str w4, [sp], #0xff", "{f}", .{(try as.nextInstruction()).?});
1103 try std.testing.expectFmt("str w0, [x1, #-0x100]!", "{f}", .{(try as.nextInstruction()).?});
1104 try std.testing.expectFmt("str w2, [x3, #0x0]!", "{f}", .{(try as.nextInstruction()).?});
1105 try std.testing.expectFmt("str w4, [sp, #0xff]!", "{f}", .{(try as.nextInstruction()).?});
1106 try std.testing.expectFmt("str w0, [x1]", "{f}", .{(try as.nextInstruction()).?});
1107 try std.testing.expectFmt("str w2, [x3]", "{f}", .{(try as.nextInstruction()).?});
1108 try std.testing.expectFmt("str w4, [sp, #0x3ffc]", "{f}", .{(try as.nextInstruction()).?});
1109
1110 try std.testing.expectFmt("str x0, [x1], #-0x100", "{f}", .{(try as.nextInstruction()).?});
1111 try std.testing.expectFmt("str x2, [x3], #0x0", "{f}", .{(try as.nextInstruction()).?});
1112 try std.testing.expectFmt("str x4, [sp], #0xff", "{f}", .{(try as.nextInstruction()).?});
1113 try std.testing.expectFmt("str x0, [x1, #-0x100]!", "{f}", .{(try as.nextInstruction()).?});
1114 try std.testing.expectFmt("str x2, [x3, #0x0]!", "{f}", .{(try as.nextInstruction()).?});
1115 try std.testing.expectFmt("str x4, [sp, #0xff]!", "{f}", .{(try as.nextInstruction()).?});
1116 try std.testing.expectFmt("str x0, [x1]", "{f}", .{(try as.nextInstruction()).?});
1117 try std.testing.expectFmt("str x2, [x3]", "{f}", .{(try as.nextInstruction()).?});
1118 try std.testing.expectFmt("str x4, [sp, #0x7ff8]", "{f}", .{(try as.nextInstruction()).?});
1119
1120 try std.testing.expect(null == try as.nextInstruction());
1121}
1122test "logical" {
1123 var as: Assemble = .{
1124 .source =
1125 \\ and w0, w0, w0
1126 \\ and w1, w1, w2, lsl #0
1127 \\ and w3, w4, w5, lsl #1
1128 \\ and w6, w6, wzr, lsl #31
1129 \\ and w7, wzr, w8, lsr #0
1130 \\ and w9, wzr, wzr, lsr #30
1131 \\ and wzr, w10, w11, lsr #31
1132 \\ and wzr, w12, wzr, asr #0x0
1133 \\ and wzr, wzr, w13, asr #0x10
1134 \\ and wzr, wzr, wzr, asr #0x1f
1135 \\ and w0, w0, wzr
1136 \\ and w1, w2, wzr, lsl #0
1137 \\ and w3, wzr, w3
1138 \\ and w4, wzr, w5, lsl #0
1139 \\ and w6, wzr, wzr
1140 \\ and w7, wzr, wzr, lsl #0
1141 \\ and wzr, w8, wzr
1142 \\ and wzr, w9, wzr, lsl #0
1143 \\ and wzr, wzr, w10
1144 \\ and wzr, wzr, w11, lsl #0
1145 \\ and wzr, wzr, wzr
1146 \\ and wzr, wzr, wzr, lsl #0
1147 \\
1148 \\ and x0, x0, x0
1149 \\ and x1, x1, x2, lsl #0
1150 \\ and x3, x4, x5, lsl #1
1151 \\ and x6, x6, xzr, lsl #63
1152 \\ and x7, xzr, x8, lsr #0
1153 \\ and x9, xzr, xzr, lsr #62
1154 \\ and xzr, x10, x11, lsr #63
1155 \\ and xzr, x12, xzr, asr #0x0
1156 \\ and xzr, xzr, x13, asr #0x1F
1157 \\ and xzr, xzr, xzr, asr #0x3f
1158 \\ and x0, x0, xzr
1159 \\ and x1, x2, xzr, lsl #0
1160 \\ and x3, xzr, x3
1161 \\ and x4, xzr, x5, lsl #0
1162 \\ and x6, xzr, xzr
1163 \\ and x7, xzr, xzr, lsl #0
1164 \\ and xzr, x8, xzr
1165 \\ and xzr, x9, xzr, lsl #0
1166 \\ and xzr, xzr, x10
1167 \\ and xzr, xzr, x11, lsl #0
1168 \\ and xzr, xzr, xzr
1169 \\ and xzr, xzr, xzr, lsl #0
1170 \\
1171 \\ orr w0, w0, w0
1172 \\ orr w1, w1, w2, lsl #0
1173 \\ orr w3, w4, w5, lsl #1
1174 \\ orr w6, w6, wzr, lsl #31
1175 \\ orr w7, wzr, w8, lsr #0
1176 \\ orr w9, wzr, wzr, lsr #30
1177 \\ orr wzr, w10, w11, lsr #31
1178 \\ orr wzr, w12, wzr, asr #0x0
1179 \\ orr wzr, wzr, w13, asr #0x10
1180 \\ orr wzr, wzr, wzr, asr #0x1f
1181 \\ orr w0, w0, wzr
1182 \\ orr w1, w2, wzr, lsl #0
1183 \\ orr w3, wzr, w3
1184 \\ orr w4, wzr, w5, lsl #0
1185 \\ orr w6, wzr, wzr
1186 \\ orr w7, wzr, wzr, lsl #0
1187 \\ orr wzr, w8, wzr
1188 \\ orr wzr, w9, wzr, lsl #0
1189 \\ orr wzr, wzr, w10
1190 \\ orr wzr, wzr, w11, lsl #0
1191 \\ orr wzr, wzr, wzr
1192 \\ orr wzr, wzr, wzr, lsl #0
1193 \\
1194 \\ orr x0, x0, x0
1195 \\ orr x1, x1, x2, lsl #0
1196 \\ orr x3, x4, x5, lsl #1
1197 \\ orr x6, x6, xzr, lsl #63
1198 \\ orr x7, xzr, x8, lsr #0
1199 \\ orr x9, xzr, xzr, lsr #62
1200 \\ orr xzr, x10, x11, lsr #63
1201 \\ orr xzr, x12, xzr, asr #0x0
1202 \\ orr xzr, xzr, x13, asr #0x1F
1203 \\ orr xzr, xzr, xzr, asr #0x3f
1204 \\ orr x0, x0, xzr
1205 \\ orr x1, x2, xzr, lsl #0
1206 \\ orr x3, xzr, x3
1207 \\ orr x4, xzr, x5, lsl #0
1208 \\ orr x6, xzr, xzr
1209 \\ orr x7, xzr, xzr, lsl #0
1210 \\ orr xzr, x8, xzr
1211 \\ orr xzr, x9, xzr, lsl #0
1212 \\ orr xzr, xzr, x10
1213 \\ orr xzr, xzr, x11, lsl #0
1214 \\ orr xzr, xzr, xzr
1215 \\ orr xzr, xzr, xzr, lsl #0
1216 \\
1217 \\ eor w0, w0, w0
1218 \\ eor w1, w1, w2, lsl #0
1219 \\ eor w3, w4, w5, lsl #1
1220 \\ eor w6, w6, wzr, lsl #31
1221 \\ eor w7, wzr, w8, lsr #0
1222 \\ eor w9, wzr, wzr, lsr #30
1223 \\ eor wzr, w10, w11, lsr #31
1224 \\ eor wzr, w12, wzr, asr #0x0
1225 \\ eor wzr, wzr, w13, asr #0x10
1226 \\ eor wzr, wzr, wzr, asr #0x1f
1227 \\ eor w0, w0, wzr
1228 \\ eor w1, w2, wzr, lsl #0
1229 \\ eor w3, wzr, w3
1230 \\ eor w4, wzr, w5, lsl #0
1231 \\ eor w6, wzr, wzr
1232 \\ eor w7, wzr, wzr, lsl #0
1233 \\ eor wzr, w8, wzr
1234 \\ eor wzr, w9, wzr, lsl #0
1235 \\ eor wzr, wzr, w10
1236 \\ eor wzr, wzr, w11, lsl #0
1237 \\ eor wzr, wzr, wzr
1238 \\ eor wzr, wzr, wzr, lsl #0
1239 \\
1240 \\ eor x0, x0, x0
1241 \\ eor x1, x1, x2, lsl #0
1242 \\ eor x3, x4, x5, lsl #1
1243 \\ eor x6, x6, xzr, lsl #63
1244 \\ eor x7, xzr, x8, lsr #0
1245 \\ eor x9, xzr, xzr, lsr #62
1246 \\ eor xzr, x10, x11, lsr #63
1247 \\ eor xzr, x12, xzr, asr #0x0
1248 \\ eor xzr, xzr, x13, asr #0x1F
1249 \\ eor xzr, xzr, xzr, asr #0x3f
1250 \\ eor x0, x0, xzr
1251 \\ eor x1, x2, xzr, lsl #0
1252 \\ eor x3, xzr, x3
1253 \\ eor x4, xzr, x5, lsl #0
1254 \\ eor x6, xzr, xzr
1255 \\ eor x7, xzr, xzr, lsl #0
1256 \\ eor xzr, x8, xzr
1257 \\ eor xzr, x9, xzr, lsl #0
1258 \\ eor xzr, xzr, x10
1259 \\ eor xzr, xzr, x11, lsl #0
1260 \\ eor xzr, xzr, xzr
1261 \\ eor xzr, xzr, xzr, lsl #0
1262 \\
1263 \\ ands w0, w0, w0
1264 \\ ands w1, w1, w2, lsl #0
1265 \\ ands w3, w4, w5, lsl #1
1266 \\ ands w6, w6, wzr, lsl #31
1267 \\ ands w7, wzr, w8, lsr #0
1268 \\ ands w9, wzr, wzr, lsr #30
1269 \\ ands wzr, w10, w11, lsr #31
1270 \\ ands wzr, w12, wzr, asr #0x0
1271 \\ ands wzr, wzr, w13, asr #0x10
1272 \\ ands wzr, wzr, wzr, asr #0x1f
1273 \\ ands w0, w0, wzr
1274 \\ ands w1, w2, wzr, lsl #0
1275 \\ ands w3, wzr, w3
1276 \\ ands w4, wzr, w5, lsl #0
1277 \\ ands w6, wzr, wzr
1278 \\ ands w7, wzr, wzr, lsl #0
1279 \\ ands wzr, w8, wzr
1280 \\ ands wzr, w9, wzr, lsl #0
1281 \\ ands wzr, wzr, w10
1282 \\ ands wzr, wzr, w11, lsl #0
1283 \\ ands wzr, wzr, wzr
1284 \\ ands wzr, wzr, wzr, lsl #0
1285 \\
1286 \\ ands x0, x0, x0
1287 \\ ands x1, x1, x2, lsl #0
1288 \\ ands x3, x4, x5, lsl #1
1289 \\ ands x6, x6, xzr, lsl #63
1290 \\ ands x7, xzr, x8, lsr #0
1291 \\ ands x9, xzr, xzr, lsr #62
1292 \\ ands xzr, x10, x11, lsr #63
1293 \\ ands xzr, x12, xzr, asr #0x0
1294 \\ ands xzr, xzr, x13, asr #0x1F
1295 \\ ands xzr, xzr, xzr, asr #0x3f
1296 \\ ands x0, x0, xzr
1297 \\ ands x1, x2, xzr, lsl #0
1298 \\ ands x3, xzr, x3
1299 \\ ands x4, xzr, x5, lsl #0
1300 \\ ands x6, xzr, xzr
1301 \\ ands x7, xzr, xzr, lsl #0
1302 \\ ands xzr, x8, xzr
1303 \\ ands xzr, x9, xzr, lsl #0
1304 \\ ands xzr, xzr, x10
1305 \\ ands xzr, xzr, x11, lsl #0
1306 \\ ands xzr, xzr, xzr
1307 \\ ands xzr, xzr, xzr, lsl #0
1308 ,
1309 .operands = .empty,
1310 };
1311
1312 try std.testing.expectFmt("and w0, w0, w0", "{f}", .{(try as.nextInstruction()).?});
1313 try std.testing.expectFmt("and w1, w1, w2", "{f}", .{(try as.nextInstruction()).?});
1314 try std.testing.expectFmt("and w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
1315 try std.testing.expectFmt("and w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?});
1316 try std.testing.expectFmt("and w7, wzr, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
1317 try std.testing.expectFmt("and w9, wzr, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?});
1318 try std.testing.expectFmt("and wzr, w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?});
1319 try std.testing.expectFmt("and wzr, w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
1320 try std.testing.expectFmt("and wzr, wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?});
1321 try std.testing.expectFmt("and wzr, wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?});
1322 try std.testing.expectFmt("and w0, w0, wzr", "{f}", .{(try as.nextInstruction()).?});
1323 try std.testing.expectFmt("and w1, w2, wzr", "{f}", .{(try as.nextInstruction()).?});
1324 try std.testing.expectFmt("and w3, wzr, w3", "{f}", .{(try as.nextInstruction()).?});
1325 try std.testing.expectFmt("and w4, wzr, w5", "{f}", .{(try as.nextInstruction()).?});
1326 try std.testing.expectFmt("and w6, wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1327 try std.testing.expectFmt("and w7, wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1328 try std.testing.expectFmt("and wzr, w8, wzr", "{f}", .{(try as.nextInstruction()).?});
1329 try std.testing.expectFmt("and wzr, w9, wzr", "{f}", .{(try as.nextInstruction()).?});
1330 try std.testing.expectFmt("and wzr, wzr, w10", "{f}", .{(try as.nextInstruction()).?});
1331 try std.testing.expectFmt("and wzr, wzr, w11", "{f}", .{(try as.nextInstruction()).?});
1332 try std.testing.expectFmt("and wzr, wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1333 try std.testing.expectFmt("and wzr, wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1334
1335 try std.testing.expectFmt("and x0, x0, x0", "{f}", .{(try as.nextInstruction()).?});
1336 try std.testing.expectFmt("and x1, x1, x2", "{f}", .{(try as.nextInstruction()).?});
1337 try std.testing.expectFmt("and x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
1338 try std.testing.expectFmt("and x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?});
1339 try std.testing.expectFmt("and x7, xzr, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
1340 try std.testing.expectFmt("and x9, xzr, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?});
1341 try std.testing.expectFmt("and xzr, x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?});
1342 try std.testing.expectFmt("and xzr, x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
1343 try std.testing.expectFmt("and xzr, xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?});
1344 try std.testing.expectFmt("and xzr, xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?});
1345 try std.testing.expectFmt("and x0, x0, xzr", "{f}", .{(try as.nextInstruction()).?});
1346 try std.testing.expectFmt("and x1, x2, xzr", "{f}", .{(try as.nextInstruction()).?});
1347 try std.testing.expectFmt("and x3, xzr, x3", "{f}", .{(try as.nextInstruction()).?});
1348 try std.testing.expectFmt("and x4, xzr, x5", "{f}", .{(try as.nextInstruction()).?});
1349 try std.testing.expectFmt("and x6, xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1350 try std.testing.expectFmt("and x7, xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1351 try std.testing.expectFmt("and xzr, x8, xzr", "{f}", .{(try as.nextInstruction()).?});
1352 try std.testing.expectFmt("and xzr, x9, xzr", "{f}", .{(try as.nextInstruction()).?});
1353 try std.testing.expectFmt("and xzr, xzr, x10", "{f}", .{(try as.nextInstruction()).?});
1354 try std.testing.expectFmt("and xzr, xzr, x11", "{f}", .{(try as.nextInstruction()).?});
1355 try std.testing.expectFmt("and xzr, xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1356 try std.testing.expectFmt("and xzr, xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1357
1358 try std.testing.expectFmt("orr w0, w0, w0", "{f}", .{(try as.nextInstruction()).?});
1359 try std.testing.expectFmt("orr w1, w1, w2", "{f}", .{(try as.nextInstruction()).?});
1360 try std.testing.expectFmt("orr w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
1361 try std.testing.expectFmt("orr w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?});
1362 try std.testing.expectFmt("orr w7, wzr, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
1363 try std.testing.expectFmt("orr w9, wzr, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?});
1364 try std.testing.expectFmt("orr wzr, w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?});
1365 try std.testing.expectFmt("orr wzr, w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
1366 try std.testing.expectFmt("orr wzr, wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?});
1367 try std.testing.expectFmt("orr wzr, wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?});
1368 try std.testing.expectFmt("orr w0, w0, wzr", "{f}", .{(try as.nextInstruction()).?});
1369 try std.testing.expectFmt("orr w1, w2, wzr", "{f}", .{(try as.nextInstruction()).?});
1370 try std.testing.expectFmt("mov w3, w3", "{f}", .{(try as.nextInstruction()).?});
1371 try std.testing.expectFmt("mov w4, w5", "{f}", .{(try as.nextInstruction()).?});
1372 try std.testing.expectFmt("mov w6, wzr", "{f}", .{(try as.nextInstruction()).?});
1373 try std.testing.expectFmt("mov w7, wzr", "{f}", .{(try as.nextInstruction()).?});
1374 try std.testing.expectFmt("orr wzr, w8, wzr", "{f}", .{(try as.nextInstruction()).?});
1375 try std.testing.expectFmt("orr wzr, w9, wzr", "{f}", .{(try as.nextInstruction()).?});
1376 try std.testing.expectFmt("mov wzr, w10", "{f}", .{(try as.nextInstruction()).?});
1377 try std.testing.expectFmt("mov wzr, w11", "{f}", .{(try as.nextInstruction()).?});
1378 try std.testing.expectFmt("mov wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1379 try std.testing.expectFmt("mov wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1380
1381 try std.testing.expectFmt("orr x0, x0, x0", "{f}", .{(try as.nextInstruction()).?});
1382 try std.testing.expectFmt("orr x1, x1, x2", "{f}", .{(try as.nextInstruction()).?});
1383 try std.testing.expectFmt("orr x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
1384 try std.testing.expectFmt("orr x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?});
1385 try std.testing.expectFmt("orr x7, xzr, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
1386 try std.testing.expectFmt("orr x9, xzr, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?});
1387 try std.testing.expectFmt("orr xzr, x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?});
1388 try std.testing.expectFmt("orr xzr, x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
1389 try std.testing.expectFmt("orr xzr, xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?});
1390 try std.testing.expectFmt("orr xzr, xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?});
1391 try std.testing.expectFmt("orr x0, x0, xzr", "{f}", .{(try as.nextInstruction()).?});
1392 try std.testing.expectFmt("orr x1, x2, xzr", "{f}", .{(try as.nextInstruction()).?});
1393 try std.testing.expectFmt("mov x3, x3", "{f}", .{(try as.nextInstruction()).?});
1394 try std.testing.expectFmt("mov x4, x5", "{f}", .{(try as.nextInstruction()).?});
1395 try std.testing.expectFmt("mov x6, xzr", "{f}", .{(try as.nextInstruction()).?});
1396 try std.testing.expectFmt("mov x7, xzr", "{f}", .{(try as.nextInstruction()).?});
1397 try std.testing.expectFmt("orr xzr, x8, xzr", "{f}", .{(try as.nextInstruction()).?});
1398 try std.testing.expectFmt("orr xzr, x9, xzr", "{f}", .{(try as.nextInstruction()).?});
1399 try std.testing.expectFmt("mov xzr, x10", "{f}", .{(try as.nextInstruction()).?});
1400 try std.testing.expectFmt("mov xzr, x11", "{f}", .{(try as.nextInstruction()).?});
1401 try std.testing.expectFmt("mov xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1402 try std.testing.expectFmt("mov xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1403
1404 try std.testing.expectFmt("eor w0, w0, w0", "{f}", .{(try as.nextInstruction()).?});
1405 try std.testing.expectFmt("eor w1, w1, w2", "{f}", .{(try as.nextInstruction()).?});
1406 try std.testing.expectFmt("eor w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
1407 try std.testing.expectFmt("eor w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?});
1408 try std.testing.expectFmt("eor w7, wzr, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
1409 try std.testing.expectFmt("eor w9, wzr, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?});
1410 try std.testing.expectFmt("eor wzr, w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?});
1411 try std.testing.expectFmt("eor wzr, w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
1412 try std.testing.expectFmt("eor wzr, wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?});
1413 try std.testing.expectFmt("eor wzr, wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?});
1414 try std.testing.expectFmt("eor w0, w0, wzr", "{f}", .{(try as.nextInstruction()).?});
1415 try std.testing.expectFmt("eor w1, w2, wzr", "{f}", .{(try as.nextInstruction()).?});
1416 try std.testing.expectFmt("eor w3, wzr, w3", "{f}", .{(try as.nextInstruction()).?});
1417 try std.testing.expectFmt("eor w4, wzr, w5", "{f}", .{(try as.nextInstruction()).?});
1418 try std.testing.expectFmt("eor w6, wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1419 try std.testing.expectFmt("eor w7, wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1420 try std.testing.expectFmt("eor wzr, w8, wzr", "{f}", .{(try as.nextInstruction()).?});
1421 try std.testing.expectFmt("eor wzr, w9, wzr", "{f}", .{(try as.nextInstruction()).?});
1422 try std.testing.expectFmt("eor wzr, wzr, w10", "{f}", .{(try as.nextInstruction()).?});
1423 try std.testing.expectFmt("eor wzr, wzr, w11", "{f}", .{(try as.nextInstruction()).?});
1424 try std.testing.expectFmt("eor wzr, wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1425 try std.testing.expectFmt("eor wzr, wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1426
1427 try std.testing.expectFmt("eor x0, x0, x0", "{f}", .{(try as.nextInstruction()).?});
1428 try std.testing.expectFmt("eor x1, x1, x2", "{f}", .{(try as.nextInstruction()).?});
1429 try std.testing.expectFmt("eor x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
1430 try std.testing.expectFmt("eor x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?});
1431 try std.testing.expectFmt("eor x7, xzr, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
1432 try std.testing.expectFmt("eor x9, xzr, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?});
1433 try std.testing.expectFmt("eor xzr, x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?});
1434 try std.testing.expectFmt("eor xzr, x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
1435 try std.testing.expectFmt("eor xzr, xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?});
1436 try std.testing.expectFmt("eor xzr, xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?});
1437 try std.testing.expectFmt("eor x0, x0, xzr", "{f}", .{(try as.nextInstruction()).?});
1438 try std.testing.expectFmt("eor x1, x2, xzr", "{f}", .{(try as.nextInstruction()).?});
1439 try std.testing.expectFmt("eor x3, xzr, x3", "{f}", .{(try as.nextInstruction()).?});
1440 try std.testing.expectFmt("eor x4, xzr, x5", "{f}", .{(try as.nextInstruction()).?});
1441 try std.testing.expectFmt("eor x6, xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1442 try std.testing.expectFmt("eor x7, xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1443 try std.testing.expectFmt("eor xzr, x8, xzr", "{f}", .{(try as.nextInstruction()).?});
1444 try std.testing.expectFmt("eor xzr, x9, xzr", "{f}", .{(try as.nextInstruction()).?});
1445 try std.testing.expectFmt("eor xzr, xzr, x10", "{f}", .{(try as.nextInstruction()).?});
1446 try std.testing.expectFmt("eor xzr, xzr, x11", "{f}", .{(try as.nextInstruction()).?});
1447 try std.testing.expectFmt("eor xzr, xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1448 try std.testing.expectFmt("eor xzr, xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1449
1450 try std.testing.expectFmt("ands w0, w0, w0", "{f}", .{(try as.nextInstruction()).?});
1451 try std.testing.expectFmt("ands w1, w1, w2", "{f}", .{(try as.nextInstruction()).?});
1452 try std.testing.expectFmt("ands w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
1453 try std.testing.expectFmt("ands w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?});
1454 try std.testing.expectFmt("ands w7, wzr, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
1455 try std.testing.expectFmt("ands w9, wzr, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?});
1456 try std.testing.expectFmt("tst w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?});
1457 try std.testing.expectFmt("tst w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
1458 try std.testing.expectFmt("tst wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?});
1459 try std.testing.expectFmt("tst wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?});
1460 try std.testing.expectFmt("ands w0, w0, wzr", "{f}", .{(try as.nextInstruction()).?});
1461 try std.testing.expectFmt("ands w1, w2, wzr", "{f}", .{(try as.nextInstruction()).?});
1462 try std.testing.expectFmt("ands w3, wzr, w3", "{f}", .{(try as.nextInstruction()).?});
1463 try std.testing.expectFmt("ands w4, wzr, w5", "{f}", .{(try as.nextInstruction()).?});
1464 try std.testing.expectFmt("ands w6, wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1465 try std.testing.expectFmt("ands w7, wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1466 try std.testing.expectFmt("tst w8, wzr", "{f}", .{(try as.nextInstruction()).?});
1467 try std.testing.expectFmt("tst w9, wzr", "{f}", .{(try as.nextInstruction()).?});
1468 try std.testing.expectFmt("tst wzr, w10", "{f}", .{(try as.nextInstruction()).?});
1469 try std.testing.expectFmt("tst wzr, w11", "{f}", .{(try as.nextInstruction()).?});
1470 try std.testing.expectFmt("tst wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1471 try std.testing.expectFmt("tst wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1472
1473 try std.testing.expectFmt("ands x0, x0, x0", "{f}", .{(try as.nextInstruction()).?});
1474 try std.testing.expectFmt("ands x1, x1, x2", "{f}", .{(try as.nextInstruction()).?});
1475 try std.testing.expectFmt("ands x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?});
1476 try std.testing.expectFmt("ands x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?});
1477 try std.testing.expectFmt("ands x7, xzr, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?});
1478 try std.testing.expectFmt("ands x9, xzr, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?});
1479 try std.testing.expectFmt("tst x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?});
1480 try std.testing.expectFmt("tst x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?});
1481 try std.testing.expectFmt("tst xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?});
1482 try std.testing.expectFmt("tst xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?});
1483 try std.testing.expectFmt("ands x0, x0, xzr", "{f}", .{(try as.nextInstruction()).?});
1484 try std.testing.expectFmt("ands x1, x2, xzr", "{f}", .{(try as.nextInstruction()).?});
1485 try std.testing.expectFmt("ands x3, xzr, x3", "{f}", .{(try as.nextInstruction()).?});
1486 try std.testing.expectFmt("ands x4, xzr, x5", "{f}", .{(try as.nextInstruction()).?});
1487 try std.testing.expectFmt("ands x6, xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1488 try std.testing.expectFmt("ands x7, xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1489 try std.testing.expectFmt("tst x8, xzr", "{f}", .{(try as.nextInstruction()).?});
1490 try std.testing.expectFmt("tst x9, xzr", "{f}", .{(try as.nextInstruction()).?});
1491 try std.testing.expectFmt("tst xzr, x10", "{f}", .{(try as.nextInstruction()).?});
1492 try std.testing.expectFmt("tst xzr, x11", "{f}", .{(try as.nextInstruction()).?});
1493 try std.testing.expectFmt("tst xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1494 try std.testing.expectFmt("tst xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1495
1496 try std.testing.expect(null == try as.nextInstruction());
1497}
1498test "mov" {
1499 var as: Assemble = .{
1500 .source =
1501 \\MOV W0, #0
1502 \\MOV WZR, #0xffff
1503 \\
1504 \\MOV X0, #0
1505 \\MOV XZR, #0xffff
1506 \\
1507 \\MOV W0, WSP
1508 \\MOV WSP, W1
1509 \\MOV WSP, WSP
1510 \\MOV X0, SP
1511 \\MOV SP, X1
1512 \\MOV SP, SP
1513 \\
1514 \\MOV W0, W0
1515 \\MOV W1, W2
1516 \\MOV W3, WZR
1517 \\MOV WZR, W4
1518 \\MOV WZR, WZR
1519 \\MOV X0, X0
1520 \\MOV X1, X2
1521 \\MOV X3, XZR
1522 \\MOV XZR, X4
1523 \\MOV XZR, XZR
1524 \\
1525 \\MOVK W0, #0
1526 \\MOVK W1, #1, lsl #0
1527 \\MOVK W2, #2, lsl #16
1528 \\MOVK X3, #3
1529 \\MOVK X4, #4, lsl #0x00
1530 \\MOVK X5, #5, lsl #0x10
1531 \\MOVK X6, #6, lsl #0x20
1532 \\MOVK X7, #7, lsl #0x30
1533 \\
1534 \\MOVN W0, #8
1535 \\MOVN W1, #9, lsl #0
1536 \\MOVN W2, #10, lsl #16
1537 \\MOVN X3, #11
1538 \\MOVN X4, #12, lsl #0x00
1539 \\MOVN X5, #13, lsl #0x10
1540 \\MOVN X6, #14, lsl #0x20
1541 \\MOVN X7, #15, lsl #0x30
1542 \\
1543 \\MOVN WZR, #0, lsl #0
1544 \\MOVN WZR, #0, lsl #16
1545 \\MOVN XZR, #0, lsl #0
1546 \\MOVN XZR, #0, lsl #16
1547 \\MOVN XZR, #0, lsl #32
1548 \\MOVN XZR, #0, lsl #48
1549 \\
1550 \\MOVN WZR, #0xffff, lsl #0
1551 \\MOVN WZR, #0xffff, lsl #16
1552 \\MOVN XZR, #0xffff, lsl #0
1553 \\MOVN XZR, #0xffff, lsl #16
1554 \\MOVN XZR, #0xffff, lsl #32
1555 \\MOVN XZR, #0xffff, lsl #48
1556 \\
1557 \\MOVZ W0, #16
1558 \\MOVZ W1, #17, lsl #0
1559 \\MOVZ W2, #18, lsl #16
1560 \\MOVZ X3, #19
1561 \\MOVZ X4, #20, lsl #0x00
1562 \\MOVZ X5, #21, lsl #0x10
1563 \\MOVZ X6, #22, lsl #0x20
1564 \\MOVZ X7, #23, lsl #0x30
1565 \\
1566 \\MOVZ WZR, #0, lsl #0
1567 \\MOVZ WZR, #0, lsl #16
1568 \\MOVZ XZR, #0, lsl #0
1569 \\MOVZ XZR, #0, lsl #16
1570 \\MOVZ XZR, #0, lsl #32
1571 \\MOVZ XZR, #0, lsl #48
1572 \\
1573 \\MOVZ WZR, #0xffff, lsl #0
1574 \\MOVZ WZR, #0xffff, lsl #16
1575 \\MOVZ XZR, #0xffff, lsl #0
1576 \\MOVZ XZR, #0xffff, lsl #16
1577 \\MOVZ XZR, #0xffff, lsl #32
1578 \\MOVZ XZR, #0xffff, lsl #48
1579 ,
1580 .operands = .empty,
1581 };
1582
1583 try std.testing.expectFmt("mov w0, #0x0", "{f}", .{(try as.nextInstruction()).?});
1584 try std.testing.expectFmt("mov wzr, #0xffff", "{f}", .{(try as.nextInstruction()).?});
1585 try std.testing.expectFmt("mov x0, #0x0", "{f}", .{(try as.nextInstruction()).?});
1586 try std.testing.expectFmt("mov xzr, #0xffff", "{f}", .{(try as.nextInstruction()).?});
1587
1588 try std.testing.expectFmt("mov w0, wsp", "{f}", .{(try as.nextInstruction()).?});
1589 try std.testing.expectFmt("mov wsp, w1", "{f}", .{(try as.nextInstruction()).?});
1590 try std.testing.expectFmt("mov wsp, wsp", "{f}", .{(try as.nextInstruction()).?});
1591 try std.testing.expectFmt("mov x0, sp", "{f}", .{(try as.nextInstruction()).?});
1592 try std.testing.expectFmt("mov sp, x1", "{f}", .{(try as.nextInstruction()).?});
1593 try std.testing.expectFmt("mov sp, sp", "{f}", .{(try as.nextInstruction()).?});
1594
1595 try std.testing.expectFmt("mov w0, w0", "{f}", .{(try as.nextInstruction()).?});
1596 try std.testing.expectFmt("mov w1, w2", "{f}", .{(try as.nextInstruction()).?});
1597 try std.testing.expectFmt("mov w3, wzr", "{f}", .{(try as.nextInstruction()).?});
1598 try std.testing.expectFmt("mov wzr, w4", "{f}", .{(try as.nextInstruction()).?});
1599 try std.testing.expectFmt("mov wzr, wzr", "{f}", .{(try as.nextInstruction()).?});
1600 try std.testing.expectFmt("mov x0, x0", "{f}", .{(try as.nextInstruction()).?});
1601 try std.testing.expectFmt("mov x1, x2", "{f}", .{(try as.nextInstruction()).?});
1602 try std.testing.expectFmt("mov x3, xzr", "{f}", .{(try as.nextInstruction()).?});
1603 try std.testing.expectFmt("mov xzr, x4", "{f}", .{(try as.nextInstruction()).?});
1604 try std.testing.expectFmt("mov xzr, xzr", "{f}", .{(try as.nextInstruction()).?});
1605
1606 try std.testing.expectFmt("movk w0, #0x0", "{f}", .{(try as.nextInstruction()).?});
1607 try std.testing.expectFmt("movk w1, #0x1", "{f}", .{(try as.nextInstruction()).?});
1608 try std.testing.expectFmt("movk w2, #0x2, lsl #16", "{f}", .{(try as.nextInstruction()).?});
1609 try std.testing.expectFmt("movk x3, #0x3", "{f}", .{(try as.nextInstruction()).?});
1610 try std.testing.expectFmt("movk x4, #0x4", "{f}", .{(try as.nextInstruction()).?});
1611 try std.testing.expectFmt("movk x5, #0x5, lsl #16", "{f}", .{(try as.nextInstruction()).?});
1612 try std.testing.expectFmt("movk x6, #0x6, lsl #32", "{f}", .{(try as.nextInstruction()).?});
1613 try std.testing.expectFmt("movk x7, #0x7, lsl #48", "{f}", .{(try as.nextInstruction()).?});
1614
1615 try std.testing.expectFmt("mov w0, #-0x9", "{f}", .{(try as.nextInstruction()).?});
1616 try std.testing.expectFmt("mov w1, #-0xa", "{f}", .{(try as.nextInstruction()).?});
1617 try std.testing.expectFmt("mov w2, #-0xa0001", "{f}", .{(try as.nextInstruction()).?});
1618 try std.testing.expectFmt("mov x3, #-0xc", "{f}", .{(try as.nextInstruction()).?});
1619 try std.testing.expectFmt("mov x4, #-0xd", "{f}", .{(try as.nextInstruction()).?});
1620 try std.testing.expectFmt("mov x5, #-0xd0001", "{f}", .{(try as.nextInstruction()).?});
1621 try std.testing.expectFmt("mov x6, #-0xe00000001", "{f}", .{(try as.nextInstruction()).?});
1622 try std.testing.expectFmt("mov x7, #-0xf000000000001", "{f}", .{(try as.nextInstruction()).?});
1623
1624 try std.testing.expectFmt("mov wzr, #-0x1", "{f}", .{(try as.nextInstruction()).?});
1625 try std.testing.expectFmt("movn wzr, #0x0, lsl #16", "{f}", .{(try as.nextInstruction()).?});
1626 try std.testing.expectFmt("mov xzr, #-0x1", "{f}", .{(try as.nextInstruction()).?});
1627 try std.testing.expectFmt("movn xzr, #0x0, lsl #16", "{f}", .{(try as.nextInstruction()).?});
1628 try std.testing.expectFmt("movn xzr, #0x0, lsl #32", "{f}", .{(try as.nextInstruction()).?});
1629 try std.testing.expectFmt("movn xzr, #0x0, lsl #48", "{f}", .{(try as.nextInstruction()).?});
1630
1631 try std.testing.expectFmt("movn wzr, #0xffff", "{f}", .{(try as.nextInstruction()).?});
1632 try std.testing.expectFmt("movn wzr, #0xffff, lsl #16", "{f}", .{(try as.nextInstruction()).?});
1633 try std.testing.expectFmt("mov xzr, #-0x10000", "{f}", .{(try as.nextInstruction()).?});
1634 try std.testing.expectFmt("mov xzr, #-0xffff0001", "{f}", .{(try as.nextInstruction()).?});
1635 try std.testing.expectFmt("mov xzr, #-0xffff00000001", "{f}", .{(try as.nextInstruction()).?});
1636 try std.testing.expectFmt("mov xzr, #0xffffffffffff", "{f}", .{(try as.nextInstruction()).?});
1637
1638 try std.testing.expectFmt("mov w0, #0x10", "{f}", .{(try as.nextInstruction()).?});
1639 try std.testing.expectFmt("mov w1, #0x11", "{f}", .{(try as.nextInstruction()).?});
1640 try std.testing.expectFmt("mov w2, #0x120000", "{f}", .{(try as.nextInstruction()).?});
1641 try std.testing.expectFmt("mov x3, #0x13", "{f}", .{(try as.nextInstruction()).?});
1642 try std.testing.expectFmt("mov x4, #0x14", "{f}", .{(try as.nextInstruction()).?});
1643 try std.testing.expectFmt("mov x5, #0x150000", "{f}", .{(try as.nextInstruction()).?});
1644 try std.testing.expectFmt("mov x6, #0x1600000000", "{f}", .{(try as.nextInstruction()).?});
1645 try std.testing.expectFmt("mov x7, #0x17000000000000", "{f}", .{(try as.nextInstruction()).?});
1646
1647 try std.testing.expectFmt("mov wzr, #0x0", "{f}", .{(try as.nextInstruction()).?});
1648 try std.testing.expectFmt("movz wzr, #0x0, lsl #16", "{f}", .{(try as.nextInstruction()).?});
1649 try std.testing.expectFmt("mov xzr, #0x0", "{f}", .{(try as.nextInstruction()).?});
1650 try std.testing.expectFmt("movz xzr, #0x0, lsl #16", "{f}", .{(try as.nextInstruction()).?});
1651 try std.testing.expectFmt("movz xzr, #0x0, lsl #32", "{f}", .{(try as.nextInstruction()).?});
1652 try std.testing.expectFmt("movz xzr, #0x0, lsl #48", "{f}", .{(try as.nextInstruction()).?});
1653
1654 try std.testing.expectFmt("mov wzr, #0xffff", "{f}", .{(try as.nextInstruction()).?});
1655 try std.testing.expectFmt("mov wzr, #-0x10000", "{f}", .{(try as.nextInstruction()).?});
1656 try std.testing.expectFmt("mov xzr, #0xffff", "{f}", .{(try as.nextInstruction()).?});
1657 try std.testing.expectFmt("mov xzr, #0xffff0000", "{f}", .{(try as.nextInstruction()).?});
1658 try std.testing.expectFmt("mov xzr, #0xffff00000000", "{f}", .{(try as.nextInstruction()).?});
1659 try std.testing.expectFmt("mov xzr, #-0x1000000000000", "{f}", .{(try as.nextInstruction()).?});
1660
1661 try std.testing.expect(null == try as.nextInstruction());
1662}
1663test "reserved" {
1664 var as: Assemble = .{
1665 .source = "\n\nudf #0x0\n\t\n\tudf\t#01234\n \nudf#65535",
1666 .operands = .empty,
1667 };
1668
1669 try std.testing.expectFmt("udf #0x0", "{f}", .{(try as.nextInstruction()).?});
1670 try std.testing.expectFmt("udf #0x4d2", "{f}", .{(try as.nextInstruction()).?});
1671 try std.testing.expectFmt("udf #0xffff", "{f}", .{(try as.nextInstruction()).?});
1672
1673 try std.testing.expect(null == try as.nextInstruction());
1674}
1675
1676const aarch64 = @import("../aarch64.zig");
1677const Assemble = @This();
1678const assert = std.debug.assert;
1679const Instruction = aarch64.encoding.Instruction;
1680const instructions = @import("instructions.zon");
1681const std = @import("std");
1682const log = std.log.scoped(.@"asm");
src/codegen/aarch64/Disassemble.zig created+905
...@@ -0,0 +1,905 @@
1case: Case = .lower,
2mnemonic_operands_separator: []const u8 = " ",
3operands_separator: []const u8 = ", ",
4enable_aliases: bool = true,
5
6pub const Case = enum { lower, upper };
7
8pub fn printInstruction(dis: Disassemble, inst: Instruction, writer: *std.Io.Writer) std.Io.Writer.Error!void {
9 unallocated: switch (inst.decode()) {
10 .unallocated => break :unallocated,
11 .reserved => |reserved| switch (reserved.decode()) {
12 .unallocated => break :unallocated,
13 .udf => |udf| return writer.print("{f}{s}#0x{x}", .{
14 fmtCase(.udf, dis.case),
15 dis.mnemonic_operands_separator,
16 udf.imm16,
17 }),
18 },
19 .sme => {},
20 .sve => {},
21 .data_processing_immediate => |data_processing_immediate| switch (data_processing_immediate.decode()) {
22 .unallocated => break :unallocated,
23 .pc_relative_addressing => |pc_relative_addressing| {
24 const group = pc_relative_addressing.group;
25 const imm = (@as(i33, group.immhi) << 2 | @as(i33, group.immlo) << 0) + @as(i33, switch (group.op) {
26 .adr => Instruction.size,
27 .adrp => 0,
28 });
29 return writer.print("{f}{s}{f}{s}.{c}0x{x}", .{
30 fmtCase(group.op, dis.case),
31 dis.mnemonic_operands_separator,
32 group.Rd.decodeInteger(.doubleword, .{}).fmtCase(dis.case),
33 dis.operands_separator,
34 @as(u8, if (imm < 0) '-' else '+'),
35 switch (group.op) {
36 .adr => @abs(imm),
37 .adrp => @abs(imm) << 12,
38 },
39 });
40 },
41 .add_subtract_immediate => |add_subtract_immediate| {
42 const group = add_subtract_immediate.group;
43 const op = group.op;
44 const S = group.S;
45 const sf = group.sf;
46 const sh = group.sh;
47 const imm12 = group.imm12;
48 const Rn = group.Rn.decodeInteger(sf, .{ .sp = true });
49 const Rd = group.Rd.decodeInteger(sf, .{ .sp = !S });
50 const elide_shift = sh == .@"0";
51 if (dis.enable_aliases and op == .add and S == false and elide_shift and imm12 == 0 and
52 (Rn.alias == .sp or Rd.alias == .sp)) try writer.print("{f}{s}{f}{s}{f}", .{
53 fmtCase(.mov, dis.case),
54 dis.mnemonic_operands_separator,
55 Rd.fmtCase(dis.case),
56 dis.operands_separator,
57 Rn.fmtCase(dis.case),
58 }) else try writer.print("{f}{s}{s}{f}{s}{f}{s}#0x{x}", .{
59 fmtCase(op, dis.case),
60 if (S) "s" else "",
61 dis.mnemonic_operands_separator,
62 Rd.fmtCase(dis.case),
63 dis.operands_separator,
64 Rn.fmtCase(dis.case),
65 dis.operands_separator,
66 imm12,
67 });
68 return if (!elide_shift) writer.print("{s}{f} #{s}", .{
69 dis.operands_separator,
70 fmtCase(.lsl, dis.case),
71 @tagName(sh),
72 });
73 },
74 .add_subtract_immediate_with_tags => {},
75 .logical_immediate => |logical_immediate| {
76 const decoded = logical_immediate.decode();
77 if (decoded == .unallocated) break :unallocated;
78 const group = logical_immediate.group;
79 const sf = group.sf;
80 const decoded_imm = group.imm.decodeImmediate(sf);
81 const imm = switch (sf) {
82 .word => @as(i32, @bitCast(@as(u32, @intCast(decoded_imm)))),
83 .doubleword => @as(i64, @bitCast(decoded_imm)),
84 };
85 const Rn = group.Rn.decodeInteger(sf, .{});
86 const Rd = group.Rd.decodeInteger(sf, .{ .sp = decoded != .ands });
87 return if (dis.enable_aliases and decoded == .orr and Rn.alias == .zr and !group.imm.moveWidePreferred(sf)) writer.print("{f}{s}{f}{s}#{s}0x{x}", .{
88 fmtCase(.mov, dis.case),
89 dis.mnemonic_operands_separator,
90 Rd.fmtCase(dis.case),
91 dis.operands_separator,
92 if (imm < 0) "-" else "",
93 @abs(imm),
94 }) else if (dis.enable_aliases and decoded == .ands and Rd.alias == .zr) writer.print("{f}{s}{f}{s}#{s}0x{x}", .{
95 fmtCase(.tst, dis.case),
96 dis.mnemonic_operands_separator,
97 Rn.fmtCase(dis.case),
98 dis.operands_separator,
99 if (imm < 0) "-" else "",
100 @abs(imm),
101 }) else writer.print("{f}{s}{f}{s}{f}{s}#0x{x}", .{
102 fmtCase(decoded, dis.case),
103 dis.mnemonic_operands_separator,
104 Rd.fmtCase(dis.case),
105 dis.operands_separator,
106 Rn.fmtCase(dis.case),
107 dis.operands_separator,
108 decoded_imm,
109 });
110 },
111 .move_wide_immediate => |move_wide_immediate| {
112 const decoded = move_wide_immediate.decode();
113 if (decoded == .unallocated) break :unallocated;
114 const group = move_wide_immediate.group;
115 const sf = group.sf;
116 const hw = group.hw;
117 const imm16 = group.imm16;
118 const Rd = group.Rd.decodeInteger(sf, .{});
119 const elide_shift = hw == .@"0";
120 if (dis.enable_aliases and switch (decoded) {
121 .unallocated => unreachable,
122 .movz => elide_shift or group.imm16 != 0,
123 .movn => (elide_shift or group.imm16 != 0) and switch (sf) {
124 .word => group.imm16 != std.math.maxInt(u16),
125 .doubleword => true,
126 },
127 .movk => false,
128 }) {
129 const decoded_imm = switch (sf) {
130 .word => @as(i32, @bitCast(@as(u32, group.imm16) << @intCast(hw.int()))),
131 .doubleword => @as(i64, @bitCast(@as(u64, group.imm16) << hw.int())),
132 };
133 const imm = switch (decoded) {
134 .unallocated => unreachable,
135 .movz => decoded_imm,
136 .movn => ~decoded_imm,
137 .movk => unreachable,
138 };
139 return writer.print("{f}{s}{f}{s}#{s}0x{x}", .{
140 fmtCase(.mov, dis.case),
141 dis.mnemonic_operands_separator,
142 Rd.fmtCase(dis.case),
143 dis.operands_separator,
144 if (imm < 0) "-" else "",
145 @abs(imm),
146 });
147 }
148 try writer.print("{f}{s}{f}{s}#0x{x}", .{
149 fmtCase(decoded, dis.case),
150 dis.mnemonic_operands_separator,
151 Rd.fmtCase(dis.case),
152 dis.operands_separator,
153 imm16,
154 });
155 return if (!elide_shift) writer.print("{s}{f} #{s}", .{
156 dis.operands_separator,
157 fmtCase(.lsl, dis.case),
158 @tagName(hw),
159 });
160 },
161 .bitfield => |bitfield| {
162 const decoded = bitfield.decode();
163 if (decoded == .unallocated) break :unallocated;
164 const group = bitfield.group;
165 const sf = group.sf;
166 return writer.print("{f}{s}{f}{s}{f}{s}#{d}{s}#{d}", .{
167 fmtCase(decoded, dis.case),
168 dis.mnemonic_operands_separator,
169 group.Rd.decodeInteger(sf, .{}).fmtCase(dis.case),
170 dis.operands_separator,
171 group.Rn.decodeInteger(sf, .{}).fmtCase(dis.case),
172 dis.operands_separator,
173 group.imm.immr,
174 dis.operands_separator,
175 group.imm.imms,
176 });
177 },
178 .extract => |extract| {
179 const decoded = extract.decode();
180 if (decoded == .unallocated) break :unallocated;
181 const group = extract.group;
182 const sf = group.sf;
183 return writer.print("{f}{s}{f}{s}{f}{s}{f}{s}#{d}", .{
184 fmtCase(decoded, dis.case),
185 dis.mnemonic_operands_separator,
186 group.Rd.decodeInteger(sf, .{}).fmtCase(dis.case),
187 dis.operands_separator,
188 group.Rn.decodeInteger(sf, .{}).fmtCase(dis.case),
189 dis.operands_separator,
190 group.Rm.decodeInteger(sf, .{}).fmtCase(dis.case),
191 dis.operands_separator,
192 group.imms,
193 });
194 },
195 },
196 .branch_exception_generating_system => |branch_exception_generating_system| switch (branch_exception_generating_system.decode()) {
197 .unallocated => break :unallocated,
198 .conditional_branch_immediate => |conditional_branch_immediate| {
199 const decoded = conditional_branch_immediate.decode();
200 if (decoded == .unallocated) break :unallocated;
201 const group = conditional_branch_immediate.group;
202 const imm = @as(i21, group.imm19);
203 return writer.print("{f}.{f}{s}.{c}0x{x}", .{
204 fmtCase(decoded, dis.case),
205 fmtCase(group.cond, dis.case),
206 dis.mnemonic_operands_separator,
207 @as(u8, if (imm < 0) '-' else '+'),
208 @abs(imm) << 2,
209 });
210 },
211 .exception_generating => |exception_generating| {
212 const decoded = exception_generating.decode();
213 switch (decoded) {
214 .unallocated => break :unallocated,
215 .svc, .hvc, .smc, .brk, .hlt, .tcancel => {},
216 .dcps1, .dcps2, .dcps3 => switch (exception_generating.group.imm16) {
217 0 => return writer.print("{f}", .{fmtCase(decoded, dis.case)}),
218 else => {},
219 },
220 }
221 return switch (exception_generating.group.imm16) {
222 0 => writer.print("{f}{s}#0", .{
223 fmtCase(decoded, dis.case),
224 dis.mnemonic_operands_separator,
225 }),
226 else => writer.print("{f}{s}#0x{x}", .{
227 fmtCase(decoded, dis.case),
228 dis.mnemonic_operands_separator,
229 exception_generating.group.imm16,
230 }),
231 };
232 },
233 .system_register_argument => {},
234 .hints => |hints| switch (hints.decode()) {
235 .hint => |hint| return writer.print("{f}{s}#0x{x}", .{
236 fmtCase(.hint, dis.case),
237 dis.mnemonic_operands_separator,
238 @as(u7, hint.CRm) << 3 | @as(u7, hint.op2) << 0,
239 }),
240 else => |decoded| return writer.print("{f}", .{fmtCase(decoded, dis.case)}),
241 },
242 .barriers => {},
243 .pstate => {},
244 .system_result => {},
245 .system => {},
246 .system_register_move => {},
247 .unconditional_branch_register => |unconditional_branch_register| {
248 const decoded = unconditional_branch_register.decode();
249 if (decoded == .unallocated) break :unallocated;
250 const group = unconditional_branch_register.group;
251 const Rn = group.Rn.decodeInteger(.doubleword, .{});
252 try writer.print("{f}", .{fmtCase(decoded, dis.case)});
253 return if (decoded != .ret or Rn.alias != .r30) try writer.print("{s}{f}", .{
254 dis.mnemonic_operands_separator,
255 Rn.fmtCase(dis.case),
256 });
257 },
258 .unconditional_branch_immediate => |unconditional_branch_immediate| {
259 const group = unconditional_branch_immediate.group;
260 const imm = @as(i28, group.imm26);
261 return writer.print("{f}{s}.{c}0x{x}", .{
262 fmtCase(group.op, dis.case),
263 dis.mnemonic_operands_separator,
264 @as(u8, if (imm < 0) '-' else '+'),
265 @abs(imm) << 2,
266 });
267 },
268 .compare_branch_immediate => |compare_branch_immediate| {
269 const group = compare_branch_immediate.group;
270 const imm = @as(i21, group.imm19);
271 return writer.print("{f}{s}{f}{s}.{c}0x{x}", .{
272 fmtCase(group.op, dis.case),
273 dis.mnemonic_operands_separator,
274 group.Rt.decodeInteger(group.sf, .{}).fmtCase(dis.case),
275 dis.operands_separator,
276 @as(u8, if (imm < 0) '-' else '+'),
277 @abs(imm) << 2,
278 });
279 },
280 .test_branch_immediate => |test_branch_immediate| {
281 const group = test_branch_immediate.group;
282 const imm = @as(i16, group.imm14);
283 return writer.print("{f}{s}{f}{s}#0x{d}{s}.{c}0x{x}", .{
284 fmtCase(group.op, dis.case),
285 dis.mnemonic_operands_separator,
286 group.Rt.decodeInteger(@enumFromInt(group.b5), .{}).fmtCase(dis.case),
287 dis.operands_separator,
288 @as(u6, group.b5) << 5 |
289 @as(u6, group.b40) << 0,
290 dis.operands_separator,
291 @as(u8, if (imm < 0) '-' else '+'),
292 @abs(imm) << 2,
293 });
294 },
295 },
296 .load_store => |load_store| switch (load_store.decode()) {
297 .unallocated => break :unallocated,
298 .register_literal => {},
299 .memory => {},
300 .no_allocate_pair_offset => {},
301 .register_pair_post_indexed => |register_pair_post_indexed| switch (register_pair_post_indexed.decode()) {
302 .integer => |integer| {
303 const decoded = integer.decode();
304 if (decoded == .unallocated) break :unallocated;
305 const group = integer.group;
306 const sf: aarch64.encoding.Register.IntegerSize = @enumFromInt(group.opc >> 1);
307 return writer.print("{f}{s}{f}{s}{f}{s}[{f}]{s}#{s}0x{x}", .{
308 fmtCase(decoded, dis.case),
309 dis.mnemonic_operands_separator,
310 group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case),
311 dis.operands_separator,
312 group.Rt2.decodeInteger(sf, .{}).fmtCase(dis.case),
313 dis.operands_separator,
314 group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case),
315 dis.operands_separator,
316 if (group.imm7 < 0) "-" else "",
317 @as(u10, @abs(group.imm7)) << (@as(u2, 2) + @intFromEnum(sf)),
318 });
319 },
320 .vector => |vector| {
321 const decoded = vector.decode();
322 if (decoded == .unallocated) break :unallocated;
323 const group = vector.group;
324 const vs = group.opc.decode();
325 return writer.print("{f}{s}{f}{s}{f}{s}[{f}]{s}#{s}0x{x}", .{
326 fmtCase(decoded, dis.case),
327 dis.mnemonic_operands_separator,
328 group.Rt.decodeVector(vs).fmtCase(dis.case),
329 dis.operands_separator,
330 group.Rt2.decodeVector(vs).fmtCase(dis.case),
331 dis.operands_separator,
332 group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case),
333 dis.operands_separator,
334 if (group.imm7 < 0) "-" else "",
335 @as(u11, @abs(group.imm7)) << (@as(u3, 2) + @intFromEnum(vs)),
336 });
337 },
338 },
339 .register_pair_offset => |register_pair_offset| switch (register_pair_offset.decode()) {
340 .integer => |integer| {
341 const decoded = integer.decode();
342 if (decoded == .unallocated) break :unallocated;
343 const group = integer.group;
344 const sf: aarch64.encoding.Register.IntegerSize = @enumFromInt(group.opc >> 1);
345 try writer.print("{f}{s}{f}{s}{f}{s}[{f}", .{
346 fmtCase(decoded, dis.case),
347 dis.mnemonic_operands_separator,
348 group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case),
349 dis.operands_separator,
350 group.Rt2.decodeInteger(sf, .{}).fmtCase(dis.case),
351 dis.operands_separator,
352 group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case),
353 });
354 if (group.imm7 != 0) try writer.print("{s}#{s}0x{x}", .{
355 dis.operands_separator,
356 if (group.imm7 < 0) "-" else "",
357 @as(u10, @abs(group.imm7)) << (@as(u2, 2) + @intFromEnum(sf)),
358 });
359 return writer.writeByte(']');
360 },
361 .vector => |vector| {
362 const decoded = vector.decode();
363 if (decoded == .unallocated) break :unallocated;
364 const group = vector.group;
365 const vs = group.opc.decode();
366 try writer.print("{f}{s}{f}{s}{f}{s}[{f}", .{
367 fmtCase(decoded, dis.case),
368 dis.mnemonic_operands_separator,
369 group.Rt.decodeVector(vs).fmtCase(dis.case),
370 dis.operands_separator,
371 group.Rt2.decodeVector(vs).fmtCase(dis.case),
372 dis.operands_separator,
373 group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case),
374 });
375 if (group.imm7 != 0) try writer.print("{s}#{s}0x{x}", .{
376 dis.operands_separator,
377 if (group.imm7 < 0) "-" else "",
378 @as(u11, @abs(group.imm7)) << (@as(u3, 2) + @intFromEnum(vs)),
379 });
380 return writer.writeByte(']');
381 },
382 },
383 .register_pair_pre_indexed => |register_pair_pre_indexed| switch (register_pair_pre_indexed.decode()) {
384 .integer => |integer| {
385 const decoded = integer.decode();
386 if (decoded == .unallocated) break :unallocated;
387 const group = integer.group;
388 const sf: aarch64.encoding.Register.IntegerSize = @enumFromInt(group.opc >> 1);
389 return writer.print("{f}{s}{f}{s}{f}{s}[{f}{s}#{s}0x{x}]!", .{
390 fmtCase(decoded, dis.case),
391 dis.mnemonic_operands_separator,
392 group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case),
393 dis.operands_separator,
394 group.Rt2.decodeInteger(sf, .{}).fmtCase(dis.case),
395 dis.operands_separator,
396 group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case),
397 dis.operands_separator,
398 if (group.imm7 < 0) "-" else "",
399 @as(u10, @abs(group.imm7)) << (@as(u2, 2) + @intFromEnum(sf)),
400 });
401 },
402 .vector => |vector| {
403 const decoded = vector.decode();
404 if (decoded == .unallocated) break :unallocated;
405 const group = vector.group;
406 const vs = group.opc.decode();
407 return writer.print("{f}{s}{f}{s}{f}{s}[{f}{s}#{s}0x{x}]!", .{
408 fmtCase(decoded, dis.case),
409 dis.mnemonic_operands_separator,
410 group.Rt.decodeVector(vs).fmtCase(dis.case),
411 dis.operands_separator,
412 group.Rt2.decodeVector(vs).fmtCase(dis.case),
413 dis.operands_separator,
414 group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case),
415 dis.operands_separator,
416 if (group.imm7 < 0) "-" else "",
417 @as(u11, @abs(group.imm7)) << (@as(u3, 2) + @intFromEnum(vs)),
418 });
419 },
420 },
421 .register_unscaled_immediate => {},
422 .register_immediate_post_indexed => |register_immediate_post_indexed| switch (register_immediate_post_indexed.decode()) {
423 .integer => |integer| {
424 const decoded = integer.decode();
425 const sf: aarch64.encoding.Register.IntegerSize = switch (decoded) {
426 .unallocated => break :unallocated,
427 .strb, .ldrb, .strh, .ldrh => .word,
428 inline .ldrsb, .ldrsh => |encoded| switch (encoded.opc0) {
429 0b0 => .doubleword,
430 0b1 => .word,
431 },
432 .ldrsw => .doubleword,
433 inline .str, .ldr => |encoded| encoded.sf,
434 };
435 const group = integer.group;
436 return writer.print("{f}{s}{f}{s}[{f}]{s}#{s}0x{x}", .{
437 fmtCase(decoded, dis.case),
438 dis.mnemonic_operands_separator,
439 group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case),
440 dis.operands_separator,
441 group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case),
442 dis.operands_separator,
443 if (group.imm9 < 0) "-" else "",
444 @abs(group.imm9),
445 });
446 },
447 .vector => {},
448 },
449 .register_unprivileged => {},
450 .register_immediate_pre_indexed => |register_immediate_pre_indexed| switch (register_immediate_pre_indexed.decode()) {
451 .integer => |integer| {
452 const decoded = integer.decode();
453 const sf: aarch64.encoding.Register.IntegerSize = switch (decoded) {
454 .unallocated => break :unallocated,
455 inline .ldrsb, .ldrsh => |encoded| switch (encoded.opc0) {
456 0b0 => .doubleword,
457 0b1 => .word,
458 },
459 .strb, .ldrb, .strh, .ldrh => .word,
460 .ldrsw => .doubleword,
461 inline .str, .ldr => |encoded| encoded.sf,
462 };
463 const group = integer.group;
464 return writer.print("{f}{s}{f}{s}[{f}{s}#{s}0x{x}]!", .{
465 fmtCase(decoded, dis.case),
466 dis.mnemonic_operands_separator,
467 group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case),
468 dis.operands_separator,
469 group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case),
470 dis.operands_separator,
471 if (group.imm9 < 0) "-" else "",
472 @abs(group.imm9),
473 });
474 },
475 .vector => |vector| {
476 const decoded = vector.decode();
477 if (decoded == .unallocated) break :unallocated;
478 const group = vector.group;
479 return writer.print("{f}{s}{f}{s}[{f}{s}#{s}0x{x}]!", .{
480 fmtCase(decoded, dis.case),
481 dis.mnemonic_operands_separator,
482 group.Rt.decodeVector(group.opc1.decode(group.size)).fmtCase(dis.case),
483 dis.operands_separator,
484 group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case),
485 dis.operands_separator,
486 if (group.imm9 < 0) "-" else "",
487 @abs(group.imm9),
488 });
489 },
490 },
491 .register_register_offset => |register_register_offset| switch (register_register_offset.decode()) {
492 .integer => |integer| {
493 const decoded = integer.decode();
494 const sf: aarch64.encoding.Register.IntegerSize = switch (decoded) {
495 .unallocated, .prfm => break :unallocated,
496 .strb, .ldrb, .strh, .ldrh => .word,
497 inline .ldrsb, .ldrsh => |encoded| switch (encoded.opc0) {
498 0b0 => .doubleword,
499 0b1 => .word,
500 },
501 .ldrsw => .doubleword,
502 inline .str, .ldr => |encoded| encoded.sf,
503 };
504 const group = integer.group;
505 try writer.print("{f}{s}{f}{s}[{f}{s}{f}", .{
506 fmtCase(decoded, dis.case),
507 dis.mnemonic_operands_separator,
508 group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case),
509 dis.operands_separator,
510 group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case),
511 dis.operands_separator,
512 group.Rm.decodeInteger(group.option.sf(), .{}).fmtCase(dis.case),
513 });
514 if (group.option != .lsl or group.S) {
515 try writer.print("{s}{f}", .{
516 dis.operands_separator,
517 fmtCase(group.option, dis.case),
518 });
519 if (group.S) try writer.print(" #{d}", .{
520 @intFromEnum(group.size),
521 });
522 }
523 return writer.writeByte(']');
524 },
525 .vector => {},
526 },
527 .register_unsigned_immediate => |register_unsigned_immediate| switch (register_unsigned_immediate.decode()) {
528 .integer => |integer| {
529 const decoded = integer.decode();
530 const sf: aarch64.encoding.Register.IntegerSize = switch (decoded) {
531 .unallocated, .prfm => break :unallocated,
532 .strb, .ldrb, .strh, .ldrh => .word,
533 inline .ldrsb, .ldrsh => |encoded| switch (encoded.opc0) {
534 0b0 => .doubleword,
535 0b1 => .word,
536 },
537 .ldrsw => .doubleword,
538 inline .str, .ldr => |encoded| encoded.sf,
539 };
540 const group = integer.group;
541 try writer.print("{f}{s}{f}{s}[{f}", .{
542 fmtCase(decoded, dis.case),
543 dis.mnemonic_operands_separator,
544 group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case),
545 dis.operands_separator,
546 group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case),
547 });
548 if (group.imm12 > 0) try writer.print("{s}#0x{x}", .{
549 dis.operands_separator,
550 @as(u15, group.imm12) << @intFromEnum(group.size),
551 });
552 return writer.writeByte(']');
553 },
554 .vector => {},
555 },
556 },
557 .data_processing_register => |data_processing_register| switch (data_processing_register.decode()) {
558 .unallocated => break :unallocated,
559 .data_processing_two_source => |data_processing_two_source| {
560 const decoded = data_processing_two_source.decode();
561 if (decoded == .unallocated) break :unallocated;
562 const group = data_processing_two_source.group;
563 const sf = group.sf;
564 return writer.print("{f}{s}{f}{s}{f}{s}{f}", .{
565 fmtCase(decoded, dis.case),
566 dis.mnemonic_operands_separator,
567 group.Rd.decodeInteger(sf, .{}).fmtCase(dis.case),
568 dis.operands_separator,
569 group.Rn.decodeInteger(sf, .{}).fmtCase(dis.case),
570 dis.operands_separator,
571 group.Rm.decodeInteger(sf, .{}).fmtCase(dis.case),
572 });
573 },
574 .data_processing_one_source => |data_processing_one_source| {
575 const decoded = data_processing_one_source.decode();
576 if (decoded == .unallocated) break :unallocated;
577 const group = data_processing_one_source.group;
578 const sf = group.sf;
579 return writer.print("{f}{s}{f}{s}{f}", .{
580 fmtCase(decoded, dis.case),
581 dis.mnemonic_operands_separator,
582 group.Rd.decodeInteger(sf, .{}).fmtCase(dis.case),
583 dis.operands_separator,
584 group.Rn.decodeInteger(sf, .{}).fmtCase(dis.case),
585 });
586 },
587 .logical_shifted_register => |logical_shifted_register| {
588 const decoded = logical_shifted_register.decode();
589 if (decoded == .unallocated) break :unallocated;
590 const group = logical_shifted_register.group;
591 const sf = group.sf;
592 const shift = group.shift;
593 const Rm = group.Rm.decodeInteger(sf, .{});
594 const amount = group.imm6;
595 const Rn = group.Rn.decodeInteger(sf, .{});
596 const Rd = group.Rd.decodeInteger(sf, .{});
597 const elide_shift = shift == .lsl and amount == 0;
598 if (dis.enable_aliases and switch (decoded) {
599 else => false,
600 .orr => elide_shift,
601 .orn => true,
602 } and Rn.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{
603 fmtCase(@as(enum { mov, mvn }, switch (decoded) {
604 else => unreachable,
605 .orr => .mov,
606 .orn => .mvn,
607 }), dis.case),
608 dis.mnemonic_operands_separator,
609 Rd.fmtCase(dis.case),
610 dis.operands_separator,
611 Rm.fmtCase(dis.case),
612 }) else if (dis.enable_aliases and decoded == .ands and Rd.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{
613 fmtCase(.tst, dis.case),
614 dis.mnemonic_operands_separator,
615 Rn.fmtCase(dis.case),
616 dis.operands_separator,
617 Rm.fmtCase(dis.case),
618 }) else try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{
619 fmtCase(decoded, dis.case),
620 dis.mnemonic_operands_separator,
621 Rd.fmtCase(dis.case),
622 dis.operands_separator,
623 Rn.fmtCase(dis.case),
624 dis.operands_separator,
625 Rm.fmtCase(dis.case),
626 });
627 return if (!elide_shift) writer.print("{s}{f} #{d}", .{
628 dis.operands_separator,
629 fmtCase(shift, dis.case),
630 amount,
631 });
632 },
633 .add_subtract_shifted_register => |add_subtract_shifted_register| {
634 const decoded = add_subtract_shifted_register.decode();
635 if (decoded == .unallocated) break :unallocated;
636 const group = add_subtract_shifted_register.group;
637 const sf = group.sf;
638 const shift = group.shift;
639 const Rm = group.Rm.decodeInteger(sf, .{});
640 const imm6 = group.imm6;
641 const Rn = group.Rn.decodeInteger(sf, .{});
642 const Rd = group.Rd.decodeInteger(sf, .{});
643 if (dis.enable_aliases and group.S and Rd.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{
644 fmtCase(@as(enum { cmn, cmp }, switch (group.op) {
645 .add => .cmn,
646 .sub => .cmp,
647 }), dis.case),
648 dis.mnemonic_operands_separator,
649 Rn.fmtCase(dis.case),
650 dis.operands_separator,
651 Rm.fmtCase(dis.case),
652 }) else if (dis.enable_aliases and group.op == .sub and Rn.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{
653 fmtCase(@as(enum { neg, negs }, switch (group.S) {
654 false => .neg,
655 true => .negs,
656 }), dis.case),
657 dis.mnemonic_operands_separator,
658 Rd.fmtCase(dis.case),
659 dis.operands_separator,
660 Rm.fmtCase(dis.case),
661 }) else try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{
662 fmtCase(decoded, dis.case),
663 dis.mnemonic_operands_separator,
664 Rd.fmtCase(dis.case),
665 dis.operands_separator,
666 Rn.fmtCase(dis.case),
667 dis.operands_separator,
668 Rm.fmtCase(dis.case),
669 });
670 return if (shift != .lsl or imm6 != 0) return writer.print("{s}{f} #{d}", .{
671 dis.operands_separator,
672 fmtCase(shift, dis.case),
673 imm6,
674 });
675 },
676 .add_subtract_extended_register => |add_subtract_extended_register| {
677 const decoded = add_subtract_extended_register.decode();
678 if (decoded == .unallocated) break :unallocated;
679 const group = add_subtract_extended_register.group;
680 const sf = group.sf;
681 const Rm = group.Rm.decodeInteger(group.option.sf(), .{});
682 const Rn = group.Rn.decodeInteger(sf, .{ .sp = true });
683 const Rd = group.Rd.decodeInteger(sf, .{ .sp = true });
684 if (dis.enable_aliases and group.S and Rd.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{
685 fmtCase(@as(enum { cmn, cmp }, switch (group.op) {
686 .add => .cmn,
687 .sub => .cmp,
688 }), dis.case),
689 dis.mnemonic_operands_separator,
690 Rn.fmtCase(dis.case),
691 dis.operands_separator,
692 Rm.fmtCase(dis.case),
693 }) else try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{
694 fmtCase(decoded, dis.case),
695 dis.mnemonic_operands_separator,
696 Rd.fmtCase(dis.case),
697 dis.operands_separator,
698 Rn.fmtCase(dis.case),
699 dis.operands_separator,
700 Rm.fmtCase(dis.case),
701 });
702 return if (group.option != @as(Instruction.DataProcessingRegister.AddSubtractExtendedRegister.Option, switch (sf) {
703 .word => .uxtw,
704 .doubleword => .uxtx,
705 }) or group.imm3 != 0) writer.print("{s}{f} #{d}", .{
706 dis.operands_separator,
707 fmtCase(group.option, dis.case),
708 group.imm3,
709 });
710 },
711 .add_subtract_with_carry => |add_subtract_with_carry| {
712 const decoded = add_subtract_with_carry.decode();
713 const group = add_subtract_with_carry.group;
714 const sf = group.sf;
715 const Rm = group.Rm.decodeInteger(sf, .{});
716 const Rn = group.Rn.decodeInteger(sf, .{});
717 const Rd = group.Rd.decodeInteger(sf, .{});
718 return if (dis.enable_aliases and group.op == .sbc and Rn.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{
719 fmtCase(@as(enum { ngc, ngcs }, switch (group.S) {
720 false => .ngc,
721 true => .ngcs,
722 }), dis.case),
723 dis.mnemonic_operands_separator,
724 Rd.fmtCase(dis.case),
725 dis.operands_separator,
726 Rm.fmtCase(dis.case),
727 }) else try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{
728 fmtCase(decoded, dis.case),
729 dis.mnemonic_operands_separator,
730 Rd.fmtCase(dis.case),
731 dis.operands_separator,
732 Rn.fmtCase(dis.case),
733 dis.operands_separator,
734 Rm.fmtCase(dis.case),
735 });
736 },
737 .rotate_right_into_flags => {},
738 .evaluate_into_flags => {},
739 .conditional_compare_register => {},
740 .conditional_compare_immediate => {},
741 .conditional_select => |conditional_select| {
742 const decoded = conditional_select.decode();
743 if (decoded == .unallocated) break :unallocated;
744 const group = conditional_select.group;
745 const sf = group.sf;
746 const Rm = group.Rm.decodeInteger(sf, .{});
747 const cond = group.cond;
748 const Rn = group.Rn.decodeInteger(sf, .{});
749 const Rd = group.Rd.decodeInteger(sf, .{});
750 return if (dis.enable_aliases and group.op != group.op2 and Rm.alias == .zr and cond != .al and cond != .nv and Rn.alias == Rm.alias) writer.print("{f}{s}{f}{s}{f}", .{
751 fmtCase(@as(enum { cset, csetm }, switch (decoded) {
752 else => unreachable,
753 .csinc => .cset,
754 .csinv => .csetm,
755 }), dis.case),
756 dis.mnemonic_operands_separator,
757 Rd.fmtCase(dis.case),
758 dis.operands_separator,
759 fmtCase(cond.invert(), dis.case),
760 }) else if (dis.enable_aliases and decoded != .csel and cond != .al and cond != .nv and Rn.alias == Rm.alias) writer.print("{f}{s}{f}{s}{f}{s}{f}", .{
761 fmtCase(@as(enum { cinc, cinv, cneg }, switch (decoded) {
762 else => unreachable,
763 .csinc => .cinc,
764 .csinv => .cinv,
765 .csneg => .cneg,
766 }), dis.case),
767 dis.mnemonic_operands_separator,
768 Rd.fmtCase(dis.case),
769 dis.operands_separator,
770 Rn.fmtCase(dis.case),
771 dis.operands_separator,
772 fmtCase(cond.invert(), dis.case),
773 }) else writer.print("{f}{s}{f}{s}{f}{s}{f}{s}{f}", .{
774 fmtCase(decoded, dis.case),
775 dis.mnemonic_operands_separator,
776 Rd.fmtCase(dis.case),
777 dis.operands_separator,
778 Rn.fmtCase(dis.case),
779 dis.operands_separator,
780 Rm.fmtCase(dis.case),
781 dis.operands_separator,
782 fmtCase(cond, dis.case),
783 });
784 },
785 .data_processing_three_source => |data_processing_three_source| {
786 const decoded = data_processing_three_source.decode();
787 if (decoded == .unallocated) break :unallocated;
788 const group = data_processing_three_source.group;
789 const sf = group.sf;
790 try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{
791 fmtCase(decoded, dis.case),
792 dis.mnemonic_operands_separator,
793 group.Rd.decodeInteger(sf, .{}).fmtCase(dis.case),
794 dis.operands_separator,
795 group.Rn.decodeInteger(sf, .{}).fmtCase(dis.case),
796 dis.operands_separator,
797 group.Rm.decodeInteger(sf, .{}).fmtCase(dis.case),
798 });
799 return switch (decoded) {
800 .unallocated => unreachable,
801 .madd, .msub, .smaddl, .smsubl, .umaddl, .umsubl => writer.print("{s}{f}", .{
802 dis.operands_separator,
803 group.Ra.decodeInteger(sf, .{}).fmtCase(dis.case),
804 }),
805 .smulh, .umulh => {},
806 };
807 },
808 },
809 .data_processing_vector => {},
810 }
811 return writer.print(".{f}{s}0x{x:0>8}", .{
812 fmtCase(.word, dis.case),
813 dis.mnemonic_operands_separator,
814 @as(Instruction.Backing, @bitCast(inst)),
815 });
816}
817
818fn fmtCase(tag: anytype, case: Case) struct {
819 tag: []const u8,
820 case: Case,
821 pub fn format(data: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void {
822 for (data.tag) |c| try writer.writeByte(switch (data.case) {
823 .lower => std.ascii.toLower(c),
824 .upper => std.ascii.toUpper(c),
825 });
826 }
827} {
828 return .{ .tag = @tagName(tag), .case = case };
829}
830
831pub const RegisterFormatter = struct {
832 reg: aarch64.encoding.Register,
833 case: Case,
834 pub fn format(data: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void {
835 switch (data.reg.format) {
836 .alias => try writer.print("{f}", .{fmtCase(data.reg.alias, data.case)}),
837 .integer => |size| switch (data.reg.alias) {
838 .r0,
839 .r1,
840 .r2,
841 .r3,
842 .r4,
843 .r5,
844 .r6,
845 .r7,
846 .r8,
847 .r9,
848 .r10,
849 .r11,
850 .r12,
851 .r13,
852 .r14,
853 .r15,
854 .r16,
855 .r17,
856 .r18,
857 .r19,
858 .r20,
859 .r21,
860 .r22,
861 .r23,
862 .r24,
863 .r25,
864 .r26,
865 .r27,
866 .r28,
867 .r29,
868 .r30,
869 => |alias| try writer.print("{c}{d}", .{
870 size.prefix(),
871 @intFromEnum(alias.encode(.{})),
872 }),
873 .zr => try writer.print("{c}{f}", .{
874 size.prefix(),
875 fmtCase(data.reg.alias, data.case),
876 }),
877 else => try writer.print("{s}{f}", .{
878 switch (size) {
879 .word => "w",
880 .doubleword => "",
881 },
882 fmtCase(data.reg.alias, data.case),
883 }),
884 },
885 .scalar => |size| try writer.print("{c}{d}", .{
886 size.prefix(),
887 @intFromEnum(data.reg.alias.encode(.{ .V = true })),
888 }),
889 .vector => |arrangement| try writer.print("{f}.{f}", .{
890 fmtCase(data.reg.alias, data.case),
891 fmtCase(arrangement, data.case),
892 }),
893 .element => |element| try writer.print("{f}.{c}[{d}]", .{
894 fmtCase(data.reg.alias, data.case),
895 element.size.prefix(),
896 element.index,
897 }),
898 }
899 }
900};
901
902const aarch64 = @import("../aarch64.zig");
903const Disassemble = @This();
904const Instruction = aarch64.encoding.Instruction;
905const std = @import("std");
src/codegen/aarch64/Mir.zig created+348
...@@ -0,0 +1,348 @@
1prologue: []const Instruction,
2body: []const Instruction,
3epilogue: []const Instruction,
4literals: []const u32,
5nav_relocs: []const Reloc.Nav,
6uav_relocs: []const Reloc.Uav,
7lazy_relocs: []const Reloc.Lazy,
8global_relocs: []const Reloc.Global,
9literal_relocs: []const Reloc.Literal,
10
11pub const Reloc = struct {
12 label: u32,
13 addend: u64 align(@alignOf(u32)) = 0,
14
15 pub const Nav = struct {
16 nav: InternPool.Nav.Index,
17 reloc: Reloc,
18 };
19
20 pub const Uav = struct {
21 uav: InternPool.Key.Ptr.BaseAddr.Uav,
22 reloc: Reloc,
23 };
24
25 pub const Lazy = struct {
26 symbol: link.File.LazySymbol,
27 reloc: Reloc,
28 };
29
30 pub const Global = struct {
31 name: [*:0]const u8,
32 reloc: Reloc,
33 };
34
35 pub const Literal = struct {
36 label: u32,
37 };
38};
39
40pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
41 assert(mir.body.ptr + mir.body.len == mir.prologue.ptr);
42 assert(mir.prologue.ptr + mir.prologue.len == mir.epilogue.ptr);
43 gpa.free(mir.body.ptr[0 .. mir.body.len + mir.prologue.len + mir.epilogue.len]);
44 gpa.free(mir.literals);
45 gpa.free(mir.nav_relocs);
46 gpa.free(mir.uav_relocs);
47 gpa.free(mir.lazy_relocs);
48 gpa.free(mir.global_relocs);
49 gpa.free(mir.literal_relocs);
50 mir.* = undefined;
51}
52
53pub fn emit(
54 mir: Mir,
55 lf: *link.File,
56 pt: Zcu.PerThread,
57 src_loc: Zcu.LazySrcLoc,
58 func_index: InternPool.Index,
59 code: *std.ArrayListUnmanaged(u8),
60 debug_output: link.File.DebugInfoOutput,
61) !void {
62 _ = debug_output;
63 const zcu = pt.zcu;
64 const ip = &zcu.intern_pool;
65 const gpa = zcu.gpa;
66 const func = zcu.funcInfo(func_index);
67 const nav = ip.getNav(func.owner_nav);
68 const mod = zcu.navFileScope(func.owner_nav).mod.?;
69 const target = &mod.resolved_target.result;
70 mir_log.debug("{f}:", .{nav.fqn.fmt(ip)});
71
72 const func_align = switch (nav.status.fully_resolved.alignment) {
73 .none => switch (mod.optimize_mode) {
74 .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target),
75 .ReleaseSmall => target_util.minFunctionAlignment(target),
76 },
77 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
78 };
79 const code_len = mir.prologue.len + mir.body.len + mir.epilogue.len;
80 const literals_align_gap = -%code_len & (@divExact(
81 @as(u5, @intCast(func_align.minStrict(.@"16").toByteUnits().?)),
82 Instruction.size,
83 ) - 1);
84 try code.ensureUnusedCapacity(gpa, Instruction.size *
85 (code_len + literals_align_gap + mir.literals.len));
86 emitInstructionsForward(code, mir.prologue);
87 emitInstructionsBackward(code, mir.body);
88 const body_end: u32 = @intCast(code.items.len);
89 emitInstructionsBackward(code, mir.epilogue);
90 code.appendNTimesAssumeCapacity(0, Instruction.size * literals_align_gap);
91 code.appendSliceAssumeCapacity(@ptrCast(mir.literals));
92 mir_log.debug("", .{});
93
94 for (mir.nav_relocs) |nav_reloc| try emitReloc(
95 lf,
96 zcu,
97 func.owner_nav,
98 switch (try @import("../../codegen.zig").genNavRef(
99 lf,
100 pt,
101 src_loc,
102 nav_reloc.nav,
103 &mod.resolved_target.result,
104 )) {
105 .sym_index => |sym_index| sym_index,
106 .fail => |em| return zcu.codegenFailMsg(func.owner_nav, em),
107 },
108 mir.body[nav_reloc.reloc.label],
109 body_end - Instruction.size * (1 + nav_reloc.reloc.label),
110 nav_reloc.reloc.addend,
111 );
112 for (mir.uav_relocs) |uav_reloc| try emitReloc(
113 lf,
114 zcu,
115 func.owner_nav,
116 switch (try lf.lowerUav(
117 pt,
118 uav_reloc.uav.val,
119 ZigType.fromInterned(uav_reloc.uav.orig_ty).ptrAlignment(zcu),
120 src_loc,
121 )) {
122 .sym_index => |sym_index| sym_index,
123 .fail => |em| return zcu.codegenFailMsg(func.owner_nav, em),
124 },
125 mir.body[uav_reloc.reloc.label],
126 body_end - Instruction.size * (1 + uav_reloc.reloc.label),
127 uav_reloc.reloc.addend,
128 );
129 for (mir.lazy_relocs) |lazy_reloc| try emitReloc(
130 lf,
131 zcu,
132 func.owner_nav,
133 if (lf.cast(.elf)) |ef|
134 ef.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(ef, pt, lazy_reloc.symbol) catch |err|
135 return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)})
136 else if (lf.cast(.macho)) |mf|
137 mf.getZigObject().?.getOrCreateMetadataForLazySymbol(mf, pt, lazy_reloc.symbol) catch |err|
138 return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)})
139 else if (lf.cast(.coff)) |cf|
140 if (cf.getOrCreateAtomForLazySymbol(pt, lazy_reloc.symbol)) |atom|
141 cf.getAtom(atom).getSymbolIndex().?
142 else |err|
143 return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)})
144 else
145 return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}),
146 mir.body[lazy_reloc.reloc.label],
147 body_end - Instruction.size * (1 + lazy_reloc.reloc.label),
148 lazy_reloc.reloc.addend,
149 );
150 for (mir.global_relocs) |global_reloc| try emitReloc(
151 lf,
152 zcu,
153 func.owner_nav,
154 if (lf.cast(.elf)) |ef|
155 try ef.getGlobalSymbol(std.mem.span(global_reloc.name), null)
156 else if (lf.cast(.macho)) |mf|
157 try mf.getGlobalSymbol(std.mem.span(global_reloc.name), null)
158 else if (lf.cast(.coff)) |cf|
159 try cf.getGlobalSymbol(std.mem.span(global_reloc.name), "compiler_rt")
160 else
161 return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}),
162 mir.body[global_reloc.reloc.label],
163 body_end - Instruction.size * (1 + global_reloc.reloc.label),
164 global_reloc.reloc.addend,
165 );
166 const literal_reloc_offset: i19 = @intCast(mir.epilogue.len + literals_align_gap);
167 for (mir.literal_relocs) |literal_reloc| {
168 var instruction = mir.body[literal_reloc.label];
169 instruction.load_store.register_literal.group.imm19 += literal_reloc_offset;
170 instruction.write(
171 code.items[body_end - Instruction.size * (1 + literal_reloc.label) ..][0..Instruction.size],
172 );
173 }
174}
175
176fn emitInstructionsForward(code: *std.ArrayListUnmanaged(u8), instructions: []const Instruction) void {
177 for (instructions) |instruction| emitInstruction(code, instruction);
178}
179fn emitInstructionsBackward(code: *std.ArrayListUnmanaged(u8), instructions: []const Instruction) void {
180 var instruction_index = instructions.len;
181 while (instruction_index > 0) {
182 instruction_index -= 1;
183 emitInstruction(code, instructions[instruction_index]);
184 }
185}
186fn emitInstruction(code: *std.ArrayListUnmanaged(u8), instruction: Instruction) void {
187 mir_log.debug(" {f}", .{instruction});
188 instruction.write(code.addManyAsArrayAssumeCapacity(Instruction.size));
189}
190
191fn emitReloc(
192 lf: *link.File,
193 zcu: *Zcu,
194 owner_nav: InternPool.Nav.Index,
195 sym_index: u32,
196 instruction: Instruction,
197 offset: u32,
198 addend: u64,
199) !void {
200 const gpa = zcu.gpa;
201 switch (instruction.decode()) {
202 else => unreachable,
203 .data_processing_immediate => |decoded| if (lf.cast(.elf)) |ef| {
204 const zo = ef.zigObjectPtr().?;
205 const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?;
206 const r_type: std.elf.R_AARCH64 = switch (decoded.decode()) {
207 else => unreachable,
208 .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) {
209 .adr => .ADR_PREL_LO21,
210 .adrp => .ADR_PREL_PG_HI21,
211 },
212 .add_subtract_immediate => |add_subtract_immediate| switch (add_subtract_immediate.group.op) {
213 .add => .ADD_ABS_LO12_NC,
214 .sub => unreachable,
215 },
216 };
217 try atom.addReloc(gpa, .{
218 .r_offset = offset,
219 .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type),
220 .r_addend = @bitCast(addend),
221 }, zo);
222 } else if (lf.cast(.macho)) |mf| {
223 const zo = mf.getZigObject().?;
224 const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?;
225 switch (decoded.decode()) {
226 else => unreachable,
227 .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) {
228 .adr => unreachable,
229 .adrp => try atom.addReloc(mf, .{
230 .tag = .@"extern",
231 .offset = offset,
232 .target = sym_index,
233 .addend = @bitCast(addend),
234 .type = .page,
235 .meta = .{
236 .pcrel = true,
237 .has_subtractor = false,
238 .length = 2,
239 .symbolnum = @intCast(sym_index),
240 },
241 }),
242 },
243 .add_subtract_immediate => |add_subtract_immediate| switch (add_subtract_immediate.group.op) {
244 .add => try atom.addReloc(mf, .{
245 .tag = .@"extern",
246 .offset = offset,
247 .target = sym_index,
248 .addend = @bitCast(addend),
249 .type = .pageoff,
250 .meta = .{
251 .pcrel = false,
252 .has_subtractor = false,
253 .length = 2,
254 .symbolnum = @intCast(sym_index),
255 },
256 }),
257 .sub => unreachable,
258 },
259 }
260 },
261 .branch_exception_generating_system => |decoded| if (lf.cast(.elf)) |ef| {
262 const zo = ef.zigObjectPtr().?;
263 const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?;
264 const r_type: std.elf.R_AARCH64 = switch (decoded.decode().unconditional_branch_immediate.group.op) {
265 .b => .JUMP26,
266 .bl => .CALL26,
267 };
268 try atom.addReloc(gpa, .{
269 .r_offset = offset,
270 .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type),
271 .r_addend = @bitCast(addend),
272 }, zo);
273 } else if (lf.cast(.macho)) |mf| {
274 const zo = mf.getZigObject().?;
275 const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?;
276 try atom.addReloc(mf, .{
277 .tag = .@"extern",
278 .offset = offset,
279 .target = sym_index,
280 .addend = @bitCast(addend),
281 .type = .branch,
282 .meta = .{
283 .pcrel = true,
284 .has_subtractor = false,
285 .length = 2,
286 .symbolnum = @intCast(sym_index),
287 },
288 });
289 },
290 .load_store => |decoded| if (lf.cast(.elf)) |ef| {
291 const zo = ef.zigObjectPtr().?;
292 const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?;
293 const r_type: std.elf.R_AARCH64 = switch (decoded.decode().register_unsigned_immediate.decode()) {
294 .integer => |integer| switch (integer.decode()) {
295 .unallocated, .prfm => unreachable,
296 .strb, .ldrb, .ldrsb => .LDST8_ABS_LO12_NC,
297 .strh, .ldrh, .ldrsh => .LDST16_ABS_LO12_NC,
298 .ldrsw => .LDST32_ABS_LO12_NC,
299 inline .str, .ldr => |encoded| switch (encoded.sf) {
300 .word => .LDST32_ABS_LO12_NC,
301 .doubleword => .LDST64_ABS_LO12_NC,
302 },
303 },
304 .vector => |vector| switch (vector.group.opc1.decode(vector.group.size)) {
305 .byte => .LDST8_ABS_LO12_NC,
306 .half => .LDST16_ABS_LO12_NC,
307 .single => .LDST32_ABS_LO12_NC,
308 .double => .LDST64_ABS_LO12_NC,
309 .quad => .LDST128_ABS_LO12_NC,
310 .scalable, .predicate => unreachable,
311 },
312 };
313 try atom.addReloc(gpa, .{
314 .r_offset = offset,
315 .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type),
316 .r_addend = @bitCast(addend),
317 }, zo);
318 } else if (lf.cast(.macho)) |mf| {
319 const zo = mf.getZigObject().?;
320 const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?;
321 try atom.addReloc(mf, .{
322 .tag = .@"extern",
323 .offset = offset,
324 .target = sym_index,
325 .addend = @bitCast(addend),
326 .type = .pageoff,
327 .meta = .{
328 .pcrel = false,
329 .has_subtractor = false,
330 .length = 2,
331 .symbolnum = @intCast(sym_index),
332 },
333 });
334 },
335 }
336}
337
338const Air = @import("../../Air.zig");
339const assert = std.debug.assert;
340const mir_log = std.log.scoped(.mir);
341const Instruction = @import("encoding.zig").Instruction;
342const InternPool = @import("../../InternPool.zig");
343const link = @import("../../link.zig");
344const Mir = @This();
345const std = @import("std");
346const target_util = @import("../../target.zig");
347const Zcu = @import("../../Zcu.zig");
348const ZigType = @import("../../Type.zig");
src/codegen/aarch64/Select.zig created+12141
...@@ -0,0 +1,12141 @@
1pt: Zcu.PerThread,
2target: *const std.Target,
3air: Air,
4nav_index: InternPool.Nav.Index,
5
6// Blocks
7def_order: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, void),
8blocks: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, Block),
9loops: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, Loop),
10active_loops: std.ArrayListUnmanaged(Loop.Index),
11loop_live: struct {
12 set: std.AutoArrayHashMapUnmanaged(struct { Loop.Index, Air.Inst.Index }, void),
13 list: std.ArrayListUnmanaged(Air.Inst.Index),
14},
15dom_start: u32,
16dom_len: u32,
17dom: std.ArrayListUnmanaged(DomInt),
18
19// Wip Mir
20saved_registers: std.enums.EnumSet(Register.Alias),
21instructions: std.ArrayListUnmanaged(codegen.aarch64.encoding.Instruction),
22literals: std.ArrayListUnmanaged(u32),
23nav_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Nav),
24uav_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Uav),
25lazy_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Lazy),
26global_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Global),
27literal_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Literal),
28
29// Stack Frame
30returns: bool,
31va_list: union(enum) {
32 other: Value.Indirect,
33 sysv: struct {
34 __stack: Value.Indirect,
35 __gr_top: Value.Indirect,
36 __vr_top: Value.Indirect,
37 __gr_offs: i32,
38 __vr_offs: i32,
39 },
40},
41stack_size: u24,
42stack_align: InternPool.Alignment,
43
44// Value Tracking
45live_registers: LiveRegisters,
46live_values: std.AutoHashMapUnmanaged(Air.Inst.Index, Value.Index),
47values: std.ArrayListUnmanaged(Value),
48
49pub const LiveRegisters = std.enums.EnumArray(Register.Alias, Value.Index);
50
51pub const Block = struct {
52 live_registers: LiveRegisters,
53 target_label: u32,
54
55 pub const main: Air.Inst.Index = @enumFromInt(
56 std.math.maxInt(@typeInfo(Air.Inst.Index).@"enum".tag_type),
57 );
58
59 fn branch(target_block: *const Block, isel: *Select) !void {
60 if (isel.instructions.items.len > target_block.target_label) {
61 try isel.emit(.b(@intCast((isel.instructions.items.len + 1 - target_block.target_label) << 2)));
62 }
63 try isel.merge(&target_block.live_registers, .{});
64 }
65};
66
67pub const Loop = struct {
68 def_order: u32,
69 dom: u32,
70 depth: u32,
71 live: u32,
72 live_registers: LiveRegisters,
73 repeat_list: u32,
74
75 pub const invalid: Air.Inst.Index = @enumFromInt(
76 std.math.maxInt(@typeInfo(Air.Inst.Index).@"enum".tag_type),
77 );
78
79 pub const Index = enum(u32) {
80 _,
81
82 fn inst(li: Loop.Index, isel: *Select) Air.Inst.Index {
83 return isel.loops.keys()[@intFromEnum(li)];
84 }
85
86 fn get(li: Loop.Index, isel: *Select) *Loop {
87 return &isel.loops.values()[@intFromEnum(li)];
88 }
89 };
90
91 pub const empty_list: u32 = std.math.maxInt(u32);
92
93 fn branch(target_loop: *Loop, isel: *Select) !void {
94 try isel.instructions.ensureUnusedCapacity(isel.pt.zcu.gpa, 1);
95 const repeat_list_tail = target_loop.repeat_list;
96 target_loop.repeat_list = @intCast(isel.instructions.items.len);
97 isel.instructions.appendAssumeCapacity(@bitCast(repeat_list_tail));
98 try isel.merge(&target_loop.live_registers, .{});
99 }
100};
101
102pub fn deinit(isel: *Select) void {
103 const gpa = isel.pt.zcu.gpa;
104
105 isel.def_order.deinit(gpa);
106 isel.blocks.deinit(gpa);
107 isel.loops.deinit(gpa);
108 isel.active_loops.deinit(gpa);
109 isel.loop_live.set.deinit(gpa);
110 isel.loop_live.list.deinit(gpa);
111 isel.dom.deinit(gpa);
112
113 isel.instructions.deinit(gpa);
114 isel.literals.deinit(gpa);
115 isel.nav_relocs.deinit(gpa);
116 isel.uav_relocs.deinit(gpa);
117 isel.lazy_relocs.deinit(gpa);
118 isel.global_relocs.deinit(gpa);
119 isel.literal_relocs.deinit(gpa);
120
121 isel.live_values.deinit(gpa);
122 isel.values.deinit(gpa);
123
124 isel.* = undefined;
125}
126
127pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
128 const zcu = isel.pt.zcu;
129 const ip = &zcu.intern_pool;
130 const gpa = zcu.gpa;
131 const air_tags = isel.air.instructions.items(.tag);
132 const air_data = isel.air.instructions.items(.data);
133 var air_body_index: usize = 0;
134 var air_inst_index = air_body[air_body_index];
135 const initial_def_order_len = isel.def_order.count();
136 air_tag: switch (air_tags[@intFromEnum(air_inst_index)]) {
137 .arg,
138 .ret_addr,
139 .frame_addr,
140 .err_return_trace,
141 .save_err_return_trace_index,
142 .runtime_nav_ptr,
143 .c_va_start,
144 => {
145 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
146
147 air_body_index += 1;
148 air_inst_index = air_body[air_body_index];
149 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
150 },
151 .add,
152 .add_safe,
153 .add_optimized,
154 .add_wrap,
155 .add_sat,
156 .sub,
157 .sub_safe,
158 .sub_optimized,
159 .sub_wrap,
160 .sub_sat,
161 .mul,
162 .mul_safe,
163 .mul_optimized,
164 .mul_wrap,
165 .mul_sat,
166 .div_float,
167 .div_float_optimized,
168 .div_trunc,
169 .div_trunc_optimized,
170 .div_floor,
171 .div_floor_optimized,
172 .div_exact,
173 .div_exact_optimized,
174 .rem,
175 .rem_optimized,
176 .mod,
177 .mod_optimized,
178 .max,
179 .min,
180 .bit_and,
181 .bit_or,
182 .shr,
183 .shr_exact,
184 .shl,
185 .shl_exact,
186 .shl_sat,
187 .xor,
188 .cmp_lt,
189 .cmp_lt_optimized,
190 .cmp_lte,
191 .cmp_lte_optimized,
192 .cmp_eq,
193 .cmp_eq_optimized,
194 .cmp_gte,
195 .cmp_gte_optimized,
196 .cmp_gt,
197 .cmp_gt_optimized,
198 .cmp_neq,
199 .cmp_neq_optimized,
200 .bool_and,
201 .bool_or,
202 .array_elem_val,
203 .slice_elem_val,
204 .ptr_elem_val,
205 => {
206 const bin_op = air_data[@intFromEnum(air_inst_index)].bin_op;
207
208 try isel.analyzeUse(bin_op.lhs);
209 try isel.analyzeUse(bin_op.rhs);
210 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
211
212 air_body_index += 1;
213 air_inst_index = air_body[air_body_index];
214 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
215 },
216 .ptr_add,
217 .ptr_sub,
218 .add_with_overflow,
219 .sub_with_overflow,
220 .mul_with_overflow,
221 .shl_with_overflow,
222 .slice,
223 .slice_elem_ptr,
224 .ptr_elem_ptr,
225 => {
226 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
227 const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data;
228
229 try isel.analyzeUse(bin_op.lhs);
230 try isel.analyzeUse(bin_op.rhs);
231 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
232
233 air_body_index += 1;
234 air_inst_index = air_body[air_body_index];
235 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
236 },
237 .alloc => {
238 const ty = air_data[@intFromEnum(air_inst_index)].ty;
239
240 isel.stack_align = isel.stack_align.maxStrict(ty.ptrAlignment(zcu));
241 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
242
243 air_body_index += 1;
244 air_inst_index = air_body[air_body_index];
245 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
246 },
247 .inferred_alloc,
248 .inferred_alloc_comptime,
249 .wasm_memory_size,
250 .wasm_memory_grow,
251 .work_item_id,
252 .work_group_size,
253 .work_group_id,
254 => unreachable,
255 .ret_ptr => {
256 const ty = air_data[@intFromEnum(air_inst_index)].ty;
257
258 if (isel.live_values.get(Block.main)) |ret_vi| switch (ret_vi.parent(isel)) {
259 .unallocated, .stack_slot => isel.stack_align = isel.stack_align.maxStrict(ty.ptrAlignment(zcu)),
260 .value, .constant => unreachable,
261 .address => |address_vi| try isel.live_values.putNoClobber(gpa, air_inst_index, address_vi.ref(isel)),
262 };
263 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
264
265 air_body_index += 1;
266 air_inst_index = air_body[air_body_index];
267 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
268 },
269 .assembly => {
270 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
271 const extra = isel.air.extraData(Air.Asm, ty_pl.payload);
272 const operands: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0 .. extra.data.flags.outputs_len + extra.data.inputs_len]);
273
274 for (operands) |operand| if (operand != .none) try isel.analyzeUse(operand);
275 if (ty_pl.ty != .void_type) try isel.def_order.putNoClobber(gpa, air_inst_index, {});
276
277 air_body_index += 1;
278 air_inst_index = air_body[air_body_index];
279 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
280 },
281 .not,
282 .clz,
283 .ctz,
284 .popcount,
285 .byte_swap,
286 .bit_reverse,
287 .abs,
288 .load,
289 .fptrunc,
290 .fpext,
291 .intcast,
292 .intcast_safe,
293 .trunc,
294 .optional_payload,
295 .optional_payload_ptr,
296 .optional_payload_ptr_set,
297 .wrap_optional,
298 .unwrap_errunion_payload,
299 .unwrap_errunion_err,
300 .unwrap_errunion_payload_ptr,
301 .unwrap_errunion_err_ptr,
302 .errunion_payload_ptr_set,
303 .wrap_errunion_payload,
304 .wrap_errunion_err,
305 .struct_field_ptr_index_0,
306 .struct_field_ptr_index_1,
307 .struct_field_ptr_index_2,
308 .struct_field_ptr_index_3,
309 .get_union_tag,
310 .ptr_slice_len_ptr,
311 .ptr_slice_ptr_ptr,
312 .array_to_slice,
313 .int_from_float,
314 .int_from_float_optimized,
315 .int_from_float_safe,
316 .int_from_float_optimized_safe,
317 .float_from_int,
318 .splat,
319 .error_set_has_value,
320 .addrspace_cast,
321 .c_va_arg,
322 .c_va_copy,
323 => {
324 const ty_op = air_data[@intFromEnum(air_inst_index)].ty_op;
325
326 try isel.analyzeUse(ty_op.operand);
327 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
328
329 air_body_index += 1;
330 air_inst_index = air_body[air_body_index];
331 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
332 },
333 .bitcast => {
334 const ty_op = air_data[@intFromEnum(air_inst_index)].ty_op;
335 maybe_noop: {
336 if (ty_op.ty.toInterned().? != isel.air.typeOf(ty_op.operand, ip).toIntern()) break :maybe_noop;
337 if (true) break :maybe_noop;
338 if (ty_op.operand.toIndex()) |src_air_inst_index| {
339 if (isel.hints.get(src_air_inst_index)) |hint_vpsi| {
340 try isel.hints.putNoClobber(gpa, air_inst_index, hint_vpsi);
341 }
342 }
343 }
344 try isel.analyzeUse(ty_op.operand);
345 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
346
347 air_body_index += 1;
348 air_inst_index = air_body[air_body_index];
349 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
350 },
351 inline .block, .dbg_inline_block => |air_tag| {
352 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
353 const extra = isel.air.extraData(switch (air_tag) {
354 else => comptime unreachable,
355 .block => Air.Block,
356 .dbg_inline_block => Air.DbgInlineBlock,
357 }, ty_pl.payload);
358 const result_ty = ty_pl.ty.toInterned().?;
359
360 if (result_ty == .noreturn_type) {
361 try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));
362
363 air_body_index += 1;
364 break :air_tag;
365 }
366
367 assert(!(try isel.blocks.getOrPut(gpa, air_inst_index)).found_existing);
368 try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));
369 const block_entry = isel.blocks.pop().?;
370 assert(block_entry.key == air_inst_index);
371
372 if (result_ty != .void_type) try isel.def_order.putNoClobber(gpa, air_inst_index, {});
373
374 air_body_index += 1;
375 air_inst_index = air_body[air_body_index];
376 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
377 },
378 .loop => {
379 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
380 const extra = isel.air.extraData(Air.Block, ty_pl.payload);
381
382 const initial_dom_start = isel.dom_start;
383 const initial_dom_len = isel.dom_len;
384 isel.dom_start = @intCast(isel.dom.items.len);
385 isel.dom_len = @intCast(isel.blocks.count());
386 try isel.active_loops.append(gpa, @enumFromInt(isel.loops.count()));
387 try isel.loops.putNoClobber(gpa, air_inst_index, .{
388 .def_order = @intCast(isel.def_order.count()),
389 .dom = isel.dom_start,
390 .depth = isel.dom_len,
391 .live = 0,
392 .live_registers = undefined,
393 .repeat_list = undefined,
394 });
395 try isel.dom.appendNTimes(gpa, 0, std.math.divCeil(usize, isel.dom_len, @bitSizeOf(DomInt)) catch unreachable);
396 try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));
397 for (
398 isel.dom.items[initial_dom_start..].ptr,
399 isel.dom.items[isel.dom_start..][0 .. std.math.divCeil(usize, initial_dom_len, @bitSizeOf(DomInt)) catch unreachable],
400 ) |*initial_dom, loop_dom| initial_dom.* |= loop_dom;
401 isel.dom_start = initial_dom_start;
402 isel.dom_len = initial_dom_len;
403 assert(isel.active_loops.pop().?.inst(isel) == air_inst_index);
404
405 air_body_index += 1;
406 },
407 .repeat, .trap, .unreach => air_body_index += 1,
408 .br => {
409 const br = air_data[@intFromEnum(air_inst_index)].br;
410 const block_index = isel.blocks.getIndex(br.block_inst).?;
411 if (block_index < isel.dom_len) isel.dom.items[isel.dom_start + block_index / @bitSizeOf(DomInt)] |= @as(DomInt, 1) << @truncate(block_index);
412 try isel.analyzeUse(br.operand);
413
414 air_body_index += 1;
415 },
416 .breakpoint, .dbg_stmt, .dbg_empty_stmt, .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline, .c_va_end => {
417 air_body_index += 1;
418 air_inst_index = air_body[air_body_index];
419 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
420 },
421 .call,
422 .call_always_tail,
423 .call_never_tail,
424 .call_never_inline,
425 => {
426 const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op;
427 const extra = isel.air.extraData(Air.Call, pl_op.payload);
428 const args: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0..extra.data.args_len]);
429 isel.saved_registers.insert(.lr);
430 const callee_ty = isel.air.typeOf(pl_op.operand, ip);
431 const func_info = switch (ip.indexToKey(callee_ty.toIntern())) {
432 else => unreachable,
433 .func_type => |func_type| func_type,
434 .ptr_type => |ptr_type| ip.indexToKey(ptr_type.child).func_type,
435 };
436
437 try isel.analyzeUse(pl_op.operand);
438 var param_it: CallAbiIterator = .init;
439 for (args, 0..) |arg, arg_index| {
440 const restore_values_len = isel.values.items.len;
441 defer isel.values.shrinkRetainingCapacity(restore_values_len);
442 const param_vi = param_vi: {
443 const param_ty = isel.air.typeOf(arg, ip);
444 if (arg_index >= func_info.param_types.len) {
445 assert(func_info.is_var_args);
446 switch (isel.va_list) {
447 .other => break :param_vi try param_it.nonSysvVarArg(isel, param_ty),
448 .sysv => {},
449 }
450 }
451 break :param_vi try param_it.param(isel, param_ty);
452 } orelse continue;
453 defer param_vi.deref(isel);
454 const passed_vi = switch (param_vi.parent(isel)) {
455 .unallocated, .stack_slot => param_vi,
456 .value, .constant => unreachable,
457 .address => |address_vi| address_vi,
458 };
459 switch (passed_vi.parent(isel)) {
460 .unallocated => {},
461 .stack_slot => |stack_slot| {
462 assert(stack_slot.base == .sp);
463 isel.stack_size = @max(
464 isel.stack_size,
465 stack_slot.offset + @as(u24, @intCast(passed_vi.size(isel))),
466 );
467 },
468 .value, .constant, .address => unreachable,
469 }
470
471 try isel.analyzeUse(arg);
472 }
473
474 var ret_it: CallAbiIterator = .init;
475 if (try ret_it.ret(isel, isel.air.typeOfIndex(air_inst_index, ip))) |ret_vi| {
476 tracking_log.debug("${d} <- %{d}", .{ @intFromEnum(ret_vi), @intFromEnum(air_inst_index) });
477 switch (ret_vi.parent(isel)) {
478 .unallocated, .stack_slot => {},
479 .value, .constant => unreachable,
480 .address => |address_vi| {
481 defer address_vi.deref(isel);
482 const ret_value = ret_vi.get(isel);
483 ret_value.flags.parent_tag = .unallocated;
484 ret_value.parent_payload = .{ .unallocated = {} };
485 },
486 }
487 try isel.live_values.putNoClobber(gpa, air_inst_index, ret_vi);
488
489 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
490 }
491
492 air_body_index += 1;
493 air_inst_index = air_body[air_body_index];
494 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
495 },
496 .sqrt,
497 .sin,
498 .cos,
499 .tan,
500 .exp,
501 .exp2,
502 .log,
503 .log2,
504 .log10,
505 .floor,
506 .ceil,
507 .round,
508 .trunc_float,
509 .neg,
510 .neg_optimized,
511 .is_null,
512 .is_non_null,
513 .is_null_ptr,
514 .is_non_null_ptr,
515 .is_err,
516 .is_non_err,
517 .is_err_ptr,
518 .is_non_err_ptr,
519 .is_named_enum_value,
520 .tag_name,
521 .error_name,
522 .cmp_lt_errors_len,
523 => {
524 const un_op = air_data[@intFromEnum(air_inst_index)].un_op;
525
526 try isel.analyzeUse(un_op);
527 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
528
529 air_body_index += 1;
530 air_inst_index = air_body[air_body_index];
531 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
532 },
533 .cmp_vector, .cmp_vector_optimized => {
534 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
535 const extra = isel.air.extraData(Air.VectorCmp, ty_pl.payload).data;
536
537 try isel.analyzeUse(extra.lhs);
538 try isel.analyzeUse(extra.rhs);
539 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
540
541 air_body_index += 1;
542 air_inst_index = air_body[air_body_index];
543 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
544 },
545 .cond_br => {
546 const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op;
547 const extra = isel.air.extraData(Air.CondBr, pl_op.payload);
548
549 try isel.analyzeUse(pl_op.operand);
550
551 try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.then_body_len]));
552 try isel.analyze(@ptrCast(isel.air.extra.items[extra.end + extra.data.then_body_len ..][0..extra.data.else_body_len]));
553
554 air_body_index += 1;
555 },
556 .switch_br => {
557 const switch_br = isel.air.unwrapSwitch(air_inst_index);
558
559 try isel.analyzeUse(switch_br.operand);
560
561 var cases_it = switch_br.iterateCases();
562 while (cases_it.next()) |case| try isel.analyze(case.body);
563 if (switch_br.else_body_len > 0) try isel.analyze(cases_it.elseBody());
564
565 air_body_index += 1;
566 },
567 .loop_switch_br => {
568 const switch_br = isel.air.unwrapSwitch(air_inst_index);
569
570 const initial_dom_start = isel.dom_start;
571 const initial_dom_len = isel.dom_len;
572 isel.dom_start = @intCast(isel.dom.items.len);
573 isel.dom_len = @intCast(isel.blocks.count());
574 try isel.active_loops.append(gpa, @enumFromInt(isel.loops.count()));
575 try isel.loops.putNoClobber(gpa, air_inst_index, .{
576 .def_order = @intCast(isel.def_order.count()),
577 .dom = isel.dom_start,
578 .depth = isel.dom_len,
579 .live = 0,
580 .live_registers = undefined,
581 .repeat_list = undefined,
582 });
583 try isel.dom.appendNTimes(gpa, 0, std.math.divCeil(usize, isel.dom_len, @bitSizeOf(DomInt)) catch unreachable);
584
585 var cases_it = switch_br.iterateCases();
586 while (cases_it.next()) |case| try isel.analyze(case.body);
587 if (switch_br.else_body_len > 0) try isel.analyze(cases_it.elseBody());
588
589 for (
590 isel.dom.items[initial_dom_start..].ptr,
591 isel.dom.items[isel.dom_start..][0 .. std.math.divCeil(usize, initial_dom_len, @bitSizeOf(DomInt)) catch unreachable],
592 ) |*initial_dom, loop_dom| initial_dom.* |= loop_dom;
593 isel.dom_start = initial_dom_start;
594 isel.dom_len = initial_dom_len;
595 assert(isel.active_loops.pop().?.inst(isel) == air_inst_index);
596
597 air_body_index += 1;
598 },
599 .switch_dispatch => {
600 const br = air_data[@intFromEnum(air_inst_index)].br;
601
602 try isel.analyzeUse(br.operand);
603
604 air_body_index += 1;
605 },
606 .@"try", .try_cold => {
607 const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op;
608 const extra = isel.air.extraData(Air.Try, pl_op.payload);
609
610 try isel.analyzeUse(pl_op.operand);
611 try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));
612 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
613
614 air_body_index += 1;
615 air_inst_index = air_body[air_body_index];
616 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
617 },
618 .try_ptr, .try_ptr_cold => {
619 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
620 const extra = isel.air.extraData(Air.TryPtr, ty_pl.payload);
621
622 try isel.analyzeUse(extra.data.ptr);
623 try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));
624 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
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 .ret, .ret_safe, .ret_load => {
631 const un_op = air_data[@intFromEnum(air_inst_index)].un_op;
632 isel.returns = true;
633
634 const block_index = 0;
635 assert(isel.blocks.keys()[block_index] == Block.main);
636 if (isel.dom_len > 0) isel.dom.items[isel.dom_start] |= 1 << block_index;
637
638 try isel.analyzeUse(un_op);
639
640 air_body_index += 1;
641 },
642 .store,
643 .store_safe,
644 .set_union_tag,
645 .memset,
646 .memset_safe,
647 .memcpy,
648 .memmove,
649 .atomic_store_unordered,
650 .atomic_store_monotonic,
651 .atomic_store_release,
652 .atomic_store_seq_cst,
653 => {
654 const bin_op = air_data[@intFromEnum(air_inst_index)].bin_op;
655
656 try isel.analyzeUse(bin_op.lhs);
657 try isel.analyzeUse(bin_op.rhs);
658
659 air_body_index += 1;
660 air_inst_index = air_body[air_body_index];
661 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
662 },
663 .struct_field_ptr, .struct_field_val => {
664 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
665 const extra = isel.air.extraData(Air.StructField, ty_pl.payload).data;
666
667 try isel.analyzeUse(extra.struct_operand);
668 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
669
670 air_body_index += 1;
671 air_inst_index = air_body[air_body_index];
672 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
673 },
674 .slice_len => {
675 const ty_op = air_data[@intFromEnum(air_inst_index)].ty_op;
676
677 try isel.analyzeUse(ty_op.operand);
678 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
679
680 const slice_vi = try isel.use(ty_op.operand);
681 var len_part_it = slice_vi.field(isel.air.typeOf(ty_op.operand, ip), 8, 8);
682 if (try len_part_it.only(isel)) |len_part_vi|
683 try isel.live_values.putNoClobber(gpa, air_inst_index, len_part_vi.ref(isel));
684
685 air_body_index += 1;
686 air_inst_index = air_body[air_body_index];
687 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
688 },
689 .slice_ptr => {
690 const ty_op = air_data[@intFromEnum(air_inst_index)].ty_op;
691
692 try isel.analyzeUse(ty_op.operand);
693 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
694
695 const slice_vi = try isel.use(ty_op.operand);
696 var ptr_part_it = slice_vi.field(isel.air.typeOf(ty_op.operand, ip), 0, 8);
697 if (try ptr_part_it.only(isel)) |ptr_part_vi|
698 try isel.live_values.putNoClobber(gpa, air_inst_index, ptr_part_vi.ref(isel));
699
700 air_body_index += 1;
701 air_inst_index = air_body[air_body_index];
702 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
703 },
704 .reduce, .reduce_optimized => {
705 const reduce = air_data[@intFromEnum(air_inst_index)].reduce;
706
707 try isel.analyzeUse(reduce.operand);
708 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
709
710 air_body_index += 1;
711 air_inst_index = air_body[air_body_index];
712 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
713 },
714 .shuffle_one => {
715 const extra = isel.air.unwrapShuffleOne(zcu, air_inst_index);
716
717 try isel.analyzeUse(extra.operand);
718 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
719
720 air_body_index += 1;
721 air_inst_index = air_body[air_body_index];
722 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
723 },
724 .shuffle_two => {
725 const extra = isel.air.unwrapShuffleTwo(zcu, air_inst_index);
726
727 try isel.analyzeUse(extra.operand_a);
728 try isel.analyzeUse(extra.operand_b);
729 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
730
731 air_body_index += 1;
732 air_inst_index = air_body[air_body_index];
733 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
734 },
735 .select, .mul_add => {
736 const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op;
737 const bin_op = isel.air.extraData(Air.Bin, pl_op.payload).data;
738
739 try isel.analyzeUse(pl_op.operand);
740 try isel.analyzeUse(bin_op.lhs);
741 try isel.analyzeUse(bin_op.rhs);
742 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
743
744 air_body_index += 1;
745 air_inst_index = air_body[air_body_index];
746 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
747 },
748 .cmpxchg_weak, .cmpxchg_strong => {
749 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
750 const extra = isel.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
751
752 try isel.analyzeUse(extra.ptr);
753 try isel.analyzeUse(extra.expected_value);
754 try isel.analyzeUse(extra.new_value);
755 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
756
757 air_body_index += 1;
758 air_inst_index = air_body[air_body_index];
759 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
760 },
761 .atomic_load => {
762 const atomic_load = air_data[@intFromEnum(air_inst_index)].atomic_load;
763
764 try isel.analyzeUse(atomic_load.ptr);
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 .atomic_rmw => {
772 const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op;
773 const extra = isel.air.extraData(Air.AtomicRmw, pl_op.payload).data;
774
775 try isel.analyzeUse(extra.operand);
776 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
777
778 air_body_index += 1;
779 air_inst_index = air_body[air_body_index];
780 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
781 },
782 .aggregate_init => {
783 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
784 const elements: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[ty_pl.payload..][0..@intCast(ty_pl.ty.toType().arrayLen(zcu))]);
785
786 for (elements) |element| try isel.analyzeUse(element);
787 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
788
789 air_body_index += 1;
790 air_inst_index = air_body[air_body_index];
791 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
792 },
793 .union_init => {
794 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
795 const extra = isel.air.extraData(Air.UnionInit, ty_pl.payload).data;
796
797 try isel.analyzeUse(extra.init);
798 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
799
800 air_body_index += 1;
801 air_inst_index = air_body[air_body_index];
802 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
803 },
804 .prefetch => {
805 const prefetch = air_data[@intFromEnum(air_inst_index)].prefetch;
806
807 try isel.analyzeUse(prefetch.ptr);
808
809 air_body_index += 1;
810 air_inst_index = air_body[air_body_index];
811 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
812 },
813 .field_parent_ptr => {
814 const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl;
815 const extra = isel.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
816
817 try isel.analyzeUse(extra.field_ptr);
818 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
819
820 air_body_index += 1;
821 air_inst_index = air_body[air_body_index];
822 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
823 },
824 .set_err_return_trace => {
825 const un_op = air_data[@intFromEnum(air_inst_index)].un_op;
826
827 try isel.analyzeUse(un_op);
828
829 air_body_index += 1;
830 air_inst_index = air_body[air_body_index];
831 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
832 },
833 .vector_store_elem => {
834 const vector_store_elem = air_data[@intFromEnum(air_inst_index)].vector_store_elem;
835 const bin_op = isel.air.extraData(Air.Bin, vector_store_elem.payload).data;
836
837 try isel.analyzeUse(vector_store_elem.vector_ptr);
838 try isel.analyzeUse(bin_op.lhs);
839 try isel.analyzeUse(bin_op.rhs);
840
841 air_body_index += 1;
842 air_inst_index = air_body[air_body_index];
843 continue :air_tag air_tags[@intFromEnum(air_inst_index)];
844 },
845 }
846 assert(air_body_index == air_body.len);
847 isel.def_order.shrinkRetainingCapacity(initial_def_order_len);
848}
849
850fn analyzeUse(isel: *Select, air_ref: Air.Inst.Ref) !void {
851 const air_inst_index = air_ref.toIndex() orelse return;
852 const def_order_index = isel.def_order.getIndex(air_inst_index).?;
853
854 // Loop liveness
855 var active_loop_index = isel.active_loops.items.len;
856 while (active_loop_index > 0) {
857 const prev_active_loop_index = active_loop_index - 1;
858 const active_loop = isel.active_loops.items[prev_active_loop_index];
859 if (def_order_index >= active_loop.get(isel).def_order) break;
860 active_loop_index = prev_active_loop_index;
861 }
862 if (active_loop_index < isel.active_loops.items.len) {
863 const active_loop = isel.active_loops.items[active_loop_index];
864 const loop_live_gop =
865 try isel.loop_live.set.getOrPut(isel.pt.zcu.gpa, .{ active_loop, air_inst_index });
866 if (!loop_live_gop.found_existing) active_loop.get(isel).live += 1;
867 }
868}
869
870pub fn finishAnalysis(isel: *Select) !void {
871 const gpa = isel.pt.zcu.gpa;
872
873 // Loop Liveness
874 if (isel.loops.count() > 0) {
875 try isel.loops.ensureUnusedCapacity(gpa, 1);
876
877 const loop_live_len: u32 = @intCast(isel.loop_live.set.count());
878 if (loop_live_len > 0) {
879 try isel.loop_live.list.resize(gpa, loop_live_len);
880
881 const loops = isel.loops.values();
882 for (loops[1..], loops[0 .. loops.len - 1]) |*loop, prev_loop| loop.live += prev_loop.live;
883 assert(loops[loops.len - 1].live == loop_live_len);
884
885 for (isel.loop_live.set.keys()) |entry| {
886 const loop, const inst = entry;
887 const loop_live = &loop.get(isel).live;
888 loop_live.* -= 1;
889 isel.loop_live.list.items[loop_live.*] = inst;
890 }
891 assert(loops[0].live == 0);
892 }
893
894 const invalid_gop = isel.loops.getOrPutAssumeCapacity(Loop.invalid);
895 assert(!invalid_gop.found_existing);
896 invalid_gop.value_ptr.live = loop_live_len;
897 }
898}
899
900pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, CodegenFail }!void {
901 const zcu = isel.pt.zcu;
902 const ip = &zcu.intern_pool;
903 const gpa = zcu.gpa;
904
905 {
906 var live_reg_it = isel.live_registers.iterator();
907 while (live_reg_it.next()) |live_reg_entry| switch (live_reg_entry.value.*) {
908 _ => {
909 const ra = &live_reg_entry.value.get(isel).location_payload.small.register;
910 assert(ra.* == live_reg_entry.key);
911 ra.* = .zr;
912 live_reg_entry.value.* = .free;
913 },
914 .allocating => live_reg_entry.value.* = .free,
915 .free => {},
916 };
917 }
918
919 var air: struct {
920 isel: *Select,
921 tag_items: []const Air.Inst.Tag,
922 data_items: []const Air.Inst.Data,
923 body: []const Air.Inst.Index,
924 body_index: u32,
925 inst_index: Air.Inst.Index,
926
927 fn tag(it: *@This(), inst_index: Air.Inst.Index) Air.Inst.Tag {
928 return it.tag_items[@intFromEnum(inst_index)];
929 }
930
931 fn data(it: *@This(), inst_index: Air.Inst.Index) Air.Inst.Data {
932 return it.data_items[@intFromEnum(inst_index)];
933 }
934
935 fn next(it: *@This()) ?Air.Inst.Tag {
936 if (it.body_index == 0) {
937 @branchHint(.unlikely);
938 return null;
939 }
940 it.body_index -= 1;
941 it.inst_index = it.body[it.body_index];
942 wip_mir_log.debug("{f}", .{it.fmtAir(it.inst_index)});
943 return it.tag(it.inst_index);
944 }
945
946 fn fmtAir(it: @This(), inst: Air.Inst.Index) struct {
947 isel: *Select,
948 inst: Air.Inst.Index,
949 pub fn format(fmt_air: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void {
950 fmt_air.isel.air.writeInst(writer, fmt_air.inst, fmt_air.isel.pt, null);
951 }
952 } {
953 return .{ .isel = it.isel, .inst = inst };
954 }
955 } = .{
956 .isel = isel,
957 .tag_items = isel.air.instructions.items(.tag),
958 .data_items = isel.air.instructions.items(.data),
959 .body = air_body,
960 .body_index = @intCast(air_body.len),
961 .inst_index = undefined,
962 };
963 air_tag: switch (air.next().?) {
964 else => |air_tag| return isel.fail("unimplemented {s}", .{@tagName(air_tag)}),
965 .arg => {
966 const arg_vi = isel.live_values.fetchRemove(air.inst_index).?.value;
967 defer arg_vi.deref(isel);
968 switch (arg_vi.parent(isel)) {
969 .unallocated, .stack_slot => if (arg_vi.hint(isel)) |arg_ra| {
970 try arg_vi.defLiveIn(isel, arg_ra, comptime &.initFill(.free));
971 } else {
972 var arg_part_it = arg_vi.parts(isel);
973 while (arg_part_it.next()) |arg_part| {
974 try arg_part.defLiveIn(isel, arg_part.hint(isel).?, comptime &.initFill(.free));
975 }
976 },
977 .value, .constant => unreachable,
978 .address => |address_vi| try address_vi.defLiveIn(isel, address_vi.hint(isel).?, comptime &.initFill(.free)),
979 }
980 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
981 },
982 .add, .add_safe, .add_optimized, .add_wrap, .sub, .sub_safe, .sub_optimized, .sub_wrap => |air_tag| {
983 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
984 defer res_vi.value.deref(isel);
985
986 const bin_op = air.data(air.inst_index).bin_op;
987 const ty = isel.air.typeOf(bin_op.lhs, ip);
988 if (!ty.isRuntimeFloat()) try res_vi.value.addOrSubtract(isel, ty, try isel.use(bin_op.lhs), switch (air_tag) {
989 else => unreachable,
990 .add, .add_safe, .add_wrap => .add,
991 .sub, .sub_safe, .sub_wrap => .sub,
992 }, try isel.use(bin_op.rhs), .{
993 .overflow = switch (air_tag) {
994 else => unreachable,
995 .add, .sub => .@"unreachable",
996 .add_safe, .sub_safe => .{ .panic = .integer_overflow },
997 .add_wrap, .sub_wrap => .wrap,
998 },
999 }) else switch (ty.floatBits(isel.target)) {
1000 else => unreachable,
1001 16, 32, 64 => |bits| {
1002 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1003 const need_fcvt = switch (bits) {
1004 else => unreachable,
1005 16 => !isel.target.cpu.has(.aarch64, .fullfp16),
1006 32, 64 => false,
1007 };
1008 if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s()));
1009 const lhs_vi = try isel.use(bin_op.lhs);
1010 const rhs_vi = try isel.use(bin_op.rhs);
1011 const lhs_mat = try lhs_vi.matReg(isel);
1012 const rhs_mat = try rhs_vi.matReg(isel);
1013 const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra;
1014 defer if (need_fcvt) isel.freeReg(lhs_ra);
1015 const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra;
1016 defer if (need_fcvt) isel.freeReg(rhs_ra);
1017 try isel.emit(bits: switch (bits) {
1018 else => unreachable,
1019 16 => if (need_fcvt) continue :bits 32 else switch (air_tag) {
1020 else => unreachable,
1021 .add, .add_optimized => .fadd(res_ra.h(), lhs_ra.h(), rhs_ra.h()),
1022 .sub, .sub_optimized => .fsub(res_ra.h(), lhs_ra.h(), rhs_ra.h()),
1023 },
1024 32 => switch (air_tag) {
1025 else => unreachable,
1026 .add, .add_optimized => .fadd(res_ra.s(), lhs_ra.s(), rhs_ra.s()),
1027 .sub, .sub_optimized => .fsub(res_ra.s(), lhs_ra.s(), rhs_ra.s()),
1028 },
1029 64 => switch (air_tag) {
1030 else => unreachable,
1031 .add, .add_optimized => .fadd(res_ra.d(), lhs_ra.d(), rhs_ra.d()),
1032 .sub, .sub_optimized => .fsub(res_ra.d(), lhs_ra.d(), rhs_ra.d()),
1033 },
1034 });
1035 if (need_fcvt) {
1036 try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h()));
1037 try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h()));
1038 }
1039 try rhs_mat.finish(isel);
1040 try lhs_mat.finish(isel);
1041 },
1042 80, 128 => |bits| {
1043 try call.prepareReturn(isel);
1044 switch (bits) {
1045 else => unreachable,
1046 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
1047 80 => {
1048 var res_hi16_it = res_vi.value.field(ty, 8, 8);
1049 const res_hi16_vi = try res_hi16_it.only(isel);
1050 try call.returnLiveIn(isel, res_hi16_vi.?, .r1);
1051 var res_lo64_it = res_vi.value.field(ty, 0, 8);
1052 const res_lo64_vi = try res_lo64_it.only(isel);
1053 try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
1054 },
1055 }
1056 try call.finishReturn(isel);
1057
1058 try call.prepareCallee(isel);
1059 try isel.global_relocs.append(gpa, .{
1060 .name = switch (air_tag) {
1061 else => unreachable,
1062 .add, .add_optimized => switch (bits) {
1063 else => unreachable,
1064 16 => "__addhf3",
1065 32 => "__addsf3",
1066 64 => "__adddf3",
1067 80 => "__addxf3",
1068 128 => "__addtf3",
1069 },
1070 .sub, .sub_optimized => switch (bits) {
1071 else => unreachable,
1072 16 => "__subhf3",
1073 32 => "__subsf3",
1074 64 => "__subdf3",
1075 80 => "__subxf3",
1076 128 => "__subtf3",
1077 },
1078 },
1079 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
1080 });
1081 try isel.emit(.bl(0));
1082 try call.finishCallee(isel);
1083
1084 try call.prepareParams(isel);
1085 const lhs_vi = try isel.use(bin_op.lhs);
1086 const rhs_vi = try isel.use(bin_op.rhs);
1087 switch (bits) {
1088 else => unreachable,
1089 16, 32, 64, 128 => {
1090 try call.paramLiveOut(isel, rhs_vi, .v1);
1091 try call.paramLiveOut(isel, lhs_vi, .v0);
1092 },
1093 80 => {
1094 var rhs_hi16_it = rhs_vi.field(ty, 8, 8);
1095 const rhs_hi16_vi = try rhs_hi16_it.only(isel);
1096 try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3);
1097 var rhs_lo64_it = rhs_vi.field(ty, 0, 8);
1098 const rhs_lo64_vi = try rhs_lo64_it.only(isel);
1099 try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2);
1100 var lhs_hi16_it = lhs_vi.field(ty, 8, 8);
1101 const lhs_hi16_vi = try lhs_hi16_it.only(isel);
1102 try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1);
1103 var lhs_lo64_it = lhs_vi.field(ty, 0, 8);
1104 const lhs_lo64_vi = try lhs_lo64_it.only(isel);
1105 try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0);
1106 },
1107 }
1108 try call.finishParams(isel);
1109 },
1110 }
1111 }
1112 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
1113 },
1114 .add_sat, .sub_sat => |air_tag| {
1115 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
1116 defer res_vi.value.deref(isel);
1117
1118 const bin_op = air.data(air.inst_index).bin_op;
1119 const ty = isel.air.typeOf(bin_op.lhs, ip);
1120 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
1121 const int_info = ty.intInfo(zcu);
1122 switch (int_info.bits) {
1123 0 => unreachable,
1124 32, 64 => |bits| switch (int_info.signedness) {
1125 .signed => return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
1126 .unsigned => {
1127 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1128 const lhs_vi = try isel.use(bin_op.lhs);
1129 const rhs_vi = try isel.use(bin_op.rhs);
1130 const lhs_mat = try lhs_vi.matReg(isel);
1131 const rhs_mat = try rhs_vi.matReg(isel);
1132 const unsat_res_ra = try isel.allocIntReg();
1133 defer isel.freeReg(unsat_res_ra);
1134 switch (air_tag) {
1135 else => unreachable,
1136 .add_sat => switch (bits) {
1137 else => unreachable,
1138 32 => {
1139 try isel.emit(.csinv(res_ra.w(), unsat_res_ra.w(), .wzr, .invert(.cs)));
1140 try isel.emit(.adds(unsat_res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() }));
1141 },
1142 64 => {
1143 try isel.emit(.csinv(res_ra.x(), unsat_res_ra.x(), .xzr, .invert(.cs)));
1144 try isel.emit(.adds(unsat_res_ra.x(), lhs_mat.ra.x(), .{ .register = rhs_mat.ra.x() }));
1145 },
1146 },
1147 .sub_sat => switch (bits) {
1148 else => unreachable,
1149 32 => {
1150 try isel.emit(.csel(res_ra.w(), unsat_res_ra.w(), .wzr, .invert(.cc)));
1151 try isel.emit(.subs(unsat_res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() }));
1152 },
1153 64 => {
1154 try isel.emit(.csel(res_ra.x(), unsat_res_ra.x(), .xzr, .invert(.cc)));
1155 try isel.emit(.subs(unsat_res_ra.x(), lhs_mat.ra.x(), .{ .register = rhs_mat.ra.x() }));
1156 },
1157 },
1158 }
1159 try rhs_mat.finish(isel);
1160 try lhs_mat.finish(isel);
1161 },
1162 },
1163 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
1164 }
1165 }
1166 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
1167 },
1168 .mul, .mul_optimized, .mul_wrap => |air_tag| {
1169 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
1170 defer res_vi.value.deref(isel);
1171
1172 const bin_op = air.data(air.inst_index).bin_op;
1173 const ty = isel.air.typeOf(bin_op.lhs, ip);
1174 if (!ty.isRuntimeFloat()) {
1175 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
1176 const int_info = ty.intInfo(zcu);
1177 switch (int_info.bits) {
1178 0 => unreachable,
1179 1 => {
1180 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1181 switch (int_info.signedness) {
1182 .signed => switch (air_tag) {
1183 else => unreachable,
1184 .mul => break :unused try isel.emit(.orr(res_ra.w(), .wzr, .{ .register = .wzr })),
1185 .mul_wrap => {},
1186 },
1187 .unsigned => {},
1188 }
1189 const lhs_vi = try isel.use(bin_op.lhs);
1190 const rhs_vi = try isel.use(bin_op.rhs);
1191 const lhs_mat = try lhs_vi.matReg(isel);
1192 const rhs_mat = try rhs_vi.matReg(isel);
1193 try isel.emit(.@"and"(res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() }));
1194 try rhs_mat.finish(isel);
1195 try lhs_mat.finish(isel);
1196 },
1197 2...32 => |bits| {
1198 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1199 switch (air_tag) {
1200 else => unreachable,
1201 .mul => {},
1202 .mul_wrap => switch (bits) {
1203 else => unreachable,
1204 1...31 => try isel.emit(switch (int_info.signedness) {
1205 .signed => .sbfm(res_ra.w(), res_ra.w(), .{
1206 .N = .word,
1207 .immr = 0,
1208 .imms = @intCast(bits - 1),
1209 }),
1210 .unsigned => .ubfm(res_ra.w(), res_ra.w(), .{
1211 .N = .word,
1212 .immr = 0,
1213 .imms = @intCast(bits - 1),
1214 }),
1215 }),
1216 32 => {},
1217 },
1218 }
1219 const lhs_vi = try isel.use(bin_op.lhs);
1220 const rhs_vi = try isel.use(bin_op.rhs);
1221 const lhs_mat = try lhs_vi.matReg(isel);
1222 const rhs_mat = try rhs_vi.matReg(isel);
1223 try isel.emit(.madd(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w(), .wzr));
1224 try rhs_mat.finish(isel);
1225 try lhs_mat.finish(isel);
1226 },
1227 33...64 => |bits| {
1228 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1229 switch (air_tag) {
1230 else => unreachable,
1231 .mul => {},
1232 .mul_wrap => switch (bits) {
1233 else => unreachable,
1234 33...63 => 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 64 => {},
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_mat = try lhs_vi.matReg(isel);
1252 const rhs_mat = try rhs_vi.matReg(isel);
1253 try isel.emit(.madd(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), .xzr));
1254 try rhs_mat.finish(isel);
1255 try lhs_mat.finish(isel);
1256 },
1257 65...128 => |bits| {
1258 var res_hi64_it = res_vi.value.field(ty, 8, 8);
1259 const res_hi64_vi = try res_hi64_it.only(isel);
1260 const res_hi64_ra = try res_hi64_vi.?.defReg(isel);
1261 var res_lo64_it = res_vi.value.field(ty, 0, 8);
1262 const res_lo64_vi = try res_lo64_it.only(isel);
1263 const res_lo64_ra = try res_lo64_vi.?.defReg(isel);
1264 if (res_hi64_ra == null and res_lo64_ra == null) break :unused;
1265 if (res_hi64_ra) |res_ra| switch (air_tag) {
1266 else => unreachable,
1267 .mul => {},
1268 .mul_wrap => switch (bits) {
1269 else => unreachable,
1270 65...127 => try isel.emit(switch (int_info.signedness) {
1271 .signed => .sbfm(res_ra.x(), res_ra.x(), .{
1272 .N = .doubleword,
1273 .immr = 0,
1274 .imms = @intCast(bits - 1),
1275 }),
1276 .unsigned => .ubfm(res_ra.x(), res_ra.x(), .{
1277 .N = .doubleword,
1278 .immr = 0,
1279 .imms = @intCast(bits - 1),
1280 }),
1281 }),
1282 128 => {},
1283 },
1284 };
1285 const lhs_vi = try isel.use(bin_op.lhs);
1286 const rhs_vi = try isel.use(bin_op.rhs);
1287 const lhs_lo64_mat, const rhs_lo64_mat = lo64_mat: {
1288 const res_hi64_lock: RegLock = if (res_hi64_ra != null and res_lo64_ra != null)
1289 isel.lockReg(res_hi64_ra.?)
1290 else
1291 .empty;
1292 defer res_hi64_lock.unlock(isel);
1293
1294 var rhs_lo64_it = rhs_vi.field(ty, 0, 8);
1295 const rhs_lo64_vi = try rhs_lo64_it.only(isel);
1296 const rhs_lo64_mat = try rhs_lo64_vi.?.matReg(isel);
1297 var lhs_lo64_it = lhs_vi.field(ty, 0, 8);
1298 const lhs_lo64_vi = try lhs_lo64_it.only(isel);
1299 const lhs_lo64_mat = try lhs_lo64_vi.?.matReg(isel);
1300 break :lo64_mat .{ lhs_lo64_mat, rhs_lo64_mat };
1301 };
1302 if (res_lo64_ra) |res_ra| try isel.emit(.madd(res_ra.x(), lhs_lo64_mat.ra.x(), rhs_lo64_mat.ra.x(), .xzr));
1303 if (res_hi64_ra) |res_ra| {
1304 var rhs_hi64_it = rhs_vi.field(ty, 8, 8);
1305 const rhs_hi64_vi = try rhs_hi64_it.only(isel);
1306 const rhs_hi64_mat = try rhs_hi64_vi.?.matReg(isel);
1307 var lhs_hi64_it = lhs_vi.field(ty, 8, 8);
1308 const lhs_hi64_vi = try lhs_hi64_it.only(isel);
1309 const lhs_hi64_mat = try lhs_hi64_vi.?.matReg(isel);
1310 const acc_ra = try isel.allocIntReg();
1311 defer isel.freeReg(acc_ra);
1312 try isel.emit(.madd(res_ra.x(), lhs_hi64_mat.ra.x(), rhs_lo64_mat.ra.x(), acc_ra.x()));
1313 try isel.emit(.madd(acc_ra.x(), lhs_lo64_mat.ra.x(), rhs_hi64_mat.ra.x(), acc_ra.x()));
1314 try isel.emit(.umulh(acc_ra.x(), lhs_lo64_mat.ra.x(), rhs_lo64_mat.ra.x()));
1315 try rhs_hi64_mat.finish(isel);
1316 try lhs_hi64_mat.finish(isel);
1317 }
1318 try rhs_lo64_mat.finish(isel);
1319 try lhs_lo64_mat.finish(isel);
1320 },
1321 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
1322 }
1323 } else switch (ty.floatBits(isel.target)) {
1324 else => unreachable,
1325 16, 32, 64 => |bits| {
1326 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1327 const need_fcvt = switch (bits) {
1328 else => unreachable,
1329 16 => !isel.target.cpu.has(.aarch64, .fullfp16),
1330 32, 64 => false,
1331 };
1332 if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s()));
1333 const lhs_vi = try isel.use(bin_op.lhs);
1334 const rhs_vi = try isel.use(bin_op.rhs);
1335 const lhs_mat = try lhs_vi.matReg(isel);
1336 const rhs_mat = try rhs_vi.matReg(isel);
1337 const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra;
1338 defer if (need_fcvt) isel.freeReg(lhs_ra);
1339 const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra;
1340 defer if (need_fcvt) isel.freeReg(rhs_ra);
1341 try isel.emit(bits: switch (bits) {
1342 else => unreachable,
1343 16 => if (need_fcvt)
1344 continue :bits 32
1345 else
1346 .fmul(res_ra.h(), lhs_ra.h(), rhs_ra.h()),
1347 32 => .fmul(res_ra.s(), lhs_ra.s(), rhs_ra.s()),
1348 64 => .fmul(res_ra.d(), lhs_ra.d(), rhs_ra.d()),
1349 });
1350 if (need_fcvt) {
1351 try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h()));
1352 try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h()));
1353 }
1354 try rhs_mat.finish(isel);
1355 try lhs_mat.finish(isel);
1356 },
1357 80, 128 => |bits| {
1358 try call.prepareReturn(isel);
1359 switch (bits) {
1360 else => unreachable,
1361 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
1362 80 => {
1363 var res_hi16_it = res_vi.value.field(ty, 8, 8);
1364 const res_hi16_vi = try res_hi16_it.only(isel);
1365 try call.returnLiveIn(isel, res_hi16_vi.?, .r1);
1366 var res_lo64_it = res_vi.value.field(ty, 0, 8);
1367 const res_lo64_vi = try res_lo64_it.only(isel);
1368 try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
1369 },
1370 }
1371 try call.finishReturn(isel);
1372
1373 try call.prepareCallee(isel);
1374 try isel.global_relocs.append(gpa, .{
1375 .name = switch (bits) {
1376 else => unreachable,
1377 16 => "__mulhf3",
1378 32 => "__mulsf3",
1379 64 => "__muldf3",
1380 80 => "__mulxf3",
1381 128 => "__multf3",
1382 },
1383 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
1384 });
1385 try isel.emit(.bl(0));
1386 try call.finishCallee(isel);
1387
1388 try call.prepareParams(isel);
1389 const lhs_vi = try isel.use(bin_op.lhs);
1390 const rhs_vi = try isel.use(bin_op.rhs);
1391 switch (bits) {
1392 else => unreachable,
1393 16, 32, 64, 128 => {
1394 try call.paramLiveOut(isel, rhs_vi, .v1);
1395 try call.paramLiveOut(isel, lhs_vi, .v0);
1396 },
1397 80 => {
1398 var rhs_hi16_it = rhs_vi.field(ty, 8, 8);
1399 const rhs_hi16_vi = try rhs_hi16_it.only(isel);
1400 try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3);
1401 var rhs_lo64_it = rhs_vi.field(ty, 0, 8);
1402 const rhs_lo64_vi = try rhs_lo64_it.only(isel);
1403 try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2);
1404 var lhs_hi16_it = lhs_vi.field(ty, 8, 8);
1405 const lhs_hi16_vi = try lhs_hi16_it.only(isel);
1406 try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1);
1407 var lhs_lo64_it = lhs_vi.field(ty, 0, 8);
1408 const lhs_lo64_vi = try lhs_lo64_it.only(isel);
1409 try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0);
1410 },
1411 }
1412 try call.finishParams(isel);
1413 },
1414 }
1415 }
1416 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
1417 },
1418 .mul_safe => |air_tag| {
1419 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
1420 defer res_vi.value.deref(isel);
1421
1422 const bin_op = air.data(air.inst_index).bin_op;
1423 const ty = isel.air.typeOf(bin_op.lhs, ip);
1424 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
1425 const int_info = ty.intInfo(zcu);
1426 switch (int_info.signedness) {
1427 .signed => switch (int_info.bits) {
1428 0 => unreachable,
1429 1 => {
1430 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1431 const lhs_vi = try isel.use(bin_op.lhs);
1432 const rhs_vi = try isel.use(bin_op.rhs);
1433 const lhs_mat = try lhs_vi.matReg(isel);
1434 const rhs_mat = try rhs_vi.matReg(isel);
1435 try isel.emit(.orr(res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() }));
1436 const skip_label = isel.instructions.items.len;
1437 try isel.emitPanic(.integer_overflow);
1438 try isel.emit(.@"b."(
1439 .invert(.ne),
1440 @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
1441 ));
1442 try isel.emit(.ands(.wzr, lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() }));
1443 try rhs_mat.finish(isel);
1444 try lhs_mat.finish(isel);
1445 },
1446 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
1447 },
1448 .unsigned => switch (int_info.bits) {
1449 0 => unreachable,
1450 1 => {
1451 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1452 const lhs_vi = try isel.use(bin_op.lhs);
1453 const rhs_vi = try isel.use(bin_op.rhs);
1454 const lhs_mat = try lhs_vi.matReg(isel);
1455 const rhs_mat = try rhs_vi.matReg(isel);
1456 try isel.emit(.@"and"(res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() }));
1457 try rhs_mat.finish(isel);
1458 try lhs_mat.finish(isel);
1459 },
1460 2...16 => |bits| {
1461 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1462 const lhs_vi = try isel.use(bin_op.lhs);
1463 const rhs_vi = try isel.use(bin_op.rhs);
1464 const lhs_mat = try lhs_vi.matReg(isel);
1465 const rhs_mat = try rhs_vi.matReg(isel);
1466 const skip_label = isel.instructions.items.len;
1467 try isel.emitPanic(.integer_overflow);
1468 try isel.emit(.@"b."(
1469 .eq,
1470 @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
1471 ));
1472 try isel.emit(.ands(.wzr, res_ra.w(), .{ .immediate = .{
1473 .N = .word,
1474 .immr = @intCast(32 - bits),
1475 .imms = @intCast(32 - bits - 1),
1476 } }));
1477 try isel.emit(.madd(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w(), .wzr));
1478 try rhs_mat.finish(isel);
1479 try lhs_mat.finish(isel);
1480 },
1481 17...32 => |bits| {
1482 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1483 const lhs_vi = try isel.use(bin_op.lhs);
1484 const rhs_vi = try isel.use(bin_op.rhs);
1485 const lhs_mat = try lhs_vi.matReg(isel);
1486 const rhs_mat = try rhs_vi.matReg(isel);
1487 const skip_label = isel.instructions.items.len;
1488 try isel.emitPanic(.integer_overflow);
1489 try isel.emit(.@"b."(
1490 .eq,
1491 @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
1492 ));
1493 try isel.emit(.ands(.xzr, res_ra.x(), .{ .immediate = .{
1494 .N = .doubleword,
1495 .immr = @intCast(64 - bits),
1496 .imms = @intCast(64 - bits - 1),
1497 } }));
1498 try isel.emit(.umaddl(res_ra.x(), lhs_mat.ra.w(), rhs_mat.ra.w(), .xzr));
1499 try rhs_mat.finish(isel);
1500 try lhs_mat.finish(isel);
1501 },
1502 33...63 => |bits| {
1503 const lo64_ra = try res_vi.value.defReg(isel) orelse break :unused;
1504 const lhs_vi = try isel.use(bin_op.lhs);
1505 const rhs_vi = try isel.use(bin_op.rhs);
1506 const lhs_mat = try lhs_vi.matReg(isel);
1507 const rhs_mat = try rhs_vi.matReg(isel);
1508 const hi64_ra = hi64_ra: {
1509 const lo64_lock = isel.tryLockReg(lo64_ra);
1510 defer lo64_lock.unlock(isel);
1511 break :hi64_ra try isel.allocIntReg();
1512 };
1513 defer isel.freeReg(hi64_ra);
1514 const skip_label = isel.instructions.items.len;
1515 try isel.emitPanic(.integer_overflow);
1516 try isel.emit(.cbz(
1517 hi64_ra.x(),
1518 @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
1519 ));
1520 try isel.emit(.orr(hi64_ra.x(), hi64_ra.x(), .{ .shifted_register = .{
1521 .register = lo64_ra.x(),
1522 .shift = .{ .lsr = @intCast(bits) },
1523 } }));
1524 try isel.emit(.madd(lo64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), .xzr));
1525 try isel.emit(.umulh(hi64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()));
1526 try rhs_mat.finish(isel);
1527 try lhs_mat.finish(isel);
1528 },
1529 64 => {
1530 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1531 const lhs_vi = try isel.use(bin_op.lhs);
1532 const rhs_vi = try isel.use(bin_op.rhs);
1533 const lhs_mat = try lhs_vi.matReg(isel);
1534 const rhs_mat = try rhs_vi.matReg(isel);
1535 try isel.emit(.madd(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), .xzr));
1536 const hi64_ra = try isel.allocIntReg();
1537 defer isel.freeReg(hi64_ra);
1538 const skip_label = isel.instructions.items.len;
1539 try isel.emitPanic(.integer_overflow);
1540 try isel.emit(.cbz(
1541 hi64_ra.x(),
1542 @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
1543 ));
1544 try isel.emit(.umulh(hi64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()));
1545 try rhs_mat.finish(isel);
1546 try lhs_mat.finish(isel);
1547 },
1548 65...128 => return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
1549 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
1550 },
1551 }
1552 }
1553 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
1554 },
1555 .mul_sat => |air_tag| {
1556 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
1557 defer res_vi.value.deref(isel);
1558
1559 const bin_op = air.data(air.inst_index).bin_op;
1560 const ty = isel.air.typeOf(bin_op.lhs, ip);
1561 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
1562 const int_info = ty.intInfo(zcu);
1563 switch (int_info.bits) {
1564 0 => unreachable,
1565 1 => {
1566 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1567 switch (int_info.signedness) {
1568 .signed => try isel.emit(.orr(res_ra.w(), .wzr, .{ .register = .wzr })),
1569 .unsigned => {
1570 const lhs_vi = try isel.use(bin_op.lhs);
1571 const rhs_vi = try isel.use(bin_op.rhs);
1572 const lhs_mat = try lhs_vi.matReg(isel);
1573 const rhs_mat = try rhs_vi.matReg(isel);
1574 try isel.emit(.@"and"(res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() }));
1575 try rhs_mat.finish(isel);
1576 try lhs_mat.finish(isel);
1577 },
1578 }
1579 },
1580 2...32 => |bits| {
1581 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1582 const saturated_ra = switch (int_info.signedness) {
1583 .signed => try isel.allocIntReg(),
1584 .unsigned => switch (bits) {
1585 else => unreachable,
1586 2...31 => try isel.allocIntReg(),
1587 32 => .zr,
1588 },
1589 };
1590 defer if (saturated_ra != .zr) isel.freeReg(saturated_ra);
1591 const unwrapped_ra = try isel.allocIntReg();
1592 defer isel.freeReg(unwrapped_ra);
1593 try isel.emit(switch (saturated_ra) {
1594 else => .csel(res_ra.w(), unwrapped_ra.w(), saturated_ra.w(), .eq),
1595 .zr => .csinv(res_ra.w(), unwrapped_ra.w(), saturated_ra.w(), .eq),
1596 });
1597 switch (bits) {
1598 else => unreachable,
1599 2...7, 9...15, 17...31 => switch (int_info.signedness) {
1600 .signed => {
1601 const wrapped_ra = try isel.allocIntReg();
1602 defer isel.freeReg(wrapped_ra);
1603 switch (bits) {
1604 else => unreachable,
1605 1...7, 9...15 => {
1606 try isel.emit(.subs(.wzr, unwrapped_ra.w(), .{ .register = wrapped_ra.w() }));
1607 try isel.emit(.sbfm(wrapped_ra.w(), unwrapped_ra.w(), .{
1608 .N = .word,
1609 .immr = 0,
1610 .imms = @intCast(bits - 1),
1611 }));
1612 },
1613 17...31 => {
1614 try isel.emit(.subs(.xzr, unwrapped_ra.x(), .{ .register = wrapped_ra.x() }));
1615 try isel.emit(.sbfm(wrapped_ra.x(), unwrapped_ra.x(), .{
1616 .N = .doubleword,
1617 .immr = 0,
1618 .imms = @intCast(bits - 1),
1619 }));
1620 },
1621 }
1622 },
1623 .unsigned => switch (bits) {
1624 else => unreachable,
1625 1...7, 9...15 => try isel.emit(.ands(.wzr, unwrapped_ra.w(), .{ .immediate = .{
1626 .N = .word,
1627 .immr = @intCast(32 - bits),
1628 .imms = @intCast(32 - bits - 1),
1629 } })),
1630 17...31 => try isel.emit(.ands(.xzr, unwrapped_ra.x(), .{ .immediate = .{
1631 .N = .doubleword,
1632 .immr = @intCast(64 - bits),
1633 .imms = @intCast(64 - bits - 1),
1634 } })),
1635 },
1636 },
1637 8 => try isel.emit(.subs(.wzr, unwrapped_ra.w(), .{ .extended_register = .{
1638 .register = unwrapped_ra.w(),
1639 .extend = switch (int_info.signedness) {
1640 .signed => .{ .sxtb = 0 },
1641 .unsigned => .{ .uxtb = 0 },
1642 },
1643 } })),
1644 16 => try isel.emit(.subs(.wzr, unwrapped_ra.w(), .{ .extended_register = .{
1645 .register = unwrapped_ra.w(),
1646 .extend = switch (int_info.signedness) {
1647 .signed => .{ .sxth = 0 },
1648 .unsigned => .{ .uxth = 0 },
1649 },
1650 } })),
1651 32 => try isel.emit(.subs(.xzr, unwrapped_ra.x(), .{ .extended_register = .{
1652 .register = unwrapped_ra.w(),
1653 .extend = switch (int_info.signedness) {
1654 .signed => .{ .sxtw = 0 },
1655 .unsigned => .{ .uxtw = 0 },
1656 },
1657 } })),
1658 }
1659 const lhs_vi = try isel.use(bin_op.lhs);
1660 const rhs_vi = try isel.use(bin_op.rhs);
1661 const lhs_mat = try lhs_vi.matReg(isel);
1662 const rhs_mat = try rhs_vi.matReg(isel);
1663 switch (int_info.signedness) {
1664 .signed => {
1665 try isel.emit(.eor(saturated_ra.w(), saturated_ra.w(), .{ .immediate = .{
1666 .N = .word,
1667 .immr = 0,
1668 .imms = @intCast(bits - 1 - 1),
1669 } }));
1670 try isel.emit(.sbfm(saturated_ra.w(), saturated_ra.w(), .{
1671 .N = .word,
1672 .immr = @intCast(bits - 1),
1673 .imms = @intCast(bits - 1 + 1 - 1),
1674 }));
1675 try isel.emit(.eor(saturated_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() }));
1676 },
1677 .unsigned => switch (bits) {
1678 else => unreachable,
1679 2...31 => try isel.movImmediate(saturated_ra.w(), @as(u32, std.math.maxInt(u32)) >> @intCast(32 - bits)),
1680 32 => {},
1681 },
1682 }
1683 switch (bits) {
1684 else => unreachable,
1685 2...16 => try isel.emit(.madd(unwrapped_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w(), .wzr)),
1686 17...32 => switch (int_info.signedness) {
1687 .signed => try isel.emit(.smaddl(unwrapped_ra.x(), lhs_mat.ra.w(), rhs_mat.ra.w(), .xzr)),
1688 .unsigned => try isel.emit(.umaddl(unwrapped_ra.x(), lhs_mat.ra.w(), rhs_mat.ra.w(), .xzr)),
1689 },
1690 }
1691 try rhs_mat.finish(isel);
1692 try lhs_mat.finish(isel);
1693 },
1694 33...64 => |bits| {
1695 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1696 const saturated_ra = switch (int_info.signedness) {
1697 .signed => try isel.allocIntReg(),
1698 .unsigned => switch (bits) {
1699 else => unreachable,
1700 33...63 => try isel.allocIntReg(),
1701 64 => .zr,
1702 },
1703 };
1704 defer if (saturated_ra != .zr) isel.freeReg(saturated_ra);
1705 const unwrapped_lo64_ra = try isel.allocIntReg();
1706 defer isel.freeReg(unwrapped_lo64_ra);
1707 const unwrapped_hi64_ra = try isel.allocIntReg();
1708 defer isel.freeReg(unwrapped_hi64_ra);
1709 try isel.emit(switch (saturated_ra) {
1710 else => .csel(res_ra.x(), unwrapped_lo64_ra.x(), saturated_ra.x(), .eq),
1711 .zr => .csinv(res_ra.x(), unwrapped_lo64_ra.x(), saturated_ra.x(), .eq),
1712 });
1713 switch (int_info.signedness) {
1714 .signed => switch (bits) {
1715 else => unreachable,
1716 32...63 => {
1717 const wrapped_lo64_ra = try isel.allocIntReg();
1718 defer isel.freeReg(wrapped_lo64_ra);
1719 try isel.emit(.ccmp(
1720 unwrapped_lo64_ra.x(),
1721 .{ .register = wrapped_lo64_ra.x() },
1722 .{ .n = false, .z = false, .c = false, .v = false },
1723 .eq,
1724 ));
1725 try isel.emit(.subs(.xzr, unwrapped_hi64_ra.x(), .{ .shifted_register = .{
1726 .register = unwrapped_lo64_ra.x(),
1727 .shift = .{ .asr = 63 },
1728 } }));
1729 try isel.emit(.sbfm(wrapped_lo64_ra.x(), unwrapped_lo64_ra.x(), .{
1730 .N = .doubleword,
1731 .immr = 0,
1732 .imms = @intCast(bits - 1),
1733 }));
1734 },
1735 64 => try isel.emit(.subs(.xzr, unwrapped_hi64_ra.x(), .{ .shifted_register = .{
1736 .register = unwrapped_lo64_ra.x(),
1737 .shift = .{ .asr = @intCast(bits - 1) },
1738 } })),
1739 },
1740 .unsigned => switch (bits) {
1741 else => unreachable,
1742 32...63 => {
1743 const overflow_ra = try isel.allocIntReg();
1744 defer isel.freeReg(overflow_ra);
1745 try isel.emit(.subs(.xzr, overflow_ra.x(), .{ .immediate = 0 }));
1746 try isel.emit(.orr(overflow_ra.x(), unwrapped_hi64_ra.x(), .{ .shifted_register = .{
1747 .register = unwrapped_lo64_ra.x(),
1748 .shift = .{ .lsr = @intCast(bits) },
1749 } }));
1750 },
1751 64 => try isel.emit(.subs(.xzr, unwrapped_hi64_ra.x(), .{ .immediate = 0 })),
1752 },
1753 }
1754 const lhs_vi = try isel.use(bin_op.lhs);
1755 const rhs_vi = try isel.use(bin_op.rhs);
1756 const lhs_mat = try lhs_vi.matReg(isel);
1757 const rhs_mat = try rhs_vi.matReg(isel);
1758 switch (int_info.signedness) {
1759 .signed => {
1760 try isel.emit(.eor(saturated_ra.x(), saturated_ra.x(), .{ .immediate = .{
1761 .N = .doubleword,
1762 .immr = 0,
1763 .imms = @intCast(bits - 1 - 1),
1764 } }));
1765 try isel.emit(.sbfm(saturated_ra.x(), saturated_ra.x(), .{
1766 .N = .doubleword,
1767 .immr = @intCast(bits - 1),
1768 .imms = @intCast(bits - 1 + 1 - 1),
1769 }));
1770 try isel.emit(.eor(saturated_ra.x(), lhs_mat.ra.x(), .{ .register = rhs_mat.ra.x() }));
1771 try isel.emit(.madd(unwrapped_lo64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), .xzr));
1772 try isel.emit(.smulh(unwrapped_hi64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()));
1773 },
1774 .unsigned => {
1775 switch (bits) {
1776 else => unreachable,
1777 32...63 => try isel.movImmediate(saturated_ra.x(), @as(u64, std.math.maxInt(u64)) >> @intCast(64 - bits)),
1778 64 => {},
1779 }
1780 try isel.emit(.madd(unwrapped_lo64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), .xzr));
1781 try isel.emit(.umulh(unwrapped_hi64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()));
1782 },
1783 }
1784 try rhs_mat.finish(isel);
1785 try lhs_mat.finish(isel);
1786 },
1787 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
1788 }
1789 }
1790 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
1791 },
1792 .div_float, .div_float_optimized => {
1793 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
1794 defer res_vi.value.deref(isel);
1795
1796 const bin_op = air.data(air.inst_index).bin_op;
1797 const ty = isel.air.typeOf(bin_op.lhs, ip);
1798 switch (ty.floatBits(isel.target)) {
1799 else => unreachable,
1800 16, 32, 64 => |bits| {
1801 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1802 const need_fcvt = switch (bits) {
1803 else => unreachable,
1804 16 => !isel.target.cpu.has(.aarch64, .fullfp16),
1805 32, 64 => false,
1806 };
1807 if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s()));
1808 const lhs_vi = try isel.use(bin_op.lhs);
1809 const rhs_vi = try isel.use(bin_op.rhs);
1810 const lhs_mat = try lhs_vi.matReg(isel);
1811 const rhs_mat = try rhs_vi.matReg(isel);
1812 const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra;
1813 defer if (need_fcvt) isel.freeReg(lhs_ra);
1814 const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra;
1815 defer if (need_fcvt) isel.freeReg(rhs_ra);
1816 try isel.emit(bits: switch (bits) {
1817 else => unreachable,
1818 16 => if (need_fcvt)
1819 continue :bits 32
1820 else
1821 .fdiv(res_ra.h(), lhs_ra.h(), rhs_ra.h()),
1822 32 => .fdiv(res_ra.s(), lhs_ra.s(), rhs_ra.s()),
1823 64 => .fdiv(res_ra.d(), lhs_ra.d(), rhs_ra.d()),
1824 });
1825 if (need_fcvt) {
1826 try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h()));
1827 try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h()));
1828 }
1829 try rhs_mat.finish(isel);
1830 try lhs_mat.finish(isel);
1831 },
1832 80, 128 => |bits| {
1833 try call.prepareReturn(isel);
1834 switch (bits) {
1835 else => unreachable,
1836 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
1837 80 => {
1838 var res_hi16_it = res_vi.value.field(ty, 8, 8);
1839 const res_hi16_vi = try res_hi16_it.only(isel);
1840 try call.returnLiveIn(isel, res_hi16_vi.?, .r1);
1841 var res_lo64_it = res_vi.value.field(ty, 0, 8);
1842 const res_lo64_vi = try res_lo64_it.only(isel);
1843 try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
1844 },
1845 }
1846 try call.finishReturn(isel);
1847
1848 try call.prepareCallee(isel);
1849 try isel.global_relocs.append(gpa, .{
1850 .name = switch (bits) {
1851 else => unreachable,
1852 16 => "__divhf3",
1853 32 => "__divsf3",
1854 64 => "__divdf3",
1855 80 => "__divxf3",
1856 128 => "__divtf3",
1857 },
1858 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
1859 });
1860 try isel.emit(.bl(0));
1861 try call.finishCallee(isel);
1862
1863 try call.prepareParams(isel);
1864 const lhs_vi = try isel.use(bin_op.lhs);
1865 const rhs_vi = try isel.use(bin_op.rhs);
1866 switch (bits) {
1867 else => unreachable,
1868 16, 32, 64, 128 => {
1869 try call.paramLiveOut(isel, rhs_vi, .v1);
1870 try call.paramLiveOut(isel, lhs_vi, .v0);
1871 },
1872 80 => {
1873 var rhs_hi16_it = rhs_vi.field(ty, 8, 8);
1874 const rhs_hi16_vi = try rhs_hi16_it.only(isel);
1875 try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3);
1876 var rhs_lo64_it = rhs_vi.field(ty, 0, 8);
1877 const rhs_lo64_vi = try rhs_lo64_it.only(isel);
1878 try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2);
1879 var lhs_hi16_it = lhs_vi.field(ty, 8, 8);
1880 const lhs_hi16_vi = try lhs_hi16_it.only(isel);
1881 try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1);
1882 var lhs_lo64_it = lhs_vi.field(ty, 0, 8);
1883 const lhs_lo64_vi = try lhs_lo64_it.only(isel);
1884 try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0);
1885 },
1886 }
1887 try call.finishParams(isel);
1888 },
1889 }
1890 }
1891 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
1892 },
1893 .div_trunc, .div_trunc_optimized, .div_floor, .div_floor_optimized, .div_exact, .div_exact_optimized => |air_tag| {
1894 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
1895 defer res_vi.value.deref(isel);
1896
1897 const bin_op = air.data(air.inst_index).bin_op;
1898 const ty = isel.air.typeOf(bin_op.lhs, ip);
1899 if (!ty.isRuntimeFloat()) {
1900 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
1901 const int_info = ty.intInfo(zcu);
1902 switch (int_info.bits) {
1903 0 => unreachable,
1904 1...64 => |bits| {
1905 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
1906 const lhs_vi = try isel.use(bin_op.lhs);
1907 const rhs_vi = try isel.use(bin_op.rhs);
1908 const lhs_mat = try lhs_vi.matReg(isel);
1909 const rhs_mat = try rhs_vi.matReg(isel);
1910 const div_ra = div_ra: switch (air_tag) {
1911 else => unreachable,
1912 .div_trunc, .div_exact => res_ra,
1913 .div_floor => switch (int_info.signedness) {
1914 .signed => {
1915 const div_ra = try isel.allocIntReg();
1916 errdefer isel.freeReg(div_ra);
1917 const rem_ra = try isel.allocIntReg();
1918 defer isel.freeReg(rem_ra);
1919 switch (bits) {
1920 else => unreachable,
1921 1...32 => {
1922 try isel.emit(.sub(res_ra.w(), div_ra.w(), .{ .register = rem_ra.w() }));
1923 try isel.emit(.csinc(rem_ra.w(), .wzr, .wzr, .ge));
1924 try isel.emit(.ccmp(
1925 rem_ra.w(),
1926 .{ .immediate = 0 },
1927 .{ .n = false, .z = false, .c = false, .v = false },
1928 .ne,
1929 ));
1930 try isel.emit(.eor(rem_ra.w(), rem_ra.w(), .{ .register = rhs_mat.ra.w() }));
1931 try isel.emit(.subs(.wzr, rem_ra.w(), .{ .immediate = 0 }));
1932 try isel.emit(.msub(rem_ra.w(), div_ra.w(), rhs_mat.ra.w(), lhs_mat.ra.w()));
1933 },
1934 33...64 => {
1935 try isel.emit(.sub(res_ra.x(), div_ra.x(), .{ .register = rem_ra.x() }));
1936 try isel.emit(.csinc(rem_ra.x(), .xzr, .xzr, .ge));
1937 try isel.emit(.ccmp(
1938 rem_ra.x(),
1939 .{ .immediate = 0 },
1940 .{ .n = false, .z = false, .c = false, .v = false },
1941 .ne,
1942 ));
1943 try isel.emit(.eor(rem_ra.x(), rem_ra.x(), .{ .register = rhs_mat.ra.x() }));
1944 try isel.emit(.subs(.xzr, rem_ra.x(), .{ .immediate = 0 }));
1945 try isel.emit(.msub(rem_ra.x(), div_ra.x(), rhs_mat.ra.x(), lhs_mat.ra.x()));
1946 },
1947 }
1948 break :div_ra div_ra;
1949 },
1950 .unsigned => res_ra,
1951 },
1952 };
1953 defer if (div_ra != res_ra) isel.freeReg(div_ra);
1954 try isel.emit(switch (bits) {
1955 else => unreachable,
1956 1...32 => switch (int_info.signedness) {
1957 .signed => .sdiv(div_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()),
1958 .unsigned => .udiv(div_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()),
1959 },
1960 33...64 => switch (int_info.signedness) {
1961 .signed => .sdiv(div_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()),
1962 .unsigned => .udiv(div_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()),
1963 },
1964 });
1965 try rhs_mat.finish(isel);
1966 try lhs_mat.finish(isel);
1967 },
1968 65...128 => {
1969 switch (air_tag) {
1970 else => unreachable,
1971 .div_trunc, .div_exact => {},
1972 .div_floor => switch (int_info.signedness) {
1973 .signed => return isel.fail("unimplemented {s}", .{@tagName(air_tag)}),
1974 .unsigned => {},
1975 },
1976 }
1977
1978 try call.prepareReturn(isel);
1979 var res_hi64_it = res_vi.value.field(ty, 8, 8);
1980 const res_hi64_vi = try res_hi64_it.only(isel);
1981 try call.returnLiveIn(isel, res_hi64_vi.?, .r1);
1982 var res_lo64_it = res_vi.value.field(ty, 0, 8);
1983 const res_lo64_vi = try res_lo64_it.only(isel);
1984 try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
1985 try call.finishReturn(isel);
1986
1987 try call.prepareCallee(isel);
1988 try isel.global_relocs.append(gpa, .{
1989 .name = switch (int_info.signedness) {
1990 .signed => "__divti3",
1991 .unsigned => "__udivti3",
1992 },
1993 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
1994 });
1995 try isel.emit(.bl(0));
1996 try call.finishCallee(isel);
1997
1998 try call.prepareParams(isel);
1999 const lhs_vi = try isel.use(bin_op.lhs);
2000 const rhs_vi = try isel.use(bin_op.rhs);
2001 var rhs_hi64_it = rhs_vi.field(ty, 8, 8);
2002 const rhs_hi64_vi = try rhs_hi64_it.only(isel);
2003 try call.paramLiveOut(isel, rhs_hi64_vi.?, .r3);
2004 var rhs_lo64_it = rhs_vi.field(ty, 0, 8);
2005 const rhs_lo64_vi = try rhs_lo64_it.only(isel);
2006 try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2);
2007 var lhs_hi64_it = lhs_vi.field(ty, 8, 8);
2008 const lhs_hi64_vi = try lhs_hi64_it.only(isel);
2009 try call.paramLiveOut(isel, lhs_hi64_vi.?, .r1);
2010 var lhs_lo64_it = lhs_vi.field(ty, 0, 8);
2011 const lhs_lo64_vi = try lhs_lo64_it.only(isel);
2012 try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0);
2013 try call.finishParams(isel);
2014 },
2015 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
2016 }
2017 } else switch (ty.floatBits(isel.target)) {
2018 else => unreachable,
2019 16, 32, 64 => |bits| {
2020 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
2021 const need_fcvt = switch (bits) {
2022 else => unreachable,
2023 16 => !isel.target.cpu.has(.aarch64, .fullfp16),
2024 32, 64 => false,
2025 };
2026 if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s()));
2027 const lhs_vi = try isel.use(bin_op.lhs);
2028 const rhs_vi = try isel.use(bin_op.rhs);
2029 const lhs_mat = try lhs_vi.matReg(isel);
2030 const rhs_mat = try rhs_vi.matReg(isel);
2031 const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra;
2032 defer if (need_fcvt) isel.freeReg(lhs_ra);
2033 const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra;
2034 defer if (need_fcvt) isel.freeReg(rhs_ra);
2035 bits: switch (bits) {
2036 else => unreachable,
2037 16 => if (need_fcvt) continue :bits 32 else {
2038 switch (air_tag) {
2039 else => unreachable,
2040 .div_trunc, .div_trunc_optimized => try isel.emit(.frintz(res_ra.h(), res_ra.h())),
2041 .div_floor, .div_floor_optimized => try isel.emit(.frintm(res_ra.h(), res_ra.h())),
2042 .div_exact, .div_exact_optimized => {},
2043 }
2044 try isel.emit(.fdiv(res_ra.h(), lhs_ra.h(), rhs_ra.h()));
2045 },
2046 32 => {
2047 switch (air_tag) {
2048 else => unreachable,
2049 .div_trunc, .div_trunc_optimized => try isel.emit(.frintz(res_ra.s(), res_ra.s())),
2050 .div_floor, .div_floor_optimized => try isel.emit(.frintm(res_ra.s(), res_ra.s())),
2051 .div_exact, .div_exact_optimized => {},
2052 }
2053 try isel.emit(.fdiv(res_ra.s(), lhs_ra.s(), rhs_ra.s()));
2054 },
2055 64 => {
2056 switch (air_tag) {
2057 else => unreachable,
2058 .div_trunc, .div_trunc_optimized => try isel.emit(.frintz(res_ra.d(), res_ra.d())),
2059 .div_floor, .div_floor_optimized => try isel.emit(.frintm(res_ra.d(), res_ra.d())),
2060 .div_exact, .div_exact_optimized => {},
2061 }
2062 try isel.emit(.fdiv(res_ra.d(), lhs_ra.d(), rhs_ra.d()));
2063 },
2064 }
2065 if (need_fcvt) {
2066 try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h()));
2067 try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h()));
2068 }
2069 try rhs_mat.finish(isel);
2070 try lhs_mat.finish(isel);
2071 },
2072 80, 128 => |bits| {
2073 try call.prepareReturn(isel);
2074 switch (bits) {
2075 else => unreachable,
2076 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
2077 80 => {
2078 var res_hi16_it = res_vi.value.field(ty, 8, 8);
2079 const res_hi16_vi = try res_hi16_it.only(isel);
2080 try call.returnLiveIn(isel, res_hi16_vi.?, .r1);
2081 var res_lo64_it = res_vi.value.field(ty, 0, 8);
2082 const res_lo64_vi = try res_lo64_it.only(isel);
2083 try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
2084 },
2085 }
2086 try call.finishReturn(isel);
2087
2088 try call.prepareCallee(isel);
2089 switch (air_tag) {
2090 else => unreachable,
2091 .div_trunc, .div_trunc_optimized => {
2092 try isel.global_relocs.append(gpa, .{
2093 .name = switch (bits) {
2094 else => unreachable,
2095 16 => "__trunch",
2096 32 => "truncf",
2097 64 => "trunc",
2098 80 => "__truncx",
2099 128 => "truncq",
2100 },
2101 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
2102 });
2103 try isel.emit(.bl(0));
2104 },
2105 .div_floor, .div_floor_optimized => {
2106 try isel.global_relocs.append(gpa, .{
2107 .name = switch (bits) {
2108 else => unreachable,
2109 16 => "__floorh",
2110 32 => "floorf",
2111 64 => "floor",
2112 80 => "__floorx",
2113 128 => "floorq",
2114 },
2115 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
2116 });
2117 try isel.emit(.bl(0));
2118 },
2119 .div_exact, .div_exact_optimized => {},
2120 }
2121 try isel.global_relocs.append(gpa, .{
2122 .name = switch (bits) {
2123 else => unreachable,
2124 16 => "__divhf3",
2125 32 => "__divsf3",
2126 64 => "__divdf3",
2127 80 => "__divxf3",
2128 128 => "__divtf3",
2129 },
2130 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
2131 });
2132 try isel.emit(.bl(0));
2133 try call.finishCallee(isel);
2134
2135 try call.prepareParams(isel);
2136 const lhs_vi = try isel.use(bin_op.lhs);
2137 const rhs_vi = try isel.use(bin_op.rhs);
2138 switch (bits) {
2139 else => unreachable,
2140 16, 32, 64, 128 => {
2141 try call.paramLiveOut(isel, rhs_vi, .v1);
2142 try call.paramLiveOut(isel, lhs_vi, .v0);
2143 },
2144 80 => {
2145 var rhs_hi16_it = rhs_vi.field(ty, 8, 8);
2146 const rhs_hi16_vi = try rhs_hi16_it.only(isel);
2147 try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3);
2148 var rhs_lo64_it = rhs_vi.field(ty, 0, 8);
2149 const rhs_lo64_vi = try rhs_lo64_it.only(isel);
2150 try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2);
2151 var lhs_hi16_it = lhs_vi.field(ty, 8, 8);
2152 const lhs_hi16_vi = try lhs_hi16_it.only(isel);
2153 try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1);
2154 var lhs_lo64_it = lhs_vi.field(ty, 0, 8);
2155 const lhs_lo64_vi = try lhs_lo64_it.only(isel);
2156 try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0);
2157 },
2158 }
2159 try call.finishParams(isel);
2160 },
2161 }
2162 }
2163 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
2164 },
2165 .rem => |air_tag| {
2166 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
2167 defer res_vi.value.deref(isel);
2168
2169 const bin_op = air.data(air.inst_index).bin_op;
2170 const ty = isel.air.typeOf(bin_op.lhs, ip);
2171 if (!ty.isRuntimeFloat()) {
2172 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
2173 const int_info = ty.intInfo(zcu);
2174 if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
2175
2176 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
2177 const lhs_vi = try isel.use(bin_op.lhs);
2178 const rhs_vi = try isel.use(bin_op.rhs);
2179 const lhs_mat = try lhs_vi.matReg(isel);
2180 const rhs_mat = try rhs_vi.matReg(isel);
2181 const div_ra = try isel.allocIntReg();
2182 defer isel.freeReg(div_ra);
2183 switch (int_info.bits) {
2184 else => unreachable,
2185 1...32 => {
2186 try isel.emit(.msub(res_ra.w(), div_ra.w(), rhs_mat.ra.w(), lhs_mat.ra.w()));
2187 try isel.emit(switch (int_info.signedness) {
2188 .signed => .sdiv(div_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()),
2189 .unsigned => .udiv(div_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()),
2190 });
2191 },
2192 33...64 => {
2193 try isel.emit(.msub(res_ra.x(), div_ra.x(), rhs_mat.ra.x(), lhs_mat.ra.x()));
2194 try isel.emit(switch (int_info.signedness) {
2195 .signed => .sdiv(div_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()),
2196 .unsigned => .udiv(div_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()),
2197 });
2198 },
2199 }
2200 try rhs_mat.finish(isel);
2201 try lhs_mat.finish(isel);
2202 } else {
2203 const bits = ty.floatBits(isel.target);
2204
2205 try call.prepareReturn(isel);
2206 switch (bits) {
2207 else => unreachable,
2208 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
2209 80 => {
2210 var res_hi16_it = res_vi.value.field(ty, 8, 8);
2211 const res_hi16_vi = try res_hi16_it.only(isel);
2212 try call.returnLiveIn(isel, res_hi16_vi.?, .r1);
2213 var res_lo64_it = res_vi.value.field(ty, 0, 8);
2214 const res_lo64_vi = try res_lo64_it.only(isel);
2215 try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
2216 },
2217 }
2218 try call.finishReturn(isel);
2219
2220 try call.prepareCallee(isel);
2221 try isel.global_relocs.append(gpa, .{
2222 .name = switch (bits) {
2223 else => unreachable,
2224 16 => "__fmodh",
2225 32 => "fmodf",
2226 64 => "fmod",
2227 80 => "__fmodx",
2228 128 => "fmodq",
2229 },
2230 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
2231 });
2232 try isel.emit(.bl(0));
2233 try call.finishCallee(isel);
2234
2235 try call.prepareParams(isel);
2236 const lhs_vi = try isel.use(bin_op.lhs);
2237 const rhs_vi = try isel.use(bin_op.rhs);
2238 switch (bits) {
2239 else => unreachable,
2240 16, 32, 64, 128 => {
2241 try call.paramLiveOut(isel, rhs_vi, .v1);
2242 try call.paramLiveOut(isel, lhs_vi, .v0);
2243 },
2244 80 => {
2245 var rhs_hi16_it = rhs_vi.field(ty, 8, 8);
2246 const rhs_hi16_vi = try rhs_hi16_it.only(isel);
2247 try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3);
2248 var rhs_lo64_it = rhs_vi.field(ty, 0, 8);
2249 const rhs_lo64_vi = try rhs_lo64_it.only(isel);
2250 try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2);
2251 var lhs_hi16_it = lhs_vi.field(ty, 8, 8);
2252 const lhs_hi16_vi = try lhs_hi16_it.only(isel);
2253 try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1);
2254 var lhs_lo64_it = lhs_vi.field(ty, 0, 8);
2255 const lhs_lo64_vi = try lhs_lo64_it.only(isel);
2256 try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0);
2257 },
2258 }
2259 try call.finishParams(isel);
2260 }
2261 }
2262 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
2263 },
2264 .ptr_add, .ptr_sub => |air_tag| {
2265 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
2266 defer res_vi.value.deref(isel);
2267 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
2268
2269 const ty_pl = air.data(air.inst_index).ty_pl;
2270 const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data;
2271 const elem_size = ty_pl.ty.toType().elemType2(zcu).abiSize(zcu);
2272
2273 const base_vi = try isel.use(bin_op.lhs);
2274 var base_part_it = base_vi.field(ty_pl.ty.toType(), 0, 8);
2275 const base_part_vi = try base_part_it.only(isel);
2276 const base_part_mat = try base_part_vi.?.matReg(isel);
2277 const index_vi = try isel.use(bin_op.rhs);
2278 try isel.elemPtr(res_ra, base_part_mat.ra, switch (air_tag) {
2279 else => unreachable,
2280 .ptr_add => .add,
2281 .ptr_sub => .sub,
2282 }, elem_size, index_vi);
2283 try base_part_mat.finish(isel);
2284 }
2285 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
2286 },
2287 .max, .min => |air_tag| {
2288 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
2289 defer res_vi.value.deref(isel);
2290
2291 const bin_op = air.data(air.inst_index).bin_op;
2292 const ty = isel.air.typeOf(bin_op.lhs, ip);
2293 if (!ty.isRuntimeFloat()) {
2294 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
2295 const int_info = ty.intInfo(zcu);
2296 if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
2297
2298 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
2299 const lhs_vi = try isel.use(bin_op.lhs);
2300 const rhs_vi = try isel.use(bin_op.rhs);
2301 const lhs_mat = try lhs_vi.matReg(isel);
2302 const rhs_mat = try rhs_vi.matReg(isel);
2303 const cond: codegen.aarch64.encoding.ConditionCode = switch (air_tag) {
2304 else => unreachable,
2305 .max => switch (int_info.signedness) {
2306 .signed => .ge,
2307 .unsigned => .hs,
2308 },
2309 .min => switch (int_info.signedness) {
2310 .signed => .lt,
2311 .unsigned => .lo,
2312 },
2313 };
2314 switch (int_info.bits) {
2315 else => unreachable,
2316 1...32 => {
2317 try isel.emit(.csel(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w(), cond));
2318 try isel.emit(.subs(.wzr, lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() }));
2319 },
2320 33...64 => {
2321 try isel.emit(.csel(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), cond));
2322 try isel.emit(.subs(.xzr, lhs_mat.ra.x(), .{ .register = rhs_mat.ra.x() }));
2323 },
2324 }
2325 try rhs_mat.finish(isel);
2326 try lhs_mat.finish(isel);
2327 } else switch (ty.floatBits(isel.target)) {
2328 else => unreachable,
2329 16, 32, 64 => |bits| {
2330 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
2331 const need_fcvt = switch (bits) {
2332 else => unreachable,
2333 16 => !isel.target.cpu.has(.aarch64, .fullfp16),
2334 32, 64 => false,
2335 };
2336 if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s()));
2337 const lhs_vi = try isel.use(bin_op.lhs);
2338 const rhs_vi = try isel.use(bin_op.rhs);
2339 const lhs_mat = try lhs_vi.matReg(isel);
2340 const rhs_mat = try rhs_vi.matReg(isel);
2341 const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra;
2342 defer if (need_fcvt) isel.freeReg(lhs_ra);
2343 const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra;
2344 defer if (need_fcvt) isel.freeReg(rhs_ra);
2345 try isel.emit(bits: switch (bits) {
2346 else => unreachable,
2347 16 => if (need_fcvt) continue :bits 32 else switch (air_tag) {
2348 else => unreachable,
2349 .max => .fmaxnm(res_ra.h(), lhs_ra.h(), rhs_ra.h()),
2350 .min => .fminnm(res_ra.h(), lhs_ra.h(), rhs_ra.h()),
2351 },
2352 32 => switch (air_tag) {
2353 else => unreachable,
2354 .max => .fmaxnm(res_ra.s(), lhs_ra.s(), rhs_ra.s()),
2355 .min => .fminnm(res_ra.s(), lhs_ra.s(), rhs_ra.s()),
2356 },
2357 64 => switch (air_tag) {
2358 else => unreachable,
2359 .max => .fmaxnm(res_ra.d(), lhs_ra.d(), rhs_ra.d()),
2360 .min => .fminnm(res_ra.d(), lhs_ra.d(), rhs_ra.d()),
2361 },
2362 });
2363 if (need_fcvt) {
2364 try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h()));
2365 try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h()));
2366 }
2367 try rhs_mat.finish(isel);
2368 try lhs_mat.finish(isel);
2369 },
2370 80, 128 => |bits| {
2371 try call.prepareReturn(isel);
2372 switch (bits) {
2373 else => unreachable,
2374 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
2375 80 => {
2376 var res_hi16_it = res_vi.value.field(ty, 8, 8);
2377 const res_hi16_vi = try res_hi16_it.only(isel);
2378 try call.returnLiveIn(isel, res_hi16_vi.?, .r1);
2379 var res_lo64_it = res_vi.value.field(ty, 0, 8);
2380 const res_lo64_vi = try res_lo64_it.only(isel);
2381 try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
2382 },
2383 }
2384 try call.finishReturn(isel);
2385
2386 try call.prepareCallee(isel);
2387 try isel.global_relocs.append(gpa, .{
2388 .name = switch (air_tag) {
2389 else => unreachable,
2390 .max => switch (bits) {
2391 else => unreachable,
2392 16 => "__fmaxh",
2393 32 => "fmaxf",
2394 64 => "fmax",
2395 80 => "__fmaxx",
2396 128 => "fmaxq",
2397 },
2398 .min => switch (bits) {
2399 else => unreachable,
2400 16 => "__fminh",
2401 32 => "fminf",
2402 64 => "fmin",
2403 80 => "__fminx",
2404 128 => "fminq",
2405 },
2406 },
2407 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
2408 });
2409 try isel.emit(.bl(0));
2410 try call.finishCallee(isel);
2411
2412 try call.prepareParams(isel);
2413 const lhs_vi = try isel.use(bin_op.lhs);
2414 const rhs_vi = try isel.use(bin_op.rhs);
2415 switch (bits) {
2416 else => unreachable,
2417 16, 32, 64, 128 => {
2418 try call.paramLiveOut(isel, rhs_vi, .v1);
2419 try call.paramLiveOut(isel, lhs_vi, .v0);
2420 },
2421 80 => {
2422 var rhs_hi16_it = rhs_vi.field(ty, 8, 8);
2423 const rhs_hi16_vi = try rhs_hi16_it.only(isel);
2424 try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3);
2425 var rhs_lo64_it = rhs_vi.field(ty, 0, 8);
2426 const rhs_lo64_vi = try rhs_lo64_it.only(isel);
2427 try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2);
2428 var lhs_hi16_it = lhs_vi.field(ty, 8, 8);
2429 const lhs_hi16_vi = try lhs_hi16_it.only(isel);
2430 try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1);
2431 var lhs_lo64_it = lhs_vi.field(ty, 0, 8);
2432 const lhs_lo64_vi = try lhs_lo64_it.only(isel);
2433 try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0);
2434 },
2435 }
2436 try call.finishParams(isel);
2437 },
2438 }
2439 }
2440 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
2441 },
2442 .add_with_overflow, .sub_with_overflow => |air_tag| {
2443 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| {
2444 defer res_vi.value.deref(isel);
2445
2446 const ty_pl = air.data(air.inst_index).ty_pl;
2447 const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data;
2448 const ty = isel.air.typeOf(bin_op.lhs, ip);
2449 const lhs_vi = try isel.use(bin_op.lhs);
2450 const rhs_vi = try isel.use(bin_op.rhs);
2451 const ty_size = lhs_vi.size(isel);
2452 var overflow_it = res_vi.value.field(ty_pl.ty.toType(), ty_size, 1);
2453 const overflow_vi = try overflow_it.only(isel);
2454 var wrapped_it = res_vi.value.field(ty_pl.ty.toType(), 0, ty_size);
2455 const wrapped_vi = try wrapped_it.only(isel);
2456 try wrapped_vi.?.addOrSubtract(isel, ty, lhs_vi, switch (air_tag) {
2457 else => unreachable,
2458 .add_with_overflow => .add,
2459 .sub_with_overflow => .sub,
2460 }, rhs_vi, .{
2461 .overflow = if (try overflow_vi.?.defReg(isel)) |overflow_ra| .{ .ra = overflow_ra } else .wrap,
2462 });
2463 }
2464 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
2465 },
2466 .alloc, .ret_ptr => |air_tag| {
2467 if (isel.live_values.fetchRemove(air.inst_index)) |ptr_vi| unused: {
2468 defer ptr_vi.value.deref(isel);
2469 switch (air_tag) {
2470 else => unreachable,
2471 .alloc => {},
2472 .ret_ptr => if (isel.live_values.get(Block.main)) |ret_vi| switch (ret_vi.parent(isel)) {
2473 .unallocated, .stack_slot => {},
2474 .value, .constant => unreachable,
2475 .address => break :unused,
2476 },
2477 }
2478 const ptr_ra = try ptr_vi.value.defReg(isel) orelse break :unused;
2479
2480 const ty = air.data(air.inst_index).ty;
2481 const slot_size = ty.childType(zcu).abiSize(zcu);
2482 const slot_align = ty.ptrAlignment(zcu);
2483 const slot_offset = slot_align.forward(isel.stack_size);
2484 isel.stack_size = @intCast(slot_offset + slot_size);
2485 const lo12: u12 = @truncate(slot_offset >> 0);
2486 const hi12: u12 = @intCast(slot_offset >> 12);
2487 if (hi12 > 0) try isel.emit(.add(
2488 ptr_ra.x(),
2489 if (lo12 > 0) ptr_ra.x() else .sp,
2490 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
2491 ));
2492 if (lo12 > 0 or hi12 == 0) try isel.emit(.add(ptr_ra.x(), .sp, .{ .immediate = lo12 }));
2493 }
2494 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
2495 },
2496 .inferred_alloc, .inferred_alloc_comptime => unreachable,
2497 .assembly => {
2498 const ty_pl = air.data(air.inst_index).ty_pl;
2499 const extra = isel.air.extraData(Air.Asm, ty_pl.payload);
2500 var extra_index = extra.end;
2501 const outputs: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra_index..][0..extra.data.flags.outputs_len]);
2502 extra_index += outputs.len;
2503 const inputs: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra_index..][0..extra.data.inputs_len]);
2504 extra_index += inputs.len;
2505
2506 var as: codegen.aarch64.Assemble = .{
2507 .source = undefined,
2508 .operands = .empty,
2509 };
2510 defer as.operands.deinit(gpa);
2511
2512 for (outputs) |output| {
2513 const extra_bytes = std.mem.sliceAsBytes(isel.air.extra.items[extra_index..]);
2514 const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(isel.air.extra.items[extra_index..]), 0);
2515 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
2516 // This equation accounts for the fact that even if we have exactly 4 bytes
2517 // for the string, we still use the next u32 for the null terminator.
2518 extra_index += (constraint.len + name.len + (2 + 3)) / 4;
2519
2520 switch (output) {
2521 else => return isel.fail("invalid constraint: '{s}'", .{constraint}),
2522 .none => if (std.mem.startsWith(u8, constraint, "={") and std.mem.endsWith(u8, constraint, "}")) {
2523 const output_reg = Register.parse(constraint["={".len .. constraint.len - "}".len]) orelse
2524 return isel.fail("invalid constraint: '{s}'", .{constraint});
2525 const output_ra = output_reg.alias;
2526 if (isel.live_values.fetchRemove(air.inst_index)) |output_vi| {
2527 defer output_vi.value.deref(isel);
2528 try output_vi.value.defLiveIn(isel, output_reg.alias, comptime &.initFill(.free));
2529 isel.freeReg(output_ra);
2530 }
2531 if (!std.mem.eql(u8, name, "_")) {
2532 const operand_gop = try as.operands.getOrPut(gpa, name);
2533 if (operand_gop.found_existing) return isel.fail("duplicate output name: '{s}'", .{name});
2534 operand_gop.value_ptr.* = .{ .register = switch (ty_pl.ty.toType().abiSize(zcu)) {
2535 0 => unreachable,
2536 1...4 => output_ra.w(),
2537 5...8 => output_ra.x(),
2538 else => return isel.fail("too big output type: '{f}'", .{isel.fmtType(ty_pl.ty.toType())}),
2539 } };
2540 }
2541 } else if (std.mem.eql(u8, constraint, "=r")) {
2542 const output_ra = if (isel.live_values.fetchRemove(air.inst_index)) |output_vi| output_ra: {
2543 defer output_vi.value.deref(isel);
2544 break :output_ra try output_vi.value.defReg(isel) orelse try isel.allocIntReg();
2545 } else try isel.allocIntReg();
2546 if (!std.mem.eql(u8, name, "_")) {
2547 const operand_gop = try as.operands.getOrPut(gpa, name);
2548 if (operand_gop.found_existing) return isel.fail("duplicate output name: '{s}'", .{name});
2549 operand_gop.value_ptr.* = .{ .register = switch (ty_pl.ty.toType().abiSize(zcu)) {
2550 0 => unreachable,
2551 1...4 => output_ra.w(),
2552 5...8 => output_ra.x(),
2553 else => return isel.fail("too big output type: '{f}'", .{isel.fmtType(ty_pl.ty.toType())}),
2554 } };
2555 }
2556 } else return isel.fail("invalid constraint: '{s}'", .{constraint}),
2557 }
2558 }
2559
2560 const input_mats = try gpa.alloc(Value.Materialize, inputs.len);
2561 defer gpa.free(input_mats);
2562 const inputs_extra_index = extra_index;
2563 for (inputs, input_mats) |input, *input_mat| {
2564 const extra_bytes = std.mem.sliceAsBytes(isel.air.extra.items[extra_index..]);
2565 const constraint = std.mem.sliceTo(extra_bytes, 0);
2566 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
2567 // This equation accounts for the fact that even if we have exactly 4 bytes
2568 // for the string, we still use the next u32 for the null terminator.
2569 extra_index += (constraint.len + name.len + (2 + 3)) / 4;
2570
2571 if (std.mem.startsWith(u8, constraint, "{") and std.mem.endsWith(u8, constraint, "}")) {
2572 const input_reg = Register.parse(constraint["{".len .. constraint.len - "}".len]) orelse
2573 return isel.fail("invalid constraint: '{s}'", .{constraint});
2574 input_mat.* = .{ .vi = try isel.use(input), .ra = input_reg.alias };
2575 if (!std.mem.eql(u8, name, "_")) {
2576 const operand_gop = try as.operands.getOrPut(gpa, name);
2577 if (operand_gop.found_existing) return isel.fail("duplicate input name: '{s}'", .{name});
2578 const input_ty = isel.air.typeOf(input, ip);
2579 operand_gop.value_ptr.* = .{ .register = switch (input_ty.abiSize(zcu)) {
2580 0 => unreachable,
2581 1...4 => input_reg.alias.w(),
2582 5...8 => input_reg.alias.x(),
2583 else => return isel.fail("too big input type: '{f}'", .{
2584 isel.fmtType(isel.air.typeOf(input, ip)),
2585 }),
2586 } };
2587 }
2588 } else if (std.mem.eql(u8, constraint, "r")) {
2589 const input_vi = try isel.use(input);
2590 input_mat.* = try input_vi.matReg(isel);
2591 if (!std.mem.eql(u8, name, "_")) {
2592 const operand_gop = try as.operands.getOrPut(gpa, name);
2593 if (operand_gop.found_existing) return isel.fail("duplicate input name: '{s}'", .{name});
2594 operand_gop.value_ptr.* = .{ .register = switch (input_vi.size(isel)) {
2595 0 => unreachable,
2596 1...4 => input_mat.ra.w(),
2597 5...8 => input_mat.ra.x(),
2598 else => return isel.fail("too big input type: '{f}'", .{
2599 isel.fmtType(isel.air.typeOf(input, ip)),
2600 }),
2601 } };
2602 }
2603 } else if (std.mem.eql(u8, name, "_")) {
2604 input_mat.vi = try isel.use(input);
2605 } else return isel.fail("invalid constraint: '{s}'", .{constraint});
2606 }
2607
2608 const clobbers = ip.indexToKey(extra.data.clobbers).aggregate;
2609 const clobbers_ty: ZigType = .fromInterned(clobbers.ty);
2610 for (0..clobbers_ty.structFieldCount(zcu)) |field_index| {
2611 switch (switch (clobbers.storage) {
2612 .bytes => unreachable,
2613 .elems => |elems| elems[field_index],
2614 .repeated_elem => |repeated_elem| repeated_elem,
2615 }) {
2616 else => unreachable,
2617 .bool_false => continue,
2618 .bool_true => {},
2619 }
2620 const clobber_name = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?;
2621 if (std.mem.eql(u8, clobber_name, "memory")) continue;
2622 if (std.mem.eql(u8, clobber_name, "nzcv")) continue;
2623 const clobber_reg = Register.parse(clobber_name) orelse
2624 return isel.fail("unable to parse clobber: '{s}'", .{clobber_name});
2625 const live_vi = isel.live_registers.getPtr(clobber_reg.alias);
2626 switch (live_vi.*) {
2627 _ => {},
2628 .allocating => return isel.fail("clobbered twice: '{s}'", .{clobber_name}),
2629 .free => live_vi.* = .allocating,
2630 }
2631 }
2632 for (0..clobbers_ty.structFieldCount(zcu)) |field_index| {
2633 switch (switch (clobbers.storage) {
2634 .bytes => unreachable,
2635 .elems => |elems| elems[field_index],
2636 .repeated_elem => |repeated_elem| repeated_elem,
2637 }) {
2638 else => unreachable,
2639 .bool_false => continue,
2640 .bool_true => {},
2641 }
2642 const clobber_name = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?;
2643 if (std.mem.eql(u8, clobber_name, "memory")) continue;
2644 if (std.mem.eql(u8, clobber_name, "nzcv")) continue;
2645 const clobber_ra = Register.parse(clobber_name).?.alias;
2646 const live_vi = isel.live_registers.getPtr(clobber_ra);
2647 switch (live_vi.*) {
2648 _ => {
2649 if (!try isel.fill(clobber_ra))
2650 return isel.fail("unable to clobber: '{s}'", .{clobber_name});
2651 assert(live_vi.* == .free);
2652 live_vi.* = .allocating;
2653 },
2654 .allocating => {},
2655 .free => unreachable,
2656 }
2657 }
2658
2659 as.source = std.mem.sliceAsBytes(isel.air.extra.items[extra_index..])[0..extra.data.source_len :0];
2660 const asm_start = isel.instructions.items.len;
2661 while (as.nextInstruction() catch |err| switch (err) {
2662 error.InvalidSyntax => {
2663 const remaining_source = std.mem.span(as.source);
2664 return isel.fail("unable to assemble: '{s}'", .{std.mem.trim(
2665 u8,
2666 as.source[0 .. std.mem.indexOfScalar(u8, remaining_source, '\n') orelse remaining_source.len],
2667 &std.ascii.whitespace,
2668 )});
2669 },
2670 }) |instruction| try isel.emit(instruction);
2671 std.mem.reverse(codegen.aarch64.encoding.Instruction, isel.instructions.items[asm_start..]);
2672
2673 extra_index = inputs_extra_index;
2674 for (input_mats) |input_mat| {
2675 const extra_bytes = std.mem.sliceAsBytes(isel.air.extra.items[extra_index..]);
2676 const constraint = std.mem.sliceTo(extra_bytes, 0);
2677 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
2678 // This equation accounts for the fact that even if we have exactly 4 bytes
2679 // for the string, we still use the next u32 for the null terminator.
2680 extra_index += (constraint.len + name.len + (2 + 3)) / 4;
2681
2682 if (std.mem.startsWith(u8, constraint, "{") and std.mem.endsWith(u8, constraint, "}")) {
2683 try input_mat.vi.liveOut(isel, input_mat.ra);
2684 } else if (std.mem.eql(u8, constraint, "r")) {
2685 try input_mat.finish(isel);
2686 } else if (std.mem.eql(u8, name, "_")) {
2687 try input_mat.vi.mat(isel);
2688 } else unreachable;
2689 }
2690
2691 for (0..clobbers_ty.structFieldCount(zcu)) |field_index| {
2692 switch (switch (clobbers.storage) {
2693 .bytes => unreachable,
2694 .elems => |elems| elems[field_index],
2695 .repeated_elem => |repeated_elem| repeated_elem,
2696 }) {
2697 else => unreachable,
2698 .bool_false => continue,
2699 .bool_true => {},
2700 }
2701 const clobber_name = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?;
2702 if (std.mem.eql(u8, clobber_name, "memory")) continue;
2703 if (std.mem.eql(u8, clobber_name, "cc")) continue;
2704 isel.freeReg(Register.parse(clobber_name).?.alias);
2705 }
2706
2707 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
2708 },
2709 .bit_and, .bit_or, .xor, .bool_and, .bool_or => |air_tag| {
2710 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| {
2711 defer res_vi.value.deref(isel);
2712
2713 const bin_op = air.data(air.inst_index).bin_op;
2714 const ty = isel.air.typeOf(bin_op.lhs, ip);
2715 const int_info: std.builtin.Type.Int = if (ty.toIntern() == .bool_type)
2716 .{ .signedness = .unsigned, .bits = 1 }
2717 else if (ty.isAbiInt(zcu))
2718 ty.intInfo(zcu)
2719 else
2720 return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
2721 if (int_info.bits > 128) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
2722
2723 const lhs_vi = try isel.use(bin_op.lhs);
2724 const rhs_vi = try isel.use(bin_op.rhs);
2725 var offset = res_vi.value.size(isel);
2726 while (offset > 0) {
2727 const size = @min(offset, 8);
2728 offset -= size;
2729 var res_part_it = res_vi.value.field(ty, offset, size);
2730 const res_part_vi = try res_part_it.only(isel);
2731 const res_part_ra = try res_part_vi.?.defReg(isel) orelse continue;
2732 var lhs_part_it = lhs_vi.field(ty, offset, size);
2733 const lhs_part_vi = try lhs_part_it.only(isel);
2734 const lhs_part_mat = try lhs_part_vi.?.matReg(isel);
2735 var rhs_part_it = rhs_vi.field(ty, offset, size);
2736 const rhs_part_vi = try rhs_part_it.only(isel);
2737 const rhs_part_mat = try rhs_part_vi.?.matReg(isel);
2738 try isel.emit(switch (air_tag) {
2739 else => unreachable,
2740 .bit_and, .bool_and => switch (size) {
2741 else => unreachable,
2742 1, 2, 4 => .@"and"(res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }),
2743 8 => .@"and"(res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }),
2744 },
2745 .bit_or, .bool_or => switch (size) {
2746 else => unreachable,
2747 1, 2, 4 => .orr(res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }),
2748 8 => .orr(res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }),
2749 },
2750 .xor => switch (size) {
2751 else => unreachable,
2752 1, 2, 4 => .eor(res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }),
2753 8 => .eor(res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }),
2754 },
2755 });
2756 try rhs_part_mat.finish(isel);
2757 try lhs_part_mat.finish(isel);
2758 }
2759 }
2760 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
2761 },
2762 .shr, .shr_exact, .shl, .shl_exact => |air_tag| {
2763 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
2764 defer res_vi.value.deref(isel);
2765
2766 const bin_op = air.data(air.inst_index).bin_op;
2767 const ty = isel.air.typeOf(bin_op.lhs, ip);
2768 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
2769 const int_info = ty.intInfo(zcu);
2770 switch (int_info.bits) {
2771 0 => unreachable,
2772 1...64 => |bits| {
2773 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
2774 switch (air_tag) {
2775 else => unreachable,
2776 .shr, .shr_exact, .shl_exact => {},
2777 .shl => switch (bits) {
2778 else => unreachable,
2779 1...31 => try isel.emit(switch (int_info.signedness) {
2780 .signed => .sbfm(res_ra.w(), res_ra.w(), .{
2781 .N = .word,
2782 .immr = 0,
2783 .imms = @intCast(bits - 1),
2784 }),
2785 .unsigned => .ubfm(res_ra.w(), res_ra.w(), .{
2786 .N = .word,
2787 .immr = 0,
2788 .imms = @intCast(bits - 1),
2789 }),
2790 }),
2791 32 => {},
2792 33...63 => try isel.emit(switch (int_info.signedness) {
2793 .signed => .sbfm(res_ra.x(), res_ra.x(), .{
2794 .N = .doubleword,
2795 .immr = 0,
2796 .imms = @intCast(bits - 1),
2797 }),
2798 .unsigned => .ubfm(res_ra.x(), res_ra.x(), .{
2799 .N = .doubleword,
2800 .immr = 0,
2801 .imms = @intCast(bits - 1),
2802 }),
2803 }),
2804 64 => {},
2805 },
2806 }
2807
2808 const lhs_vi = try isel.use(bin_op.lhs);
2809 const rhs_vi = try isel.use(bin_op.rhs);
2810 const lhs_mat = try lhs_vi.matReg(isel);
2811 const rhs_mat = try rhs_vi.matReg(isel);
2812 try isel.emit(switch (air_tag) {
2813 else => unreachable,
2814 .shr, .shr_exact => switch (bits) {
2815 else => unreachable,
2816 1...32 => switch (int_info.signedness) {
2817 .signed => .asrv(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()),
2818 .unsigned => .lsrv(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()),
2819 },
2820 33...64 => switch (int_info.signedness) {
2821 .signed => .asrv(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()),
2822 .unsigned => .lsrv(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()),
2823 },
2824 },
2825 .shl, .shl_exact => switch (bits) {
2826 else => unreachable,
2827 1...32 => .lslv(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()),
2828 33...64 => .lslv(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()),
2829 },
2830 });
2831 try rhs_mat.finish(isel);
2832 try lhs_mat.finish(isel);
2833 },
2834 65...128 => |bits| {
2835 var res_hi64_it = res_vi.value.field(ty, 8, 8);
2836 const res_hi64_vi = try res_hi64_it.only(isel);
2837 const res_hi64_ra = try res_hi64_vi.?.defReg(isel);
2838 var res_lo64_it = res_vi.value.field(ty, 0, 8);
2839 const res_lo64_vi = try res_lo64_it.only(isel);
2840 const res_lo64_ra = try res_lo64_vi.?.defReg(isel);
2841 if (res_hi64_ra == null and res_lo64_ra == null) break :unused;
2842 if (res_hi64_ra) |res_ra| switch (air_tag) {
2843 else => unreachable,
2844 .shr, .shr_exact, .shl_exact => {},
2845 .shl => switch (bits) {
2846 else => unreachable,
2847 65...127 => try isel.emit(switch (int_info.signedness) {
2848 .signed => .sbfm(res_ra.x(), res_ra.x(), .{
2849 .N = .doubleword,
2850 .immr = 0,
2851 .imms = @intCast(bits - 64 - 1),
2852 }),
2853 .unsigned => .ubfm(res_ra.x(), res_ra.x(), .{
2854 .N = .doubleword,
2855 .immr = 0,
2856 .imms = @intCast(bits - 64 - 1),
2857 }),
2858 }),
2859 128 => {},
2860 },
2861 };
2862
2863 const lhs_vi = try isel.use(bin_op.lhs);
2864 const lhs_hi64_mat = lhs_hi64_mat: {
2865 const res_lock: RegLock = switch (air_tag) {
2866 else => unreachable,
2867 .shr, .shr_exact => switch (int_info.signedness) {
2868 .signed => if (res_lo64_ra) |res_ra| isel.lockReg(res_ra) else .empty,
2869 .unsigned => .empty,
2870 },
2871 .shl, .shl_exact => .empty,
2872 };
2873 defer res_lock.unlock(isel);
2874 var lhs_hi64_it = lhs_vi.field(ty, 8, 8);
2875 const lhs_hi64_vi = try lhs_hi64_it.only(isel);
2876 break :lhs_hi64_mat try lhs_hi64_vi.?.matReg(isel);
2877 };
2878 var lhs_lo64_it = lhs_vi.field(ty, 0, 8);
2879 const lhs_lo64_vi = try lhs_lo64_it.only(isel);
2880 const lhs_lo64_mat = try lhs_lo64_vi.?.matReg(isel);
2881 const rhs_vi = try isel.use(bin_op.rhs);
2882 const rhs_mat = try rhs_vi.matReg(isel);
2883 const lo64_ra = lo64_ra: {
2884 const res_lock: RegLock = switch (air_tag) {
2885 else => unreachable,
2886 .shr, .shr_exact => switch (int_info.signedness) {
2887 .signed => if (res_lo64_ra) |res_ra| isel.tryLockReg(res_ra) else .empty,
2888 .unsigned => .empty,
2889 },
2890 .shl, .shl_exact => if (res_hi64_ra) |res_ra| isel.tryLockReg(res_ra) else .empty,
2891 };
2892 defer res_lock.unlock(isel);
2893 break :lo64_ra try isel.allocIntReg();
2894 };
2895 defer isel.freeReg(lo64_ra);
2896 const hi64_ra = hi64_ra: {
2897 const res_lock: RegLock = switch (air_tag) {
2898 else => unreachable,
2899 .shr, .shr_exact => if (res_lo64_ra) |res_ra| isel.tryLockReg(res_ra) else .empty,
2900 .shl, .shl_exact => .empty,
2901 };
2902 defer res_lock.unlock(isel);
2903 break :hi64_ra try isel.allocIntReg();
2904 };
2905 defer isel.freeReg(hi64_ra);
2906 switch (air_tag) {
2907 else => unreachable,
2908 .shr, .shr_exact => {
2909 if (res_hi64_ra) |res_ra| switch (int_info.signedness) {
2910 .signed => {
2911 try isel.emit(.csel(res_ra.x(), hi64_ra.x(), lo64_ra.x(), .eq));
2912 try isel.emit(.sbfm(lo64_ra.x(), lhs_hi64_mat.ra.x(), .{
2913 .N = .doubleword,
2914 .immr = @intCast(bits - 64 - 1),
2915 .imms = @intCast(bits - 64 - 1),
2916 }));
2917 },
2918 .unsigned => try isel.emit(.csel(res_ra.x(), hi64_ra.x(), .xzr, .eq)),
2919 };
2920 if (res_lo64_ra) |res_ra| try isel.emit(.csel(res_ra.x(), lo64_ra.x(), hi64_ra.x(), .eq));
2921 switch (int_info.signedness) {
2922 .signed => try isel.emit(.asrv(hi64_ra.x(), lhs_hi64_mat.ra.x(), rhs_mat.ra.x())),
2923 .unsigned => try isel.emit(.lsrv(hi64_ra.x(), lhs_hi64_mat.ra.x(), rhs_mat.ra.x())),
2924 }
2925 },
2926 .shl, .shl_exact => {
2927 if (res_lo64_ra) |res_ra| try isel.emit(.csel(res_ra.x(), lo64_ra.x(), .xzr, .eq));
2928 if (res_hi64_ra) |res_ra| try isel.emit(.csel(res_ra.x(), hi64_ra.x(), lo64_ra.x(), .eq));
2929 try isel.emit(.lslv(lo64_ra.x(), lhs_lo64_mat.ra.x(), rhs_mat.ra.x()));
2930 },
2931 }
2932 try isel.emit(.ands(.wzr, rhs_mat.ra.w(), .{ .immediate = .{ .N = .word, .immr = 32 - 6, .imms = 0 } }));
2933 switch (air_tag) {
2934 else => unreachable,
2935 .shr, .shr_exact => if (res_lo64_ra) |_| {
2936 try isel.emit(.orr(
2937 lo64_ra.x(),
2938 lo64_ra.x(),
2939 .{ .shifted_register = .{ .register = hi64_ra.x(), .shift = .{ .lsl = 1 } } },
2940 ));
2941 try isel.emit(.lslv(hi64_ra.x(), lhs_hi64_mat.ra.x(), hi64_ra.x()));
2942 try isel.emit(.lsrv(lo64_ra.x(), lhs_lo64_mat.ra.x(), rhs_mat.ra.x()));
2943 try isel.emit(.orn(hi64_ra.w(), .wzr, .{ .register = rhs_mat.ra.w() }));
2944 },
2945 .shl, .shl_exact => if (res_hi64_ra) |_| {
2946 try isel.emit(.orr(
2947 hi64_ra.x(),
2948 hi64_ra.x(),
2949 .{ .shifted_register = .{ .register = lo64_ra.x(), .shift = .{ .lsr = 1 } } },
2950 ));
2951 try isel.emit(.lsrv(lo64_ra.x(), lhs_lo64_mat.ra.x(), lo64_ra.x()));
2952 try isel.emit(.lslv(hi64_ra.x(), lhs_hi64_mat.ra.x(), rhs_mat.ra.x()));
2953 try isel.emit(.orn(lo64_ra.w(), .wzr, .{ .register = rhs_mat.ra.w() }));
2954 },
2955 }
2956 try rhs_mat.finish(isel);
2957 try lhs_lo64_mat.finish(isel);
2958 try lhs_hi64_mat.finish(isel);
2959 break :unused;
2960 },
2961 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
2962 }
2963 }
2964 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
2965 },
2966 .not => |air_tag| {
2967 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| {
2968 defer res_vi.value.deref(isel);
2969
2970 const ty_op = air.data(air.inst_index).ty_op;
2971 const ty = ty_op.ty.toType();
2972 const int_info: std.builtin.Type.Int = int_info: {
2973 if (ty_op.ty == .bool_type) break :int_info .{ .signedness = .unsigned, .bits = 1 };
2974 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
2975 break :int_info ty.intInfo(zcu);
2976 };
2977 if (int_info.bits > 128) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
2978
2979 const src_vi = try isel.use(ty_op.operand);
2980 var offset = res_vi.value.size(isel);
2981 while (offset > 0) {
2982 const size = @min(offset, 8);
2983 offset -= size;
2984 var res_part_it = res_vi.value.field(ty, offset, size);
2985 const res_part_vi = try res_part_it.only(isel);
2986 const res_part_ra = try res_part_vi.?.defReg(isel) orelse continue;
2987 var src_part_it = src_vi.field(ty, offset, size);
2988 const src_part_vi = try src_part_it.only(isel);
2989 const src_part_mat = try src_part_vi.?.matReg(isel);
2990 try isel.emit(switch (int_info.signedness) {
2991 .signed => switch (size) {
2992 else => unreachable,
2993 1, 2, 4 => .orn(res_part_ra.w(), .wzr, .{ .register = src_part_mat.ra.w() }),
2994 8 => .orn(res_part_ra.x(), .xzr, .{ .register = src_part_mat.ra.x() }),
2995 },
2996 .unsigned => switch (@min(int_info.bits - 8 * offset, 64)) {
2997 else => unreachable,
2998 1...31 => |bits| .eor(res_part_ra.w(), src_part_mat.ra.w(), .{ .immediate = .{
2999 .N = .word,
3000 .immr = 0,
3001 .imms = @intCast(bits - 1),
3002 } }),
3003 32 => .orn(res_part_ra.w(), .wzr, .{ .register = src_part_mat.ra.w() }),
3004 33...63 => |bits| .eor(res_part_ra.x(), src_part_mat.ra.x(), .{ .immediate = .{
3005 .N = .doubleword,
3006 .immr = 0,
3007 .imms = @intCast(bits - 1),
3008 } }),
3009 64 => .orn(res_part_ra.x(), .xzr, .{ .register = src_part_mat.ra.x() }),
3010 },
3011 });
3012 try src_part_mat.finish(isel);
3013 }
3014 }
3015 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3016 },
3017 .bitcast => |air_tag| {
3018 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
3019 defer dst_vi.value.deref(isel);
3020 const ty_op = air.data(air.inst_index).ty_op;
3021 const dst_ty = ty_op.ty.toType();
3022 const dst_tag = dst_ty.zigTypeTag(zcu);
3023 const src_ty = isel.air.typeOf(ty_op.operand, ip);
3024 const src_tag = src_ty.zigTypeTag(zcu);
3025 if (dst_ty.isAbiInt(zcu) and (src_tag == .bool or src_ty.isAbiInt(zcu))) {
3026 const dst_int_info = dst_ty.intInfo(zcu);
3027 const src_int_info: std.builtin.Type.Int = if (src_tag == .bool) .{ .signedness = undefined, .bits = 1 } else src_ty.intInfo(zcu);
3028 assert(dst_int_info.bits == src_int_info.bits);
3029 if (dst_tag != .@"struct" and src_tag != .@"struct" and src_tag != .bool and dst_int_info.signedness == src_int_info.signedness) {
3030 try dst_vi.value.move(isel, ty_op.operand);
3031 } else switch (dst_int_info.bits) {
3032 0 => unreachable,
3033 1...31 => |dst_bits| {
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(switch (dst_int_info.signedness) {
3038 .signed => .sbfm(dst_ra.w(), src_mat.ra.w(), .{
3039 .N = .word,
3040 .immr = 0,
3041 .imms = @intCast(dst_bits - 1),
3042 }),
3043 .unsigned => .ubfm(dst_ra.w(), src_mat.ra.w(), .{
3044 .N = .word,
3045 .immr = 0,
3046 .imms = @intCast(dst_bits - 1),
3047 }),
3048 });
3049 try src_mat.finish(isel);
3050 },
3051 32 => try dst_vi.value.move(isel, ty_op.operand),
3052 33...63 => |dst_bits| {
3053 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
3054 const src_vi = try isel.use(ty_op.operand);
3055 const src_mat = try src_vi.matReg(isel);
3056 try isel.emit(switch (dst_int_info.signedness) {
3057 .signed => .sbfm(dst_ra.x(), src_mat.ra.x(), .{
3058 .N = .doubleword,
3059 .immr = 0,
3060 .imms = @intCast(dst_bits - 1),
3061 }),
3062 .unsigned => .ubfm(dst_ra.x(), src_mat.ra.x(), .{
3063 .N = .doubleword,
3064 .immr = 0,
3065 .imms = @intCast(dst_bits - 1),
3066 }),
3067 });
3068 try src_mat.finish(isel);
3069 },
3070 64 => try dst_vi.value.move(isel, ty_op.operand),
3071 65...127 => |dst_bits| {
3072 const src_vi = try isel.use(ty_op.operand);
3073 var dst_hi64_it = dst_vi.value.field(dst_ty, 8, 8);
3074 const dst_hi64_vi = try dst_hi64_it.only(isel);
3075 if (try dst_hi64_vi.?.defReg(isel)) |dst_hi64_ra| {
3076 var src_hi64_it = src_vi.field(src_ty, 8, 8);
3077 const src_hi64_vi = try src_hi64_it.only(isel);
3078 const src_hi64_mat = try src_hi64_vi.?.matReg(isel);
3079 try isel.emit(switch (dst_int_info.signedness) {
3080 .signed => .sbfm(dst_hi64_ra.x(), src_hi64_mat.ra.x(), .{
3081 .N = .doubleword,
3082 .immr = 0,
3083 .imms = @intCast(dst_bits - 64 - 1),
3084 }),
3085 .unsigned => .ubfm(dst_hi64_ra.x(), src_hi64_mat.ra.x(), .{
3086 .N = .doubleword,
3087 .immr = 0,
3088 .imms = @intCast(dst_bits - 64 - 1),
3089 }),
3090 });
3091 try src_hi64_mat.finish(isel);
3092 }
3093 var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8);
3094 const dst_lo64_vi = try dst_lo64_it.only(isel);
3095 if (try dst_lo64_vi.?.defReg(isel)) |dst_lo64_ra| {
3096 var src_lo64_it = src_vi.field(src_ty, 0, 8);
3097 const src_lo64_vi = try src_lo64_it.only(isel);
3098 try src_lo64_vi.?.liveOut(isel, dst_lo64_ra);
3099 }
3100 },
3101 128 => try dst_vi.value.move(isel, ty_op.operand),
3102 else => return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }),
3103 }
3104 } else if ((dst_ty.isPtrAtRuntime(zcu) or dst_ty.isAbiInt(zcu)) and (src_ty.isPtrAtRuntime(zcu) or src_ty.isAbiInt(zcu))) {
3105 try dst_vi.value.move(isel, ty_op.operand);
3106 } else if (dst_ty.isSliceAtRuntime(zcu) and src_ty.isSliceAtRuntime(zcu)) {
3107 try dst_vi.value.move(isel, ty_op.operand);
3108 } else if (dst_tag == .error_union and src_tag == .error_union) {
3109 assert(dst_ty.errorUnionSet(zcu).hasRuntimeBitsIgnoreComptime(zcu) ==
3110 src_ty.errorUnionSet(zcu).hasRuntimeBitsIgnoreComptime(zcu));
3111 if (dst_ty.errorUnionPayload(zcu).toIntern() == src_ty.errorUnionPayload(zcu).toIntern()) {
3112 try dst_vi.value.move(isel, ty_op.operand);
3113 } else return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });
3114 } else if (dst_tag == .float and src_tag == .float) {
3115 assert(dst_ty.floatBits(isel.target) == src_ty.floatBits(isel.target));
3116 try dst_vi.value.move(isel, ty_op.operand);
3117 } else if (dst_ty.isAbiInt(zcu) and src_tag == .float) {
3118 const dst_int_info = dst_ty.intInfo(zcu);
3119 assert(dst_int_info.bits == src_ty.floatBits(isel.target));
3120 switch (dst_int_info.bits) {
3121 else => unreachable,
3122 16 => {
3123 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
3124 const src_vi = try isel.use(ty_op.operand);
3125 const src_mat = try src_vi.matReg(isel);
3126 switch (dst_int_info.signedness) {
3127 .signed => try isel.emit(.smov(dst_ra.w(), src_mat.ra.@"h[]"(0))),
3128 .unsigned => try isel.emit(if (isel.target.cpu.has(.aarch64, .fullfp16))
3129 .fmov(dst_ra.w(), .{ .register = src_mat.ra.h() })
3130 else
3131 .umov(dst_ra.w(), src_mat.ra.@"h[]"(0))),
3132 }
3133 try src_mat.finish(isel);
3134 },
3135 32 => {
3136 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
3137 const src_vi = try isel.use(ty_op.operand);
3138 const src_mat = try src_vi.matReg(isel);
3139 try isel.emit(.fmov(dst_ra.w(), .{ .register = src_mat.ra.s() }));
3140 try src_mat.finish(isel);
3141 },
3142 64 => {
3143 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
3144 const src_vi = try isel.use(ty_op.operand);
3145 const src_mat = try src_vi.matReg(isel);
3146 try isel.emit(.fmov(dst_ra.x(), .{ .register = src_mat.ra.d() }));
3147 try src_mat.finish(isel);
3148 },
3149 80 => switch (dst_int_info.signedness) {
3150 .signed => {
3151 const src_vi = try isel.use(ty_op.operand);
3152 var dst_hi16_it = dst_vi.value.field(dst_ty, 8, 8);
3153 const dst_hi16_vi = try dst_hi16_it.only(isel);
3154 if (try dst_hi16_vi.?.defReg(isel)) |dst_hi16_ra| {
3155 var src_hi16_it = src_vi.field(src_ty, 8, 8);
3156 const src_hi16_vi = try src_hi16_it.only(isel);
3157 const src_hi16_mat = try src_hi16_vi.?.matReg(isel);
3158 try isel.emit(.sbfm(dst_hi16_ra.x(), src_hi16_mat.ra.x(), .{
3159 .N = .doubleword,
3160 .immr = 0,
3161 .imms = 16 - 1,
3162 }));
3163 try src_hi16_mat.finish(isel);
3164 }
3165 var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8);
3166 const dst_lo64_vi = try dst_lo64_it.only(isel);
3167 if (try dst_lo64_vi.?.defReg(isel)) |dst_lo64_ra| {
3168 var src_lo64_it = src_vi.field(src_ty, 0, 8);
3169 const src_lo64_vi = try src_lo64_it.only(isel);
3170 try src_lo64_vi.?.liveOut(isel, dst_lo64_ra);
3171 }
3172 },
3173 else => try dst_vi.value.move(isel, ty_op.operand),
3174 },
3175 128 => {
3176 const src_vi = try isel.use(ty_op.operand);
3177 const src_mat = try src_vi.matReg(isel);
3178 var dst_hi64_it = dst_vi.value.field(dst_ty, 8, 8);
3179 const dst_hi64_vi = try dst_hi64_it.only(isel);
3180 if (try dst_hi64_vi.?.defReg(isel)) |dst_hi64_ra| try isel.emit(.fmov(dst_hi64_ra.x(), .{ .register = src_mat.ra.@"d[]"(1) }));
3181 var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8);
3182 const dst_lo64_vi = try dst_lo64_it.only(isel);
3183 if (try dst_lo64_vi.?.defReg(isel)) |dst_lo64_ra| try isel.emit(.fmov(dst_lo64_ra.x(), .{ .register = src_mat.ra.d() }));
3184 try src_mat.finish(isel);
3185 },
3186 }
3187 } else if (dst_tag == .float and src_ty.isAbiInt(zcu)) {
3188 const src_int_info = src_ty.intInfo(zcu);
3189 assert(dst_ty.floatBits(isel.target) == src_int_info.bits);
3190 switch (src_int_info.bits) {
3191 else => unreachable,
3192 16 => {
3193 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
3194 const src_vi = try isel.use(ty_op.operand);
3195 const src_mat = try src_vi.matReg(isel);
3196 try isel.emit(.fmov(
3197 if (isel.target.cpu.has(.aarch64, .fullfp16)) dst_ra.h() else dst_ra.s(),
3198 .{ .register = src_mat.ra.w() },
3199 ));
3200 try src_mat.finish(isel);
3201 },
3202 32 => {
3203 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
3204 const src_vi = try isel.use(ty_op.operand);
3205 const src_mat = try src_vi.matReg(isel);
3206 try isel.emit(.fmov(dst_ra.s(), .{ .register = src_mat.ra.w() }));
3207 try src_mat.finish(isel);
3208 },
3209 64 => {
3210 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
3211 const src_vi = try isel.use(ty_op.operand);
3212 const src_mat = try src_vi.matReg(isel);
3213 try isel.emit(.fmov(dst_ra.d(), .{ .register = src_mat.ra.x() }));
3214 try src_mat.finish(isel);
3215 },
3216 80 => switch (src_int_info.signedness) {
3217 .signed => {
3218 const src_vi = try isel.use(ty_op.operand);
3219 var dst_hi16_it = dst_vi.value.field(dst_ty, 8, 8);
3220 const dst_hi16_vi = try dst_hi16_it.only(isel);
3221 if (try dst_hi16_vi.?.defReg(isel)) |dst_hi16_ra| {
3222 var src_hi16_it = src_vi.field(src_ty, 8, 8);
3223 const src_hi16_vi = try src_hi16_it.only(isel);
3224 const src_hi16_mat = try src_hi16_vi.?.matReg(isel);
3225 try isel.emit(.ubfm(dst_hi16_ra.x(), src_hi16_mat.ra.x(), .{
3226 .N = .doubleword,
3227 .immr = 0,
3228 .imms = 16 - 1,
3229 }));
3230 try src_hi16_mat.finish(isel);
3231 }
3232 var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8);
3233 const dst_lo64_vi = try dst_lo64_it.only(isel);
3234 if (try dst_lo64_vi.?.defReg(isel)) |dst_lo64_ra| {
3235 var src_lo64_it = src_vi.field(src_ty, 0, 8);
3236 const src_lo64_vi = try src_lo64_it.only(isel);
3237 try src_lo64_vi.?.liveOut(isel, dst_lo64_ra);
3238 }
3239 },
3240 else => try dst_vi.value.move(isel, ty_op.operand),
3241 },
3242 128 => {
3243 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
3244 const src_vi = try isel.use(ty_op.operand);
3245 var src_hi64_it = src_vi.field(src_ty, 8, 8);
3246 const src_hi64_vi = try src_hi64_it.only(isel);
3247 const src_hi64_mat = try src_hi64_vi.?.matReg(isel);
3248 try isel.emit(.fmov(dst_ra.@"d[]"(1), .{ .register = src_hi64_mat.ra.x() }));
3249 try src_hi64_mat.finish(isel);
3250 var src_lo64_it = src_vi.field(src_ty, 0, 8);
3251 const src_lo64_vi = try src_lo64_it.only(isel);
3252 const src_lo64_mat = try src_lo64_vi.?.matReg(isel);
3253 try isel.emit(.fmov(dst_ra.d(), .{ .register = src_lo64_mat.ra.x() }));
3254 try src_lo64_mat.finish(isel);
3255 },
3256 }
3257 } else if (dst_ty.isAbiInt(zcu) and src_tag == .array and src_ty.childType(zcu).isAbiInt(zcu)) {
3258 const dst_int_info = dst_ty.intInfo(zcu);
3259 const src_child_int_info = src_ty.childType(zcu).intInfo(zcu);
3260 const src_len = src_ty.arrayLenIncludingSentinel(zcu);
3261 assert(dst_int_info.bits == src_child_int_info.bits * src_len);
3262 const src_child_size = src_ty.childType(zcu).abiSize(zcu);
3263 if (8 * src_child_size == src_child_int_info.bits) {
3264 try dst_vi.value.defAddr(isel, dst_ty, dst_int_info, comptime &.initFill(.free)) orelse break :unused;
3265
3266 try call.prepareReturn(isel);
3267 try call.finishReturn(isel);
3268
3269 try call.prepareCallee(isel);
3270 try isel.global_relocs.append(gpa, .{
3271 .name = "memcpy",
3272 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
3273 });
3274 try isel.emit(.bl(0));
3275 try call.finishCallee(isel);
3276
3277 try call.prepareParams(isel);
3278 const src_vi = try isel.use(ty_op.operand);
3279 try isel.movImmediate(.x2, src_child_size * src_len);
3280 try call.paramAddress(isel, src_vi, .r1);
3281 try call.paramAddress(isel, dst_vi.value, .r0);
3282 try call.finishParams(isel);
3283 } else return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });
3284 } else if (dst_tag == .array and dst_ty.childType(zcu).isAbiInt(zcu) and src_ty.isAbiInt(zcu)) {
3285 const dst_child_int_info = dst_ty.childType(zcu).intInfo(zcu);
3286 const src_int_info = src_ty.intInfo(zcu);
3287 const dst_len = dst_ty.arrayLenIncludingSentinel(zcu);
3288 assert(dst_child_int_info.bits * dst_len == src_int_info.bits);
3289 const dst_child_size = dst_ty.childType(zcu).abiSize(zcu);
3290 if (8 * dst_child_size == dst_child_int_info.bits) {
3291 try dst_vi.value.defAddr(isel, dst_ty, null, comptime &.initFill(.free)) orelse break :unused;
3292
3293 try call.prepareReturn(isel);
3294 try call.finishReturn(isel);
3295
3296 try call.prepareCallee(isel);
3297 try isel.global_relocs.append(gpa, .{
3298 .name = "memcpy",
3299 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
3300 });
3301 try isel.emit(.bl(0));
3302 try call.finishCallee(isel);
3303
3304 try call.prepareParams(isel);
3305 const src_vi = try isel.use(ty_op.operand);
3306 try isel.movImmediate(.x2, dst_child_size * dst_len);
3307 try call.paramAddress(isel, src_vi, .r1);
3308 try call.paramAddress(isel, dst_vi.value, .r0);
3309 try call.finishParams(isel);
3310 } else return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });
3311 } else return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });
3312 }
3313 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3314 },
3315 .block => {
3316 const ty_pl = air.data(air.inst_index).ty_pl;
3317 const extra = isel.air.extraData(Air.Block, ty_pl.payload);
3318 try isel.block(air.inst_index, ty_pl.ty.toType(), @ptrCast(
3319 isel.air.extra.items[extra.end..][0..extra.data.body_len],
3320 ));
3321 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3322 },
3323 .loop => {
3324 const ty_pl = air.data(air.inst_index).ty_pl;
3325 const extra = isel.air.extraData(Air.Block, ty_pl.payload);
3326 const loops = isel.loops.values();
3327 const loop_index = isel.loops.getIndex(air.inst_index).?;
3328 const loop = &loops[loop_index];
3329
3330 tracking_log.debug("{f}", .{
3331 isel.fmtDom(air.inst_index, loop.dom, @intCast(isel.blocks.count())),
3332 });
3333 tracking_log.debug("{f}", .{isel.fmtLoopLive(air.inst_index)});
3334 assert(loop.depth == isel.blocks.count());
3335
3336 if (false) {
3337 // loops are dumb...
3338 for (isel.loop_live.list.items[loop.live..loops[loop_index + 1].live]) |live_inst| {
3339 const live_vi = try isel.use(live_inst.toRef());
3340 try live_vi.mat(isel);
3341 }
3342
3343 // IT'S DOM TIME!!!
3344 for (isel.blocks.values(), 0..) |*dom_block, dom_index| {
3345 if (@as(u1, @truncate(isel.dom.items[
3346 loop.dom + dom_index / @bitSizeOf(DomInt)
3347 ] >> @truncate(dom_index))) == 0) continue;
3348 var live_reg_it = dom_block.live_registers.iterator();
3349 while (live_reg_it.next()) |live_reg_entry| switch (live_reg_entry.value.*) {
3350 _ => |live_vi| try live_vi.mat(isel),
3351 .allocating => unreachable,
3352 .free => {},
3353 };
3354 }
3355 }
3356
3357 loop.live_registers = isel.live_registers;
3358 loop.repeat_list = Loop.empty_list;
3359 try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));
3360 try isel.merge(&loop.live_registers, .{ .fill_extra = true });
3361
3362 var repeat_label = loop.repeat_list;
3363 assert(repeat_label != Loop.empty_list);
3364 while (repeat_label != Loop.empty_list) {
3365 const instruction = &isel.instructions.items[repeat_label];
3366 const next_repeat_label = instruction.*;
3367 instruction.* = .b(-@as(i28, @intCast((isel.instructions.items.len - 1 - repeat_label) << 2)));
3368 repeat_label = @bitCast(next_repeat_label);
3369 }
3370
3371 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3372 },
3373 .repeat => {
3374 const repeat = air.data(air.inst_index).repeat;
3375 try isel.loops.getPtr(repeat.loop_inst).?.branch(isel);
3376 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3377 },
3378 .br => {
3379 const br = air.data(air.inst_index).br;
3380 try isel.blocks.getPtr(br.block_inst).?.branch(isel);
3381 if (isel.live_values.get(br.block_inst)) |dst_vi| try dst_vi.move(isel, br.operand);
3382 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3383 },
3384 .trap => {
3385 try isel.emit(.brk(0x1));
3386 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3387 },
3388 .breakpoint => {
3389 try isel.emit(.brk(0xf000));
3390 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3391 },
3392 .ret_addr => {
3393 if (isel.live_values.fetchRemove(air.inst_index)) |addr_vi| unused: {
3394 defer addr_vi.value.deref(isel);
3395 const addr_ra = try addr_vi.value.defReg(isel) orelse break :unused;
3396 try isel.emit(.ldr(addr_ra.x(), .{ .unsigned_offset = .{ .base = .fp, .offset = 8 } }));
3397 }
3398 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3399 },
3400 .frame_addr => {
3401 if (isel.live_values.fetchRemove(air.inst_index)) |addr_vi| unused: {
3402 defer addr_vi.value.deref(isel);
3403 const addr_ra = try addr_vi.value.defReg(isel) orelse break :unused;
3404 try isel.emit(.orr(addr_ra.x(), .xzr, .{ .register = .fp }));
3405 }
3406 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3407 },
3408 .call => {
3409 const pl_op = air.data(air.inst_index).pl_op;
3410 const extra = isel.air.extraData(Air.Call, pl_op.payload);
3411 const args: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0..extra.data.args_len]);
3412 const callee_ty = isel.air.typeOf(pl_op.operand, ip);
3413 const func_info = switch (ip.indexToKey(callee_ty.toIntern())) {
3414 else => unreachable,
3415 .func_type => |func_type| func_type,
3416 .ptr_type => |ptr_type| ip.indexToKey(ptr_type.child).func_type,
3417 };
3418
3419 try call.prepareReturn(isel);
3420 const maybe_def_ret_vi = isel.live_values.fetchRemove(air.inst_index);
3421 var maybe_ret_addr_vi: ?Value.Index = null;
3422 if (maybe_def_ret_vi) |def_ret_vi| {
3423 defer def_ret_vi.value.deref(isel);
3424
3425 var ret_it: CallAbiIterator = .init;
3426 const ret_vi = try ret_it.ret(isel, isel.air.typeOfIndex(air.inst_index, ip));
3427 defer ret_vi.?.deref(isel);
3428 switch (ret_vi.?.parent(isel)) {
3429 .unallocated, .stack_slot => if (ret_vi.?.hint(isel)) |ret_ra| {
3430 try call.returnLiveIn(isel, def_ret_vi.value, ret_ra);
3431 } else {
3432 var def_ret_part_it = def_ret_vi.value.parts(isel);
3433 var ret_part_it = ret_vi.?.parts(isel);
3434 while (def_ret_part_it.next()) |ret_part_vi| {
3435 try call.returnLiveIn(isel, ret_part_vi, ret_part_it.next().?.hint(isel).?);
3436 }
3437 },
3438 .value, .constant => unreachable,
3439 .address => |address_vi| {
3440 maybe_ret_addr_vi = address_vi;
3441 _ = try def_ret_vi.value.defAddr(
3442 isel,
3443 isel.air.typeOfIndex(air.inst_index, ip),
3444 null,
3445 &call.caller_saved_regs,
3446 );
3447 },
3448 }
3449 }
3450 try call.finishReturn(isel);
3451
3452 try call.prepareCallee(isel);
3453 if (pl_op.operand.toInterned()) |ct_callee| {
3454 try isel.nav_relocs.append(gpa, switch (ip.indexToKey(ct_callee)) {
3455 else => unreachable,
3456 inline .@"extern", .func => |func| .{
3457 .nav = func.owner_nav,
3458 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
3459 },
3460 .ptr => |ptr| .{
3461 .nav = ptr.base_addr.nav,
3462 .reloc = .{
3463 .label = @intCast(isel.instructions.items.len),
3464 .addend = ptr.byte_offset,
3465 },
3466 },
3467 });
3468 try isel.emit(.bl(0));
3469 } else {
3470 const callee_vi = try isel.use(pl_op.operand);
3471 const callee_mat = try callee_vi.matReg(isel);
3472 try isel.emit(.blr(callee_mat.ra.x()));
3473 try callee_mat.finish(isel);
3474 }
3475 try call.finishCallee(isel);
3476
3477 try call.prepareParams(isel);
3478 if (maybe_ret_addr_vi) |ret_addr_vi| try call.paramAddress(
3479 isel,
3480 maybe_def_ret_vi.?.value,
3481 ret_addr_vi.hint(isel).?,
3482 );
3483 var param_it: CallAbiIterator = .init;
3484 for (args, 0..) |arg, arg_index| {
3485 const param_ty = isel.air.typeOf(arg, ip);
3486 const param_vi = param_vi: {
3487 if (arg_index >= func_info.param_types.len) {
3488 assert(func_info.is_var_args);
3489 switch (isel.va_list) {
3490 .other => break :param_vi try param_it.nonSysvVarArg(isel, param_ty),
3491 .sysv => {},
3492 }
3493 }
3494 break :param_vi try param_it.param(isel, param_ty);
3495 } orelse continue;
3496 defer param_vi.deref(isel);
3497 const arg_vi = try isel.use(arg);
3498 switch (param_vi.parent(isel)) {
3499 .unallocated => if (param_vi.hint(isel)) |param_ra| {
3500 try call.paramLiveOut(isel, arg_vi, param_ra);
3501 } else {
3502 var param_part_it = param_vi.parts(isel);
3503 var arg_part_it = arg_vi.parts(isel);
3504 if (arg_part_it.only()) |_| {
3505 try isel.values.ensureUnusedCapacity(gpa, param_part_it.remaining);
3506 arg_vi.setParts(isel, param_part_it.remaining);
3507 while (param_part_it.next()) |param_part_vi| _ = arg_vi.addPart(
3508 isel,
3509 param_part_vi.get(isel).offset_from_parent,
3510 param_part_vi.size(isel),
3511 );
3512 param_part_it = param_vi.parts(isel);
3513 arg_part_it = arg_vi.parts(isel);
3514 }
3515 while (param_part_it.next()) |param_part_vi| {
3516 const arg_part_vi = arg_part_it.next().?;
3517 assert(arg_part_vi.get(isel).offset_from_parent ==
3518 param_part_vi.get(isel).offset_from_parent);
3519 assert(arg_part_vi.size(isel) == param_part_vi.size(isel));
3520 try call.paramLiveOut(isel, arg_part_vi, param_part_vi.hint(isel).?);
3521 }
3522 },
3523 .stack_slot => |stack_slot| try arg_vi.store(isel, param_ty, stack_slot.base, .{
3524 .offset = @intCast(stack_slot.offset),
3525 }),
3526 .value, .constant => unreachable,
3527 .address => |address_vi| try call.paramAddress(isel, arg_vi, address_vi.hint(isel).?),
3528 }
3529 }
3530 try call.finishParams(isel);
3531
3532 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3533 },
3534 .clz => |air_tag| {
3535 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
3536 defer res_vi.value.deref(isel);
3537
3538 const ty_op = air.data(air.inst_index).ty_op;
3539 const ty = isel.air.typeOf(ty_op.operand, ip);
3540 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
3541 const int_info = ty.intInfo(zcu);
3542 switch (int_info.bits) {
3543 0 => unreachable,
3544 1...64 => {
3545 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3546 const src_vi = try isel.use(ty_op.operand);
3547 const src_mat = try src_vi.matReg(isel);
3548 try isel.clzLimb(res_ra, int_info, src_mat.ra);
3549 try src_mat.finish(isel);
3550 },
3551 65...128 => |bits| {
3552 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3553 const src_vi = try isel.use(ty_op.operand);
3554 var src_hi64_it = src_vi.field(ty, 8, 8);
3555 const src_hi64_vi = try src_hi64_it.only(isel);
3556 const src_hi64_mat = try src_hi64_vi.?.matReg(isel);
3557 var src_lo64_it = src_vi.field(ty, 0, 8);
3558 const src_lo64_vi = try src_lo64_it.only(isel);
3559 const src_lo64_mat = try src_lo64_vi.?.matReg(isel);
3560 const lo64_ra = try isel.allocIntReg();
3561 defer isel.freeReg(lo64_ra);
3562 const hi64_ra = try isel.allocIntReg();
3563 defer isel.freeReg(hi64_ra);
3564 try isel.emit(.csel(res_ra.w(), lo64_ra.w(), hi64_ra.w(), .eq));
3565 try isel.emit(.add(lo64_ra.w(), lo64_ra.w(), .{ .immediate = @intCast(bits - 64) }));
3566 try isel.emit(.subs(.xzr, src_hi64_mat.ra.x(), .{ .immediate = 0 }));
3567 try isel.clzLimb(hi64_ra, .{ .signedness = int_info.signedness, .bits = bits - 64 }, src_hi64_mat.ra);
3568 try isel.clzLimb(lo64_ra, .{ .signedness = .unsigned, .bits = 64 }, src_lo64_mat.ra);
3569 try src_hi64_mat.finish(isel);
3570 try src_lo64_mat.finish(isel);
3571 },
3572 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
3573 }
3574 }
3575 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3576 },
3577 .ctz => |air_tag| {
3578 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
3579 defer res_vi.value.deref(isel);
3580
3581 const ty_op = air.data(air.inst_index).ty_op;
3582 const ty = isel.air.typeOf(ty_op.operand, ip);
3583 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
3584 const int_info = ty.intInfo(zcu);
3585 switch (int_info.bits) {
3586 0 => unreachable,
3587 1...64 => {
3588 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3589 const src_vi = try isel.use(ty_op.operand);
3590 const src_mat = try src_vi.matReg(isel);
3591 try isel.ctzLimb(res_ra, int_info, src_mat.ra);
3592 try src_mat.finish(isel);
3593 },
3594 65...128 => |bits| {
3595 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3596 const src_vi = try isel.use(ty_op.operand);
3597 var src_hi64_it = src_vi.field(ty, 8, 8);
3598 const src_hi64_vi = try src_hi64_it.only(isel);
3599 const src_hi64_mat = try src_hi64_vi.?.matReg(isel);
3600 var src_lo64_it = src_vi.field(ty, 0, 8);
3601 const src_lo64_vi = try src_lo64_it.only(isel);
3602 const src_lo64_mat = try src_lo64_vi.?.matReg(isel);
3603 const lo64_ra = try isel.allocIntReg();
3604 defer isel.freeReg(lo64_ra);
3605 const hi64_ra = try isel.allocIntReg();
3606 defer isel.freeReg(hi64_ra);
3607 try isel.emit(.csel(res_ra.w(), lo64_ra.w(), hi64_ra.w(), .ne));
3608 try isel.emit(.add(hi64_ra.w(), hi64_ra.w(), .{ .immediate = 64 }));
3609 try isel.emit(.subs(.xzr, src_lo64_mat.ra.x(), .{ .immediate = 0 }));
3610 try isel.ctzLimb(hi64_ra, .{ .signedness = .unsigned, .bits = 64 }, src_hi64_mat.ra);
3611 try isel.ctzLimb(lo64_ra, .{ .signedness = int_info.signedness, .bits = bits - 64 }, src_lo64_mat.ra);
3612 try src_hi64_mat.finish(isel);
3613 try src_lo64_mat.finish(isel);
3614 },
3615 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
3616 }
3617 }
3618 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3619 },
3620 .popcount => |air_tag| {
3621 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
3622 defer res_vi.value.deref(isel);
3623
3624 const ty_op = air.data(air.inst_index).ty_op;
3625 const ty = isel.air.typeOf(ty_op.operand, ip);
3626 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
3627 const int_info = ty.intInfo(zcu);
3628 if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
3629
3630 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3631 const src_vi = try isel.use(ty_op.operand);
3632 const src_mat = try src_vi.matReg(isel);
3633 const vec_ra = try isel.allocVecReg();
3634 defer isel.freeReg(vec_ra);
3635 try isel.emit(.umov(res_ra.w(), vec_ra.@"b[]"(0)));
3636 switch (int_info.bits) {
3637 else => unreachable,
3638 1...8 => {},
3639 9...16 => try isel.emit(.addp(vec_ra.@"8b"(), vec_ra.@"8b"(), .{ .vector = vec_ra.@"8b"() })),
3640 17...64 => try isel.emit(.addv(vec_ra.b(), vec_ra.@"8b"())),
3641 }
3642 try isel.emit(.cnt(vec_ra.@"8b"(), vec_ra.@"8b"()));
3643 switch (int_info.bits) {
3644 else => unreachable,
3645 1...31 => |bits| switch (int_info.signedness) {
3646 .signed => {
3647 try isel.emit(.fmov(vec_ra.s(), .{ .register = res_ra.w() }));
3648 try isel.emit(.ubfm(res_ra.w(), src_mat.ra.w(), .{
3649 .N = .word,
3650 .immr = 0,
3651 .imms = @intCast(bits - 1),
3652 }));
3653 },
3654 .unsigned => try isel.emit(.fmov(vec_ra.s(), .{ .register = src_mat.ra.w() })),
3655 },
3656 32 => try isel.emit(.fmov(vec_ra.s(), .{ .register = src_mat.ra.w() })),
3657 33...63 => |bits| switch (int_info.signedness) {
3658 .signed => {
3659 try isel.emit(.fmov(vec_ra.d(), .{ .register = res_ra.x() }));
3660 try isel.emit(.ubfm(res_ra.x(), src_mat.ra.x(), .{
3661 .N = .doubleword,
3662 .immr = 0,
3663 .imms = @intCast(bits - 1),
3664 }));
3665 },
3666 .unsigned => try isel.emit(.fmov(vec_ra.d(), .{ .register = src_mat.ra.x() })),
3667 },
3668 64 => try isel.emit(.fmov(vec_ra.d(), .{ .register = src_mat.ra.x() })),
3669 }
3670 try src_mat.finish(isel);
3671 }
3672 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3673 },
3674 .byte_swap => |air_tag| {
3675 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
3676 defer res_vi.value.deref(isel);
3677
3678 const ty_op = air.data(air.inst_index).ty_op;
3679 const ty = ty_op.ty.toType();
3680 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
3681 const int_info = ty.intInfo(zcu);
3682 if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
3683
3684 if (int_info.bits == 8) break :unused try res_vi.value.move(isel, ty_op.operand);
3685 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3686 const src_vi = try isel.use(ty_op.operand);
3687 const src_mat = try src_vi.matReg(isel);
3688 switch (int_info.bits) {
3689 else => unreachable,
3690 16 => switch (int_info.signedness) {
3691 .signed => {
3692 try isel.emit(.sbfm(res_ra.w(), res_ra.w(), .{
3693 .N = .word,
3694 .immr = 32 - 16,
3695 .imms = 32 - 1,
3696 }));
3697 try isel.emit(.rev(res_ra.w(), src_mat.ra.w()));
3698 },
3699 .unsigned => try isel.emit(.rev16(res_ra.w(), src_mat.ra.w())),
3700 },
3701 24 => {
3702 switch (int_info.signedness) {
3703 .signed => try isel.emit(.sbfm(res_ra.w(), res_ra.w(), .{
3704 .N = .word,
3705 .immr = 32 - 24,
3706 .imms = 32 - 1,
3707 })),
3708 .unsigned => try isel.emit(.ubfm(res_ra.w(), res_ra.w(), .{
3709 .N = .word,
3710 .immr = 32 - 24,
3711 .imms = 32 - 1,
3712 })),
3713 }
3714 try isel.emit(.rev(res_ra.w(), src_mat.ra.w()));
3715 },
3716 32 => try isel.emit(.rev(res_ra.w(), src_mat.ra.w())),
3717 40, 48, 56 => |bits| {
3718 switch (int_info.signedness) {
3719 .signed => try isel.emit(.sbfm(res_ra.x(), res_ra.x(), .{
3720 .N = .doubleword,
3721 .immr = @intCast(64 - bits),
3722 .imms = 64 - 1,
3723 })),
3724 .unsigned => try isel.emit(.ubfm(res_ra.x(), res_ra.x(), .{
3725 .N = .doubleword,
3726 .immr = @intCast(64 - bits),
3727 .imms = 64 - 1,
3728 })),
3729 }
3730 try isel.emit(.rev(res_ra.x(), src_mat.ra.x()));
3731 },
3732 64 => try isel.emit(.rev(res_ra.x(), src_mat.ra.x())),
3733 }
3734 try src_mat.finish(isel);
3735 }
3736 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3737 },
3738 .bit_reverse => |air_tag| {
3739 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
3740 defer res_vi.value.deref(isel);
3741
3742 const ty_op = air.data(air.inst_index).ty_op;
3743 const ty = ty_op.ty.toType();
3744 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
3745 const int_info = ty.intInfo(zcu);
3746 if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
3747
3748 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3749 const src_vi = try isel.use(ty_op.operand);
3750 const src_mat = try src_vi.matReg(isel);
3751 switch (int_info.bits) {
3752 else => unreachable,
3753 1...31 => |bits| {
3754 switch (int_info.signedness) {
3755 .signed => try isel.emit(.sbfm(res_ra.w(), res_ra.w(), .{
3756 .N = .word,
3757 .immr = @intCast(32 - bits),
3758 .imms = 32 - 1,
3759 })),
3760 .unsigned => try isel.emit(.ubfm(res_ra.w(), res_ra.w(), .{
3761 .N = .word,
3762 .immr = @intCast(32 - bits),
3763 .imms = 32 - 1,
3764 })),
3765 }
3766 try isel.emit(.rbit(res_ra.w(), src_mat.ra.w()));
3767 },
3768 32 => try isel.emit(.rbit(res_ra.w(), src_mat.ra.w())),
3769 33...63 => |bits| {
3770 switch (int_info.signedness) {
3771 .signed => try isel.emit(.sbfm(res_ra.x(), res_ra.x(), .{
3772 .N = .doubleword,
3773 .immr = @intCast(64 - bits),
3774 .imms = 64 - 1,
3775 })),
3776 .unsigned => try isel.emit(.ubfm(res_ra.x(), res_ra.x(), .{
3777 .N = .doubleword,
3778 .immr = @intCast(64 - bits),
3779 .imms = 64 - 1,
3780 })),
3781 }
3782 try isel.emit(.rbit(res_ra.x(), src_mat.ra.x()));
3783 },
3784 64 => try isel.emit(.rbit(res_ra.x(), src_mat.ra.x())),
3785 }
3786 try src_mat.finish(isel);
3787 }
3788 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3789 },
3790 .sqrt, .floor, .ceil, .round, .trunc_float => |air_tag| {
3791 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
3792 defer res_vi.value.deref(isel);
3793
3794 const un_op = air.data(air.inst_index).un_op;
3795 const ty = isel.air.typeOf(un_op, ip);
3796 switch (ty.floatBits(isel.target)) {
3797 else => unreachable,
3798 16, 32, 64 => |bits| {
3799 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
3800 const need_fcvt = switch (bits) {
3801 else => unreachable,
3802 16 => !isel.target.cpu.has(.aarch64, .fullfp16),
3803 32, 64 => false,
3804 };
3805 if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s()));
3806 const src_vi = try isel.use(un_op);
3807 const src_mat = try src_vi.matReg(isel);
3808 const src_ra = if (need_fcvt) try isel.allocVecReg() else src_mat.ra;
3809 defer if (need_fcvt) isel.freeReg(src_ra);
3810 try isel.emit(bits: switch (bits) {
3811 else => unreachable,
3812 16 => if (need_fcvt) continue :bits 32 else switch (air_tag) {
3813 else => unreachable,
3814 .sqrt => .fsqrt(res_ra.h(), src_ra.h()),
3815 .floor => .frintm(res_ra.h(), src_ra.h()),
3816 .ceil => .frintp(res_ra.h(), src_ra.h()),
3817 .round => .frinta(res_ra.h(), src_ra.h()),
3818 .trunc_float => .frintz(res_ra.h(), src_ra.h()),
3819 },
3820 32 => switch (air_tag) {
3821 else => unreachable,
3822 .sqrt => .fsqrt(res_ra.s(), src_ra.s()),
3823 .floor => .frintm(res_ra.s(), src_ra.s()),
3824 .ceil => .frintp(res_ra.s(), src_ra.s()),
3825 .round => .frinta(res_ra.s(), src_ra.s()),
3826 .trunc_float => .frintz(res_ra.s(), src_ra.s()),
3827 },
3828 64 => switch (air_tag) {
3829 else => unreachable,
3830 .sqrt => .fsqrt(res_ra.d(), src_ra.d()),
3831 .floor => .frintm(res_ra.d(), src_ra.d()),
3832 .ceil => .frintp(res_ra.d(), src_ra.d()),
3833 .round => .frinta(res_ra.d(), src_ra.d()),
3834 .trunc_float => .frintz(res_ra.d(), src_ra.d()),
3835 },
3836 });
3837 if (need_fcvt) try isel.emit(.fcvt(src_ra.s(), src_mat.ra.h()));
3838 try src_mat.finish(isel);
3839 },
3840 80, 128 => |bits| {
3841 try call.prepareReturn(isel);
3842 switch (bits) {
3843 else => unreachable,
3844 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
3845 80 => {
3846 var res_hi16_it = res_vi.value.field(ty, 8, 8);
3847 const res_hi16_vi = try res_hi16_it.only(isel);
3848 try call.returnLiveIn(isel, res_hi16_vi.?, .r1);
3849 var res_lo64_it = res_vi.value.field(ty, 0, 8);
3850 const res_lo64_vi = try res_lo64_it.only(isel);
3851 try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
3852 },
3853 }
3854 try call.finishReturn(isel);
3855
3856 try call.prepareCallee(isel);
3857 try isel.global_relocs.append(gpa, .{
3858 .name = switch (air_tag) {
3859 else => unreachable,
3860 .sqrt => switch (bits) {
3861 else => unreachable,
3862 16 => "__sqrth",
3863 32 => "sqrtf",
3864 64 => "sqrt",
3865 80 => "__sqrtx",
3866 128 => "sqrtq",
3867 },
3868 .floor => switch (bits) {
3869 else => unreachable,
3870 16 => "__floorh",
3871 32 => "floorf",
3872 64 => "floor",
3873 80 => "__floorx",
3874 128 => "floorq",
3875 },
3876 .ceil => switch (bits) {
3877 else => unreachable,
3878 16 => "__ceilh",
3879 32 => "ceilf",
3880 64 => "ceil",
3881 80 => "__ceilx",
3882 128 => "ceilq",
3883 },
3884 .round => switch (bits) {
3885 else => unreachable,
3886 16 => "__roundh",
3887 32 => "roundf",
3888 64 => "round",
3889 80 => "__roundx",
3890 128 => "roundq",
3891 },
3892 .trunc_float => switch (bits) {
3893 else => unreachable,
3894 16 => "__trunch",
3895 32 => "truncf",
3896 64 => "trunc",
3897 80 => "__truncx",
3898 128 => "truncq",
3899 },
3900 },
3901 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
3902 });
3903 try isel.emit(.bl(0));
3904 try call.finishCallee(isel);
3905
3906 try call.prepareParams(isel);
3907 const src_vi = try isel.use(un_op);
3908 switch (bits) {
3909 else => unreachable,
3910 16, 32, 64, 128 => try call.paramLiveOut(isel, src_vi, .v0),
3911 80 => {
3912 var src_hi16_it = src_vi.field(ty, 8, 8);
3913 const src_hi16_vi = try src_hi16_it.only(isel);
3914 try call.paramLiveOut(isel, src_hi16_vi.?, .r1);
3915 var src_lo64_it = src_vi.field(ty, 0, 8);
3916 const src_lo64_vi = try src_lo64_it.only(isel);
3917 try call.paramLiveOut(isel, src_lo64_vi.?, .r0);
3918 },
3919 }
3920 try call.finishParams(isel);
3921 },
3922 }
3923 }
3924 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
3925 },
3926 .sin, .cos, .tan, .exp, .exp2, .log, .log2, .log10 => |air_tag| {
3927 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| {
3928 defer res_vi.value.deref(isel);
3929
3930 const un_op = air.data(air.inst_index).un_op;
3931 const ty = isel.air.typeOf(un_op, ip);
3932 const bits = ty.floatBits(isel.target);
3933 try call.prepareReturn(isel);
3934 switch (bits) {
3935 else => unreachable,
3936 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
3937 80 => {
3938 var res_hi16_it = res_vi.value.field(ty, 8, 8);
3939 const res_hi16_vi = try res_hi16_it.only(isel);
3940 try call.returnLiveIn(isel, res_hi16_vi.?, .r1);
3941 var res_lo64_it = res_vi.value.field(ty, 0, 8);
3942 const res_lo64_vi = try res_lo64_it.only(isel);
3943 try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
3944 },
3945 }
3946 try call.finishReturn(isel);
3947
3948 try call.prepareCallee(isel);
3949 try isel.global_relocs.append(gpa, .{
3950 .name = switch (air_tag) {
3951 else => unreachable,
3952 .sin => switch (bits) {
3953 else => unreachable,
3954 16 => "__sinh",
3955 32 => "sinf",
3956 64 => "sin",
3957 80 => "__sinx",
3958 128 => "sinq",
3959 },
3960 .cos => switch (bits) {
3961 else => unreachable,
3962 16 => "__cosh",
3963 32 => "cosf",
3964 64 => "cos",
3965 80 => "__cosx",
3966 128 => "cosq",
3967 },
3968 .tan => switch (bits) {
3969 else => unreachable,
3970 16 => "__tanh",
3971 32 => "tanf",
3972 64 => "tan",
3973 80 => "__tanx",
3974 128 => "tanq",
3975 },
3976 .exp => switch (bits) {
3977 else => unreachable,
3978 16 => "__exph",
3979 32 => "expf",
3980 64 => "exp",
3981 80 => "__expx",
3982 128 => "expq",
3983 },
3984 .exp2 => switch (bits) {
3985 else => unreachable,
3986 16 => "__exp2h",
3987 32 => "exp2f",
3988 64 => "exp2",
3989 80 => "__exp2x",
3990 128 => "exp2q",
3991 },
3992 .log => switch (bits) {
3993 else => unreachable,
3994 16 => "__logh",
3995 32 => "logf",
3996 64 => "log",
3997 80 => "__logx",
3998 128 => "logq",
3999 },
4000 .log2 => switch (bits) {
4001 else => unreachable,
4002 16 => "__log2h",
4003 32 => "log2f",
4004 64 => "log2",
4005 80 => "__log2x",
4006 128 => "log2q",
4007 },
4008 .log10 => switch (bits) {
4009 else => unreachable,
4010 16 => "__log10h",
4011 32 => "log10f",
4012 64 => "log10",
4013 80 => "__log10x",
4014 128 => "log10q",
4015 },
4016 },
4017 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
4018 });
4019 try isel.emit(.bl(0));
4020 try call.finishCallee(isel);
4021
4022 try call.prepareParams(isel);
4023 const src_vi = try isel.use(un_op);
4024 switch (bits) {
4025 else => unreachable,
4026 16, 32, 64, 128 => try call.paramLiveOut(isel, src_vi, .v0),
4027 80 => {
4028 var src_hi16_it = src_vi.field(ty, 8, 8);
4029 const src_hi16_vi = try src_hi16_it.only(isel);
4030 try call.paramLiveOut(isel, src_hi16_vi.?, .r1);
4031 var src_lo64_it = src_vi.field(ty, 0, 8);
4032 const src_lo64_vi = try src_lo64_it.only(isel);
4033 try call.paramLiveOut(isel, src_lo64_vi.?, .r0);
4034 },
4035 }
4036 try call.finishParams(isel);
4037 }
4038 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4039 },
4040 .abs => |air_tag| {
4041 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
4042 defer res_vi.value.deref(isel);
4043
4044 const ty_op = air.data(air.inst_index).ty_op;
4045 const ty = ty_op.ty.toType();
4046 if (!ty.isRuntimeFloat()) {
4047 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
4048 switch (ty.intInfo(zcu).bits) {
4049 0 => unreachable,
4050 1...32 => {
4051 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
4052 const src_vi = try isel.use(ty_op.operand);
4053 const src_mat = try src_vi.matReg(isel);
4054 try isel.emit(.csneg(res_ra.w(), src_mat.ra.w(), src_mat.ra.w(), .pl));
4055 try isel.emit(.subs(.wzr, src_mat.ra.w(), .{ .immediate = 0 }));
4056 try src_mat.finish(isel);
4057 },
4058 33...64 => {
4059 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
4060 const src_vi = try isel.use(ty_op.operand);
4061 const src_mat = try src_vi.matReg(isel);
4062 try isel.emit(.csneg(res_ra.x(), src_mat.ra.x(), src_mat.ra.x(), .pl));
4063 try isel.emit(.subs(.xzr, src_mat.ra.x(), .{ .immediate = 0 }));
4064 try src_mat.finish(isel);
4065 },
4066 65...128 => {
4067 var res_hi64_it = res_vi.value.field(ty, 8, 8);
4068 const res_hi64_vi = try res_hi64_it.only(isel);
4069 const res_hi64_ra = try res_hi64_vi.?.defReg(isel);
4070 var res_lo64_it = res_vi.value.field(ty, 0, 8);
4071 const res_lo64_vi = try res_lo64_it.only(isel);
4072 const res_lo64_ra = try res_lo64_vi.?.defReg(isel);
4073 if (res_hi64_ra == null and res_lo64_ra == null) break :unused;
4074 const src_ty = isel.air.typeOf(ty_op.operand, ip);
4075 const src_vi = try isel.use(ty_op.operand);
4076 var src_hi64_it = src_vi.field(src_ty, 8, 8);
4077 const src_hi64_vi = try src_hi64_it.only(isel);
4078 const src_hi64_mat = try src_hi64_vi.?.matReg(isel);
4079 var src_lo64_it = src_vi.field(src_ty, 0, 8);
4080 const src_lo64_vi = try src_lo64_it.only(isel);
4081 const src_lo64_mat = try src_lo64_vi.?.matReg(isel);
4082 const lo64_ra = try isel.allocIntReg();
4083 defer isel.freeReg(lo64_ra);
4084 const hi64_ra, const mask_ra = alloc_ras: {
4085 const res_lo64_lock: RegLock = if (res_lo64_ra) |res_ra| isel.tryLockReg(res_ra) else .empty;
4086 defer res_lo64_lock.unlock(isel);
4087 break :alloc_ras .{ try isel.allocIntReg(), try isel.allocIntReg() };
4088 };
4089 defer {
4090 isel.freeReg(hi64_ra);
4091 isel.freeReg(mask_ra);
4092 }
4093 if (res_hi64_ra) |res_ra| try isel.emit(.sbc(res_ra.x(), hi64_ra.x(), mask_ra.x()));
4094 try isel.emit(.subs(
4095 if (res_lo64_ra) |res_ra| res_ra.x() else .xzr,
4096 lo64_ra.x(),
4097 .{ .register = mask_ra.x() },
4098 ));
4099 if (res_hi64_ra) |_| try isel.emit(.eor(hi64_ra.x(), src_hi64_mat.ra.x(), .{ .register = mask_ra.x() }));
4100 try isel.emit(.eor(lo64_ra.x(), src_lo64_mat.ra.x(), .{ .register = mask_ra.x() }));
4101 try isel.emit(.sbfm(mask_ra.x(), src_hi64_mat.ra.x(), .{
4102 .N = .doubleword,
4103 .immr = 64 - 1,
4104 .imms = 64 - 1,
4105 }));
4106 try src_lo64_mat.finish(isel);
4107 try src_hi64_mat.finish(isel);
4108 },
4109 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }),
4110 }
4111 } else switch (ty.floatBits(isel.target)) {
4112 else => unreachable,
4113 16 => {
4114 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
4115 const src_vi = try isel.use(ty_op.operand);
4116 const src_mat = try src_vi.matReg(isel);
4117 try isel.emit(if (isel.target.cpu.has(.aarch64, .fullfp16))
4118 .fabs(res_ra.h(), src_mat.ra.h())
4119 else
4120 .bic(res_ra.@"4h"(), res_ra.@"4h"(), .{ .shifted_immediate = .{
4121 .immediate = 0b10000000,
4122 .lsl = 8,
4123 } }));
4124 try src_mat.finish(isel);
4125 },
4126 32 => {
4127 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
4128 const src_vi = try isel.use(ty_op.operand);
4129 const src_mat = try src_vi.matReg(isel);
4130 try isel.emit(.fabs(res_ra.s(), src_mat.ra.s()));
4131 try src_mat.finish(isel);
4132 },
4133 64 => {
4134 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
4135 const src_vi = try isel.use(ty_op.operand);
4136 const src_mat = try src_vi.matReg(isel);
4137 try isel.emit(.fabs(res_ra.d(), src_mat.ra.d()));
4138 try src_mat.finish(isel);
4139 },
4140 80 => {
4141 const src_vi = try isel.use(ty_op.operand);
4142 var res_hi16_it = res_vi.value.field(ty, 8, 8);
4143 const res_hi16_vi = try res_hi16_it.only(isel);
4144 if (try res_hi16_vi.?.defReg(isel)) |res_hi16_ra| {
4145 var src_hi16_it = src_vi.field(ty, 8, 8);
4146 const src_hi16_vi = try src_hi16_it.only(isel);
4147 const src_hi16_mat = try src_hi16_vi.?.matReg(isel);
4148 try isel.emit(.@"and"(res_hi16_ra.w(), src_hi16_mat.ra.w(), .{ .immediate = .{
4149 .N = .word,
4150 .immr = 0,
4151 .imms = 15 - 1,
4152 } }));
4153 try src_hi16_mat.finish(isel);
4154 }
4155 var res_lo64_it = res_vi.value.field(ty, 0, 8);
4156 const res_lo64_vi = try res_lo64_it.only(isel);
4157 if (try res_lo64_vi.?.defReg(isel)) |res_lo64_ra| {
4158 var src_lo64_it = src_vi.field(ty, 0, 8);
4159 const src_lo64_vi = try src_lo64_it.only(isel);
4160 try src_lo64_vi.?.liveOut(isel, res_lo64_ra);
4161 }
4162 },
4163 128 => {
4164 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
4165 const src_vi = try isel.use(ty_op.operand);
4166 const src_mat = try src_vi.matReg(isel);
4167 const neg_zero_ra = try isel.allocVecReg();
4168 defer isel.freeReg(neg_zero_ra);
4169 try isel.emit(.bic(res_ra.@"16b"(), src_mat.ra.@"16b"(), .{ .register = neg_zero_ra.@"16b"() }));
4170 try isel.literals.appendNTimes(gpa, 0, -%isel.literals.items.len % 4);
4171 try isel.literal_relocs.append(gpa, .{
4172 .label = @intCast(isel.instructions.items.len),
4173 });
4174 try isel.emit(.ldr(neg_zero_ra.q(), .{
4175 .literal = @intCast((isel.instructions.items.len + 1 + isel.literals.items.len) << 2),
4176 }));
4177 try isel.emitLiteral(&(.{0} ** 15 ++ .{0x80}));
4178 try src_mat.finish(isel);
4179 },
4180 }
4181 }
4182 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4183 },
4184 .neg, .neg_optimized => {
4185 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
4186 defer res_vi.value.deref(isel);
4187
4188 const un_op = air.data(air.inst_index).un_op;
4189 const ty = isel.air.typeOf(un_op, ip);
4190 switch (ty.floatBits(isel.target)) {
4191 else => unreachable,
4192 16 => {
4193 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
4194 const src_vi = try isel.use(un_op);
4195 const src_mat = try src_vi.matReg(isel);
4196 if (isel.target.cpu.has(.aarch64, .fullfp16)) {
4197 try isel.emit(.fneg(res_ra.h(), src_mat.ra.h()));
4198 } else {
4199 const neg_zero_ra = try isel.allocVecReg();
4200 defer isel.freeReg(neg_zero_ra);
4201 try isel.emit(.eor(res_ra.@"8b"(), res_ra.@"8b"(), .{ .register = neg_zero_ra.@"8b"() }));
4202 try isel.emit(.movi(neg_zero_ra.@"4h"(), 0b10000000, .{ .lsl = 8 }));
4203 }
4204 try src_mat.finish(isel);
4205 },
4206 32 => {
4207 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
4208 const src_vi = try isel.use(un_op);
4209 const src_mat = try src_vi.matReg(isel);
4210 try isel.emit(.fneg(res_ra.s(), src_mat.ra.s()));
4211 try src_mat.finish(isel);
4212 },
4213 64 => {
4214 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
4215 const src_vi = try isel.use(un_op);
4216 const src_mat = try src_vi.matReg(isel);
4217 try isel.emit(.fneg(res_ra.d(), src_mat.ra.d()));
4218 try src_mat.finish(isel);
4219 },
4220 80 => {
4221 const src_vi = try isel.use(un_op);
4222 var res_hi16_it = res_vi.value.field(ty, 8, 8);
4223 const res_hi16_vi = try res_hi16_it.only(isel);
4224 if (try res_hi16_vi.?.defReg(isel)) |res_hi16_ra| {
4225 var src_hi16_it = src_vi.field(ty, 8, 8);
4226 const src_hi16_vi = try src_hi16_it.only(isel);
4227 const src_hi16_mat = try src_hi16_vi.?.matReg(isel);
4228 try isel.emit(.eor(res_hi16_ra.w(), src_hi16_mat.ra.w(), .{ .immediate = .{
4229 .N = .word,
4230 .immr = 32 - 15,
4231 .imms = 1 - 1,
4232 } }));
4233 try src_hi16_mat.finish(isel);
4234 }
4235 var res_lo64_it = res_vi.value.field(ty, 0, 8);
4236 const res_lo64_vi = try res_lo64_it.only(isel);
4237 if (try res_lo64_vi.?.defReg(isel)) |res_lo64_ra| {
4238 var src_lo64_it = src_vi.field(ty, 0, 8);
4239 const src_lo64_vi = try src_lo64_it.only(isel);
4240 try src_lo64_vi.?.liveOut(isel, res_lo64_ra);
4241 }
4242 },
4243 128 => {
4244 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
4245 const src_vi = try isel.use(un_op);
4246 const src_mat = try src_vi.matReg(isel);
4247 const neg_zero_ra = try isel.allocVecReg();
4248 defer isel.freeReg(neg_zero_ra);
4249 try isel.emit(.eor(res_ra.@"16b"(), src_mat.ra.@"16b"(), .{ .register = neg_zero_ra.@"16b"() }));
4250 try isel.literals.appendNTimes(gpa, 0, -%isel.literals.items.len % 4);
4251 try isel.literal_relocs.append(gpa, .{
4252 .label = @intCast(isel.instructions.items.len),
4253 });
4254 try isel.emit(.ldr(neg_zero_ra.q(), .{
4255 .literal = @intCast((isel.instructions.items.len + 1 + isel.literals.items.len) << 2),
4256 }));
4257 try isel.emitLiteral(&(.{0} ** 15 ++ .{0x80}));
4258 try src_mat.finish(isel);
4259 },
4260 }
4261 }
4262 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4263 },
4264 .cmp_lt, .cmp_lte, .cmp_eq, .cmp_gte, .cmp_gt, .cmp_neq => |air_tag| {
4265 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
4266 defer res_vi.value.deref(isel);
4267
4268 var bin_op = air.data(air.inst_index).bin_op;
4269 const ty = isel.air.typeOf(bin_op.lhs, ip);
4270 if (!ty.isRuntimeFloat()) {
4271 const int_info: std.builtin.Type.Int = if (ty.toIntern() == .bool_type)
4272 .{ .signedness = .unsigned, .bits = 1 }
4273 else if (ty.isAbiInt(zcu))
4274 ty.intInfo(zcu)
4275 else if (ty.isPtrAtRuntime(zcu))
4276 .{ .signedness = .unsigned, .bits = 64 }
4277 else
4278 return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
4279 if (int_info.bits > 256) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) });
4280
4281 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
4282 try isel.emit(.csinc(res_ra.w(), .wzr, .wzr, .invert(cond: switch (air_tag) {
4283 else => unreachable,
4284 .cmp_lt => switch (int_info.signedness) {
4285 .signed => .lt,
4286 .unsigned => .lo,
4287 },
4288 .cmp_lte => switch (int_info.bits) {
4289 else => unreachable,
4290 1...64 => switch (int_info.signedness) {
4291 .signed => .le,
4292 .unsigned => .ls,
4293 },
4294 65...128 => {
4295 std.mem.swap(Air.Inst.Ref, &bin_op.lhs, &bin_op.rhs);
4296 continue :cond .cmp_gte;
4297 },
4298 },
4299 .cmp_eq => .eq,
4300 .cmp_gte => switch (int_info.signedness) {
4301 .signed => .ge,
4302 .unsigned => .hs,
4303 },
4304 .cmp_gt => switch (int_info.bits) {
4305 else => unreachable,
4306 1...64 => switch (int_info.signedness) {
4307 .signed => .gt,
4308 .unsigned => .hi,
4309 },
4310 65...128 => {
4311 std.mem.swap(Air.Inst.Ref, &bin_op.lhs, &bin_op.rhs);
4312 continue :cond .cmp_lt;
4313 },
4314 },
4315 .cmp_neq => .ne,
4316 })));
4317
4318 const lhs_vi = try isel.use(bin_op.lhs);
4319 const rhs_vi = try isel.use(bin_op.rhs);
4320 var part_offset = lhs_vi.size(isel);
4321 while (part_offset > 0) {
4322 const part_size = @min(part_offset, 8);
4323 part_offset -= part_size;
4324 var lhs_part_it = lhs_vi.field(ty, part_offset, part_size);
4325 const lhs_part_vi = try lhs_part_it.only(isel);
4326 const lhs_part_mat = try lhs_part_vi.?.matReg(isel);
4327 var rhs_part_it = rhs_vi.field(ty, part_offset, part_size);
4328 const rhs_part_vi = try rhs_part_it.only(isel);
4329 const rhs_part_mat = try rhs_part_vi.?.matReg(isel);
4330 try isel.emit(switch (part_size) {
4331 else => unreachable,
4332 1...4 => switch (part_offset) {
4333 0 => .subs(.wzr, lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }),
4334 else => switch (air_tag) {
4335 else => unreachable,
4336 .cmp_lt, .cmp_lte, .cmp_gte, .cmp_gt => .sbcs(
4337 .wzr,
4338 lhs_part_mat.ra.w(),
4339 rhs_part_mat.ra.w(),
4340 ),
4341 .cmp_eq, .cmp_neq => .ccmp(
4342 lhs_part_mat.ra.w(),
4343 .{ .register = rhs_part_mat.ra.w() },
4344 .{ .n = false, .z = false, .c = false, .v = false },
4345 .eq,
4346 ),
4347 },
4348 },
4349 5...8 => switch (part_offset) {
4350 0 => .subs(.xzr, lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }),
4351 else => switch (air_tag) {
4352 else => unreachable,
4353 .cmp_lt, .cmp_lte, .cmp_gte, .cmp_gt => .sbcs(
4354 .xzr,
4355 lhs_part_mat.ra.x(),
4356 rhs_part_mat.ra.x(),
4357 ),
4358 .cmp_eq, .cmp_neq => .ccmp(
4359 lhs_part_mat.ra.x(),
4360 .{ .register = rhs_part_mat.ra.x() },
4361 .{ .n = false, .z = false, .c = false, .v = false },
4362 .eq,
4363 ),
4364 },
4365 },
4366 });
4367 try rhs_part_mat.finish(isel);
4368 try lhs_part_mat.finish(isel);
4369 }
4370 } else switch (ty.floatBits(isel.target)) {
4371 else => unreachable,
4372 16, 32, 64 => |bits| {
4373 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
4374 const need_fcvt = switch (bits) {
4375 else => unreachable,
4376 16 => !isel.target.cpu.has(.aarch64, .fullfp16),
4377 32, 64 => false,
4378 };
4379 try isel.emit(.csinc(res_ra.w(), .wzr, .wzr, .invert(switch (air_tag) {
4380 else => unreachable,
4381 .cmp_lt => .lo,
4382 .cmp_lte => .ls,
4383 .cmp_eq => .eq,
4384 .cmp_gte => .ge,
4385 .cmp_gt => .gt,
4386 .cmp_neq => .ne,
4387 })));
4388
4389 const lhs_vi = try isel.use(bin_op.lhs);
4390 const rhs_vi = try isel.use(bin_op.rhs);
4391 const lhs_mat = try lhs_vi.matReg(isel);
4392 const rhs_mat = try rhs_vi.matReg(isel);
4393 const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra;
4394 defer if (need_fcvt) isel.freeReg(lhs_ra);
4395 const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra;
4396 defer if (need_fcvt) isel.freeReg(rhs_ra);
4397 try isel.emit(bits: switch (bits) {
4398 else => unreachable,
4399 16 => if (need_fcvt)
4400 continue :bits 32
4401 else
4402 .fcmp(lhs_ra.h(), .{ .register = rhs_ra.h() }),
4403 32 => .fcmp(lhs_ra.s(), .{ .register = rhs_ra.s() }),
4404 64 => .fcmp(lhs_ra.d(), .{ .register = rhs_ra.d() }),
4405 });
4406 if (need_fcvt) {
4407 try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h()));
4408 try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h()));
4409 }
4410 try rhs_mat.finish(isel);
4411 try lhs_mat.finish(isel);
4412 },
4413 80, 128 => |bits| {
4414 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
4415
4416 try call.prepareReturn(isel);
4417 try call.returnFill(isel, .r0);
4418 try isel.emit(.csinc(res_ra.w(), .wzr, .wzr, .invert(cond: switch (air_tag) {
4419 else => unreachable,
4420 .cmp_lt => .lt,
4421 .cmp_lte => .le,
4422 .cmp_eq => .eq,
4423 .cmp_gte => {
4424 std.mem.swap(Air.Inst.Ref, &bin_op.lhs, &bin_op.rhs);
4425 continue :cond .cmp_lte;
4426 },
4427 .cmp_gt => {
4428 std.mem.swap(Air.Inst.Ref, &bin_op.lhs, &bin_op.rhs);
4429 continue :cond .cmp_lt;
4430 },
4431 .cmp_neq => .ne,
4432 })));
4433 try isel.emit(.subs(.wzr, .w0, .{ .immediate = 0 }));
4434 try call.finishReturn(isel);
4435
4436 try call.prepareCallee(isel);
4437 try isel.global_relocs.append(gpa, .{
4438 .name = switch (bits) {
4439 else => unreachable,
4440 16 => "__cmphf2",
4441 32 => "__cmpsf2",
4442 64 => "__cmpdf2",
4443 80 => "__cmpxf2",
4444 128 => "__cmptf2",
4445 },
4446 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
4447 });
4448 try isel.emit(.bl(0));
4449 try call.finishCallee(isel);
4450
4451 try call.prepareParams(isel);
4452 const lhs_vi = try isel.use(bin_op.lhs);
4453 const rhs_vi = try isel.use(bin_op.rhs);
4454 switch (bits) {
4455 else => unreachable,
4456 16, 32, 64, 128 => {
4457 try call.paramLiveOut(isel, rhs_vi, .v1);
4458 try call.paramLiveOut(isel, lhs_vi, .v0);
4459 },
4460 80 => {
4461 var rhs_hi16_it = rhs_vi.field(ty, 8, 8);
4462 const rhs_hi16_vi = try rhs_hi16_it.only(isel);
4463 try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3);
4464 var rhs_lo64_it = rhs_vi.field(ty, 0, 8);
4465 const rhs_lo64_vi = try rhs_lo64_it.only(isel);
4466 try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2);
4467 var lhs_hi16_it = lhs_vi.field(ty, 8, 8);
4468 const lhs_hi16_vi = try lhs_hi16_it.only(isel);
4469 try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1);
4470 var lhs_lo64_it = lhs_vi.field(ty, 0, 8);
4471 const lhs_lo64_vi = try lhs_lo64_it.only(isel);
4472 try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0);
4473 },
4474 }
4475 try call.finishParams(isel);
4476 },
4477 }
4478 }
4479 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4480 },
4481 .cond_br => {
4482 const pl_op = air.data(air.inst_index).pl_op;
4483 const extra = isel.air.extraData(Air.CondBr, pl_op.payload);
4484
4485 try isel.body(@ptrCast(isel.air.extra.items[extra.end + extra.data.then_body_len ..][0..extra.data.else_body_len]));
4486 const else_label = isel.instructions.items.len;
4487 const else_live_registers = isel.live_registers;
4488 try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.then_body_len]));
4489 try isel.merge(&else_live_registers, .{});
4490
4491 const cond_vi = try isel.use(pl_op.operand);
4492 const cond_mat = try cond_vi.matReg(isel);
4493 try isel.emit(.tbz(
4494 cond_mat.ra.x(),
4495 0,
4496 @intCast((isel.instructions.items.len + 1 - else_label) << 2),
4497 ));
4498 try cond_mat.finish(isel);
4499
4500 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4501 },
4502 .switch_br => {
4503 const switch_br = isel.air.unwrapSwitch(air.inst_index);
4504 const cond_ty = isel.air.typeOf(switch_br.operand, ip);
4505 const cond_int_info: std.builtin.Type.Int = if (cond_ty.toIntern() == .bool_type)
4506 .{ .signedness = .unsigned, .bits = 1 }
4507 else if (cond_ty.isAbiInt(zcu))
4508 cond_ty.intInfo(zcu)
4509 else
4510 return isel.fail("bad switch cond {f}", .{isel.fmtType(cond_ty)});
4511
4512 var final_case = true;
4513 if (switch_br.else_body_len > 0) {
4514 var cases_it = switch_br.iterateCases();
4515 while (cases_it.next()) |_| {}
4516 try isel.body(cases_it.elseBody());
4517 assert(final_case);
4518 final_case = false;
4519 }
4520 const zero_reg: Register = switch (cond_int_info.bits) {
4521 else => unreachable,
4522 1...32 => .wzr,
4523 33...64 => .xzr,
4524 };
4525 var cond_mat: ?Value.Materialize = null;
4526 var cond_reg: Register = undefined;
4527 var cases_it = switch_br.iterateCases();
4528 while (cases_it.next()) |case| {
4529 const next_label = isel.instructions.items.len;
4530 const next_live_registers = isel.live_registers;
4531 try isel.body(case.body);
4532 if (final_case) {
4533 final_case = false;
4534 continue;
4535 }
4536 try isel.merge(&next_live_registers, .{});
4537 if (cond_mat == null) {
4538 var cond_vi = try isel.use(switch_br.operand);
4539 cond_mat = try cond_vi.matReg(isel);
4540 cond_reg = switch (cond_int_info.bits) {
4541 else => unreachable,
4542 1...32 => cond_mat.?.ra.w(),
4543 33...64 => cond_mat.?.ra.x(),
4544 };
4545 }
4546 if (case.ranges.len == 0 and case.items.len == 1 and Constant.fromInterned(
4547 case.items[0].toInterned().?,
4548 ).orderAgainstZero(zcu).compare(.eq)) {
4549 try isel.emit(.cbnz(
4550 cond_reg,
4551 @intCast((isel.instructions.items.len + 1 - next_label) << 2),
4552 ));
4553 continue;
4554 }
4555 try isel.emit(.@"b."(
4556 .invert(switch (case.ranges.len) {
4557 0 => .eq,
4558 else => .ls,
4559 }),
4560 @intCast((isel.instructions.items.len + 1 - next_label) << 2),
4561 ));
4562 var case_range_index = case.ranges.len;
4563 while (case_range_index > 0) {
4564 case_range_index -= 1;
4565
4566 const low_val: Constant = .fromInterned(case.ranges[case_range_index][0].toInterned().?);
4567 var low_bigint_space: Constant.BigIntSpace = undefined;
4568 const low_bigint = low_val.toBigInt(&low_bigint_space, zcu);
4569 const low_int: i64 = if (low_bigint.positive) @bitCast(
4570 low_bigint.toInt(u64) catch
4571 return isel.fail("too big case range start: {f}", .{isel.fmtConstant(low_val)}),
4572 ) else low_bigint.toInt(i64) catch
4573 return isel.fail("too big case range start: {f}", .{isel.fmtConstant(low_val)});
4574
4575 const high_val: Constant = .fromInterned(case.ranges[case_range_index][1].toInterned().?);
4576 var high_bigint_space: Constant.BigIntSpace = undefined;
4577 const high_bigint = high_val.toBigInt(&high_bigint_space, zcu);
4578 const high_int: i64 = if (high_bigint.positive) @bitCast(
4579 high_bigint.toInt(u64) catch
4580 return isel.fail("too big case range end: {f}", .{isel.fmtConstant(high_val)}),
4581 ) else high_bigint.toInt(i64) catch
4582 return isel.fail("too big case range end: {f}", .{isel.fmtConstant(high_val)});
4583
4584 const adjusted_ra = switch (low_int) {
4585 0 => cond_mat.?.ra,
4586 else => try isel.allocIntReg(),
4587 };
4588 defer if (adjusted_ra != cond_mat.?.ra) isel.freeReg(adjusted_ra);
4589 const adjusted_reg = switch (cond_int_info.bits) {
4590 else => unreachable,
4591 1...32 => adjusted_ra.w(),
4592 33...64 => adjusted_ra.x(),
4593 };
4594 const delta_int = high_int -% low_int;
4595 if (case_range_index | case.items.len > 0) {
4596 if (std.math.cast(u5, delta_int)) |pos_imm| try isel.emit(.ccmp(
4597 adjusted_reg,
4598 .{ .immediate = pos_imm },
4599 .{ .n = false, .z = true, .c = false, .v = false },
4600 if (case_range_index > 0) .hi else .ne,
4601 )) else if (std.math.cast(u5, -delta_int)) |neg_imm| try isel.emit(.ccmn(
4602 adjusted_reg,
4603 .{ .immediate = neg_imm },
4604 .{ .n = false, .z = true, .c = false, .v = false },
4605 if (case_range_index > 0) .hi else .ne,
4606 )) else {
4607 const imm_ra = try isel.allocIntReg();
4608 defer isel.freeReg(imm_ra);
4609 const imm_reg = switch (cond_int_info.bits) {
4610 else => unreachable,
4611 1...32 => imm_ra.w(),
4612 33...64 => imm_ra.x(),
4613 };
4614 try isel.emit(.ccmp(
4615 cond_reg,
4616 .{ .register = imm_reg },
4617 .{ .n = false, .z = true, .c = false, .v = false },
4618 if (case_range_index > 0) .hi else .ne,
4619 ));
4620 try isel.movImmediate(imm_reg, @bitCast(delta_int));
4621 }
4622 } else {
4623 if (std.math.cast(u12, delta_int)) |pos_imm| try isel.emit(.subs(
4624 zero_reg,
4625 adjusted_reg,
4626 .{ .immediate = pos_imm },
4627 )) else if (std.math.cast(u12, -delta_int)) |neg_imm| try isel.emit(.adds(
4628 zero_reg,
4629 adjusted_reg,
4630 .{ .immediate = neg_imm },
4631 )) else if (if (@as(i12, @truncate(delta_int)) == 0)
4632 std.math.cast(u12, delta_int >> 12)
4633 else
4634 null) |pos_imm_lsr_12| try isel.emit(.subs(
4635 zero_reg,
4636 adjusted_reg,
4637 .{ .shifted_immediate = .{ .immediate = pos_imm_lsr_12, .lsl = .@"12" } },
4638 )) else if (if (@as(i12, @truncate(-delta_int)) == 0)
4639 std.math.cast(u12, -delta_int >> 12)
4640 else
4641 null) |neg_imm_lsr_12| try isel.emit(.adds(
4642 zero_reg,
4643 adjusted_reg,
4644 .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } },
4645 )) else {
4646 const imm_ra = try isel.allocIntReg();
4647 defer isel.freeReg(imm_ra);
4648 const imm_reg = switch (cond_int_info.bits) {
4649 else => unreachable,
4650 1...32 => imm_ra.w(),
4651 33...64 => imm_ra.x(),
4652 };
4653 try isel.emit(.subs(zero_reg, adjusted_reg, .{ .register = imm_reg }));
4654 try isel.movImmediate(imm_reg, @bitCast(delta_int));
4655 }
4656 }
4657
4658 switch (low_int) {
4659 0 => {},
4660 else => {
4661 if (std.math.cast(u12, low_int)) |pos_imm| try isel.emit(.sub(
4662 adjusted_reg,
4663 cond_reg,
4664 .{ .immediate = pos_imm },
4665 )) else if (std.math.cast(u12, -low_int)) |neg_imm| try isel.emit(.add(
4666 adjusted_reg,
4667 cond_reg,
4668 .{ .immediate = neg_imm },
4669 )) else if (if (@as(i12, @truncate(low_int)) == 0)
4670 std.math.cast(u12, low_int >> 12)
4671 else
4672 null) |pos_imm_lsr_12| try isel.emit(.sub(
4673 adjusted_reg,
4674 cond_reg,
4675 .{ .shifted_immediate = .{ .immediate = pos_imm_lsr_12, .lsl = .@"12" } },
4676 )) else if (if (@as(i12, @truncate(-low_int)) == 0)
4677 std.math.cast(u12, -low_int >> 12)
4678 else
4679 null) |neg_imm_lsr_12| try isel.emit(.add(
4680 adjusted_reg,
4681 cond_reg,
4682 .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } },
4683 )) else {
4684 const imm_ra = try isel.allocIntReg();
4685 defer isel.freeReg(imm_ra);
4686 const imm_reg = switch (cond_int_info.bits) {
4687 else => unreachable,
4688 1...32 => imm_ra.w(),
4689 33...64 => imm_ra.x(),
4690 };
4691 try isel.emit(.sub(adjusted_reg, cond_reg, .{ .register = imm_reg }));
4692 try isel.movImmediate(imm_reg, @bitCast(low_int));
4693 }
4694 },
4695 }
4696 }
4697 var case_item_index = case.items.len;
4698 while (case_item_index > 0) {
4699 case_item_index -= 1;
4700
4701 const item_val: Constant = .fromInterned(case.items[case_item_index].toInterned().?);
4702 var item_bigint_space: Constant.BigIntSpace = undefined;
4703 const item_bigint = item_val.toBigInt(&item_bigint_space, zcu);
4704 const item_int: i64 = if (item_bigint.positive) @bitCast(
4705 item_bigint.toInt(u64) catch
4706 return isel.fail("too big case item: {f}", .{isel.fmtConstant(item_val)}),
4707 ) else item_bigint.toInt(i64) catch
4708 return isel.fail("too big case item: {f}", .{isel.fmtConstant(item_val)});
4709
4710 if (case_item_index > 0) {
4711 if (std.math.cast(u5, item_int)) |pos_imm| try isel.emit(.ccmp(
4712 cond_reg,
4713 .{ .immediate = pos_imm },
4714 .{ .n = false, .z = true, .c = false, .v = false },
4715 .ne,
4716 )) else if (std.math.cast(u5, -item_int)) |neg_imm| try isel.emit(.ccmn(
4717 cond_reg,
4718 .{ .immediate = neg_imm },
4719 .{ .n = false, .z = true, .c = false, .v = false },
4720 .ne,
4721 )) else {
4722 const imm_ra = try isel.allocIntReg();
4723 defer isel.freeReg(imm_ra);
4724 const imm_reg = switch (cond_int_info.bits) {
4725 else => unreachable,
4726 1...32 => imm_ra.w(),
4727 33...64 => imm_ra.x(),
4728 };
4729 try isel.emit(.ccmp(
4730 cond_reg,
4731 .{ .register = imm_reg },
4732 .{ .n = false, .z = true, .c = false, .v = false },
4733 .ne,
4734 ));
4735 try isel.movImmediate(imm_reg, @bitCast(item_int));
4736 }
4737 } else {
4738 if (std.math.cast(u12, item_int)) |pos_imm| try isel.emit(.subs(
4739 zero_reg,
4740 cond_reg,
4741 .{ .immediate = pos_imm },
4742 )) else if (std.math.cast(u12, -item_int)) |neg_imm| try isel.emit(.adds(
4743 zero_reg,
4744 cond_reg,
4745 .{ .immediate = neg_imm },
4746 )) else if (if (@as(i12, @truncate(item_int)) == 0)
4747 std.math.cast(u12, item_int >> 12)
4748 else
4749 null) |pos_imm_lsr_12| try isel.emit(.subs(
4750 zero_reg,
4751 cond_reg,
4752 .{ .shifted_immediate = .{ .immediate = pos_imm_lsr_12, .lsl = .@"12" } },
4753 )) else if (if (@as(i12, @truncate(-item_int)) == 0)
4754 std.math.cast(u12, -item_int >> 12)
4755 else
4756 null) |neg_imm_lsr_12| try isel.emit(.adds(
4757 zero_reg,
4758 cond_reg,
4759 .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } },
4760 )) else {
4761 const imm_ra = try isel.allocIntReg();
4762 defer isel.freeReg(imm_ra);
4763 const imm_reg = switch (cond_int_info.bits) {
4764 else => unreachable,
4765 1...32 => imm_ra.w(),
4766 33...64 => imm_ra.x(),
4767 };
4768 try isel.emit(.subs(zero_reg, cond_reg, .{ .register = imm_reg }));
4769 try isel.movImmediate(imm_reg, @bitCast(item_int));
4770 }
4771 }
4772 }
4773 }
4774 if (cond_mat) |mat| try mat.finish(isel);
4775 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4776 },
4777 .@"try", .try_cold => {
4778 const pl_op = air.data(air.inst_index).pl_op;
4779 const extra = isel.air.extraData(Air.Try, pl_op.payload);
4780 const error_union_ty = isel.air.typeOf(pl_op.operand, ip);
4781 const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type;
4782 const payload_ty: ZigType = .fromInterned(error_union_info.payload_type);
4783
4784 const error_union_vi = try isel.use(pl_op.operand);
4785 if (isel.live_values.fetchRemove(air.inst_index)) |payload_vi| {
4786 defer payload_vi.value.deref(isel);
4787
4788 var payload_part_it = error_union_vi.field(
4789 error_union_ty,
4790 codegen.errUnionPayloadOffset(payload_ty, zcu),
4791 payload_vi.value.size(isel),
4792 );
4793 const payload_part_vi = try payload_part_it.only(isel);
4794 try payload_vi.value.copy(isel, payload_ty, payload_part_vi.?);
4795 }
4796
4797 const cont_label = isel.instructions.items.len;
4798 const cont_live_registers = isel.live_registers;
4799 try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));
4800 try isel.merge(&cont_live_registers, .{});
4801
4802 var error_set_part_it = error_union_vi.field(
4803 error_union_ty,
4804 codegen.errUnionErrorOffset(payload_ty, zcu),
4805 ZigType.fromInterned(error_union_info.error_set_type).abiSize(zcu),
4806 );
4807 const error_set_part_vi = try error_set_part_it.only(isel);
4808 const error_set_part_mat = try error_set_part_vi.?.matReg(isel);
4809 try isel.emit(.cbz(
4810 error_set_part_mat.ra.w(),
4811 @intCast((isel.instructions.items.len + 1 - cont_label) << 2),
4812 ));
4813 try error_set_part_mat.finish(isel);
4814
4815 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4816 },
4817 .try_ptr, .try_ptr_cold => {
4818 const ty_pl = air.data(air.inst_index).ty_pl;
4819 const extra = isel.air.extraData(Air.TryPtr, ty_pl.payload);
4820 const error_union_ty = isel.air.typeOf(extra.data.ptr, ip).childType(zcu);
4821 const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type;
4822 const payload_ty: ZigType = .fromInterned(error_union_info.payload_type);
4823
4824 const error_union_ptr_vi = try isel.use(extra.data.ptr);
4825 const error_union_ptr_mat = try error_union_ptr_vi.matReg(isel);
4826 if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| unused: {
4827 defer payload_ptr_vi.value.deref(isel);
4828 switch (codegen.errUnionPayloadOffset(ty_pl.ty.toType().childType(zcu), zcu)) {
4829 0 => try payload_ptr_vi.value.move(isel, extra.data.ptr),
4830 else => |payload_offset| {
4831 const payload_ptr_ra = try payload_ptr_vi.value.defReg(isel) orelse break :unused;
4832 const lo12: u12 = @truncate(payload_offset >> 0);
4833 const hi12: u12 = @intCast(payload_offset >> 12);
4834 if (hi12 > 0) try isel.emit(.add(
4835 payload_ptr_ra.x(),
4836 if (lo12 > 0) payload_ptr_ra.x() else error_union_ptr_mat.ra.x(),
4837 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
4838 ));
4839 if (lo12 > 0) try isel.emit(.add(payload_ptr_ra.x(), error_union_ptr_mat.ra.x(), .{ .immediate = lo12 }));
4840 },
4841 }
4842 }
4843
4844 const cont_label = isel.instructions.items.len;
4845 const cont_live_registers = isel.live_registers;
4846 try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len]));
4847 try isel.merge(&cont_live_registers, .{});
4848
4849 const error_set_ra = try isel.allocIntReg();
4850 defer isel.freeReg(error_set_ra);
4851 try isel.loadReg(
4852 error_set_ra,
4853 ZigType.fromInterned(error_union_info.error_set_type).abiSize(zcu),
4854 .unsigned,
4855 error_union_ptr_mat.ra,
4856 codegen.errUnionErrorOffset(payload_ty, zcu),
4857 );
4858 try error_union_ptr_mat.finish(isel);
4859 try isel.emit(.cbz(
4860 error_set_ra.w(),
4861 @intCast((isel.instructions.items.len + 1 - cont_label) << 2),
4862 ));
4863
4864 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4865 },
4866 .dbg_stmt => if (air.next()) |next_air_tag| continue :air_tag next_air_tag,
4867 .dbg_empty_stmt => {
4868 try isel.emit(.nop());
4869 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4870 },
4871 .dbg_inline_block => {
4872 const ty_pl = air.data(air.inst_index).ty_pl;
4873 const extra = isel.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
4874 try isel.block(air.inst_index, ty_pl.ty.toType(), @ptrCast(
4875 isel.air.extra.items[extra.end..][0..extra.data.body_len],
4876 ));
4877 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4878 },
4879 .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => {
4880 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4881 },
4882 .is_null, .is_non_null => |air_tag| {
4883 if (isel.live_values.fetchRemove(air.inst_index)) |is_vi| unused: {
4884 defer is_vi.value.deref(isel);
4885 const is_ra = try is_vi.value.defReg(isel) orelse break :unused;
4886
4887 const un_op = air.data(air.inst_index).un_op;
4888 const opt_ty = isel.air.typeOf(un_op, ip);
4889 const payload_ty = opt_ty.optionalChild(zcu);
4890 const payload_size = payload_ty.abiSize(zcu);
4891 const has_value_offset, const has_value_size = if (!opt_ty.optionalReprIsPayload(zcu))
4892 .{ payload_size, 1 }
4893 else if (payload_ty.isSlice(zcu))
4894 .{ 0, 8 }
4895 else
4896 .{ 0, payload_size };
4897
4898 try isel.emit(.csinc(is_ra.w(), .wzr, .wzr, .invert(switch (air_tag) {
4899 else => unreachable,
4900 .is_null => .eq,
4901 .is_non_null => .ne,
4902 })));
4903 const opt_vi = try isel.use(un_op);
4904 var has_value_part_it = opt_vi.field(opt_ty, has_value_offset, has_value_size);
4905 const has_value_part_vi = try has_value_part_it.only(isel);
4906 const has_value_part_mat = try has_value_part_vi.?.matReg(isel);
4907 try isel.emit(switch (has_value_size) {
4908 else => unreachable,
4909 1...4 => .subs(.wzr, has_value_part_mat.ra.w(), .{ .immediate = 0 }),
4910 5...8 => .subs(.xzr, has_value_part_mat.ra.x(), .{ .immediate = 0 }),
4911 });
4912 try has_value_part_mat.finish(isel);
4913 }
4914 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4915 },
4916 .is_err, .is_non_err => |air_tag| {
4917 if (isel.live_values.fetchRemove(air.inst_index)) |is_vi| unused: {
4918 defer is_vi.value.deref(isel);
4919 const is_ra = try is_vi.value.defReg(isel) orelse break :unused;
4920
4921 const un_op = air.data(air.inst_index).un_op;
4922 const error_union_ty = isel.air.typeOf(un_op, ip);
4923 const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type;
4924 const error_set_ty: ZigType = .fromInterned(error_union_info.error_set_type);
4925 const payload_ty: ZigType = .fromInterned(error_union_info.payload_type);
4926 const error_set_offset = codegen.errUnionErrorOffset(payload_ty, zcu);
4927 const error_set_size = error_set_ty.abiSize(zcu);
4928
4929 try isel.emit(.csinc(is_ra.w(), .wzr, .wzr, .invert(switch (air_tag) {
4930 else => unreachable,
4931 .is_err => .ne,
4932 .is_non_err => .eq,
4933 })));
4934 const error_union_vi = try isel.use(un_op);
4935 var error_set_part_it = error_union_vi.field(error_union_ty, error_set_offset, error_set_size);
4936 const error_set_part_vi = try error_set_part_it.only(isel);
4937 const error_set_part_mat = try error_set_part_vi.?.matReg(isel);
4938 try isel.emit(.ands(.wzr, error_set_part_mat.ra.w(), .{ .immediate = .{
4939 .N = .word,
4940 .immr = 0,
4941 .imms = @intCast(8 * error_set_size - 1),
4942 } }));
4943 try error_set_part_mat.finish(isel);
4944 }
4945 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4946 },
4947 .load => {
4948 const ty_op = air.data(air.inst_index).ty_op;
4949 const ptr_ty = isel.air.typeOf(ty_op.operand, ip);
4950 const ptr_info = ptr_ty.ptrInfo(zcu);
4951 if (ptr_info.packed_offset.host_size > 0) return isel.fail("packed load", .{});
4952
4953 if (ptr_info.flags.is_volatile) _ = try isel.use(air.inst_index.toRef());
4954 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
4955 defer dst_vi.value.deref(isel);
4956 switch (dst_vi.value.size(isel)) {
4957 0 => unreachable,
4958 1...Value.max_parts => {
4959 const ptr_vi = try isel.use(ty_op.operand);
4960 const ptr_mat = try ptr_vi.matReg(isel);
4961 _ = try dst_vi.value.load(isel, ty_op.ty.toType(), ptr_mat.ra, .{
4962 .@"volatile" = ptr_info.flags.is_volatile,
4963 });
4964 try ptr_mat.finish(isel);
4965 },
4966 else => |size| {
4967 try dst_vi.value.defAddr(isel, .fromInterned(ptr_info.child), null, comptime &.initFill(.free)) orelse break :unused;
4968
4969 try call.prepareReturn(isel);
4970 try call.finishReturn(isel);
4971
4972 try call.prepareCallee(isel);
4973 try isel.global_relocs.append(gpa, .{
4974 .name = "memcpy",
4975 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
4976 });
4977 try isel.emit(.bl(0));
4978 try call.finishCallee(isel);
4979
4980 try call.prepareParams(isel);
4981 const ptr_vi = try isel.use(ty_op.operand);
4982 try isel.movImmediate(.x2, size);
4983 try call.paramLiveOut(isel, ptr_vi, .r1);
4984 try call.paramAddress(isel, dst_vi.value, .r0);
4985 try call.finishParams(isel);
4986 },
4987 }
4988 }
4989
4990 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
4991 },
4992 .ret, .ret_safe => {
4993 assert(isel.blocks.keys()[0] == Block.main);
4994 try isel.blocks.values()[0].branch(isel);
4995 if (isel.live_values.get(Block.main)) |ret_vi| {
4996 const un_op = air.data(air.inst_index).un_op;
4997 const src_vi = try isel.use(un_op);
4998 switch (ret_vi.parent(isel)) {
4999 .unallocated, .stack_slot => if (ret_vi.hint(isel)) |ret_ra| {
5000 try src_vi.liveOut(isel, ret_ra);
5001 } else {
5002 var ret_part_it = ret_vi.parts(isel);
5003 var src_part_it = src_vi.parts(isel);
5004 if (src_part_it.only()) |_| {
5005 try isel.values.ensureUnusedCapacity(gpa, ret_part_it.remaining);
5006 src_vi.setParts(isel, ret_part_it.remaining);
5007 while (ret_part_it.next()) |ret_part_vi| {
5008 const src_part_vi = src_vi.addPart(
5009 isel,
5010 ret_part_vi.get(isel).offset_from_parent,
5011 ret_part_vi.size(isel),
5012 );
5013 switch (ret_part_vi.signedness(isel)) {
5014 .signed => src_part_vi.setSignedness(isel, .signed),
5015 .unsigned => {},
5016 }
5017 if (ret_part_vi.isVector(isel)) src_part_vi.setIsVector(isel);
5018 }
5019 ret_part_it = ret_vi.parts(isel);
5020 src_part_it = src_vi.parts(isel);
5021 }
5022 while (ret_part_it.next()) |ret_part_vi| {
5023 const src_part_vi = src_part_it.next().?;
5024 assert(ret_part_vi.get(isel).offset_from_parent == src_part_vi.get(isel).offset_from_parent);
5025 assert(ret_part_vi.size(isel) == src_part_vi.size(isel));
5026 try src_part_vi.liveOut(isel, ret_part_vi.hint(isel).?);
5027 }
5028 },
5029 .value, .constant => unreachable,
5030 .address => |address_vi| {
5031 const ptr_mat = try address_vi.matReg(isel);
5032 try src_vi.store(isel, isel.air.typeOf(un_op, ip), ptr_mat.ra, .{});
5033 try ptr_mat.finish(isel);
5034 },
5035 }
5036 }
5037 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5038 },
5039 .ret_load => {
5040 const un_op = air.data(air.inst_index).un_op;
5041 const ptr_ty = isel.air.typeOf(un_op, ip);
5042 const ptr_info = ptr_ty.ptrInfo(zcu);
5043 if (ptr_info.packed_offset.host_size > 0) return isel.fail("packed load", .{});
5044
5045 assert(isel.blocks.keys()[0] == Block.main);
5046 try isel.blocks.values()[0].branch(isel);
5047 if (isel.live_values.get(Block.main)) |ret_vi| switch (ret_vi.parent(isel)) {
5048 .unallocated, .stack_slot => {
5049 var ret_part_it: Value.PartIterator = if (ret_vi.hint(isel)) |_| .initOne(ret_vi) else ret_vi.parts(isel);
5050 while (ret_part_it.next()) |ret_part_vi| try ret_part_vi.liveOut(isel, ret_part_vi.hint(isel).?);
5051 const ptr_vi = try isel.use(un_op);
5052 const ptr_mat = try ptr_vi.matReg(isel);
5053 _ = try ret_vi.load(isel, .fromInterned(ptr_info.child), ptr_mat.ra, .{});
5054 try ptr_mat.finish(isel);
5055 },
5056 .value, .constant => unreachable,
5057 .address => {},
5058 };
5059 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5060 },
5061 .store, .store_safe, .atomic_store_unordered => {
5062 const bin_op = air.data(air.inst_index).bin_op;
5063 const ptr_ty = isel.air.typeOf(bin_op.lhs, ip);
5064 const ptr_info = ptr_ty.ptrInfo(zcu);
5065 if (ptr_info.packed_offset.host_size > 0) return isel.fail("packed store", .{});
5066 if (bin_op.rhs.toInterned()) |rhs_val| if (ip.isUndef(rhs_val))
5067 break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5068
5069 const src_vi = try isel.use(bin_op.rhs);
5070 const size = src_vi.size(isel);
5071 if (ZigType.fromInterned(ptr_info.child).zigTypeTag(zcu) != .@"union") switch (size) {
5072 0 => unreachable,
5073 1...Value.max_parts => {
5074 const ptr_vi = try isel.use(bin_op.lhs);
5075 const ptr_mat = try ptr_vi.matReg(isel);
5076 try src_vi.store(isel, isel.air.typeOf(bin_op.rhs, ip), ptr_mat.ra, .{
5077 .@"volatile" = ptr_info.flags.is_volatile,
5078 });
5079 try ptr_mat.finish(isel);
5080
5081 break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5082 },
5083 else => {},
5084 };
5085 try call.prepareReturn(isel);
5086 try call.finishReturn(isel);
5087
5088 try call.prepareCallee(isel);
5089 try isel.global_relocs.append(gpa, .{
5090 .name = "memcpy",
5091 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
5092 });
5093 try isel.emit(.bl(0));
5094 try call.finishCallee(isel);
5095
5096 try call.prepareParams(isel);
5097 const ptr_vi = try isel.use(bin_op.lhs);
5098 try isel.movImmediate(.x2, size);
5099 try call.paramAddress(isel, src_vi, .r1);
5100 try call.paramLiveOut(isel, ptr_vi, .r0);
5101 try call.finishParams(isel);
5102
5103 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5104 },
5105 .unreach => if (air.next()) |next_air_tag| continue :air_tag next_air_tag,
5106 .fptrunc, .fpext => {
5107 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
5108 defer dst_vi.value.deref(isel);
5109
5110 const ty_op = air.data(air.inst_index).ty_op;
5111 const dst_ty = ty_op.ty.toType();
5112 const dst_bits = dst_ty.floatBits(isel.target);
5113 const src_ty = isel.air.typeOf(ty_op.operand, ip);
5114 const src_bits = src_ty.floatBits(isel.target);
5115 assert(dst_bits != src_bits);
5116 switch (@max(dst_bits, src_bits)) {
5117 else => unreachable,
5118 16, 32, 64 => {
5119 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
5120 const src_vi = try isel.use(ty_op.operand);
5121 const src_mat = try src_vi.matReg(isel);
5122 try isel.emit(.fcvt(switch (dst_bits) {
5123 else => unreachable,
5124 16 => dst_ra.h(),
5125 32 => dst_ra.s(),
5126 64 => dst_ra.d(),
5127 }, switch (src_bits) {
5128 else => unreachable,
5129 16 => src_mat.ra.h(),
5130 32 => src_mat.ra.s(),
5131 64 => src_mat.ra.d(),
5132 }));
5133 try src_mat.finish(isel);
5134 },
5135 80, 128 => {
5136 try call.prepareReturn(isel);
5137 switch (dst_bits) {
5138 else => unreachable,
5139 16, 32, 64, 128 => try call.returnLiveIn(isel, dst_vi.value, .v0),
5140 80 => {
5141 var dst_hi16_it = dst_vi.value.field(dst_ty, 8, 8);
5142 const dst_hi16_vi = try dst_hi16_it.only(isel);
5143 try call.returnLiveIn(isel, dst_hi16_vi.?, .r1);
5144 var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8);
5145 const dst_lo64_vi = try dst_lo64_it.only(isel);
5146 try call.returnLiveIn(isel, dst_lo64_vi.?, .r0);
5147 },
5148 }
5149 try call.finishReturn(isel);
5150
5151 try call.prepareCallee(isel);
5152 try isel.global_relocs.append(gpa, .{
5153 .name = switch (dst_bits) {
5154 else => unreachable,
5155 16 => switch (src_bits) {
5156 else => unreachable,
5157 32 => "__truncsfhf2",
5158 64 => "__truncdfhf2",
5159 80 => "__truncxfhf2",
5160 128 => "__trunctfhf2",
5161 },
5162 32 => switch (src_bits) {
5163 else => unreachable,
5164 16 => "__extendhfsf2",
5165 64 => "__truncdfsf2",
5166 80 => "__truncxfsf2",
5167 128 => "__trunctfsf2",
5168 },
5169 64 => switch (src_bits) {
5170 else => unreachable,
5171 16 => "__extendhfdf2",
5172 32 => "__extendsfdf2",
5173 80 => "__truncxfdf2",
5174 128 => "__trunctfdf2",
5175 },
5176 80 => switch (src_bits) {
5177 else => unreachable,
5178 16 => "__extendhfxf2",
5179 32 => "__extendsfxf2",
5180 64 => "__extenddfxf2",
5181 128 => "__trunctfxf2",
5182 },
5183 128 => switch (src_bits) {
5184 else => unreachable,
5185 16 => "__extendhftf2",
5186 32 => "__extendsftf2",
5187 64 => "__extenddftf2",
5188 80 => "__extendxftf2",
5189 },
5190 },
5191 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
5192 });
5193 try isel.emit(.bl(0));
5194 try call.finishCallee(isel);
5195
5196 try call.prepareParams(isel);
5197 const src_vi = try isel.use(ty_op.operand);
5198 switch (src_bits) {
5199 else => unreachable,
5200 16, 32, 64, 128 => try call.paramLiveOut(isel, src_vi, .v0),
5201 80 => {
5202 var src_hi16_it = src_vi.field(src_ty, 8, 8);
5203 const src_hi16_vi = try src_hi16_it.only(isel);
5204 try call.paramLiveOut(isel, src_hi16_vi.?, .r1);
5205 var src_lo64_it = src_vi.field(src_ty, 0, 8);
5206 const src_lo64_vi = try src_lo64_it.only(isel);
5207 try call.paramLiveOut(isel, src_lo64_vi.?, .r0);
5208 },
5209 }
5210 try call.finishParams(isel);
5211 },
5212 }
5213 }
5214 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5215 },
5216 .intcast => |air_tag| {
5217 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
5218 defer dst_vi.value.deref(isel);
5219
5220 const ty_op = air.data(air.inst_index).ty_op;
5221 const dst_ty = ty_op.ty.toType();
5222 const dst_int_info = dst_ty.intInfo(zcu);
5223 const src_ty = isel.air.typeOf(ty_op.operand, ip);
5224 const src_int_info = src_ty.intInfo(zcu);
5225 const can_be_negative = dst_int_info.signedness == .signed and
5226 src_int_info.signedness == .signed;
5227 if ((dst_int_info.bits <= 8 and src_int_info.bits <= 8) or
5228 (dst_int_info.bits > 8 and dst_int_info.bits <= 16 and
5229 src_int_info.bits > 8 and src_int_info.bits <= 16) or
5230 (dst_int_info.bits > 16 and dst_int_info.bits <= 32 and
5231 src_int_info.bits > 16 and src_int_info.bits <= 32) or
5232 (dst_int_info.bits > 32 and dst_int_info.bits <= 64 and
5233 src_int_info.bits > 32 and src_int_info.bits <= 64) or
5234 (dst_int_info.bits > 64 and src_int_info.bits > 64 and
5235 (dst_int_info.bits - 1) / 128 == (src_int_info.bits - 1) / 128))
5236 {
5237 try dst_vi.value.move(isel, ty_op.operand);
5238 } else if (dst_int_info.bits <= 32 and src_int_info.bits <= 64) {
5239 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
5240 const src_vi = try isel.use(ty_op.operand);
5241 const src_mat = try src_vi.matReg(isel);
5242 try isel.emit(.orr(dst_ra.w(), .wzr, .{ .register = src_mat.ra.w() }));
5243 try src_mat.finish(isel);
5244 } else if (dst_int_info.bits <= 64 and src_int_info.bits <= 32) {
5245 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
5246 const src_vi = try isel.use(ty_op.operand);
5247 const src_mat = try src_vi.matReg(isel);
5248 try isel.emit(if (can_be_negative) .sbfm(dst_ra.x(), src_mat.ra.x(), .{
5249 .N = .doubleword,
5250 .immr = 0,
5251 .imms = @intCast(src_int_info.bits - 1),
5252 }) else .orr(dst_ra.w(), .wzr, .{ .register = src_mat.ra.w() }));
5253 try src_mat.finish(isel);
5254 } else if (dst_int_info.bits <= 32 and src_int_info.bits <= 128) {
5255 assert(src_int_info.bits > 64);
5256 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
5257 const src_vi = try isel.use(ty_op.operand);
5258
5259 var src_lo64_it = src_vi.field(src_ty, 0, 8);
5260 const src_lo64_vi = try src_lo64_it.only(isel);
5261 const src_lo64_mat = try src_lo64_vi.?.matReg(isel);
5262 try isel.emit(.orr(dst_ra.w(), .wzr, .{ .register = src_lo64_mat.ra.w() }));
5263 try src_lo64_mat.finish(isel);
5264 } else if (dst_int_info.bits <= 64 and src_int_info.bits <= 128) {
5265 assert(dst_int_info.bits > 32 and src_int_info.bits > 64);
5266 const src_vi = try isel.use(ty_op.operand);
5267
5268 var src_lo64_it = src_vi.field(src_ty, 0, 8);
5269 const src_lo64_vi = try src_lo64_it.only(isel);
5270 try dst_vi.value.copy(isel, dst_ty, src_lo64_vi.?);
5271 } else if (dst_int_info.bits <= 128 and src_int_info.bits <= 64) {
5272 assert(dst_int_info.bits > 64);
5273 const src_vi = try isel.use(ty_op.operand);
5274
5275 var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8);
5276 const dst_lo64_vi = try dst_lo64_it.only(isel);
5277 if (src_int_info.bits <= 32) unused_lo64: {
5278 const dst_lo64_ra = try dst_lo64_vi.?.defReg(isel) orelse break :unused_lo64;
5279 const src_mat = try src_vi.matReg(isel);
5280 try isel.emit(if (can_be_negative) .sbfm(dst_lo64_ra.x(), src_mat.ra.x(), .{
5281 .N = .doubleword,
5282 .immr = 0,
5283 .imms = @intCast(src_int_info.bits - 1),
5284 }) else .orr(dst_lo64_ra.w(), .wzr, .{ .register = src_mat.ra.w() }));
5285 try src_mat.finish(isel);
5286 } else try dst_lo64_vi.?.copy(isel, src_ty, src_vi);
5287
5288 var dst_hi64_it = dst_vi.value.field(dst_ty, 8, 8);
5289 const dst_hi64_vi = try dst_hi64_it.only(isel);
5290 const dst_hi64_ra = try dst_hi64_vi.?.defReg(isel);
5291 if (dst_hi64_ra) |dst_ra| switch (can_be_negative) {
5292 false => try isel.emit(.orr(dst_ra.x(), .xzr, .{ .register = .xzr })),
5293 true => {
5294 const src_mat = try src_vi.matReg(isel);
5295 try isel.emit(.sbfm(dst_ra.x(), src_mat.ra.x(), .{
5296 .N = .doubleword,
5297 .immr = @intCast(src_int_info.bits - 1),
5298 .imms = @intCast(src_int_info.bits - 1),
5299 }));
5300 try src_mat.finish(isel);
5301 },
5302 };
5303 } else return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });
5304 }
5305 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5306 },
5307 .intcast_safe => |air_tag| {
5308 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
5309 defer dst_vi.value.deref(isel);
5310
5311 const ty_op = air.data(air.inst_index).ty_op;
5312 const dst_ty = ty_op.ty.toType();
5313 const dst_int_info = dst_ty.intInfo(zcu);
5314 const src_ty = isel.air.typeOf(ty_op.operand, ip);
5315 const src_int_info = src_ty.intInfo(zcu);
5316 const can_be_negative = dst_int_info.signedness == .signed and
5317 src_int_info.signedness == .signed;
5318 const panic_id: Zcu.SimplePanicId = panic_id: switch (dst_ty.zigTypeTag(zcu)) {
5319 else => unreachable,
5320 .int => .integer_out_of_bounds,
5321 .@"enum" => {
5322 if (!dst_ty.isNonexhaustiveEnum(zcu)) {
5323 return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });
5324 }
5325 break :panic_id .invalid_enum_value;
5326 },
5327 };
5328 if (dst_ty.toIntern() == src_ty.toIntern()) {
5329 try dst_vi.value.move(isel, ty_op.operand);
5330 } else if (dst_int_info.bits <= 64 and src_int_info.bits <= 64) {
5331 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
5332 const src_vi = try isel.use(ty_op.operand);
5333 const dst_active_bits = dst_int_info.bits - @intFromBool(dst_int_info.signedness == .signed);
5334 const src_active_bits = src_int_info.bits - @intFromBool(src_int_info.signedness == .signed);
5335 if ((dst_int_info.signedness != .unsigned or src_int_info.signedness != .signed) and dst_active_bits >= src_active_bits) {
5336 const src_mat = try src_vi.matReg(isel);
5337 try isel.emit(if (can_be_negative and dst_active_bits > 32 and src_active_bits <= 32)
5338 .sbfm(dst_ra.x(), src_mat.ra.x(), .{
5339 .N = .doubleword,
5340 .immr = 0,
5341 .imms = @intCast(src_int_info.bits - 1),
5342 })
5343 else switch (src_int_info.bits) {
5344 else => unreachable,
5345 1...32 => .orr(dst_ra.w(), .wzr, .{ .register = src_mat.ra.w() }),
5346 33...64 => .orr(dst_ra.x(), .xzr, .{ .register = src_mat.ra.x() }),
5347 });
5348 try src_mat.finish(isel);
5349 } else {
5350 const skip_label = isel.instructions.items.len;
5351 try isel.emitPanic(panic_id);
5352 try isel.emit(.@"b."(
5353 .eq,
5354 @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
5355 ));
5356 if (can_be_negative) {
5357 const src_mat = src_mat: {
5358 const dst_lock = isel.lockReg(dst_ra);
5359 defer dst_lock.unlock(isel);
5360 break :src_mat try src_vi.matReg(isel);
5361 };
5362 try isel.emit(switch (src_int_info.bits) {
5363 else => unreachable,
5364 1...32 => .subs(.wzr, dst_ra.w(), .{ .register = src_mat.ra.w() }),
5365 33...64 => .subs(.xzr, dst_ra.x(), .{ .register = src_mat.ra.x() }),
5366 });
5367 try isel.emit(switch (@max(dst_int_info.bits, src_int_info.bits)) {
5368 else => unreachable,
5369 1...32 => .sbfm(dst_ra.w(), src_mat.ra.w(), .{
5370 .N = .word,
5371 .immr = 0,
5372 .imms = @intCast(dst_int_info.bits - 1),
5373 }),
5374 33...64 => .sbfm(dst_ra.x(), src_mat.ra.x(), .{
5375 .N = .doubleword,
5376 .immr = 0,
5377 .imms = @intCast(dst_int_info.bits - 1),
5378 }),
5379 });
5380 try src_mat.finish(isel);
5381 } else {
5382 const src_mat = try src_vi.matReg(isel);
5383 try isel.emit(switch (@min(dst_int_info.bits, src_int_info.bits)) {
5384 else => unreachable,
5385 1...32 => .orr(dst_ra.w(), .wzr, .{ .register = src_mat.ra.w() }),
5386 33...64 => .orr(dst_ra.x(), .xzr, .{ .register = src_mat.ra.x() }),
5387 });
5388 const active_bits = @min(dst_active_bits, src_active_bits);
5389 try isel.emit(switch (src_int_info.bits) {
5390 else => unreachable,
5391 1...32 => .ands(.wzr, src_mat.ra.w(), .{ .immediate = .{
5392 .N = .word,
5393 .immr = @intCast(32 - active_bits),
5394 .imms = @intCast(32 - active_bits - 1),
5395 } }),
5396 33...64 => .ands(.xzr, src_mat.ra.x(), .{ .immediate = .{
5397 .N = .doubleword,
5398 .immr = @intCast(64 - active_bits),
5399 .imms = @intCast(64 - active_bits - 1),
5400 } }),
5401 });
5402 try src_mat.finish(isel);
5403 }
5404 }
5405 } else return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });
5406 }
5407 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5408 },
5409 .trunc => |air_tag| {
5410 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
5411 defer dst_vi.value.deref(isel);
5412
5413 const ty_op = air.data(air.inst_index).ty_op;
5414 const dst_ty = ty_op.ty.toType();
5415 const src_ty = isel.air.typeOf(ty_op.operand, ip);
5416 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) });
5417 const dst_int_info = dst_ty.intInfo(zcu);
5418 switch (dst_int_info.bits) {
5419 0 => unreachable,
5420 1...64 => |dst_bits| {
5421 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
5422 const src_vi = try isel.use(ty_op.operand);
5423 var src_part_it = src_vi.field(src_ty, 0, @min(src_vi.size(isel), 8));
5424 const src_part_vi = try src_part_it.only(isel);
5425 const src_part_mat = try src_part_vi.?.matReg(isel);
5426 try isel.emit(switch (dst_bits) {
5427 else => unreachable,
5428 1...31 => |bits| switch (dst_int_info.signedness) {
5429 .signed => .sbfm(dst_ra.w(), src_part_mat.ra.w(), .{
5430 .N = .word,
5431 .immr = 0,
5432 .imms = @intCast(bits - 1),
5433 }),
5434 .unsigned => .ubfm(dst_ra.w(), src_part_mat.ra.w(), .{
5435 .N = .word,
5436 .immr = 0,
5437 .imms = @intCast(bits - 1),
5438 }),
5439 },
5440 32 => .orr(dst_ra.w(), .wzr, .{ .register = src_part_mat.ra.w() }),
5441 33...63 => |bits| switch (dst_int_info.signedness) {
5442 .signed => .sbfm(dst_ra.x(), src_part_mat.ra.x(), .{
5443 .N = .doubleword,
5444 .immr = 0,
5445 .imms = @intCast(bits - 1),
5446 }),
5447 .unsigned => .ubfm(dst_ra.x(), src_part_mat.ra.x(), .{
5448 .N = .doubleword,
5449 .immr = 0,
5450 .imms = @intCast(bits - 1),
5451 }),
5452 },
5453 64 => .orr(dst_ra.x(), .xzr, .{ .register = src_part_mat.ra.x() }),
5454 });
5455 try src_part_mat.finish(isel);
5456 },
5457 65...128 => |dst_bits| switch (src_ty.intInfo(zcu).bits) {
5458 0 => unreachable,
5459 65...128 => {
5460 const src_vi = try isel.use(ty_op.operand);
5461 var dst_hi64_it = dst_vi.value.field(dst_ty, 8, 8);
5462 const dst_hi64_vi = try dst_hi64_it.only(isel);
5463 if (try dst_hi64_vi.?.defReg(isel)) |dst_hi64_ra| {
5464 var src_hi64_it = src_vi.field(src_ty, 8, 8);
5465 const src_hi64_vi = try src_hi64_it.only(isel);
5466 const src_hi64_mat = try src_hi64_vi.?.matReg(isel);
5467 try isel.emit(switch (dst_int_info.signedness) {
5468 .signed => .sbfm(dst_hi64_ra.x(), src_hi64_mat.ra.x(), .{
5469 .N = .doubleword,
5470 .immr = 0,
5471 .imms = @intCast(dst_bits - 64 - 1),
5472 }),
5473 .unsigned => .ubfm(dst_hi64_ra.x(), src_hi64_mat.ra.x(), .{
5474 .N = .doubleword,
5475 .immr = 0,
5476 .imms = @intCast(dst_bits - 64 - 1),
5477 }),
5478 });
5479 try src_hi64_mat.finish(isel);
5480 }
5481 var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8);
5482 const dst_lo64_vi = try dst_lo64_it.only(isel);
5483 if (try dst_lo64_vi.?.defReg(isel)) |dst_lo64_ra| {
5484 var src_lo64_it = src_vi.field(src_ty, 0, 8);
5485 const src_lo64_vi = try src_lo64_it.only(isel);
5486 try src_lo64_vi.?.liveOut(isel, dst_lo64_ra);
5487 }
5488 },
5489 else => return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }),
5490 },
5491 else => return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }),
5492 }
5493 }
5494 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5495 },
5496 .optional_payload => {
5497 if (isel.live_values.fetchRemove(air.inst_index)) |payload_vi| unused: {
5498 defer payload_vi.value.deref(isel);
5499
5500 const ty_op = air.data(air.inst_index).ty_op;
5501 const opt_ty = isel.air.typeOf(ty_op.operand, ip);
5502 if (opt_ty.optionalReprIsPayload(zcu)) {
5503 try payload_vi.value.move(isel, ty_op.operand);
5504 break :unused;
5505 }
5506
5507 const opt_vi = try isel.use(ty_op.operand);
5508 var payload_part_it = opt_vi.field(opt_ty, 0, payload_vi.value.size(isel));
5509 const payload_part_vi = try payload_part_it.only(isel);
5510 try payload_vi.value.copy(isel, ty_op.ty.toType(), payload_part_vi.?);
5511 }
5512 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5513 },
5514 .optional_payload_ptr => {
5515 if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| {
5516 defer payload_ptr_vi.value.deref(isel);
5517 const ty_op = air.data(air.inst_index).ty_op;
5518 try payload_ptr_vi.value.move(isel, ty_op.operand);
5519 }
5520 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5521 },
5522 .optional_payload_ptr_set => {
5523 if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| {
5524 defer payload_ptr_vi.value.deref(isel);
5525 const ty_op = air.data(air.inst_index).ty_op;
5526 const opt_ty = isel.air.typeOf(ty_op.operand, ip).childType(zcu);
5527 if (!opt_ty.optionalReprIsPayload(zcu)) {
5528 const opt_ptr_vi = try isel.use(ty_op.operand);
5529 const opt_ptr_mat = try opt_ptr_vi.matReg(isel);
5530 const has_value_ra = try isel.allocIntReg();
5531 defer isel.freeReg(has_value_ra);
5532 try isel.storeReg(
5533 has_value_ra,
5534 1,
5535 opt_ptr_mat.ra,
5536 opt_ty.optionalChild(zcu).abiSize(zcu),
5537 );
5538 try opt_ptr_mat.finish(isel);
5539 try isel.emit(.movz(has_value_ra.w(), 1, .{ .lsl = .@"0" }));
5540 }
5541 try payload_ptr_vi.value.move(isel, ty_op.operand);
5542 }
5543 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5544 },
5545 .wrap_optional => {
5546 if (isel.live_values.fetchRemove(air.inst_index)) |opt_vi| unused: {
5547 defer opt_vi.value.deref(isel);
5548
5549 const ty_op = air.data(air.inst_index).ty_op;
5550 if (ty_op.ty.toType().optionalReprIsPayload(zcu)) {
5551 try opt_vi.value.move(isel, ty_op.operand);
5552 break :unused;
5553 }
5554
5555 const payload_size = isel.air.typeOf(ty_op.operand, ip).abiSize(zcu);
5556 var payload_part_it = opt_vi.value.field(ty_op.ty.toType(), 0, payload_size);
5557 const payload_part_vi = try payload_part_it.only(isel);
5558 try payload_part_vi.?.move(isel, ty_op.operand);
5559 var has_value_part_it = opt_vi.value.field(ty_op.ty.toType(), payload_size, 1);
5560 const has_value_part_vi = try has_value_part_it.only(isel);
5561 const has_value_part_ra = try has_value_part_vi.?.defReg(isel) orelse break :unused;
5562 try isel.emit(.movz(has_value_part_ra.w(), 1, .{ .lsl = .@"0" }));
5563 }
5564 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5565 },
5566 .unwrap_errunion_payload => {
5567 if (isel.live_values.fetchRemove(air.inst_index)) |payload_vi| {
5568 defer payload_vi.value.deref(isel);
5569
5570 const ty_op = air.data(air.inst_index).ty_op;
5571 const error_union_ty = isel.air.typeOf(ty_op.operand, ip);
5572
5573 const error_union_vi = try isel.use(ty_op.operand);
5574 var payload_part_it = error_union_vi.field(
5575 error_union_ty,
5576 codegen.errUnionPayloadOffset(ty_op.ty.toType(), zcu),
5577 payload_vi.value.size(isel),
5578 );
5579 const payload_part_vi = try payload_part_it.only(isel);
5580 try payload_vi.value.copy(isel, ty_op.ty.toType(), payload_part_vi.?);
5581 }
5582 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5583 },
5584 .unwrap_errunion_err => {
5585 if (isel.live_values.fetchRemove(air.inst_index)) |error_set_vi| {
5586 defer error_set_vi.value.deref(isel);
5587
5588 const ty_op = air.data(air.inst_index).ty_op;
5589 const error_union_ty = isel.air.typeOf(ty_op.operand, ip);
5590
5591 const error_union_vi = try isel.use(ty_op.operand);
5592 var error_set_part_it = error_union_vi.field(
5593 error_union_ty,
5594 codegen.errUnionErrorOffset(error_union_ty.errorUnionPayload(zcu), zcu),
5595 error_set_vi.value.size(isel),
5596 );
5597 const error_set_part_vi = try error_set_part_it.only(isel);
5598 try error_set_vi.value.copy(isel, ty_op.ty.toType(), error_set_part_vi.?);
5599 }
5600 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5601 },
5602 .unwrap_errunion_payload_ptr => {
5603 if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| unused: {
5604 defer payload_ptr_vi.value.deref(isel);
5605 const ty_op = air.data(air.inst_index).ty_op;
5606 switch (codegen.errUnionPayloadOffset(ty_op.ty.toType().childType(zcu), zcu)) {
5607 0 => try payload_ptr_vi.value.move(isel, ty_op.operand),
5608 else => |payload_offset| {
5609 const payload_ptr_ra = try payload_ptr_vi.value.defReg(isel) orelse break :unused;
5610 const error_union_ptr_vi = try isel.use(ty_op.operand);
5611 const error_union_ptr_mat = try error_union_ptr_vi.matReg(isel);
5612 const lo12: u12 = @truncate(payload_offset >> 0);
5613 const hi12: u12 = @intCast(payload_offset >> 12);
5614 if (hi12 > 0) try isel.emit(.add(
5615 payload_ptr_ra.x(),
5616 if (lo12 > 0) payload_ptr_ra.x() else error_union_ptr_mat.ra.x(),
5617 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
5618 ));
5619 if (lo12 > 0) try isel.emit(.add(payload_ptr_ra.x(), error_union_ptr_mat.ra.x(), .{ .immediate = lo12 }));
5620 try error_union_ptr_mat.finish(isel);
5621 },
5622 }
5623 }
5624 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5625 },
5626 .unwrap_errunion_err_ptr => {
5627 if (isel.live_values.fetchRemove(air.inst_index)) |error_ptr_vi| unused: {
5628 defer error_ptr_vi.value.deref(isel);
5629 const ty_op = air.data(air.inst_index).ty_op;
5630 switch (codegen.errUnionErrorOffset(
5631 isel.air.typeOf(ty_op.operand, ip).childType(zcu).errorUnionPayload(zcu),
5632 zcu,
5633 )) {
5634 0 => try error_ptr_vi.value.move(isel, ty_op.operand),
5635 else => |error_offset| {
5636 const error_ptr_ra = try error_ptr_vi.value.defReg(isel) orelse break :unused;
5637 const error_union_ptr_vi = try isel.use(ty_op.operand);
5638 const error_union_ptr_mat = try error_union_ptr_vi.matReg(isel);
5639 const lo12: u12 = @truncate(error_offset >> 0);
5640 const hi12: u12 = @intCast(error_offset >> 12);
5641 if (hi12 > 0) try isel.emit(.add(
5642 error_ptr_ra.x(),
5643 if (lo12 > 0) error_ptr_ra.x() else error_union_ptr_mat.ra.x(),
5644 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
5645 ));
5646 if (lo12 > 0) try isel.emit(.add(error_ptr_ra.x(), error_union_ptr_mat.ra.x(), .{ .immediate = lo12 }));
5647 try error_union_ptr_mat.finish(isel);
5648 },
5649 }
5650 }
5651 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5652 },
5653 .errunion_payload_ptr_set => {
5654 if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| unused: {
5655 defer payload_ptr_vi.value.deref(isel);
5656 const ty_op = air.data(air.inst_index).ty_op;
5657 const payload_ty = ty_op.ty.toType().childType(zcu);
5658 const error_union_ty = isel.air.typeOf(ty_op.operand, ip).childType(zcu);
5659 const error_set_size = error_union_ty.errorUnionSet(zcu).abiSize(zcu);
5660 const error_union_ptr_vi = try isel.use(ty_op.operand);
5661 const error_union_ptr_mat = try error_union_ptr_vi.matReg(isel);
5662 if (error_set_size > 0) try isel.storeReg(
5663 .zr,
5664 error_set_size,
5665 error_union_ptr_mat.ra,
5666 codegen.errUnionErrorOffset(payload_ty, zcu),
5667 );
5668 switch (codegen.errUnionPayloadOffset(payload_ty, zcu)) {
5669 0 => {
5670 try error_union_ptr_mat.finish(isel);
5671 try payload_ptr_vi.value.move(isel, ty_op.operand);
5672 },
5673 else => |payload_offset| {
5674 const payload_ptr_ra = try payload_ptr_vi.value.defReg(isel) orelse break :unused;
5675 const lo12: u12 = @truncate(payload_offset >> 0);
5676 const hi12: u12 = @intCast(payload_offset >> 12);
5677 if (hi12 > 0) try isel.emit(.add(
5678 payload_ptr_ra.x(),
5679 if (lo12 > 0) payload_ptr_ra.x() else error_union_ptr_mat.ra.x(),
5680 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
5681 ));
5682 if (lo12 > 0) try isel.emit(.add(payload_ptr_ra.x(), error_union_ptr_mat.ra.x(), .{ .immediate = lo12 }));
5683 try error_union_ptr_mat.finish(isel);
5684 },
5685 }
5686 }
5687 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5688 },
5689 .wrap_errunion_payload => {
5690 if (isel.live_values.fetchRemove(air.inst_index)) |error_union_vi| {
5691 defer error_union_vi.value.deref(isel);
5692
5693 const ty_op = air.data(air.inst_index).ty_op;
5694 const error_union_ty = ty_op.ty.toType();
5695 const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type;
5696 const error_set_ty: ZigType = .fromInterned(error_union_info.error_set_type);
5697 const payload_ty: ZigType = .fromInterned(error_union_info.payload_type);
5698 const error_set_offset = codegen.errUnionErrorOffset(payload_ty, zcu);
5699 const payload_offset = codegen.errUnionPayloadOffset(payload_ty, zcu);
5700 const error_set_size = error_set_ty.abiSize(zcu);
5701 const payload_size = payload_ty.abiSize(zcu);
5702
5703 var payload_part_it = error_union_vi.value.field(error_union_ty, payload_offset, payload_size);
5704 const payload_part_vi = try payload_part_it.only(isel);
5705 try payload_part_vi.?.move(isel, ty_op.operand);
5706 var error_set_part_it = error_union_vi.value.field(error_union_ty, error_set_offset, error_set_size);
5707 const error_set_part_vi = try error_set_part_it.only(isel);
5708 if (try error_set_part_vi.?.defReg(isel)) |error_set_part_ra| try isel.emit(switch (error_set_size) {
5709 else => unreachable,
5710 1...4 => .orr(error_set_part_ra.w(), .wzr, .{ .register = .wzr }),
5711 5...8 => .orr(error_set_part_ra.x(), .xzr, .{ .register = .xzr }),
5712 });
5713 }
5714 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5715 },
5716 .wrap_errunion_err => {
5717 if (isel.live_values.fetchRemove(air.inst_index)) |error_union_vi| {
5718 defer error_union_vi.value.deref(isel);
5719
5720 const ty_op = air.data(air.inst_index).ty_op;
5721 const error_union_ty = ty_op.ty.toType();
5722 const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type;
5723 const error_set_ty: ZigType = .fromInterned(error_union_info.error_set_type);
5724 const payload_ty: ZigType = .fromInterned(error_union_info.payload_type);
5725 const error_set_offset = codegen.errUnionErrorOffset(payload_ty, zcu);
5726 const payload_offset = codegen.errUnionPayloadOffset(payload_ty, zcu);
5727 const error_set_size = error_set_ty.abiSize(zcu);
5728 const payload_size = payload_ty.abiSize(zcu);
5729
5730 if (payload_size > 0) {
5731 var payload_part_it = error_union_vi.value.field(error_union_ty, payload_offset, payload_size);
5732 const payload_part_vi = try payload_part_it.only(isel);
5733 if (try payload_part_vi.?.defReg(isel)) |payload_part_ra| try isel.emit(switch (payload_size) {
5734 else => unreachable,
5735 1...4 => .orr(payload_part_ra.w(), .wzr, .{ .immediate = .{
5736 .N = .word,
5737 .immr = 0b000001,
5738 .imms = 0b111100,
5739 } }),
5740 5...8 => .orr(payload_part_ra.x(), .xzr, .{ .immediate = .{
5741 .N = .word,
5742 .immr = 0b000001,
5743 .imms = 0b111100,
5744 } }),
5745 });
5746 }
5747 var error_set_part_it = error_union_vi.value.field(error_union_ty, error_set_offset, error_set_size);
5748 const error_set_part_vi = try error_set_part_it.only(isel);
5749 try error_set_part_vi.?.move(isel, ty_op.operand);
5750 }
5751 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5752 },
5753 .struct_field_ptr => {
5754 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
5755 defer dst_vi.value.deref(isel);
5756 const ty_pl = air.data(air.inst_index).ty_pl;
5757 const extra = isel.air.extraData(Air.StructField, ty_pl.payload).data;
5758 switch (codegen.fieldOffset(
5759 isel.air.typeOf(extra.struct_operand, ip),
5760 ty_pl.ty.toType(),
5761 extra.field_index,
5762 zcu,
5763 )) {
5764 0 => try dst_vi.value.move(isel, extra.struct_operand),
5765 else => |field_offset| {
5766 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
5767 const src_vi = try isel.use(extra.struct_operand);
5768 const src_mat = try src_vi.matReg(isel);
5769 const lo12: u12 = @truncate(field_offset >> 0);
5770 const hi12: u12 = @intCast(field_offset >> 12);
5771 if (hi12 > 0) try isel.emit(.add(
5772 dst_ra.x(),
5773 if (lo12 > 0) dst_ra.x() else src_mat.ra.x(),
5774 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
5775 ));
5776 if (lo12 > 0) try isel.emit(.add(dst_ra.x(), src_mat.ra.x(), .{ .immediate = lo12 }));
5777 try src_mat.finish(isel);
5778 },
5779 }
5780 }
5781 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5782 },
5783 .struct_field_ptr_index_0,
5784 .struct_field_ptr_index_1,
5785 .struct_field_ptr_index_2,
5786 .struct_field_ptr_index_3,
5787 => |air_tag| {
5788 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
5789 defer dst_vi.value.deref(isel);
5790 const ty_op = air.data(air.inst_index).ty_op;
5791 switch (codegen.fieldOffset(
5792 isel.air.typeOf(ty_op.operand, ip),
5793 ty_op.ty.toType(),
5794 switch (air_tag) {
5795 else => unreachable,
5796 .struct_field_ptr_index_0 => 0,
5797 .struct_field_ptr_index_1 => 1,
5798 .struct_field_ptr_index_2 => 2,
5799 .struct_field_ptr_index_3 => 3,
5800 },
5801 zcu,
5802 )) {
5803 0 => try dst_vi.value.move(isel, ty_op.operand),
5804 else => |field_offset| {
5805 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
5806 const src_vi = try isel.use(ty_op.operand);
5807 const src_mat = try src_vi.matReg(isel);
5808 const lo12: u12 = @truncate(field_offset >> 0);
5809 const hi12: u12 = @intCast(field_offset >> 12);
5810 if (hi12 > 0) try isel.emit(.add(
5811 dst_ra.x(),
5812 if (lo12 > 0) dst_ra.x() else src_mat.ra.x(),
5813 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
5814 ));
5815 if (lo12 > 0) try isel.emit(.add(dst_ra.x(), src_mat.ra.x(), .{ .immediate = lo12 }));
5816 try src_mat.finish(isel);
5817 },
5818 }
5819 }
5820 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5821 },
5822 .struct_field_val => {
5823 if (isel.live_values.fetchRemove(air.inst_index)) |field_vi| {
5824 defer field_vi.value.deref(isel);
5825
5826 const ty_pl = air.data(air.inst_index).ty_pl;
5827 const extra = isel.air.extraData(Air.StructField, ty_pl.payload).data;
5828 const agg_ty = isel.air.typeOf(extra.struct_operand, ip);
5829 const field_ty = ty_pl.ty.toType();
5830 const field_bit_offset, const field_bit_size, const is_packed = switch (agg_ty.containerLayout(zcu)) {
5831 .auto, .@"extern" => .{
5832 8 * agg_ty.structFieldOffset(extra.field_index, zcu),
5833 8 * field_ty.abiSize(zcu),
5834 false,
5835 },
5836 .@"packed" => .{
5837 if (zcu.typeToPackedStruct(agg_ty)) |loaded_struct|
5838 zcu.structPackedFieldBitOffset(loaded_struct, extra.field_index)
5839 else
5840 0,
5841 field_ty.bitSize(zcu),
5842 true,
5843 },
5844 };
5845 if (is_packed) return isel.fail("packed field of {f}", .{
5846 isel.fmtType(agg_ty),
5847 });
5848
5849 const agg_vi = try isel.use(extra.struct_operand);
5850 var agg_part_it = agg_vi.field(agg_ty, @divExact(field_bit_offset, 8), @divExact(field_bit_size, 8));
5851 while (try agg_part_it.next(isel)) |agg_part| {
5852 var field_part_it = field_vi.value.field(ty_pl.ty.toType(), agg_part.offset, agg_part.vi.size(isel));
5853 const field_part_vi = try field_part_it.only(isel);
5854 if (field_part_vi.? == agg_part.vi) continue;
5855 var field_subpart_it = field_part_vi.?.parts(isel);
5856 const field_part_offset = if (field_subpart_it.only()) |field_subpart_vi|
5857 field_subpart_vi.get(isel).offset_from_parent
5858 else
5859 0;
5860 while (field_subpart_it.next()) |field_subpart_vi| {
5861 const field_subpart_ra = try field_subpart_vi.defReg(isel) orelse continue;
5862 const field_subpart_offset, const field_subpart_size = field_subpart_vi.position(isel);
5863 var agg_subpart_it = agg_part.vi.field(
5864 field_ty,
5865 agg_part.offset + field_subpart_offset - field_part_offset,
5866 field_subpart_size,
5867 );
5868 const agg_subpart_vi = try agg_subpart_it.only(isel);
5869 try agg_subpart_vi.?.liveOut(isel, field_subpart_ra);
5870 }
5871 }
5872 }
5873 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5874 },
5875 .set_union_tag => {
5876 const bin_op = air.data(air.inst_index).bin_op;
5877 const union_ty = isel.air.typeOf(bin_op.lhs, ip).childType(zcu);
5878 const union_layout = union_ty.unionGetLayout(zcu);
5879 const tag_vi = try isel.use(bin_op.rhs);
5880 const union_ptr_vi = try isel.use(bin_op.lhs);
5881 const union_ptr_mat = try union_ptr_vi.matReg(isel);
5882 try tag_vi.store(isel, isel.air.typeOf(bin_op.rhs, ip), union_ptr_mat.ra, .{
5883 .offset = union_layout.tagOffset(),
5884 });
5885 try union_ptr_mat.finish(isel);
5886 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5887 },
5888 .get_union_tag => {
5889 if (isel.live_values.fetchRemove(air.inst_index)) |tag_vi| {
5890 defer tag_vi.value.deref(isel);
5891 const ty_op = air.data(air.inst_index).ty_op;
5892 const union_ty = isel.air.typeOf(ty_op.operand, ip);
5893 const union_layout = union_ty.unionGetLayout(zcu);
5894 const union_vi = try isel.use(ty_op.operand);
5895 var tag_part_it = union_vi.field(union_ty, union_layout.tagOffset(), union_layout.tag_size);
5896 const tag_part_vi = try tag_part_it.only(isel);
5897 try tag_vi.value.copy(isel, ty_op.ty.toType(), tag_part_vi.?);
5898 }
5899 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5900 },
5901 .slice => {
5902 if (isel.live_values.fetchRemove(air.inst_index)) |slice_vi| {
5903 defer slice_vi.value.deref(isel);
5904 const ty_pl = air.data(air.inst_index).ty_pl;
5905 const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data;
5906 var ptr_part_it = slice_vi.value.field(ty_pl.ty.toType(), 0, 8);
5907 const ptr_part_vi = try ptr_part_it.only(isel);
5908 try ptr_part_vi.?.move(isel, bin_op.lhs);
5909 var len_part_it = slice_vi.value.field(ty_pl.ty.toType(), 8, 8);
5910 const len_part_vi = try len_part_it.only(isel);
5911 try len_part_vi.?.move(isel, bin_op.rhs);
5912 }
5913 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5914 },
5915 .slice_len => {
5916 if (isel.live_values.fetchRemove(air.inst_index)) |len_vi| {
5917 defer len_vi.value.deref(isel);
5918 const ty_op = air.data(air.inst_index).ty_op;
5919 const slice_vi = try isel.use(ty_op.operand);
5920 var len_part_it = slice_vi.field(isel.air.typeOf(ty_op.operand, ip), 8, 8);
5921 const len_part_vi = try len_part_it.only(isel);
5922 try len_vi.value.copy(isel, ty_op.ty.toType(), len_part_vi.?);
5923 }
5924 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5925 },
5926 .slice_ptr => {
5927 if (isel.live_values.fetchRemove(air.inst_index)) |ptr_vi| {
5928 defer ptr_vi.value.deref(isel);
5929 const ty_op = air.data(air.inst_index).ty_op;
5930 const slice_vi = try isel.use(ty_op.operand);
5931 var ptr_part_it = slice_vi.field(isel.air.typeOf(ty_op.operand, ip), 0, 8);
5932 const ptr_part_vi = try ptr_part_it.only(isel);
5933 try ptr_vi.value.copy(isel, ty_op.ty.toType(), ptr_part_vi.?);
5934 }
5935 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
5936 },
5937 .array_elem_val => {
5938 if (isel.live_values.fetchRemove(air.inst_index)) |elem_vi| unused: {
5939 defer elem_vi.value.deref(isel);
5940
5941 const bin_op = air.data(air.inst_index).bin_op;
5942 const array_ty = isel.air.typeOf(bin_op.lhs, ip);
5943 const elem_ty = array_ty.childType(zcu);
5944 const elem_size = elem_ty.abiSize(zcu);
5945 if (elem_size <= 16 and array_ty.arrayLenIncludingSentinel(zcu) <= Value.max_parts) if (bin_op.rhs.toInterned()) |index_val| {
5946 const elem_offset = elem_size * Constant.fromInterned(index_val).toUnsignedInt(zcu);
5947 const array_vi = try isel.use(bin_op.lhs);
5948 var elem_part_it = array_vi.field(array_ty, elem_offset, elem_size);
5949 const elem_part_vi = try elem_part_it.only(isel);
5950 try elem_vi.value.copy(isel, elem_ty, elem_part_vi.?);
5951 break :unused;
5952 };
5953 switch (elem_size) {
5954 0 => unreachable,
5955 1, 2, 4, 8 => {
5956 const elem_ra = try elem_vi.value.defReg(isel) orelse break :unused;
5957 const array_ptr_ra = try isel.allocIntReg();
5958 defer isel.freeReg(array_ptr_ra);
5959 const index_vi = try isel.use(bin_op.rhs);
5960 const index_mat = try index_vi.matReg(isel);
5961 try isel.emit(switch (elem_size) {
5962 else => unreachable,
5963 1 => if (elem_vi.value.isVector(isel)) .ldr(elem_ra.b(), .{ .extended_register = .{
5964 .base = array_ptr_ra.x(),
5965 .index = index_mat.ra.x(),
5966 .extend = .{ .lsl = 0 },
5967 } }) else switch (elem_vi.value.signedness(isel)) {
5968 .signed => .ldrsb(elem_ra.w(), .{ .extended_register = .{
5969 .base = array_ptr_ra.x(),
5970 .index = index_mat.ra.x(),
5971 .extend = .{ .lsl = 0 },
5972 } }),
5973 .unsigned => .ldrb(elem_ra.w(), .{ .extended_register = .{
5974 .base = array_ptr_ra.x(),
5975 .index = index_mat.ra.x(),
5976 .extend = .{ .lsl = 0 },
5977 } }),
5978 },
5979 2 => if (elem_vi.value.isVector(isel)) .ldr(elem_ra.h(), .{ .extended_register = .{
5980 .base = array_ptr_ra.x(),
5981 .index = index_mat.ra.x(),
5982 .extend = .{ .lsl = 1 },
5983 } }) else switch (elem_vi.value.signedness(isel)) {
5984 .signed => .ldrsh(elem_ra.w(), .{ .extended_register = .{
5985 .base = array_ptr_ra.x(),
5986 .index = index_mat.ra.x(),
5987 .extend = .{ .lsl = 1 },
5988 } }),
5989 .unsigned => .ldrh(elem_ra.w(), .{ .extended_register = .{
5990 .base = array_ptr_ra.x(),
5991 .index = index_mat.ra.x(),
5992 .extend = .{ .lsl = 1 },
5993 } }),
5994 },
5995 4 => .ldr(if (elem_vi.value.isVector(isel)) elem_ra.s() else elem_ra.w(), .{ .extended_register = .{
5996 .base = array_ptr_ra.x(),
5997 .index = index_mat.ra.x(),
5998 .extend = .{ .lsl = 2 },
5999 } }),
6000 8 => .ldr(if (elem_vi.value.isVector(isel)) elem_ra.d() else elem_ra.x(), .{ .extended_register = .{
6001 .base = array_ptr_ra.x(),
6002 .index = index_mat.ra.x(),
6003 .extend = .{ .lsl = 3 },
6004 } }),
6005 16 => .ldr(elem_ra.q(), .{ .extended_register = .{
6006 .base = array_ptr_ra.x(),
6007 .index = index_mat.ra.x(),
6008 .extend = .{ .lsl = 4 },
6009 } }),
6010 });
6011 try index_mat.finish(isel);
6012 const array_vi = try isel.use(bin_op.lhs);
6013 try array_vi.address(isel, 0, array_ptr_ra);
6014 },
6015 else => {
6016 const ptr_ra = try isel.allocIntReg();
6017 defer isel.freeReg(ptr_ra);
6018 if (!try elem_vi.value.load(isel, elem_ty, ptr_ra, .{})) break :unused;
6019 const index_vi = try isel.use(bin_op.rhs);
6020 try isel.elemPtr(ptr_ra, ptr_ra, .add, elem_size, index_vi);
6021 const array_vi = try isel.use(bin_op.lhs);
6022 try array_vi.address(isel, 0, ptr_ra);
6023 },
6024 }
6025 }
6026 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6027 },
6028 .slice_elem_val => {
6029 if (isel.live_values.fetchRemove(air.inst_index)) |elem_vi| unused: {
6030 defer elem_vi.value.deref(isel);
6031
6032 const bin_op = air.data(air.inst_index).bin_op;
6033 const slice_ty = isel.air.typeOf(bin_op.lhs, ip);
6034 const ptr_info = slice_ty.ptrInfo(zcu);
6035 const elem_size = elem_vi.value.size(isel);
6036 const elem_is_vector = elem_vi.value.isVector(isel);
6037 if (switch (elem_size) {
6038 0 => unreachable,
6039 1, 2, 4, 8 => true,
6040 16 => elem_is_vector,
6041 else => false,
6042 }) {
6043 const elem_ra = try elem_vi.value.defReg(isel) orelse break :unused;
6044 const slice_vi = try isel.use(bin_op.lhs);
6045 const index_vi = try isel.use(bin_op.rhs);
6046 var ptr_part_it = slice_vi.field(slice_ty, 0, 8);
6047 const ptr_part_vi = try ptr_part_it.only(isel);
6048 const base_mat = try ptr_part_vi.?.matReg(isel);
6049 const index_mat = try index_vi.matReg(isel);
6050 try isel.emit(switch (elem_size) {
6051 else => unreachable,
6052 1 => if (elem_is_vector) .ldr(elem_ra.b(), .{ .extended_register = .{
6053 .base = base_mat.ra.x(),
6054 .index = index_mat.ra.x(),
6055 .extend = .{ .lsl = 0 },
6056 } }) else switch (elem_vi.value.signedness(isel)) {
6057 .signed => .ldrsb(elem_ra.w(), .{ .extended_register = .{
6058 .base = base_mat.ra.x(),
6059 .index = index_mat.ra.x(),
6060 .extend = .{ .lsl = 0 },
6061 } }),
6062 .unsigned => .ldrb(elem_ra.w(), .{ .extended_register = .{
6063 .base = base_mat.ra.x(),
6064 .index = index_mat.ra.x(),
6065 .extend = .{ .lsl = 0 },
6066 } }),
6067 },
6068 2 => if (elem_is_vector) .ldr(elem_ra.h(), .{ .extended_register = .{
6069 .base = base_mat.ra.x(),
6070 .index = index_mat.ra.x(),
6071 .extend = .{ .lsl = 1 },
6072 } }) else switch (elem_vi.value.signedness(isel)) {
6073 .signed => .ldrsh(elem_ra.w(), .{ .extended_register = .{
6074 .base = base_mat.ra.x(),
6075 .index = index_mat.ra.x(),
6076 .extend = .{ .lsl = 1 },
6077 } }),
6078 .unsigned => .ldrh(elem_ra.w(), .{ .extended_register = .{
6079 .base = base_mat.ra.x(),
6080 .index = index_mat.ra.x(),
6081 .extend = .{ .lsl = 1 },
6082 } }),
6083 },
6084 4 => .ldr(if (elem_is_vector) elem_ra.s() else elem_ra.w(), .{ .extended_register = .{
6085 .base = base_mat.ra.x(),
6086 .index = index_mat.ra.x(),
6087 .extend = .{ .lsl = 2 },
6088 } }),
6089 8 => .ldr(if (elem_is_vector) elem_ra.d() else elem_ra.x(), .{ .extended_register = .{
6090 .base = base_mat.ra.x(),
6091 .index = index_mat.ra.x(),
6092 .extend = .{ .lsl = 3 },
6093 } }),
6094 16 => if (elem_is_vector) .ldr(elem_ra.q(), .{ .extended_register = .{
6095 .base = base_mat.ra.x(),
6096 .index = index_mat.ra.x(),
6097 .extend = .{ .lsl = 4 },
6098 } }) else unreachable,
6099 });
6100 try index_mat.finish(isel);
6101 try base_mat.finish(isel);
6102 } else {
6103 const elem_ptr_ra = try isel.allocIntReg();
6104 defer isel.freeReg(elem_ptr_ra);
6105 if (!try elem_vi.value.load(isel, slice_ty.elemType2(zcu), elem_ptr_ra, .{
6106 .@"volatile" = ptr_info.flags.is_volatile,
6107 })) break :unused;
6108 const slice_vi = try isel.use(bin_op.lhs);
6109 var ptr_part_it = slice_vi.field(slice_ty, 0, 8);
6110 const ptr_part_vi = try ptr_part_it.only(isel);
6111 const ptr_part_mat = try ptr_part_vi.?.matReg(isel);
6112 const index_vi = try isel.use(bin_op.rhs);
6113 try isel.elemPtr(elem_ptr_ra, ptr_part_mat.ra, .add, elem_size, index_vi);
6114 try ptr_part_mat.finish(isel);
6115 }
6116 }
6117 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6118 },
6119 .slice_elem_ptr => {
6120 if (isel.live_values.fetchRemove(air.inst_index)) |elem_ptr_vi| unused: {
6121 defer elem_ptr_vi.value.deref(isel);
6122 const elem_ptr_ra = try elem_ptr_vi.value.defReg(isel) orelse break :unused;
6123
6124 const ty_pl = air.data(air.inst_index).ty_pl;
6125 const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data;
6126 const elem_size = ty_pl.ty.toType().childType(zcu).abiSize(zcu);
6127
6128 const slice_vi = try isel.use(bin_op.lhs);
6129 var ptr_part_it = slice_vi.field(isel.air.typeOf(bin_op.lhs, ip), 0, 8);
6130 const ptr_part_vi = try ptr_part_it.only(isel);
6131 const ptr_part_mat = try ptr_part_vi.?.matReg(isel);
6132 const index_vi = try isel.use(bin_op.rhs);
6133 try isel.elemPtr(elem_ptr_ra, ptr_part_mat.ra, .add, elem_size, index_vi);
6134 try ptr_part_mat.finish(isel);
6135 }
6136 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6137 },
6138 .ptr_elem_val => {
6139 if (isel.live_values.fetchRemove(air.inst_index)) |elem_vi| unused: {
6140 defer elem_vi.value.deref(isel);
6141
6142 const bin_op = air.data(air.inst_index).bin_op;
6143 const ptr_ty = isel.air.typeOf(bin_op.lhs, ip);
6144 const ptr_info = ptr_ty.ptrInfo(zcu);
6145 const elem_size = elem_vi.value.size(isel);
6146 const elem_is_vector = elem_vi.value.isVector(isel);
6147 if (switch (elem_size) {
6148 0 => unreachable,
6149 1, 2, 4, 8 => true,
6150 16 => elem_is_vector,
6151 else => false,
6152 }) {
6153 const elem_ra = try elem_vi.value.defReg(isel) orelse break :unused;
6154 const base_vi = try isel.use(bin_op.lhs);
6155 const index_vi = try isel.use(bin_op.rhs);
6156 const base_mat = try base_vi.matReg(isel);
6157 const index_mat = try index_vi.matReg(isel);
6158 try isel.emit(switch (elem_size) {
6159 else => unreachable,
6160 1 => if (elem_is_vector) .ldr(elem_ra.b(), .{ .extended_register = .{
6161 .base = base_mat.ra.x(),
6162 .index = index_mat.ra.x(),
6163 .extend = .{ .lsl = 0 },
6164 } }) else switch (elem_vi.value.signedness(isel)) {
6165 .signed => .ldrsb(elem_ra.w(), .{ .extended_register = .{
6166 .base = base_mat.ra.x(),
6167 .index = index_mat.ra.x(),
6168 .extend = .{ .lsl = 0 },
6169 } }),
6170 .unsigned => .ldrb(elem_ra.w(), .{ .extended_register = .{
6171 .base = base_mat.ra.x(),
6172 .index = index_mat.ra.x(),
6173 .extend = .{ .lsl = 0 },
6174 } }),
6175 },
6176 2 => if (elem_is_vector) .ldr(elem_ra.h(), .{ .extended_register = .{
6177 .base = base_mat.ra.x(),
6178 .index = index_mat.ra.x(),
6179 .extend = .{ .lsl = 1 },
6180 } }) else switch (elem_vi.value.signedness(isel)) {
6181 .signed => .ldrsh(elem_ra.w(), .{ .extended_register = .{
6182 .base = base_mat.ra.x(),
6183 .index = index_mat.ra.x(),
6184 .extend = .{ .lsl = 1 },
6185 } }),
6186 .unsigned => .ldrh(elem_ra.w(), .{ .extended_register = .{
6187 .base = base_mat.ra.x(),
6188 .index = index_mat.ra.x(),
6189 .extend = .{ .lsl = 1 },
6190 } }),
6191 },
6192 4 => .ldr(if (elem_is_vector) elem_ra.s() else elem_ra.w(), .{ .extended_register = .{
6193 .base = base_mat.ra.x(),
6194 .index = index_mat.ra.x(),
6195 .extend = .{ .lsl = 2 },
6196 } }),
6197 8 => .ldr(if (elem_is_vector) elem_ra.d() else elem_ra.x(), .{ .extended_register = .{
6198 .base = base_mat.ra.x(),
6199 .index = index_mat.ra.x(),
6200 .extend = .{ .lsl = 3 },
6201 } }),
6202 16 => if (elem_is_vector) .ldr(elem_ra.q(), .{ .extended_register = .{
6203 .base = base_mat.ra.x(),
6204 .index = index_mat.ra.x(),
6205 .extend = .{ .lsl = 4 },
6206 } }) else unreachable,
6207 });
6208 try index_mat.finish(isel);
6209 try base_mat.finish(isel);
6210 } else {
6211 const elem_ptr_ra = try isel.allocIntReg();
6212 defer isel.freeReg(elem_ptr_ra);
6213 if (!try elem_vi.value.load(isel, ptr_ty.elemType2(zcu), elem_ptr_ra, .{
6214 .@"volatile" = ptr_info.flags.is_volatile,
6215 })) break :unused;
6216 const base_vi = try isel.use(bin_op.lhs);
6217 const base_mat = try base_vi.matReg(isel);
6218 const index_vi = try isel.use(bin_op.rhs);
6219 try isel.elemPtr(elem_ptr_ra, base_mat.ra, .add, elem_size, index_vi);
6220 try base_mat.finish(isel);
6221 }
6222 }
6223 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6224 },
6225 .ptr_elem_ptr => {
6226 if (isel.live_values.fetchRemove(air.inst_index)) |elem_ptr_vi| unused: {
6227 defer elem_ptr_vi.value.deref(isel);
6228 const elem_ptr_ra = try elem_ptr_vi.value.defReg(isel) orelse break :unused;
6229
6230 const ty_pl = air.data(air.inst_index).ty_pl;
6231 const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data;
6232 const elem_size = ty_pl.ty.toType().childType(zcu).abiSize(zcu);
6233
6234 const base_vi = try isel.use(bin_op.lhs);
6235 const base_mat = try base_vi.matReg(isel);
6236 const index_vi = try isel.use(bin_op.rhs);
6237 try isel.elemPtr(elem_ptr_ra, base_mat.ra, .add, elem_size, index_vi);
6238 try base_mat.finish(isel);
6239 }
6240 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6241 },
6242 .array_to_slice => {
6243 if (isel.live_values.fetchRemove(air.inst_index)) |slice_vi| {
6244 defer slice_vi.value.deref(isel);
6245 const ty_op = air.data(air.inst_index).ty_op;
6246 var ptr_part_it = slice_vi.value.field(ty_op.ty.toType(), 0, 8);
6247 const ptr_part_vi = try ptr_part_it.only(isel);
6248 try ptr_part_vi.?.move(isel, ty_op.operand);
6249 var len_part_it = slice_vi.value.field(ty_op.ty.toType(), 8, 8);
6250 const len_part_vi = try len_part_it.only(isel);
6251 if (try len_part_vi.?.defReg(isel)) |len_ra| try isel.movImmediate(
6252 len_ra.x(),
6253 isel.air.typeOf(ty_op.operand, ip).childType(zcu).arrayLen(zcu),
6254 );
6255 }
6256 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6257 },
6258 .int_from_float, .int_from_float_optimized => |air_tag| {
6259 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
6260 defer dst_vi.value.deref(isel);
6261
6262 const ty_op = air.data(air.inst_index).ty_op;
6263 const dst_ty = ty_op.ty.toType();
6264 const src_ty = isel.air.typeOf(ty_op.operand, ip);
6265 if (!dst_ty.isAbiInt(zcu)) return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });
6266 const dst_int_info = dst_ty.intInfo(zcu);
6267 const src_bits = src_ty.floatBits(isel.target);
6268 switch (@max(dst_int_info.bits, src_bits)) {
6269 0 => unreachable,
6270 1...64 => {
6271 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
6272 const need_fcvt = switch (src_bits) {
6273 else => unreachable,
6274 16 => !isel.target.cpu.has(.aarch64, .fullfp16),
6275 32, 64 => false,
6276 };
6277 const src_vi = try isel.use(ty_op.operand);
6278 const src_mat = try src_vi.matReg(isel);
6279 const src_ra = if (need_fcvt) try isel.allocVecReg() else src_mat.ra;
6280 defer if (need_fcvt) isel.freeReg(src_ra);
6281 const dst_reg = switch (dst_int_info.bits) {
6282 else => unreachable,
6283 1...32 => dst_ra.w(),
6284 33...64 => dst_ra.x(),
6285 };
6286 const src_reg = switch (src_bits) {
6287 else => unreachable,
6288 16 => if (need_fcvt) src_ra.s() else src_ra.h(),
6289 32 => src_ra.s(),
6290 64 => src_ra.d(),
6291 };
6292 try isel.emit(switch (dst_int_info.signedness) {
6293 .signed => .fcvtzs(dst_reg, src_reg),
6294 .unsigned => .fcvtzu(dst_reg, src_reg),
6295 });
6296 if (need_fcvt) try isel.emit(.fcvt(src_reg, src_mat.ra.h()));
6297 try src_mat.finish(isel);
6298 },
6299 65...128 => {
6300 try call.prepareReturn(isel);
6301 switch (dst_int_info.bits) {
6302 else => unreachable,
6303 1...64 => try call.returnLiveIn(isel, dst_vi.value, .r0),
6304 65...128 => {
6305 var dst_hi64_it = dst_vi.value.field(dst_ty, 8, 8);
6306 const dst_hi64_vi = try dst_hi64_it.only(isel);
6307 try call.returnLiveIn(isel, dst_hi64_vi.?, .r1);
6308 var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8);
6309 const dst_lo64_vi = try dst_lo64_it.only(isel);
6310 try call.returnLiveIn(isel, dst_lo64_vi.?, .r0);
6311 },
6312 }
6313 try call.finishReturn(isel);
6314
6315 try call.prepareCallee(isel);
6316 try isel.global_relocs.append(gpa, .{
6317 .name = switch (dst_int_info.bits) {
6318 else => unreachable,
6319 1...32 => switch (dst_int_info.signedness) {
6320 .signed => switch (src_bits) {
6321 else => unreachable,
6322 16 => "__fixhfsi",
6323 32 => "__fixsfsi",
6324 64 => "__fixdfsi",
6325 80 => "__fixxfsi",
6326 128 => "__fixtfsi",
6327 },
6328 .unsigned => switch (src_bits) {
6329 else => unreachable,
6330 16 => "__fixunshfsi",
6331 32 => "__fixunssfsi",
6332 64 => "__fixunsdfsi",
6333 80 => "__fixunsxfsi",
6334 128 => "__fixunstfsi",
6335 },
6336 },
6337 33...64 => switch (dst_int_info.signedness) {
6338 .signed => switch (src_bits) {
6339 else => unreachable,
6340 16 => "__fixhfdi",
6341 32 => "__fixsfdi",
6342 64 => "__fixdfdi",
6343 80 => "__fixxfdi",
6344 128 => "__fixtfdi",
6345 },
6346 .unsigned => switch (src_bits) {
6347 else => unreachable,
6348 16 => "__fixunshfdi",
6349 32 => "__fixunssfdi",
6350 64 => "__fixunsdfdi",
6351 80 => "__fixunsxfdi",
6352 128 => "__fixunstfdi",
6353 },
6354 },
6355 65...128 => switch (dst_int_info.signedness) {
6356 .signed => switch (src_bits) {
6357 else => unreachable,
6358 16 => "__fixhfti",
6359 32 => "__fixsfti",
6360 64 => "__fixdfti",
6361 80 => "__fixxfti",
6362 128 => "__fixtfti",
6363 },
6364 .unsigned => switch (src_bits) {
6365 else => unreachable,
6366 16 => "__fixunshfti",
6367 32 => "__fixunssfti",
6368 64 => "__fixunsdfti",
6369 80 => "__fixunsxfti",
6370 128 => "__fixunstfti",
6371 },
6372 },
6373 },
6374 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
6375 });
6376 try isel.emit(.bl(0));
6377 try call.finishCallee(isel);
6378
6379 try call.prepareParams(isel);
6380 const src_vi = try isel.use(ty_op.operand);
6381 switch (src_bits) {
6382 else => unreachable,
6383 16, 32, 64, 128 => try call.paramLiveOut(isel, src_vi, .v0),
6384 80 => {
6385 var src_hi16_it = src_vi.field(src_ty, 8, 8);
6386 const src_hi16_vi = try src_hi16_it.only(isel);
6387 try call.paramLiveOut(isel, src_hi16_vi.?, .r1);
6388 var src_lo64_it = src_vi.field(src_ty, 0, 8);
6389 const src_lo64_vi = try src_lo64_it.only(isel);
6390 try call.paramLiveOut(isel, src_lo64_vi.?, .r0);
6391 },
6392 }
6393 try call.finishParams(isel);
6394 },
6395 else => return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }),
6396 }
6397 }
6398 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6399 },
6400 .float_from_int => |air_tag| {
6401 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
6402 defer dst_vi.value.deref(isel);
6403
6404 const ty_op = air.data(air.inst_index).ty_op;
6405 const dst_ty = ty_op.ty.toType();
6406 const src_ty = isel.air.typeOf(ty_op.operand, ip);
6407 const dst_bits = dst_ty.floatBits(isel.target);
6408 if (!src_ty.isAbiInt(zcu)) return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) });
6409 const src_int_info = src_ty.intInfo(zcu);
6410 switch (@max(dst_bits, src_int_info.bits)) {
6411 0 => unreachable,
6412 1...64 => {
6413 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
6414 const need_fcvt = switch (dst_bits) {
6415 else => unreachable,
6416 16 => !isel.target.cpu.has(.aarch64, .fullfp16),
6417 32, 64 => false,
6418 };
6419 if (need_fcvt) try isel.emit(.fcvt(dst_ra.h(), dst_ra.s()));
6420 const src_vi = try isel.use(ty_op.operand);
6421 const src_mat = try src_vi.matReg(isel);
6422 const dst_reg = switch (dst_bits) {
6423 else => unreachable,
6424 16 => if (need_fcvt) dst_ra.s() else dst_ra.h(),
6425 32 => dst_ra.s(),
6426 64 => dst_ra.d(),
6427 };
6428 const src_reg = switch (src_int_info.bits) {
6429 else => unreachable,
6430 1...32 => src_mat.ra.w(),
6431 33...64 => src_mat.ra.x(),
6432 };
6433 try isel.emit(switch (src_int_info.signedness) {
6434 .signed => .scvtf(dst_reg, src_reg),
6435 .unsigned => .ucvtf(dst_reg, src_reg),
6436 });
6437 try src_mat.finish(isel);
6438 },
6439 65...128 => {
6440 try call.prepareReturn(isel);
6441 switch (dst_bits) {
6442 else => unreachable,
6443 16, 32, 64, 128 => try call.returnLiveIn(isel, dst_vi.value, .v0),
6444 80 => {
6445 var dst_hi16_it = dst_vi.value.field(dst_ty, 8, 8);
6446 const dst_hi16_vi = try dst_hi16_it.only(isel);
6447 try call.returnLiveIn(isel, dst_hi16_vi.?, .r1);
6448 var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8);
6449 const dst_lo64_vi = try dst_lo64_it.only(isel);
6450 try call.returnLiveIn(isel, dst_lo64_vi.?, .r0);
6451 },
6452 }
6453 try call.finishReturn(isel);
6454
6455 try call.prepareCallee(isel);
6456 try isel.global_relocs.append(gpa, .{
6457 .name = switch (src_int_info.bits) {
6458 else => unreachable,
6459 1...32 => switch (src_int_info.signedness) {
6460 .signed => switch (dst_bits) {
6461 else => unreachable,
6462 16 => "__floatsihf",
6463 32 => "__floatsisf",
6464 64 => "__floatsidf",
6465 80 => "__floatsixf",
6466 128 => "__floatsitf",
6467 },
6468 .unsigned => switch (dst_bits) {
6469 else => unreachable,
6470 16 => "__floatunsihf",
6471 32 => "__floatunsisf",
6472 64 => "__floatunsidf",
6473 80 => "__floatunsixf",
6474 128 => "__floatunsitf",
6475 },
6476 },
6477 33...64 => switch (src_int_info.signedness) {
6478 .signed => switch (dst_bits) {
6479 else => unreachable,
6480 16 => "__floatdihf",
6481 32 => "__floatdisf",
6482 64 => "__floatdidf",
6483 80 => "__floatdixf",
6484 128 => "__floatditf",
6485 },
6486 .unsigned => switch (dst_bits) {
6487 else => unreachable,
6488 16 => "__floatundihf",
6489 32 => "__floatundisf",
6490 64 => "__floatundidf",
6491 80 => "__floatundixf",
6492 128 => "__floatunditf",
6493 },
6494 },
6495 65...128 => switch (src_int_info.signedness) {
6496 .signed => switch (dst_bits) {
6497 else => unreachable,
6498 16 => "__floattihf",
6499 32 => "__floattisf",
6500 64 => "__floattidf",
6501 80 => "__floattixf",
6502 128 => "__floattitf",
6503 },
6504 .unsigned => switch (dst_bits) {
6505 else => unreachable,
6506 16 => "__floatuntihf",
6507 32 => "__floatuntisf",
6508 64 => "__floatuntidf",
6509 80 => "__floatuntixf",
6510 128 => "__floatuntitf",
6511 },
6512 },
6513 },
6514 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
6515 });
6516 try isel.emit(.bl(0));
6517 try call.finishCallee(isel);
6518
6519 try call.prepareParams(isel);
6520 const src_vi = try isel.use(ty_op.operand);
6521 switch (src_int_info.bits) {
6522 else => unreachable,
6523 1...64 => try call.paramLiveOut(isel, src_vi, .r0),
6524 65...128 => {
6525 var src_hi64_it = src_vi.field(src_ty, 8, 8);
6526 const src_hi64_vi = try src_hi64_it.only(isel);
6527 try call.paramLiveOut(isel, src_hi64_vi.?, .r1);
6528 var src_lo64_it = src_vi.field(src_ty, 0, 8);
6529 const src_lo64_vi = try src_lo64_it.only(isel);
6530 try call.paramLiveOut(isel, src_lo64_vi.?, .r0);
6531 },
6532 }
6533 try call.finishParams(isel);
6534 },
6535 else => return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }),
6536 }
6537 }
6538 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6539 },
6540 .memset, .memset_safe => |air_tag| {
6541 const bin_op = air.data(air.inst_index).bin_op;
6542 const dst_ty = isel.air.typeOf(bin_op.lhs, ip);
6543 const dst_info = dst_ty.ptrInfo(zcu);
6544 const fill_byte: union(enum) { constant: u8, value: Air.Inst.Ref } = fill_byte: {
6545 if (bin_op.rhs.toInterned()) |fill_val| {
6546 if (ip.isUndef(fill_val)) switch (air_tag) {
6547 else => unreachable,
6548 .memset => break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag,
6549 .memset_safe => break :fill_byte .{ .constant = 0xaa },
6550 };
6551 if (try isel.hasRepeatedByteRepr(.fromInterned(fill_val))) |fill_byte|
6552 break :fill_byte .{ .constant = fill_byte };
6553 }
6554 switch (dst_ty.elemType2(zcu).abiSize(zcu)) {
6555 0 => unreachable,
6556 1 => break :fill_byte .{ .value = bin_op.rhs },
6557 2, 4, 8 => |size| {
6558 const dst_vi = try isel.use(bin_op.lhs);
6559 const ptr_ra = try isel.allocIntReg();
6560 const fill_vi = try isel.use(bin_op.rhs);
6561 const fill_mat = try fill_vi.matReg(isel);
6562 const len_mat: Value.Materialize = len_mat: switch (dst_info.flags.size) {
6563 .one => .{ .vi = undefined, .ra = try isel.allocIntReg() },
6564 .many => unreachable,
6565 .slice => {
6566 var dst_len_it = dst_vi.field(dst_ty, 8, 8);
6567 const dst_len_vi = try dst_len_it.only(isel);
6568 break :len_mat try dst_len_vi.?.matReg(isel);
6569 },
6570 .c => unreachable,
6571 };
6572
6573 const skip_label = isel.instructions.items.len;
6574 _ = try isel.instructions.addOne(gpa);
6575 try isel.emit(.sub(len_mat.ra.x(), len_mat.ra.x(), .{ .immediate = 1 }));
6576 try isel.emit(switch (size) {
6577 else => unreachable,
6578 2 => .strh(fill_mat.ra.w(), .{ .post_index = .{ .base = ptr_ra.x(), .index = 2 } }),
6579 4 => .str(fill_mat.ra.w(), .{ .post_index = .{ .base = ptr_ra.x(), .index = 4 } }),
6580 8 => .str(fill_mat.ra.x(), .{ .post_index = .{ .base = ptr_ra.x(), .index = 8 } }),
6581 });
6582 isel.instructions.items[skip_label] = .cbnz(
6583 len_mat.ra.x(),
6584 -@as(i21, @intCast((isel.instructions.items.len - 1 - skip_label) << 2)),
6585 );
6586 switch (dst_info.flags.size) {
6587 .one => {
6588 const len_imm = ZigType.fromInterned(dst_info.child).arrayLen(zcu);
6589 assert(len_imm > 0);
6590 try isel.movImmediate(len_mat.ra.x(), len_imm);
6591 isel.freeReg(len_mat.ra);
6592 try fill_mat.finish(isel);
6593 isel.freeReg(ptr_ra);
6594 try dst_vi.liveOut(isel, ptr_ra);
6595 },
6596 .many => unreachable,
6597 .slice => {
6598 try isel.emit(.cbz(
6599 len_mat.ra.x(),
6600 @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
6601 ));
6602 try len_mat.finish(isel);
6603 try fill_mat.finish(isel);
6604 isel.freeReg(ptr_ra);
6605 var dst_ptr_it = dst_vi.field(dst_ty, 0, 8);
6606 const dst_ptr_vi = try dst_ptr_it.only(isel);
6607 try dst_ptr_vi.?.liveOut(isel, ptr_ra);
6608 },
6609 .c => unreachable,
6610 }
6611
6612 break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6613 },
6614 else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty) }),
6615 }
6616 };
6617
6618 try call.prepareReturn(isel);
6619 try call.finishReturn(isel);
6620
6621 try call.prepareCallee(isel);
6622 try isel.global_relocs.append(gpa, .{
6623 .name = "memset",
6624 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
6625 });
6626 try isel.emit(.bl(0));
6627 try call.finishCallee(isel);
6628
6629 try call.prepareParams(isel);
6630 const dst_vi = try isel.use(bin_op.lhs);
6631 switch (dst_info.flags.size) {
6632 .one => {
6633 try isel.movImmediate(.x2, ZigType.fromInterned(dst_info.child).abiSize(zcu));
6634 switch (fill_byte) {
6635 .constant => |byte| try isel.movImmediate(.w1, byte),
6636 .value => |byte| try call.paramLiveOut(isel, try isel.use(byte), .r1),
6637 }
6638 try call.paramLiveOut(isel, dst_vi, .r0);
6639 },
6640 .many => unreachable,
6641 .slice => {
6642 var dst_ptr_it = dst_vi.field(dst_ty, 0, 8);
6643 const dst_ptr_vi = try dst_ptr_it.only(isel);
6644 var dst_len_it = dst_vi.field(dst_ty, 8, 8);
6645 const dst_len_vi = try dst_len_it.only(isel);
6646 try isel.elemPtr(.r2, .zr, .add, ZigType.fromInterned(dst_info.child).abiSize(zcu), dst_len_vi.?);
6647 switch (fill_byte) {
6648 .constant => |byte| try isel.movImmediate(.w1, byte),
6649 .value => |byte| try call.paramLiveOut(isel, try isel.use(byte), .r1),
6650 }
6651 try call.paramLiveOut(isel, dst_ptr_vi.?, .r0);
6652 },
6653 .c => unreachable,
6654 }
6655 try call.finishParams(isel);
6656
6657 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6658 },
6659 .memcpy, .memmove => |air_tag| {
6660 const bin_op = air.data(air.inst_index).bin_op;
6661 const dst_ty = isel.air.typeOf(bin_op.lhs, ip);
6662 const dst_info = dst_ty.ptrInfo(zcu);
6663
6664 try call.prepareReturn(isel);
6665 try call.finishReturn(isel);
6666
6667 try call.prepareCallee(isel);
6668 try isel.global_relocs.append(gpa, .{
6669 .name = @tagName(air_tag),
6670 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
6671 });
6672 try isel.emit(.bl(0));
6673 try call.finishCallee(isel);
6674
6675 try call.prepareParams(isel);
6676 switch (dst_info.flags.size) {
6677 .one => {
6678 const dst_vi = try isel.use(bin_op.lhs);
6679 const src_vi = try isel.use(bin_op.rhs);
6680 try isel.movImmediate(.x2, ZigType.fromInterned(dst_info.child).abiSize(zcu));
6681 try call.paramLiveOut(isel, src_vi, .r1);
6682 try call.paramLiveOut(isel, dst_vi, .r0);
6683 },
6684 .many => unreachable,
6685 .slice => {
6686 const dst_vi = try isel.use(bin_op.lhs);
6687 var dst_ptr_it = dst_vi.field(dst_ty, 0, 8);
6688 const dst_ptr_vi = try dst_ptr_it.only(isel);
6689 var dst_len_it = dst_vi.field(dst_ty, 8, 8);
6690 const dst_len_vi = try dst_len_it.only(isel);
6691 const src_vi = try isel.use(bin_op.rhs);
6692 try isel.elemPtr(.r2, .zr, .add, ZigType.fromInterned(dst_info.child).abiSize(zcu), dst_len_vi.?);
6693 try call.paramLiveOut(isel, src_vi, .r1);
6694 try call.paramLiveOut(isel, dst_ptr_vi.?, .r0);
6695 },
6696 .c => unreachable,
6697 }
6698 try call.finishParams(isel);
6699
6700 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6701 },
6702 .atomic_load => {
6703 const atomic_load = air.data(air.inst_index).atomic_load;
6704 const ptr_ty = isel.air.typeOf(atomic_load.ptr, ip);
6705 const ptr_info = ptr_ty.ptrInfo(zcu);
6706 if (atomic_load.order != .unordered) return isel.fail("ordered atomic load", .{});
6707 if (ptr_info.packed_offset.host_size > 0) return isel.fail("packed atomic load", .{});
6708
6709 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| {
6710 defer dst_vi.value.deref(isel);
6711 var ptr_mat: ?Value.Materialize = null;
6712 var dst_part_it = dst_vi.value.parts(isel);
6713 while (dst_part_it.next()) |dst_part_vi| {
6714 const dst_ra = try dst_part_vi.defReg(isel) orelse continue;
6715 if (ptr_mat == null) {
6716 const ptr_vi = try isel.use(atomic_load.ptr);
6717 ptr_mat = try ptr_vi.matReg(isel);
6718 }
6719 try isel.emit(switch (dst_part_vi.size(isel)) {
6720 else => |size| return isel.fail("bad atomic load size of {d} from {f}", .{
6721 size, isel.fmtType(ptr_ty),
6722 }),
6723 1 => switch (dst_part_vi.signedness(isel)) {
6724 .signed => .ldrsb(dst_ra.w(), .{ .unsigned_offset = .{
6725 .base = ptr_mat.?.ra.x(),
6726 .offset = @intCast(dst_part_vi.get(isel).offset_from_parent),
6727 } }),
6728 .unsigned => .ldrb(dst_ra.w(), .{ .unsigned_offset = .{
6729 .base = ptr_mat.?.ra.x(),
6730 .offset = @intCast(dst_part_vi.get(isel).offset_from_parent),
6731 } }),
6732 },
6733 2 => switch (dst_part_vi.signedness(isel)) {
6734 .signed => .ldrsh(dst_ra.w(), .{ .unsigned_offset = .{
6735 .base = ptr_mat.?.ra.x(),
6736 .offset = @intCast(dst_part_vi.get(isel).offset_from_parent),
6737 } }),
6738 .unsigned => .ldrh(dst_ra.w(), .{ .unsigned_offset = .{
6739 .base = ptr_mat.?.ra.x(),
6740 .offset = @intCast(dst_part_vi.get(isel).offset_from_parent),
6741 } }),
6742 },
6743 4 => .ldr(dst_ra.w(), .{ .unsigned_offset = .{
6744 .base = ptr_mat.?.ra.x(),
6745 .offset = @intCast(dst_part_vi.get(isel).offset_from_parent),
6746 } }),
6747 8 => .ldr(dst_ra.x(), .{ .unsigned_offset = .{
6748 .base = ptr_mat.?.ra.x(),
6749 .offset = @intCast(dst_part_vi.get(isel).offset_from_parent),
6750 } }),
6751 });
6752 }
6753 if (ptr_mat) |mat| try mat.finish(isel);
6754 } else if (ptr_info.flags.is_volatile) return isel.fail("volatile atomic load", .{});
6755
6756 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6757 },
6758 .error_name => {
6759 if (isel.live_values.fetchRemove(air.inst_index)) |name_vi| unused: {
6760 defer name_vi.value.deref(isel);
6761 var ptr_part_it = name_vi.value.field(.slice_const_u8_sentinel_0, 0, 8);
6762 const ptr_part_vi = try ptr_part_it.only(isel);
6763 const ptr_part_ra = try ptr_part_vi.?.defReg(isel);
6764 var len_part_it = name_vi.value.field(.slice_const_u8_sentinel_0, 8, 8);
6765 const len_part_vi = try len_part_it.only(isel);
6766 const len_part_ra = try len_part_vi.?.defReg(isel);
6767 if (ptr_part_ra == null and len_part_ra == null) break :unused;
6768
6769 const un_op = air.data(air.inst_index).un_op;
6770 const error_vi = try isel.use(un_op);
6771 const error_mat = try error_vi.matReg(isel);
6772 const ptr_ra = try isel.allocIntReg();
6773 defer isel.freeReg(ptr_ra);
6774 const start_ra, const end_ra = range_ras: {
6775 const name_lock: RegLock = if (len_part_ra != null) if (ptr_part_ra) |name_ptr_ra|
6776 isel.tryLockReg(name_ptr_ra)
6777 else
6778 .empty else .empty;
6779 defer name_lock.unlock(isel);
6780 break :range_ras .{ try isel.allocIntReg(), try isel.allocIntReg() };
6781 };
6782 defer {
6783 isel.freeReg(start_ra);
6784 isel.freeReg(end_ra);
6785 }
6786 if (len_part_ra) |name_len_ra| try isel.emit(.sub(
6787 name_len_ra.w(),
6788 end_ra.w(),
6789 .{ .register = start_ra.w() },
6790 ));
6791 if (ptr_part_ra) |name_ptr_ra| try isel.emit(.add(
6792 name_ptr_ra.x(),
6793 ptr_ra.x(),
6794 .{ .extended_register = .{
6795 .register = start_ra.w(),
6796 .extend = .{ .uxtw = 0 },
6797 } },
6798 ));
6799 if (len_part_ra) |_| try isel.emit(.sub(end_ra.w(), end_ra.w(), .{ .immediate = 1 }));
6800 try isel.emit(.ldp(start_ra.w(), end_ra.w(), .{ .base = start_ra.x() }));
6801 try isel.emit(.add(start_ra.x(), ptr_ra.x(), .{ .extended_register = .{
6802 .register = error_mat.ra.w(),
6803 .extend = switch (zcu.errorSetBits()) {
6804 else => unreachable,
6805 1...8 => .{ .uxtb = 2 },
6806 9...16 => .{ .uxth = 2 },
6807 17...32 => .{ .uxtw = 2 },
6808 },
6809 } }));
6810 try isel.lazy_relocs.append(gpa, .{
6811 .symbol = .{ .kind = .const_data, .ty = .anyerror_type },
6812 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
6813 });
6814 try isel.emit(.add(ptr_ra.x(), ptr_ra.x(), .{ .immediate = 0 }));
6815 try isel.lazy_relocs.append(gpa, .{
6816 .symbol = .{ .kind = .const_data, .ty = .anyerror_type },
6817 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
6818 });
6819 try isel.emit(.adrp(ptr_ra.x(), 0));
6820 try error_mat.finish(isel);
6821 }
6822 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6823 },
6824 .aggregate_init => {
6825 if (isel.live_values.fetchRemove(air.inst_index)) |agg_vi| {
6826 defer agg_vi.value.deref(isel);
6827
6828 const ty_pl = air.data(air.inst_index).ty_pl;
6829 const agg_ty = ty_pl.ty.toType();
6830 switch (ip.indexToKey(agg_ty.toIntern())) {
6831 .array_type => |array_type| {
6832 const elems: []const Air.Inst.Ref =
6833 @ptrCast(isel.air.extra.items[ty_pl.payload..][0..@intCast(array_type.len)]);
6834 var elem_offset: u64 = 0;
6835 const elem_size = ZigType.fromInterned(array_type.child).abiSize(zcu);
6836 for (elems) |elem| {
6837 var agg_part_it = agg_vi.value.field(agg_ty, elem_offset, elem_size);
6838 const agg_part_vi = try agg_part_it.only(isel);
6839 try agg_part_vi.?.move(isel, elem);
6840 elem_offset += elem_size;
6841 }
6842 switch (array_type.sentinel) {
6843 .none => {},
6844 else => |sentinel| {
6845 var agg_part_it = agg_vi.value.field(agg_ty, elem_offset, elem_size);
6846 const agg_part_vi = try agg_part_it.only(isel);
6847 try agg_part_vi.?.move(isel, .fromIntern(sentinel));
6848 },
6849 }
6850 },
6851 .struct_type => {
6852 const loaded_struct = ip.loadStructType(agg_ty.toIntern());
6853 const elems: []const Air.Inst.Ref =
6854 @ptrCast(isel.air.extra.items[ty_pl.payload..][0..loaded_struct.field_types.len]);
6855 var field_offset: u64 = 0;
6856 var field_it = loaded_struct.iterateRuntimeOrder(ip);
6857 while (field_it.next()) |field_index| {
6858 const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
6859 field_offset = field_ty.structFieldAlignment(
6860 loaded_struct.fieldAlign(ip, field_index),
6861 loaded_struct.layout,
6862 zcu,
6863 ).forward(field_offset);
6864 const field_size = field_ty.abiSize(zcu);
6865 if (field_size == 0) continue;
6866 var agg_part_it = agg_vi.value.field(agg_ty, field_offset, field_size);
6867 const agg_part_vi = try agg_part_it.only(isel);
6868 try agg_part_vi.?.move(isel, elems[field_index]);
6869 field_offset += field_size;
6870 }
6871 assert(loaded_struct.flagsUnordered(ip).alignment.forward(field_offset) == agg_vi.value.size(isel));
6872 },
6873 .tuple_type => |tuple_type| {
6874 const elems: []const Air.Inst.Ref =
6875 @ptrCast(isel.air.extra.items[ty_pl.payload..][0..tuple_type.types.len]);
6876 var tuple_align: InternPool.Alignment = .@"1";
6877 var field_offset: u64 = 0;
6878 for (
6879 tuple_type.types.get(ip),
6880 tuple_type.values.get(ip),
6881 elems,
6882 ) |field_ty_index, field_val, elem| {
6883 if (field_val != .none) continue;
6884 const field_ty: ZigType = .fromInterned(field_ty_index);
6885 const field_align = field_ty.abiAlignment(zcu);
6886 tuple_align = tuple_align.maxStrict(field_align);
6887 field_offset = field_align.forward(field_offset);
6888 const field_size = field_ty.abiSize(zcu);
6889 if (field_size == 0) continue;
6890 var agg_part_it = agg_vi.value.field(agg_ty, field_offset, field_size);
6891 const agg_part_vi = try agg_part_it.only(isel);
6892 try agg_part_vi.?.move(isel, elem);
6893 field_offset += field_size;
6894 }
6895 assert(tuple_align.forward(field_offset) == agg_vi.value.size(isel));
6896 },
6897 else => return isel.fail("aggregate init {f}", .{isel.fmtType(agg_ty)}),
6898 }
6899 }
6900 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6901 },
6902 .union_init => {
6903 if (isel.live_values.fetchRemove(air.inst_index)) |un_vi| unused: {
6904 defer un_vi.value.deref(isel);
6905
6906 const ty_pl = air.data(air.inst_index).ty_pl;
6907 const extra = isel.air.extraData(Air.UnionInit, ty_pl.payload).data;
6908 const un_ty = ty_pl.ty.toType();
6909 if (un_ty.containerLayout(zcu) != .@"extern") return isel.fail("bad union init {f}", .{isel.fmtType(un_ty)});
6910
6911 try un_vi.value.defAddr(isel, un_ty, null, comptime &.initFill(.free)) orelse break :unused;
6912
6913 try call.prepareReturn(isel);
6914 try call.finishReturn(isel);
6915
6916 try call.prepareCallee(isel);
6917 try isel.global_relocs.append(gpa, .{
6918 .name = "memcpy",
6919 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
6920 });
6921 try isel.emit(.bl(0));
6922 try call.finishCallee(isel);
6923
6924 try call.prepareParams(isel);
6925 const init_vi = try isel.use(extra.init);
6926 try isel.movImmediate(.x2, init_vi.size(isel));
6927 try call.paramAddress(isel, init_vi, .r1);
6928 try call.paramAddress(isel, un_vi.value, .r0);
6929 try call.finishParams(isel);
6930 }
6931 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6932 },
6933 .prefetch => {
6934 const prefetch = air.data(air.inst_index).prefetch;
6935 if (!(prefetch.rw == .write and prefetch.cache == .instruction)) {
6936 const maybe_slice_ty = isel.air.typeOf(prefetch.ptr, ip);
6937 const maybe_slice_vi = try isel.use(prefetch.ptr);
6938 const ptr_vi = if (maybe_slice_ty.isSlice(zcu)) ptr_vi: {
6939 var ptr_part_it = maybe_slice_vi.field(maybe_slice_ty, 0, 8);
6940 const ptr_part_vi = try ptr_part_it.only(isel);
6941 break :ptr_vi ptr_part_vi.?;
6942 } else maybe_slice_vi;
6943 const ptr_mat = try ptr_vi.matReg(isel);
6944 try isel.emit(.prfm(.{
6945 .policy = switch (prefetch.locality) {
6946 1, 2, 3 => .keep,
6947 0 => .strm,
6948 },
6949 .target = switch (prefetch.locality) {
6950 0, 3 => .l1,
6951 2 => .l2,
6952 1 => .l3,
6953 },
6954 .type = switch (prefetch.rw) {
6955 .read => switch (prefetch.cache) {
6956 .data => .pld,
6957 .instruction => .pli,
6958 },
6959 .write => switch (prefetch.cache) {
6960 .data => .pst,
6961 .instruction => unreachable,
6962 },
6963 },
6964 }, .{ .base = ptr_mat.ra.x() }));
6965 try ptr_mat.finish(isel);
6966 }
6967 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
6968 },
6969 .mul_add => {
6970 if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
6971 defer res_vi.value.deref(isel);
6972
6973 const pl_op = air.data(air.inst_index).pl_op;
6974 const bin_op = isel.air.extraData(Air.Bin, pl_op.payload).data;
6975 const ty = isel.air.typeOf(pl_op.operand, ip);
6976 switch (ty.floatBits(isel.target)) {
6977 else => unreachable,
6978 16, 32, 64 => |bits| {
6979 const res_ra = try res_vi.value.defReg(isel) orelse break :unused;
6980 const need_fcvt = switch (bits) {
6981 else => unreachable,
6982 16 => !isel.target.cpu.has(.aarch64, .fullfp16),
6983 32, 64 => false,
6984 };
6985 if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s()));
6986 const lhs_vi = try isel.use(bin_op.lhs);
6987 const rhs_vi = try isel.use(bin_op.rhs);
6988 const addend_vi = try isel.use(pl_op.operand);
6989 const lhs_mat = try lhs_vi.matReg(isel);
6990 const rhs_mat = try rhs_vi.matReg(isel);
6991 const addend_mat = try addend_vi.matReg(isel);
6992 const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra;
6993 defer if (need_fcvt) isel.freeReg(lhs_ra);
6994 const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra;
6995 defer if (need_fcvt) isel.freeReg(rhs_ra);
6996 const addend_ra = if (need_fcvt) try isel.allocVecReg() else addend_mat.ra;
6997 defer if (need_fcvt) isel.freeReg(addend_ra);
6998 try isel.emit(bits: switch (bits) {
6999 else => unreachable,
7000 16 => if (need_fcvt)
7001 continue :bits 32
7002 else
7003 .fmadd(res_ra.h(), lhs_ra.h(), rhs_ra.h(), addend_ra.h()),
7004 32 => .fmadd(res_ra.s(), lhs_ra.s(), rhs_ra.s(), addend_ra.s()),
7005 64 => .fmadd(res_ra.d(), lhs_ra.d(), rhs_ra.d(), addend_ra.d()),
7006 });
7007 if (need_fcvt) {
7008 try isel.emit(.fcvt(addend_ra.s(), addend_mat.ra.h()));
7009 try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h()));
7010 try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h()));
7011 }
7012 try addend_mat.finish(isel);
7013 try rhs_mat.finish(isel);
7014 try lhs_mat.finish(isel);
7015 },
7016 80, 128 => |bits| {
7017 try call.prepareReturn(isel);
7018 switch (bits) {
7019 else => unreachable,
7020 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0),
7021 80 => {
7022 var res_hi16_it = res_vi.value.field(ty, 8, 8);
7023 const res_hi16_vi = try res_hi16_it.only(isel);
7024 try call.returnLiveIn(isel, res_hi16_vi.?, .r1);
7025 var res_lo64_it = res_vi.value.field(ty, 0, 8);
7026 const res_lo64_vi = try res_lo64_it.only(isel);
7027 try call.returnLiveIn(isel, res_lo64_vi.?, .r0);
7028 },
7029 }
7030 try call.finishReturn(isel);
7031
7032 try call.prepareCallee(isel);
7033 try isel.global_relocs.append(gpa, .{
7034 .name = switch (bits) {
7035 else => unreachable,
7036 16 => "__fmah",
7037 32 => "fmaf",
7038 64 => "fma",
7039 80 => "__fmax",
7040 128 => "fmaq",
7041 },
7042 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
7043 });
7044 try isel.emit(.bl(0));
7045 try call.finishCallee(isel);
7046
7047 try call.prepareParams(isel);
7048 const lhs_vi = try isel.use(bin_op.lhs);
7049 const rhs_vi = try isel.use(bin_op.rhs);
7050 const addend_vi = try isel.use(pl_op.operand);
7051 switch (bits) {
7052 else => unreachable,
7053 16, 32, 64, 128 => {
7054 try call.paramLiveOut(isel, addend_vi, .v2);
7055 try call.paramLiveOut(isel, rhs_vi, .v1);
7056 try call.paramLiveOut(isel, lhs_vi, .v0);
7057 },
7058 80 => {
7059 var addend_hi16_it = addend_vi.field(ty, 8, 8);
7060 const addend_hi16_vi = try addend_hi16_it.only(isel);
7061 try call.paramLiveOut(isel, addend_hi16_vi.?, .r5);
7062 var addend_lo64_it = addend_vi.field(ty, 0, 8);
7063 const addend_lo64_vi = try addend_lo64_it.only(isel);
7064 try call.paramLiveOut(isel, addend_lo64_vi.?, .r4);
7065 var rhs_hi16_it = rhs_vi.field(ty, 8, 8);
7066 const rhs_hi16_vi = try rhs_hi16_it.only(isel);
7067 try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3);
7068 var rhs_lo64_it = rhs_vi.field(ty, 0, 8);
7069 const rhs_lo64_vi = try rhs_lo64_it.only(isel);
7070 try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2);
7071 var lhs_hi16_it = lhs_vi.field(ty, 8, 8);
7072 const lhs_hi16_vi = try lhs_hi16_it.only(isel);
7073 try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1);
7074 var lhs_lo64_it = lhs_vi.field(ty, 0, 8);
7075 const lhs_lo64_vi = try lhs_lo64_it.only(isel);
7076 try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0);
7077 },
7078 }
7079 try call.finishParams(isel);
7080 },
7081 }
7082 }
7083 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
7084 },
7085 .field_parent_ptr => {
7086 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: {
7087 defer dst_vi.value.deref(isel);
7088 const ty_pl = air.data(air.inst_index).ty_pl;
7089 const extra = isel.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
7090 switch (codegen.fieldOffset(
7091 ty_pl.ty.toType(),
7092 isel.air.typeOf(extra.field_ptr, ip),
7093 extra.field_index,
7094 zcu,
7095 )) {
7096 0 => try dst_vi.value.move(isel, extra.field_ptr),
7097 else => |field_offset| {
7098 const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused;
7099 const src_vi = try isel.use(extra.field_ptr);
7100 const src_mat = try src_vi.matReg(isel);
7101 const lo12: u12 = @truncate(field_offset >> 0);
7102 const hi12: u12 = @intCast(field_offset >> 12);
7103 if (hi12 > 0) try isel.emit(.sub(
7104 dst_ra.x(),
7105 if (lo12 > 0) dst_ra.x() else src_mat.ra.x(),
7106 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
7107 ));
7108 if (lo12 > 0) try isel.emit(.sub(dst_ra.x(), src_mat.ra.x(), .{ .immediate = lo12 }));
7109 try src_mat.finish(isel);
7110 },
7111 }
7112 }
7113 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
7114 },
7115 .wasm_memory_size, .wasm_memory_grow => unreachable,
7116 .cmp_lt_errors_len => {
7117 if (isel.live_values.fetchRemove(air.inst_index)) |is_vi| unused: {
7118 defer is_vi.value.deref(isel);
7119 const is_ra = try is_vi.value.defReg(isel) orelse break :unused;
7120 try isel.emit(.csinc(is_ra.w(), .wzr, .wzr, .invert(.ls)));
7121
7122 const un_op = air.data(air.inst_index).un_op;
7123 const error_vi = try isel.use(un_op);
7124 const error_mat = try error_vi.matReg(isel);
7125 const ptr_ra = try isel.allocIntReg();
7126 defer isel.freeReg(ptr_ra);
7127 try isel.emit(.subs(.wzr, error_mat.ra.w(), .{ .register = ptr_ra.w() }));
7128 try isel.lazy_relocs.append(gpa, .{
7129 .symbol = .{ .kind = .const_data, .ty = .anyerror_type },
7130 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
7131 });
7132 try isel.emit(.ldr(ptr_ra.w(), .{ .base = ptr_ra.x() }));
7133 try isel.lazy_relocs.append(gpa, .{
7134 .symbol = .{ .kind = .const_data, .ty = .anyerror_type },
7135 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
7136 });
7137 try isel.emit(.adrp(ptr_ra.x(), 0));
7138 try error_mat.finish(isel);
7139 }
7140 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
7141 },
7142 .runtime_nav_ptr => {
7143 if (isel.live_values.fetchRemove(air.inst_index)) |ptr_vi| unused: {
7144 defer ptr_vi.value.deref(isel);
7145 const ptr_ra = try ptr_vi.value.defReg(isel) orelse break :unused;
7146
7147 const ty_nav = air.data(air.inst_index).ty_nav;
7148 if (ZigType.fromInterned(ip.getNav(ty_nav.nav).typeOf(ip)).isFnOrHasRuntimeBits(zcu)) switch (true) {
7149 false => {
7150 try isel.nav_relocs.append(gpa, .{
7151 .nav = ty_nav.nav,
7152 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
7153 });
7154 try isel.emit(.adr(ptr_ra.x(), 0));
7155 },
7156 true => {
7157 try isel.nav_relocs.append(gpa, .{
7158 .nav = ty_nav.nav,
7159 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
7160 });
7161 try isel.emit(.add(ptr_ra.x(), ptr_ra.x(), .{ .immediate = 0 }));
7162 try isel.nav_relocs.append(gpa, .{
7163 .nav = ty_nav.nav,
7164 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
7165 });
7166 try isel.emit(.adrp(ptr_ra.x(), 0));
7167 },
7168 } else try isel.movImmediate(ptr_ra.x(), isel.pt.navAlignment(ty_nav.nav).forward(0xaaaaaaaaaaaaaaaa));
7169 }
7170 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
7171 },
7172 .c_va_arg => {
7173 const maybe_arg_vi = isel.live_values.fetchRemove(air.inst_index);
7174 defer if (maybe_arg_vi) |arg_vi| arg_vi.value.deref(isel);
7175 const ty_op = air.data(air.inst_index).ty_op;
7176 const ty = ty_op.ty.toType();
7177 var param_it: CallAbiIterator = .init;
7178 const param_vi = try param_it.param(isel, ty);
7179 defer param_vi.?.deref(isel);
7180 const passed_vi = switch (param_vi.?.parent(isel)) {
7181 .unallocated => param_vi.?,
7182 .stack_slot, .value, .constant => unreachable,
7183 .address => |address_vi| address_vi,
7184 };
7185 const passed_size: u5 = @intCast(passed_vi.alignment(isel).forward(passed_vi.size(isel)));
7186 const passed_is_vector = passed_vi.isVector(isel);
7187
7188 const va_list_ptr_vi = try isel.use(ty_op.operand);
7189 const va_list_ptr_mat = try va_list_ptr_vi.matReg(isel);
7190 const offs_ra = try isel.allocIntReg();
7191 defer isel.freeReg(offs_ra);
7192 const stack_ra = try isel.allocIntReg();
7193 defer isel.freeReg(stack_ra);
7194
7195 var part_vis: [2]Value.Index = undefined;
7196 var arg_part_ras: [2]?Register.Alias = @splat(null);
7197 const parts_len = parts_len: {
7198 var parts_len: u2 = 0;
7199 var part_it = passed_vi.parts(isel);
7200 while (part_it.next()) |part_vi| : (parts_len += 1) {
7201 part_vis[parts_len] = part_vi;
7202 const arg_vi = maybe_arg_vi orelse continue;
7203 const part_offset, const part_size = part_vi.position(isel);
7204 var arg_part_it = arg_vi.value.field(ty, part_offset, part_size);
7205 const arg_part_vi = try arg_part_it.only(isel);
7206 arg_part_ras[parts_len] = try arg_part_vi.?.defReg(isel);
7207 }
7208 break :parts_len parts_len;
7209 };
7210
7211 const done_label = isel.instructions.items.len;
7212 try isel.emit(.str(stack_ra.x(), .{ .unsigned_offset = .{
7213 .base = va_list_ptr_mat.ra.x(),
7214 .offset = 0,
7215 } }));
7216 try isel.emit(switch (parts_len) {
7217 else => unreachable,
7218 1 => if (arg_part_ras[0]) |arg_part_ra| switch (part_vis[0].size(isel)) {
7219 else => unreachable,
7220 1 => if (arg_part_ra.isVector()) .ldr(arg_part_ra.b(), .{ .post_index = .{
7221 .base = stack_ra.x(),
7222 .index = passed_size,
7223 } }) else switch (part_vis[0].signedness(isel)) {
7224 .signed => .ldrsb(arg_part_ra.w(), .{ .post_index = .{
7225 .base = stack_ra.x(),
7226 .index = passed_size,
7227 } }),
7228 .unsigned => .ldrb(arg_part_ra.w(), .{ .post_index = .{
7229 .base = stack_ra.x(),
7230 .index = passed_size,
7231 } }),
7232 },
7233 2 => if (arg_part_ra.isVector()) .ldr(arg_part_ra.h(), .{ .post_index = .{
7234 .base = stack_ra.x(),
7235 .index = passed_size,
7236 } }) else switch (part_vis[0].signedness(isel)) {
7237 .signed => .ldrsh(arg_part_ra.w(), .{ .post_index = .{
7238 .base = stack_ra.x(),
7239 .index = passed_size,
7240 } }),
7241 .unsigned => .ldrh(arg_part_ra.w(), .{ .post_index = .{
7242 .base = stack_ra.x(),
7243 .index = passed_size,
7244 } }),
7245 },
7246 4 => .ldr(if (arg_part_ra.isVector()) arg_part_ra.s() else arg_part_ra.w(), .{ .post_index = .{
7247 .base = stack_ra.x(),
7248 .index = passed_size,
7249 } }),
7250 8 => .ldr(if (arg_part_ra.isVector()) arg_part_ra.d() else arg_part_ra.x(), .{ .post_index = .{
7251 .base = stack_ra.x(),
7252 .index = passed_size,
7253 } }),
7254 16 => .ldr(arg_part_ra.q(), .{ .post_index = .{
7255 .base = stack_ra.x(),
7256 .index = passed_size,
7257 } }),
7258 } else .add(stack_ra.x(), stack_ra.x(), .{ .immediate = passed_size }),
7259 2 => if (arg_part_ras[0] != null or arg_part_ras[1] != null) .ldp(
7260 @as(Register.Alias, arg_part_ras[0] orelse .zr).x(),
7261 @as(Register.Alias, arg_part_ras[1] orelse .zr).x(),
7262 .{ .post_index = .{
7263 .base = stack_ra.x(),
7264 .index = passed_size,
7265 } },
7266 ) else .add(stack_ra.x(), stack_ra.x(), .{ .immediate = passed_size }),
7267 });
7268 try isel.emit(.ldr(stack_ra.x(), .{ .unsigned_offset = .{
7269 .base = va_list_ptr_mat.ra.x(),
7270 .offset = 0,
7271 } }));
7272 switch (isel.va_list) {
7273 .other => {},
7274 .sysv => {
7275 const stack_label = isel.instructions.items.len;
7276 try isel.emit(.b(
7277 @intCast((isel.instructions.items.len + 1 - done_label) << 2),
7278 ));
7279 switch (parts_len) {
7280 else => unreachable,
7281 1 => if (arg_part_ras[0]) |arg_part_ra| try isel.emit(switch (part_vis[0].size(isel)) {
7282 else => unreachable,
7283 1 => if (arg_part_ra.isVector()) .ldr(arg_part_ra.b(), .{ .extended_register = .{
7284 .base = stack_ra.x(),
7285 .index = offs_ra.w(),
7286 .extend = .{ .sxtw = 0 },
7287 } }) else switch (part_vis[0].signedness(isel)) {
7288 .signed => .ldrsb(arg_part_ra.w(), .{ .extended_register = .{
7289 .base = stack_ra.x(),
7290 .index = offs_ra.w(),
7291 .extend = .{ .sxtw = 0 },
7292 } }),
7293 .unsigned => .ldrb(arg_part_ra.w(), .{ .extended_register = .{
7294 .base = stack_ra.x(),
7295 .index = offs_ra.w(),
7296 .extend = .{ .sxtw = 0 },
7297 } }),
7298 },
7299 2 => if (arg_part_ra.isVector()) .ldr(arg_part_ra.h(), .{ .extended_register = .{
7300 .base = stack_ra.x(),
7301 .index = offs_ra.w(),
7302 .extend = .{ .sxtw = 0 },
7303 } }) else switch (part_vis[0].signedness(isel)) {
7304 .signed => .ldrsh(arg_part_ra.w(), .{ .extended_register = .{
7305 .base = stack_ra.x(),
7306 .index = offs_ra.w(),
7307 .extend = .{ .sxtw = 0 },
7308 } }),
7309 .unsigned => .ldrh(arg_part_ra.w(), .{ .extended_register = .{
7310 .base = stack_ra.x(),
7311 .index = offs_ra.w(),
7312 .extend = .{ .sxtw = 0 },
7313 } }),
7314 },
7315 4 => .ldr(if (arg_part_ra.isVector()) arg_part_ra.s() else arg_part_ra.w(), .{ .extended_register = .{
7316 .base = stack_ra.x(),
7317 .index = offs_ra.w(),
7318 .extend = .{ .sxtw = 0 },
7319 } }),
7320 8 => .ldr(if (arg_part_ra.isVector()) arg_part_ra.d() else arg_part_ra.x(), .{ .extended_register = .{
7321 .base = stack_ra.x(),
7322 .index = offs_ra.w(),
7323 .extend = .{ .sxtw = 0 },
7324 } }),
7325 16 => .ldr(arg_part_ra.q(), .{ .extended_register = .{
7326 .base = stack_ra.x(),
7327 .index = offs_ra.w(),
7328 .extend = .{ .sxtw = 0 },
7329 } }),
7330 }),
7331 2 => if (arg_part_ras[0] != null or arg_part_ras[1] != null) {
7332 try isel.emit(.ldp(
7333 @as(Register.Alias, arg_part_ras[0] orelse .zr).x(),
7334 @as(Register.Alias, arg_part_ras[1] orelse .zr).x(),
7335 .{ .base = stack_ra.x() },
7336 ));
7337 try isel.emit(.add(stack_ra.x(), stack_ra.x(), .{ .extended_register = .{
7338 .register = offs_ra.w(),
7339 .extend = .{ .sxtw = 0 },
7340 } }));
7341 },
7342 }
7343 try isel.emit(.ldr(stack_ra.x(), .{ .unsigned_offset = .{
7344 .base = va_list_ptr_mat.ra.x(),
7345 .offset = if (passed_is_vector) 16 else 8,
7346 } }));
7347 try isel.emit(.@"b."(
7348 .gt,
7349 @intCast((isel.instructions.items.len + 1 - stack_label) << 2),
7350 ));
7351 try isel.emit(.str(stack_ra.w(), .{ .unsigned_offset = .{
7352 .base = va_list_ptr_mat.ra.x(),
7353 .offset = if (passed_is_vector) 28 else 24,
7354 } }));
7355 try isel.emit(.adds(stack_ra.w(), offs_ra.w(), .{ .immediate = passed_size }));
7356 try isel.emit(.tbz(
7357 offs_ra.w(),
7358 31,
7359 @intCast((isel.instructions.items.len + 1 - stack_label) << 2),
7360 ));
7361 try isel.emit(.ldr(offs_ra.w(), .{ .unsigned_offset = .{
7362 .base = va_list_ptr_mat.ra.x(),
7363 .offset = if (passed_is_vector) 28 else 24,
7364 } }));
7365 },
7366 }
7367 try va_list_ptr_mat.finish(isel);
7368 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
7369 },
7370 .c_va_copy => {
7371 if (isel.live_values.fetchRemove(air.inst_index)) |va_list_vi| {
7372 defer va_list_vi.value.deref(isel);
7373 const ty_op = air.data(air.inst_index).ty_op;
7374 const va_list_ptr_vi = try isel.use(ty_op.operand);
7375 const va_list_ptr_mat = try va_list_ptr_vi.matReg(isel);
7376 _ = try va_list_vi.value.load(isel, ty_op.ty.toType(), va_list_ptr_mat.ra, .{});
7377 try va_list_ptr_mat.finish(isel);
7378 }
7379 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
7380 },
7381 .c_va_end => if (air.next()) |next_air_tag| continue :air_tag next_air_tag,
7382 .c_va_start => {
7383 if (isel.live_values.fetchRemove(air.inst_index)) |va_list_vi| {
7384 defer va_list_vi.value.deref(isel);
7385 const ty = air.data(air.inst_index).ty;
7386 switch (isel.va_list) {
7387 .other => |va_list| if (try va_list_vi.value.defReg(isel)) |va_list_ra| try isel.emit(.add(
7388 va_list_ra.x(),
7389 va_list.base.x(),
7390 .{ .immediate = @intCast(va_list.offset) },
7391 )),
7392 .sysv => |va_list| {
7393 var vr_offs_it = va_list_vi.value.field(ty, 28, 4);
7394 const vr_offs_vi = try vr_offs_it.only(isel);
7395 if (try vr_offs_vi.?.defReg(isel)) |vr_offs_ra| try isel.movImmediate(
7396 vr_offs_ra.w(),
7397 @as(u32, @bitCast(va_list.__vr_offs)),
7398 );
7399 var gr_offs_it = va_list_vi.value.field(ty, 24, 4);
7400 const gr_offs_vi = try gr_offs_it.only(isel);
7401 if (try gr_offs_vi.?.defReg(isel)) |gr_offs_ra| try isel.movImmediate(
7402 gr_offs_ra.w(),
7403 @as(u32, @bitCast(va_list.__gr_offs)),
7404 );
7405 var vr_top_it = va_list_vi.value.field(ty, 16, 8);
7406 const vr_top_vi = try vr_top_it.only(isel);
7407 if (try vr_top_vi.?.defReg(isel)) |vr_top_ra| try isel.emit(.add(
7408 vr_top_ra.x(),
7409 va_list.__vr_top.base.x(),
7410 .{ .immediate = @intCast(va_list.__vr_top.offset) },
7411 ));
7412 var gr_top_it = va_list_vi.value.field(ty, 8, 8);
7413 const gr_top_vi = try gr_top_it.only(isel);
7414 if (try gr_top_vi.?.defReg(isel)) |gr_top_ra| try isel.emit(.add(
7415 gr_top_ra.x(),
7416 va_list.__gr_top.base.x(),
7417 .{ .immediate = @intCast(va_list.__gr_top.offset) },
7418 ));
7419 var stack_it = va_list_vi.value.field(ty, 0, 8);
7420 const stack_vi = try stack_it.only(isel);
7421 if (try stack_vi.?.defReg(isel)) |stack_ra| try isel.emit(.add(
7422 stack_ra.x(),
7423 va_list.__stack.base.x(),
7424 .{ .immediate = @intCast(va_list.__stack.offset) },
7425 ));
7426 },
7427 }
7428 }
7429 if (air.next()) |next_air_tag| continue :air_tag next_air_tag;
7430 },
7431 .work_item_id, .work_group_size, .work_group_id => unreachable,
7432 }
7433 assert(air.body_index == 0);
7434}
7435
7436pub fn verify(isel: *Select, check_values: bool) void {
7437 if (!std.debug.runtime_safety) return;
7438 assert(isel.blocks.count() == 1 and isel.blocks.keys()[0] == Select.Block.main);
7439 assert(isel.active_loops.items.len == 0);
7440 assert(isel.dom_start == 0 and isel.dom_len == 0);
7441 var live_reg_it = isel.live_registers.iterator();
7442 while (live_reg_it.next()) |live_reg_entry| switch (live_reg_entry.value.*) {
7443 _ => {
7444 isel.dumpValues(.all);
7445 unreachable;
7446 },
7447 .allocating, .free => {},
7448 };
7449 if (check_values) for (isel.values.items) |value| if (value.refs != 0) {
7450 isel.dumpValues(.only_referenced);
7451 unreachable;
7452 };
7453}
7454
7455/// Stack Frame Layout
7456/// +-+-----------------------------------+
7457/// |R| allocated stack |
7458/// +-+-----------------------------------+
7459/// |S| caller frame record | +---------------+
7460/// +-+-----------------------------------+ <-| entry/exit FP |
7461/// |R| caller frame | +---------------+
7462/// +-+-----------------------------------+
7463/// |R| variable incoming stack arguments | +---------------+
7464/// +-+-----------------------------------+ <-| __stack |
7465/// |S| named incoming stack arguments | +---------------+
7466/// +-+-----------------------------------+ <-| entry/exit SP |
7467/// |S| incoming gr arguments | | __gr_top |
7468/// +-+-----------------------------------+ +---------------+
7469/// |S| alignment gap |
7470/// +-+-----------------------------------+
7471/// |S| frame record | +----------+
7472/// +-+-----------------------------------+ <-| FP |
7473/// |S| incoming vr arguments | | __vr_top |
7474/// +-+-----------------------------------+ +----------+
7475/// |L| alignment gap |
7476/// +-+-----------------------------------+
7477/// |L| callee saved vr area |
7478/// +-+-----------------------------------+
7479/// |L| callee saved gr area | +----------------------+
7480/// +-+-----------------------------------+ <-| prologue/epilogue SP |
7481/// |R| realignment gap | +----------------------+
7482/// +-+-----------------------------------+
7483/// |L| locals |
7484/// +-+-----------------------------------+
7485/// |S| outgoing stack arguments | +----+
7486/// +-+-----------------------------------+ <-| SP |
7487/// |R| unallocated stack | +----+
7488/// +-+-----------------------------------+
7489/// [S] Size computed by `analyze`, can be used by the body.
7490/// [L] Size computed by `layout`, can be used by the prologue/epilogue.
7491/// [R] Size unknown until runtime, can vary from one call to the next.
7492///
7493/// Constraints that led to this layout:
7494/// * FP to __stack/__gr_top/__vr_top must only pass through [S]
7495/// * SP to outgoing stack arguments/locals must only pass through [S]
7496/// * entry/exit SP to prologue/epilogue SP must only pass through [S/L]
7497/// * all save areas must be at a positive offset from prologue/epilogue SP
7498/// * the entry/exit SP to prologue/epilogue SP distance must
7499/// - be a multiple of 16 due to hardware restrictions on the value of SP
7500/// - conform to the limit from the first matching condition in the
7501/// following list due to instruction encoding limitations
7502/// 1. callee saved gr count >= 2: multiple of 8 of at most 504 bytes
7503/// 2. callee saved vr count >= 2: multiple of 8 of at most 504 bytes
7504/// 3. callee saved gr count >= 1: at most 255 bytes
7505/// 4. callee saved vr count >= 1: at most 255 bytes
7506/// 5. variable incoming vr argument count >= 2: multiple of 16 of at most 1008 bytes
7507/// 6. variable incoming vr argument count >= 1: at most 255 bytes
7508/// 7. have frame record: multiple of 8 of at most 504 bytes
7509pub fn layout(
7510 isel: *Select,
7511 incoming: CallAbiIterator,
7512 is_sysv_var_args: bool,
7513 saved_gra_len: u7,
7514 saved_vra_len: u7,
7515 mod: *const Package.Module,
7516) !usize {
7517 const zcu = isel.pt.zcu;
7518 const ip = &zcu.intern_pool;
7519 const nav = ip.getNav(isel.nav_index);
7520 wip_mir_log.debug("{f}<body>:\n", .{nav.fqn.fmt(ip)});
7521
7522 const stack_size: u24 = @intCast(InternPool.Alignment.@"16".forward(isel.stack_size));
7523
7524 var saves_buf: [10 + 8 + 8 + 2 + 8]struct {
7525 class: enum { integer, vector },
7526 needs_restore: bool,
7527 register: Register,
7528 offset: u10,
7529 size: u5,
7530 } = undefined;
7531 const saves, const saves_size, const frame_record_offset = saves: {
7532 var saves_len: usize = 0;
7533 var saves_size: u10 = 0;
7534 var save_ra: Register.Alias = undefined;
7535
7536 // callee saved gr area
7537 save_ra = .r19;
7538 while (save_ra != .r29) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) {
7539 if (!isel.saved_registers.contains(save_ra)) continue;
7540 saves_size = std.mem.alignForward(u10, saves_size, 8);
7541 saves_buf[saves_len] = .{
7542 .class = .integer,
7543 .needs_restore = true,
7544 .register = save_ra.x(),
7545 .offset = saves_size,
7546 .size = 8,
7547 };
7548 saves_len += 1;
7549 saves_size += 8;
7550 }
7551 var deferred_gr = if (saves_size == 8 or (saves_size % 16 != 0 and saved_gra_len % 2 != 0)) gr: {
7552 saves_len -= 1;
7553 saves_size -= 8;
7554 break :gr saves_buf[saves_len].register;
7555 } else null;
7556 defer assert(deferred_gr == null);
7557
7558 // callee saved vr area
7559 save_ra = .v8;
7560 while (save_ra != .v16) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) {
7561 if (!isel.saved_registers.contains(save_ra)) continue;
7562 saves_size = std.mem.alignForward(u10, saves_size, 8);
7563 saves_buf[saves_len] = .{
7564 .class = .vector,
7565 .needs_restore = true,
7566 .register = save_ra.d(),
7567 .offset = saves_size,
7568 .size = 8,
7569 };
7570 saves_len += 1;
7571 saves_size += 8;
7572 }
7573 if (deferred_gr != null and saved_gra_len % 2 == 0) {
7574 saves_size = std.mem.alignForward(u10, saves_size, 8);
7575 saves_buf[saves_len] = .{
7576 .class = .integer,
7577 .needs_restore = true,
7578 .register = deferred_gr.?,
7579 .offset = saves_size,
7580 .size = 8,
7581 };
7582 saves_len += 1;
7583 saves_size += 8;
7584 deferred_gr = null;
7585 }
7586 if (saves_size % 16 != 0 and saved_vra_len % 2 != 0) {
7587 const prev_save = &saves_buf[saves_len - 1];
7588 switch (prev_save.class) {
7589 .integer => {},
7590 .vector => {
7591 prev_save.register = prev_save.register.alias.q();
7592 prev_save.size = 16;
7593 saves_size += 8;
7594 },
7595 }
7596 }
7597
7598 // incoming vr arguments
7599 save_ra = if (mod.strip) incoming.nsrn else CallAbiIterator.nsrn_start;
7600 while (save_ra != if (is_sysv_var_args) CallAbiIterator.nsrn_end else incoming.nsrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) {
7601 saves_size = std.mem.alignForward(u10, saves_size, 16);
7602 saves_buf[saves_len] = .{
7603 .class = .vector,
7604 .needs_restore = false,
7605 .register = save_ra.q(),
7606 .offset = saves_size,
7607 .size = 16,
7608 };
7609 saves_len += 1;
7610 saves_size += 16;
7611 }
7612
7613 // frame record
7614 saves_size = std.mem.alignForward(u10, saves_size, 16);
7615 const frame_record_offset = saves_size;
7616 saves_buf[saves_len] = .{
7617 .class = .integer,
7618 .needs_restore = true,
7619 .register = .fp,
7620 .offset = saves_size,
7621 .size = 8,
7622 };
7623 saves_len += 1;
7624 saves_size += 8;
7625
7626 saves_size = std.mem.alignForward(u10, saves_size, 8);
7627 saves_buf[saves_len] = .{
7628 .class = .integer,
7629 .needs_restore = true,
7630 .register = .lr,
7631 .offset = saves_size,
7632 .size = 8,
7633 };
7634 saves_len += 1;
7635 saves_size += 8;
7636
7637 // incoming gr arguments
7638 if (deferred_gr) |gr| {
7639 saves_size = std.mem.alignForward(u10, saves_size, 8);
7640 saves_buf[saves_len] = .{
7641 .class = .integer,
7642 .needs_restore = true,
7643 .register = gr,
7644 .offset = saves_size,
7645 .size = 8,
7646 };
7647 saves_len += 1;
7648 saves_size += 8;
7649 deferred_gr = null;
7650 } else switch (@as(u1, @truncate(saved_gra_len))) {
7651 0 => {},
7652 1 => saves_size += 8,
7653 }
7654 save_ra = if (mod.strip) incoming.ngrn else CallAbiIterator.ngrn_start;
7655 while (save_ra != if (is_sysv_var_args) CallAbiIterator.ngrn_end else incoming.ngrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) {
7656 saves_size = std.mem.alignForward(u10, saves_size, 8);
7657 saves_buf[saves_len] = .{
7658 .class = .integer,
7659 .needs_restore = false,
7660 .register = save_ra.x(),
7661 .offset = saves_size,
7662 .size = 8,
7663 };
7664 saves_len += 1;
7665 saves_size += 8;
7666 }
7667
7668 assert(InternPool.Alignment.@"16".check(saves_size));
7669 break :saves .{ saves_buf[0..saves_len], saves_size, frame_record_offset };
7670 };
7671
7672 {
7673 wip_mir_log.debug("{f}<prologue>:", .{nav.fqn.fmt(ip)});
7674 var save_index: usize = 0;
7675 while (save_index < saves.len) if (save_index + 2 <= saves.len and
7676 saves[save_index + 0].class == saves[save_index + 1].class and
7677 saves[save_index + 0].size == saves[save_index + 1].size and
7678 saves[save_index + 0].offset + saves[save_index + 0].size == saves[save_index + 1].offset)
7679 {
7680 try isel.emit(.stp(
7681 saves[save_index + 0].register,
7682 saves[save_index + 1].register,
7683 switch (saves[save_index + 0].offset) {
7684 0 => .{ .pre_index = .{
7685 .base = .sp,
7686 .index = @intCast(-@as(i11, saves_size)),
7687 } },
7688 else => |offset| .{ .signed_offset = .{
7689 .base = .sp,
7690 .offset = @intCast(offset),
7691 } },
7692 },
7693 ));
7694 save_index += 2;
7695 } else {
7696 try isel.emit(.str(
7697 saves[save_index].register,
7698 switch (saves[save_index].offset) {
7699 0 => .{ .pre_index = .{
7700 .base = .sp,
7701 .index = @intCast(-@as(i11, saves_size)),
7702 } },
7703 else => |offset| .{ .unsigned_offset = .{
7704 .base = .sp,
7705 .offset = @intCast(offset),
7706 } },
7707 },
7708 ));
7709 save_index += 1;
7710 };
7711
7712 try isel.emit(.add(.fp, .sp, .{ .immediate = frame_record_offset }));
7713 const scratch_reg: Register = if (isel.stack_align == .@"16")
7714 .sp
7715 else if (stack_size == 0 and frame_record_offset == 0)
7716 .fp
7717 else
7718 .ip0;
7719 const stack_size_lo: u12 = @truncate(stack_size >> 0);
7720 const stack_size_hi: u12 = @truncate(stack_size >> 12);
7721 if (mod.stack_check) {
7722 if (stack_size_hi > 2) {
7723 try isel.movImmediate(.ip1, stack_size_hi);
7724 const loop_label = isel.instructions.items.len;
7725 try isel.emit(.sub(.sp, .sp, .{
7726 .shifted_immediate = .{ .immediate = 1, .lsl = .@"12" },
7727 }));
7728 try isel.emit(.sub(.ip1, .ip1, .{ .immediate = 1 }));
7729 try isel.emit(.ldr(.xzr, .{ .base = .sp }));
7730 try isel.emit(.cbnz(.ip1, -@as(i21, @intCast(
7731 (isel.instructions.items.len - loop_label) << 2,
7732 ))));
7733 } else for (0..stack_size_hi) |_| {
7734 try isel.emit(.sub(.sp, .sp, .{
7735 .shifted_immediate = .{ .immediate = 1, .lsl = .@"12" },
7736 }));
7737 try isel.emit(.ldr(.xzr, .{ .base = .sp }));
7738 }
7739 if (stack_size_lo > 0) try isel.emit(.sub(
7740 scratch_reg,
7741 .sp,
7742 .{ .immediate = stack_size_lo },
7743 )) else if (scratch_reg.alias == Register.Alias.ip0)
7744 try isel.emit(.add(scratch_reg, .sp, .{ .immediate = 0 }));
7745 } else {
7746 if (stack_size_hi > 0) try isel.emit(.sub(scratch_reg, .sp, .{
7747 .shifted_immediate = .{ .immediate = stack_size_hi, .lsl = .@"12" },
7748 }));
7749 if (stack_size_lo > 0) try isel.emit(.sub(
7750 scratch_reg,
7751 if (stack_size_hi > 0) scratch_reg else .sp,
7752 .{ .immediate = stack_size_lo },
7753 )) else if (scratch_reg.alias == Register.Alias.ip0 and stack_size_hi == 0)
7754 try isel.emit(.add(scratch_reg, .sp, .{ .immediate = 0 }));
7755 }
7756 if (isel.stack_align != .@"16") try isel.emit(.@"and"(.sp, scratch_reg, .{ .immediate = .{
7757 .N = .doubleword,
7758 .immr = -%isel.stack_align.toLog2Units(),
7759 .imms = ~isel.stack_align.toLog2Units(),
7760 } }));
7761 wip_mir_log.debug("", .{});
7762 }
7763
7764 const epilogue = isel.instructions.items.len;
7765 if (isel.returns) {
7766 try isel.emit(.ret(.lr));
7767 var save_index: usize = 0;
7768 var first_offset: ?u10 = null;
7769 while (save_index < saves.len) {
7770 if (save_index + 2 <= saves.len and saves[save_index + 1].needs_restore and
7771 saves[save_index + 0].class == saves[save_index + 1].class and
7772 saves[save_index + 0].offset + saves[save_index + 0].size == saves[save_index + 1].offset)
7773 {
7774 try isel.emit(.ldp(
7775 saves[save_index + 0].register,
7776 saves[save_index + 1].register,
7777 if (first_offset) |offset| .{ .signed_offset = .{
7778 .base = .sp,
7779 .offset = @intCast(saves[save_index + 0].offset - offset),
7780 } } else form: {
7781 first_offset = @intCast(saves[save_index + 0].offset);
7782 break :form .{ .post_index = .{
7783 .base = .sp,
7784 .index = @intCast(saves_size - first_offset.?),
7785 } };
7786 },
7787 ));
7788 save_index += 2;
7789 } else if (saves[save_index].needs_restore) {
7790 try isel.emit(.ldr(
7791 saves[save_index].register,
7792 if (first_offset) |offset| .{ .unsigned_offset = .{
7793 .base = .sp,
7794 .offset = saves[save_index + 0].offset - offset,
7795 } } else form: {
7796 const offset = saves[save_index + 0].offset;
7797 first_offset = offset;
7798 break :form .{ .post_index = .{
7799 .base = .sp,
7800 .index = @intCast(saves_size - offset),
7801 } };
7802 },
7803 ));
7804 save_index += 1;
7805 } else save_index += 1;
7806 }
7807 const offset = stack_size + first_offset.?;
7808 const offset_lo: u12 = @truncate(offset >> 0);
7809 const offset_hi: u12 = @truncate(offset >> 12);
7810 if (isel.stack_align != .@"16" or (offset_lo > 0 and offset_hi > 0)) {
7811 const fp_offset = @as(i11, first_offset.?) - frame_record_offset;
7812 try isel.emit(if (fp_offset >= 0)
7813 .add(.sp, .fp, .{ .immediate = @intCast(fp_offset) })
7814 else
7815 .sub(.sp, .fp, .{ .immediate = @intCast(-fp_offset) }));
7816 } else {
7817 if (offset_hi > 0) try isel.emit(.add(.sp, .sp, .{
7818 .shifted_immediate = .{ .immediate = offset_hi, .lsl = .@"12" },
7819 }));
7820 if (offset_lo > 0) try isel.emit(.add(.sp, .sp, .{
7821 .immediate = offset_lo,
7822 }));
7823 }
7824 wip_mir_log.debug("{f}<epilogue>:\n", .{nav.fqn.fmt(ip)});
7825 }
7826 return epilogue;
7827}
7828
7829fn fmtDom(isel: *Select, inst: Air.Inst.Index, start: u32, len: u32) struct {
7830 isel: *Select,
7831 inst: Air.Inst.Index,
7832 start: u32,
7833 len: u32,
7834 pub fn format(data: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void {
7835 try writer.print("%{d} -> {{", .{@intFromEnum(data.inst)});
7836 var first = true;
7837 for (data.isel.blocks.keys()[0..data.len], 0..) |block_inst_index, dom_index| {
7838 if (@as(u1, @truncate(data.isel.dom.items[
7839 data.start + dom_index / @bitSizeOf(DomInt)
7840 ] >> @truncate(dom_index))) == 0) continue;
7841 if (first) {
7842 first = false;
7843 } else {
7844 try writer.writeByte(',');
7845 }
7846 switch (block_inst_index) {
7847 Block.main => try writer.writeAll(" %main"),
7848 else => try writer.print(" %{d}", .{@intFromEnum(block_inst_index)}),
7849 }
7850 }
7851 if (!first) try writer.writeByte(' ');
7852 try writer.writeByte('}');
7853 }
7854} {
7855 return .{ .isel = isel, .inst = inst, .start = start, .len = len };
7856}
7857
7858fn fmtLoopLive(isel: *Select, loop_inst: Air.Inst.Index) struct {
7859 isel: *Select,
7860 inst: Air.Inst.Index,
7861 pub fn format(data: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void {
7862 const loops = data.isel.loops.values();
7863 const loop_index = data.isel.loops.getIndex(data.inst).?;
7864 const live_insts =
7865 data.isel.loop_live.list.items[loops[loop_index].live..loops[loop_index + 1].live];
7866
7867 try writer.print("%{d} <- {{", .{@intFromEnum(data.inst)});
7868 var first = true;
7869 for (live_insts) |live_inst| {
7870 if (first) {
7871 first = false;
7872 } else {
7873 try writer.writeByte(',');
7874 }
7875 try writer.print(" %{d}", .{@intFromEnum(live_inst)});
7876 }
7877 if (!first) try writer.writeByte(' ');
7878 try writer.writeByte('}');
7879 }
7880} {
7881 return .{ .isel = isel, .inst = loop_inst };
7882}
7883
7884fn fmtType(isel: *Select, ty: ZigType) ZigType.Formatter {
7885 return ty.fmt(isel.pt);
7886}
7887
7888fn fmtConstant(isel: *Select, constant: Constant) @typeInfo(@TypeOf(Constant.fmtValue)).@"fn".return_type.? {
7889 return constant.fmtValue(isel.pt);
7890}
7891
7892fn block(
7893 isel: *Select,
7894 air_inst_index: Air.Inst.Index,
7895 res_ty: ZigType,
7896 air_body: []const Air.Inst.Index,
7897) !void {
7898 if (res_ty.toIntern() != .noreturn_type) {
7899 isel.blocks.putAssumeCapacityNoClobber(air_inst_index, .{
7900 .live_registers = isel.live_registers,
7901 .target_label = @intCast(isel.instructions.items.len),
7902 });
7903 }
7904 try isel.body(air_body);
7905 if (res_ty.toIntern() != .noreturn_type) {
7906 const block_entry = isel.blocks.pop().?;
7907 assert(block_entry.key == air_inst_index);
7908 if (isel.live_values.fetchRemove(air_inst_index)) |result_vi| result_vi.value.deref(isel);
7909 }
7910}
7911
7912fn emit(isel: *Select, instruction: codegen.aarch64.encoding.Instruction) !void {
7913 wip_mir_log.debug(" | {f}", .{instruction});
7914 try isel.instructions.append(isel.pt.zcu.gpa, instruction);
7915}
7916
7917fn emitPanic(isel: *Select, panic_id: Zcu.SimplePanicId) !void {
7918 const zcu = isel.pt.zcu;
7919 try isel.nav_relocs.append(zcu.gpa, .{
7920 .nav = switch (zcu.intern_pool.indexToKey(zcu.builtin_decl_values.get(panic_id.toBuiltin()))) {
7921 else => unreachable,
7922 inline .@"extern", .func => |func| func.owner_nav,
7923 },
7924 .reloc = .{ .label = @intCast(isel.instructions.items.len) },
7925 });
7926 try isel.emit(.bl(0));
7927}
7928
7929fn emitLiteral(isel: *Select, bytes: []const u8) !void {
7930 const words: []align(1) const u32 = @ptrCast(bytes);
7931 const literals = try isel.literals.addManyAsSlice(isel.pt.zcu.gpa, words.len);
7932 switch (isel.target.cpu.arch.endian()) {
7933 .little => @memcpy(literals, words),
7934 .big => for (words, 0..) |word, word_index| {
7935 literals[literals.len - 1 - word_index] = @byteSwap(word);
7936 },
7937 }
7938}
7939
7940fn fail(isel: *Select, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {
7941 @branchHint(.cold);
7942 return isel.pt.zcu.codegenFail(isel.nav_index, format, args);
7943}
7944
7945/// dst = src
7946fn movImmediate(isel: *Select, dst_reg: Register, src_imm: u64) !void {
7947 const sf = dst_reg.format.integer;
7948 if (src_imm == 0) {
7949 const zr: Register = switch (sf) {
7950 .word => .wzr,
7951 .doubleword => .xzr,
7952 };
7953 return isel.emit(.orr(dst_reg, zr, .{ .register = zr }));
7954 }
7955
7956 const Part = u16;
7957 const min_part: Part = std.math.minInt(Part);
7958 const max_part: Part = std.math.maxInt(Part);
7959
7960 const parts: [4]Part = @bitCast(switch (sf) {
7961 .word => @as(u32, @intCast(src_imm)),
7962 .doubleword => @as(u64, @intCast(src_imm)),
7963 });
7964 const width: u7 = switch (sf) {
7965 .word => 32,
7966 .doubleword => 64,
7967 };
7968 const parts_len: u3 = @intCast(@divExact(width, @bitSizeOf(Part)));
7969 var equal_min_count: u3 = 0;
7970 var equal_max_count: u3 = 0;
7971 for (parts[0..parts_len]) |part| {
7972 equal_min_count += @intFromBool(part == min_part);
7973 equal_max_count += @intFromBool(part == max_part);
7974 }
7975
7976 const equal_fill_count, const fill_part: Part = if (equal_min_count >= equal_max_count)
7977 .{ equal_min_count, min_part }
7978 else
7979 .{ equal_max_count, max_part };
7980 var remaining_parts = @max(parts_len - equal_fill_count, 1);
7981
7982 if (remaining_parts > 1) {
7983 var elem_width: u8 = 2;
7984 while (elem_width <= width) : (elem_width <<= 1) {
7985 const emask = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - elem_width);
7986 const rmask = @divExact(@as(u64, switch (sf) {
7987 .word => std.math.maxInt(u32),
7988 .doubleword => std.math.maxInt(u64),
7989 }), emask);
7990 const elem = src_imm & emask;
7991 if (src_imm != elem * rmask) continue;
7992 const imask: u64 = @bitCast(@as(i64, @bitCast(elem << 63)) >> 63);
7993 const lsb0 = elem ^ (imask & emask);
7994 const lsb1 = (lsb0 - 1) | lsb0;
7995 if ((lsb1 +% 1) & lsb1 == 0) {
7996 const lo: u6 = @intCast(@ctz(lsb0));
7997 const hi: u6 = @intCast(@clz(lsb0) - (64 - elem_width));
7998 const mid: u6 = @intCast(elem_width - lo - hi);
7999 const smask: u6 = @truncate(imask);
8000 const mid_masked = mid & ~smask;
8001 return isel.emit(.orr(
8002 dst_reg,
8003 switch (sf) {
8004 .word => .wzr,
8005 .doubleword => .xzr,
8006 },
8007 .{ .immediate = .{
8008 .N = @enumFromInt(elem_width >> 6),
8009 .immr = hi + mid_masked,
8010 .imms = ((((lo + hi) & smask) | mid_masked) - 1) | -%@as(u6, @truncate(elem_width)) << 1,
8011 } },
8012 ));
8013 }
8014 }
8015 }
8016
8017 var part_index = parts_len;
8018 while (part_index > 0) {
8019 part_index -= 1;
8020 if (part_index >= remaining_parts and parts[part_index] == fill_part) continue;
8021 remaining_parts -= 1;
8022 try isel.emit(if (remaining_parts > 0) .movk(
8023 dst_reg,
8024 parts[part_index],
8025 .{ .lsl = @enumFromInt(part_index) },
8026 ) else switch (fill_part) {
8027 else => unreachable,
8028 min_part => .movz(
8029 dst_reg,
8030 parts[part_index],
8031 .{ .lsl = @enumFromInt(part_index) },
8032 ),
8033 max_part => .movn(
8034 dst_reg,
8035 ~parts[part_index],
8036 .{ .lsl = @enumFromInt(part_index) },
8037 ),
8038 });
8039 }
8040 assert(remaining_parts == 0);
8041}
8042
8043/// elem_ptr = base +- elem_size * index
8044/// elem_ptr, base, and index may alias
8045fn elemPtr(
8046 isel: *Select,
8047 elem_ptr_ra: Register.Alias,
8048 base_ra: Register.Alias,
8049 op: codegen.aarch64.encoding.Instruction.AddSubtractOp,
8050 elem_size: u64,
8051 index_vi: Value.Index,
8052) !void {
8053 const index_mat = try index_vi.matReg(isel);
8054 switch (@popCount(elem_size)) {
8055 0 => unreachable,
8056 1 => try isel.emit(switch (op) {
8057 .add => switch (base_ra) {
8058 else => .add(elem_ptr_ra.x(), base_ra.x(), .{ .shifted_register = .{
8059 .register = index_mat.ra.x(),
8060 .shift = .{ .lsl = @intCast(@ctz(elem_size)) },
8061 } }),
8062 .zr => switch (@ctz(elem_size)) {
8063 0 => .orr(elem_ptr_ra.x(), .xzr, .{ .register = index_mat.ra.x() }),
8064 else => |shift| .ubfm(elem_ptr_ra.x(), index_mat.ra.x(), .{
8065 .N = .doubleword,
8066 .immr = @intCast(64 - shift),
8067 .imms = @intCast(63 - shift),
8068 }),
8069 },
8070 },
8071 .sub => .sub(elem_ptr_ra.x(), base_ra.x(), .{ .shifted_register = .{
8072 .register = index_mat.ra.x(),
8073 .shift = .{ .lsl = @intCast(@ctz(elem_size)) },
8074 } }),
8075 }),
8076 2 => {
8077 const shift: u6 = @intCast(@ctz(elem_size));
8078 const temp_ra = temp_ra: switch (op) {
8079 .add => switch (base_ra) {
8080 else => {
8081 const temp_ra = try isel.allocIntReg();
8082 errdefer isel.freeReg(temp_ra);
8083 try isel.emit(.add(elem_ptr_ra.x(), base_ra.x(), .{ .shifted_register = .{
8084 .register = temp_ra.x(),
8085 .shift = .{ .lsl = shift },
8086 } }));
8087 break :temp_ra temp_ra;
8088 },
8089 .zr => {
8090 if (shift > 0) try isel.emit(.ubfm(elem_ptr_ra.x(), elem_ptr_ra.x(), .{
8091 .N = .doubleword,
8092 .immr = -%shift,
8093 .imms = ~shift,
8094 }));
8095 break :temp_ra elem_ptr_ra;
8096 },
8097 },
8098 .sub => {
8099 const temp_ra = try isel.allocIntReg();
8100 errdefer isel.freeReg(temp_ra);
8101 try isel.emit(.sub(elem_ptr_ra.x(), base_ra.x(), .{ .shifted_register = .{
8102 .register = temp_ra.x(),
8103 .shift = .{ .lsl = shift },
8104 } }));
8105 break :temp_ra temp_ra;
8106 },
8107 };
8108 defer if (temp_ra != elem_ptr_ra) isel.freeReg(temp_ra);
8109 try isel.emit(.add(temp_ra.x(), index_mat.ra.x(), .{ .shifted_register = .{
8110 .register = index_mat.ra.x(),
8111 .shift = .{ .lsl = @intCast(63 - @clz(elem_size) - shift) },
8112 } }));
8113 },
8114 else => {
8115 const elem_size_lsb1 = (elem_size - 1) | elem_size;
8116 if ((elem_size_lsb1 +% 1) & elem_size_lsb1 == 0) {
8117 const shift: u6 = @intCast(@ctz(elem_size));
8118 const temp_ra = temp_ra: switch (op) {
8119 .add => {
8120 const temp_ra = try isel.allocIntReg();
8121 errdefer isel.freeReg(temp_ra);
8122 try isel.emit(.sub(elem_ptr_ra.x(), base_ra.x(), .{ .shifted_register = .{
8123 .register = temp_ra.x(),
8124 .shift = .{ .lsl = shift },
8125 } }));
8126 break :temp_ra temp_ra;
8127 },
8128 .sub => switch (base_ra) {
8129 else => {
8130 const temp_ra = try isel.allocIntReg();
8131 errdefer isel.freeReg(temp_ra);
8132 try isel.emit(.add(elem_ptr_ra.x(), base_ra.x(), .{ .shifted_register = .{
8133 .register = temp_ra.x(),
8134 .shift = .{ .lsl = shift },
8135 } }));
8136 break :temp_ra temp_ra;
8137 },
8138 .zr => {
8139 if (shift > 0) try isel.emit(.ubfm(elem_ptr_ra.x(), elem_ptr_ra.x(), .{
8140 .N = .doubleword,
8141 .immr = -%shift,
8142 .imms = ~shift,
8143 }));
8144 break :temp_ra elem_ptr_ra;
8145 },
8146 },
8147 };
8148 defer if (temp_ra != elem_ptr_ra) isel.freeReg(temp_ra);
8149 try isel.emit(.sub(temp_ra.x(), index_mat.ra.x(), .{ .shifted_register = .{
8150 .register = index_mat.ra.x(),
8151 .shift = .{ .lsl = @intCast(64 - @clz(elem_size) - shift) },
8152 } }));
8153 } else {
8154 try isel.emit(switch (op) {
8155 .add => .madd(elem_ptr_ra.x(), index_mat.ra.x(), elem_ptr_ra.x(), base_ra.x()),
8156 .sub => .msub(elem_ptr_ra.x(), index_mat.ra.x(), elem_ptr_ra.x(), base_ra.x()),
8157 });
8158 try isel.movImmediate(elem_ptr_ra.x(), elem_size);
8159 }
8160 },
8161 }
8162 try index_mat.finish(isel);
8163}
8164
8165fn clzLimb(
8166 isel: *Select,
8167 res_ra: Register.Alias,
8168 src_int_info: std.builtin.Type.Int,
8169 src_ra: Register.Alias,
8170) !void {
8171 switch (src_int_info.bits) {
8172 else => unreachable,
8173 1...31 => |bits| {
8174 try isel.emit(.sub(res_ra.w(), res_ra.w(), .{
8175 .immediate = @intCast(32 - bits),
8176 }));
8177 switch (src_int_info.signedness) {
8178 .signed => {
8179 try isel.emit(.clz(res_ra.w(), res_ra.w()));
8180 try isel.emit(.ubfm(res_ra.w(), src_ra.w(), .{
8181 .N = .word,
8182 .immr = 0,
8183 .imms = @intCast(bits - 1),
8184 }));
8185 },
8186 .unsigned => try isel.emit(.clz(res_ra.w(), src_ra.w())),
8187 }
8188 },
8189 32 => try isel.emit(.clz(res_ra.w(), src_ra.w())),
8190 33...63 => |bits| {
8191 try isel.emit(.sub(res_ra.w(), res_ra.w(), .{
8192 .immediate = @intCast(64 - bits),
8193 }));
8194 switch (src_int_info.signedness) {
8195 .signed => {
8196 try isel.emit(.clz(res_ra.x(), res_ra.x()));
8197 try isel.emit(.ubfm(res_ra.x(), src_ra.x(), .{
8198 .N = .doubleword,
8199 .immr = 0,
8200 .imms = @intCast(bits - 1),
8201 }));
8202 },
8203 .unsigned => try isel.emit(.clz(res_ra.x(), src_ra.x())),
8204 }
8205 },
8206 64 => try isel.emit(.clz(res_ra.x(), src_ra.x())),
8207 }
8208}
8209
8210fn ctzLimb(
8211 isel: *Select,
8212 res_ra: Register.Alias,
8213 src_int_info: std.builtin.Type.Int,
8214 src_ra: Register.Alias,
8215) !void {
8216 switch (src_int_info.bits) {
8217 else => unreachable,
8218 1...31 => |bits| {
8219 try isel.emit(.clz(res_ra.w(), res_ra.w()));
8220 try isel.emit(.rbit(res_ra.w(), res_ra.w()));
8221 try isel.emit(.orr(res_ra.w(), src_ra.w(), .{ .immediate = .{
8222 .N = .word,
8223 .immr = @intCast(32 - bits),
8224 .imms = @intCast(32 - bits - 1),
8225 } }));
8226 },
8227 32 => {
8228 try isel.emit(.clz(res_ra.w(), res_ra.w()));
8229 try isel.emit(.rbit(res_ra.w(), src_ra.w()));
8230 },
8231 33...63 => |bits| {
8232 try isel.emit(.clz(res_ra.x(), res_ra.x()));
8233 try isel.emit(.rbit(res_ra.x(), res_ra.x()));
8234 try isel.emit(.orr(res_ra.x(), src_ra.x(), .{ .immediate = .{
8235 .N = .doubleword,
8236 .immr = @intCast(64 - bits),
8237 .imms = @intCast(64 - bits - 1),
8238 } }));
8239 },
8240 64 => {
8241 try isel.emit(.clz(res_ra.x(), res_ra.x()));
8242 try isel.emit(.rbit(res_ra.x(), src_ra.x()));
8243 },
8244 }
8245}
8246
8247fn loadReg(
8248 isel: *Select,
8249 ra: Register.Alias,
8250 size: u64,
8251 signedness: std.builtin.Signedness,
8252 base_ra: Register.Alias,
8253 offset: i65,
8254) !void {
8255 switch (size) {
8256 0 => unreachable,
8257 1 => {
8258 if (std.math.cast(u12, offset)) |unsigned_offset| return isel.emit(if (ra.isVector()) .ldr(
8259 ra.b(),
8260 .{ .unsigned_offset = .{
8261 .base = base_ra.x(),
8262 .offset = unsigned_offset,
8263 } },
8264 ) else switch (signedness) {
8265 .signed => .ldrsb(ra.w(), .{ .unsigned_offset = .{
8266 .base = base_ra.x(),
8267 .offset = unsigned_offset,
8268 } }),
8269 .unsigned => .ldrb(ra.w(), .{ .unsigned_offset = .{
8270 .base = base_ra.x(),
8271 .offset = unsigned_offset,
8272 } }),
8273 });
8274 if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(if (ra.isVector())
8275 .ldur(ra.b(), base_ra.x(), signed_offset)
8276 else switch (signedness) {
8277 .signed => .ldursb(ra.w(), base_ra.x(), signed_offset),
8278 .unsigned => .ldurb(ra.w(), base_ra.x(), signed_offset),
8279 });
8280 },
8281 2 => {
8282 if (std.math.cast(u13, offset)) |unsigned_offset| if (unsigned_offset % 2 == 0)
8283 return isel.emit(if (ra.isVector()) .ldr(
8284 ra.h(),
8285 .{ .unsigned_offset = .{
8286 .base = base_ra.x(),
8287 .offset = unsigned_offset,
8288 } },
8289 ) else switch (signedness) {
8290 .signed => .ldrsh(
8291 ra.w(),
8292 .{ .unsigned_offset = .{
8293 .base = base_ra.x(),
8294 .offset = unsigned_offset,
8295 } },
8296 ),
8297 .unsigned => .ldrh(
8298 ra.w(),
8299 .{ .unsigned_offset = .{
8300 .base = base_ra.x(),
8301 .offset = unsigned_offset,
8302 } },
8303 ),
8304 });
8305 if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(if (ra.isVector())
8306 .ldur(ra.h(), base_ra.x(), signed_offset)
8307 else switch (signedness) {
8308 .signed => .ldursh(ra.w(), base_ra.x(), signed_offset),
8309 .unsigned => .ldurh(ra.w(), base_ra.x(), signed_offset),
8310 });
8311 },
8312 3 => {
8313 const lo16_ra = try isel.allocIntReg();
8314 defer isel.freeReg(lo16_ra);
8315 try isel.emit(.orr(ra.w(), lo16_ra.w(), .{ .shifted_register = .{
8316 .register = ra.w(),
8317 .shift = .{ .lsl = 16 },
8318 } }));
8319 try isel.loadReg(ra, 1, signedness, base_ra, offset + 2);
8320 return isel.loadReg(lo16_ra, 2, .unsigned, base_ra, offset);
8321 },
8322 4 => {
8323 if (std.math.cast(u14, offset)) |unsigned_offset| if (unsigned_offset % 4 == 0) return isel.emit(.ldr(
8324 if (ra.isVector()) ra.s() else ra.w(),
8325 .{ .unsigned_offset = .{
8326 .base = base_ra.x(),
8327 .offset = unsigned_offset,
8328 } },
8329 ));
8330 if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(.ldur(
8331 if (ra.isVector()) ra.s() else ra.w(),
8332 base_ra.x(),
8333 signed_offset,
8334 ));
8335 },
8336 5, 6 => {
8337 const lo32_ra = try isel.allocIntReg();
8338 defer isel.freeReg(lo32_ra);
8339 try isel.emit(.orr(ra.x(), lo32_ra.x(), .{ .shifted_register = .{
8340 .register = ra.x(),
8341 .shift = .{ .lsl = 32 },
8342 } }));
8343 try isel.loadReg(ra, size - 4, signedness, base_ra, offset + 4);
8344 return isel.loadReg(lo32_ra, 4, .unsigned, base_ra, offset);
8345 },
8346 7 => {
8347 const lo32_ra = try isel.allocIntReg();
8348 defer isel.freeReg(lo32_ra);
8349 const lo48_ra = try isel.allocIntReg();
8350 defer isel.freeReg(lo48_ra);
8351 try isel.emit(.orr(ra.x(), lo48_ra.x(), .{ .shifted_register = .{
8352 .register = ra.x(),
8353 .shift = .{ .lsl = 32 + 16 },
8354 } }));
8355 try isel.loadReg(ra, 1, signedness, base_ra, offset + 4 + 2);
8356 try isel.emit(.orr(lo48_ra.x(), lo32_ra.x(), .{ .shifted_register = .{
8357 .register = lo48_ra.x(),
8358 .shift = .{ .lsl = 32 },
8359 } }));
8360 try isel.loadReg(lo48_ra, 2, .unsigned, base_ra, offset + 4);
8361 return isel.loadReg(lo32_ra, 4, .unsigned, base_ra, offset);
8362 },
8363 8 => {
8364 if (std.math.cast(u15, offset)) |unsigned_offset| if (unsigned_offset % 8 == 0) return isel.emit(.ldr(
8365 if (ra.isVector()) ra.d() else ra.x(),
8366 .{ .unsigned_offset = .{
8367 .base = base_ra.x(),
8368 .offset = unsigned_offset,
8369 } },
8370 ));
8371 if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(.ldur(
8372 if (ra.isVector()) ra.d() else ra.x(),
8373 base_ra.x(),
8374 signed_offset,
8375 ));
8376 },
8377 16 => {
8378 if (std.math.cast(u16, offset)) |unsigned_offset| if (unsigned_offset % 16 == 0) return isel.emit(.ldr(
8379 ra.q(),
8380 .{ .unsigned_offset = .{
8381 .base = base_ra.x(),
8382 .offset = unsigned_offset,
8383 } },
8384 ));
8385 if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(.ldur(ra.q(), base_ra.x(), signed_offset));
8386 },
8387 else => return isel.fail("bad load size: {d}", .{size}),
8388 }
8389 const ptr_ra = try isel.allocIntReg();
8390 defer isel.freeReg(ptr_ra);
8391 try isel.loadReg(ra, size, signedness, ptr_ra, 0);
8392 if (std.math.cast(u24, offset)) |pos_offset| {
8393 const lo12: u12 = @truncate(pos_offset >> 0);
8394 const hi12: u12 = @intCast(pos_offset >> 12);
8395 if (hi12 > 0) try isel.emit(.add(
8396 ptr_ra.x(),
8397 if (lo12 > 0) ptr_ra.x() else base_ra.x(),
8398 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
8399 ));
8400 if (lo12 > 0 or hi12 == 0) try isel.emit(.add(ptr_ra.x(), base_ra.x(), .{ .immediate = lo12 }));
8401 } else if (std.math.cast(u24, -offset)) |neg_offset| {
8402 const lo12: u12 = @truncate(neg_offset >> 0);
8403 const hi12: u12 = @intCast(neg_offset >> 12);
8404 if (hi12 > 0) try isel.emit(.sub(
8405 ptr_ra.x(),
8406 if (lo12 > 0) ptr_ra.x() else base_ra.x(),
8407 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
8408 ));
8409 if (lo12 > 0 or hi12 == 0) try isel.emit(.sub(ptr_ra.x(), base_ra.x(), .{ .immediate = lo12 }));
8410 } else {
8411 try isel.emit(.add(ptr_ra.x(), base_ra.x(), .{ .register = ptr_ra.x() }));
8412 try isel.movImmediate(ptr_ra.x(), @truncate(@as(u65, @bitCast(offset))));
8413 }
8414}
8415
8416fn storeReg(
8417 isel: *Select,
8418 ra: Register.Alias,
8419 size: u64,
8420 base_ra: Register.Alias,
8421 offset: i65,
8422) !void {
8423 switch (size) {
8424 0 => unreachable,
8425 1 => {
8426 if (std.math.cast(u12, offset)) |unsigned_offset| return isel.emit(if (ra.isVector()) .str(
8427 ra.b(),
8428 .{ .unsigned_offset = .{
8429 .base = base_ra.x(),
8430 .offset = unsigned_offset,
8431 } },
8432 ) else .strb(
8433 ra.w(),
8434 .{ .unsigned_offset = .{
8435 .base = base_ra.x(),
8436 .offset = unsigned_offset,
8437 } },
8438 ));
8439 if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(if (ra.isVector())
8440 .stur(ra.b(), base_ra.x(), signed_offset)
8441 else
8442 .sturb(ra.w(), base_ra.x(), signed_offset));
8443 },
8444 2 => {
8445 if (std.math.cast(u13, offset)) |unsigned_offset| if (unsigned_offset % 2 == 0)
8446 return isel.emit(if (ra.isVector()) .str(
8447 ra.h(),
8448 .{ .unsigned_offset = .{
8449 .base = base_ra.x(),
8450 .offset = unsigned_offset,
8451 } },
8452 ) else .strh(
8453 ra.w(),
8454 .{ .unsigned_offset = .{
8455 .base = base_ra.x(),
8456 .offset = unsigned_offset,
8457 } },
8458 ));
8459 if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(if (ra.isVector())
8460 .stur(ra.h(), base_ra.x(), signed_offset)
8461 else
8462 .sturh(ra.w(), base_ra.x(), signed_offset));
8463 },
8464 3 => {
8465 const hi8_ra = try isel.allocIntReg();
8466 defer isel.freeReg(hi8_ra);
8467 try isel.storeReg(hi8_ra, 1, base_ra, offset + 2);
8468 try isel.storeReg(ra, 2, base_ra, offset);
8469 return isel.emit(.ubfm(hi8_ra.w(), ra.w(), .{
8470 .N = .word,
8471 .immr = 16,
8472 .imms = 16 + 8 - 1,
8473 }));
8474 },
8475 4 => {
8476 if (std.math.cast(u14, offset)) |unsigned_offset| if (unsigned_offset % 4 == 0) return isel.emit(.str(
8477 if (ra.isVector()) ra.s() else ra.w(),
8478 .{ .unsigned_offset = .{
8479 .base = base_ra.x(),
8480 .offset = unsigned_offset,
8481 } },
8482 ));
8483 if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(.stur(
8484 if (ra.isVector()) ra.s() else ra.w(),
8485 base_ra.x(),
8486 signed_offset,
8487 ));
8488 },
8489 5 => {
8490 const hi8_ra = try isel.allocIntReg();
8491 defer isel.freeReg(hi8_ra);
8492 try isel.storeReg(hi8_ra, 1, base_ra, offset + 4);
8493 try isel.storeReg(ra, 4, base_ra, offset);
8494 return isel.emit(.ubfm(hi8_ra.x(), ra.x(), .{
8495 .N = .doubleword,
8496 .immr = 32,
8497 .imms = 32 + 8 - 1,
8498 }));
8499 },
8500 6 => {
8501 const hi16_ra = try isel.allocIntReg();
8502 defer isel.freeReg(hi16_ra);
8503 try isel.storeReg(hi16_ra, 2, base_ra, offset + 4);
8504 try isel.storeReg(ra, 4, base_ra, offset);
8505 return isel.emit(.ubfm(hi16_ra.x(), ra.x(), .{
8506 .N = .doubleword,
8507 .immr = 32,
8508 .imms = 32 + 16 - 1,
8509 }));
8510 },
8511 7 => {
8512 const hi16_ra = try isel.allocIntReg();
8513 defer isel.freeReg(hi16_ra);
8514 const hi8_ra = try isel.allocIntReg();
8515 defer isel.freeReg(hi8_ra);
8516 try isel.storeReg(hi8_ra, 1, base_ra, offset + 6);
8517 try isel.storeReg(hi16_ra, 2, base_ra, offset + 4);
8518 try isel.storeReg(ra, 4, base_ra, offset);
8519 try isel.emit(.ubfm(hi8_ra.x(), ra.x(), .{
8520 .N = .doubleword,
8521 .immr = 32 + 16,
8522 .imms = 32 + 16 + 8 - 1,
8523 }));
8524 return isel.emit(.ubfm(hi16_ra.x(), ra.x(), .{
8525 .N = .doubleword,
8526 .immr = 32,
8527 .imms = 32 + 16 - 1,
8528 }));
8529 },
8530 8 => {
8531 if (std.math.cast(u15, offset)) |unsigned_offset| if (unsigned_offset % 8 == 0) return isel.emit(.str(
8532 if (ra.isVector()) ra.d() else ra.x(),
8533 .{ .unsigned_offset = .{
8534 .base = base_ra.x(),
8535 .offset = unsigned_offset,
8536 } },
8537 ));
8538 if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(.stur(
8539 if (ra.isVector()) ra.d() else ra.x(),
8540 base_ra.x(),
8541 signed_offset,
8542 ));
8543 },
8544 16 => {
8545 if (std.math.cast(u16, offset)) |unsigned_offset| if (unsigned_offset % 16 == 0) return isel.emit(.str(
8546 ra.q(),
8547 .{ .unsigned_offset = .{
8548 .base = base_ra.x(),
8549 .offset = unsigned_offset,
8550 } },
8551 ));
8552 if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(.stur(ra.q(), base_ra.x(), signed_offset));
8553 },
8554 else => return isel.fail("bad store size: {d}", .{size}),
8555 }
8556 const ptr_ra = try isel.allocIntReg();
8557 defer isel.freeReg(ptr_ra);
8558 try isel.storeReg(ra, size, ptr_ra, 0);
8559 if (std.math.cast(u24, offset)) |pos_offset| {
8560 const lo12: u12 = @truncate(pos_offset >> 0);
8561 const hi12: u12 = @intCast(pos_offset >> 12);
8562 if (hi12 > 0) try isel.emit(.add(
8563 ptr_ra.x(),
8564 if (lo12 > 0) ptr_ra.x() else base_ra.x(),
8565 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
8566 ));
8567 if (lo12 > 0 or hi12 == 0) try isel.emit(.add(ptr_ra.x(), base_ra.x(), .{ .immediate = lo12 }));
8568 } else if (std.math.cast(u24, -offset)) |neg_offset| {
8569 const lo12: u12 = @truncate(neg_offset >> 0);
8570 const hi12: u12 = @intCast(neg_offset >> 12);
8571 if (hi12 > 0) try isel.emit(.sub(
8572 ptr_ra.x(),
8573 if (lo12 > 0) ptr_ra.x() else base_ra.x(),
8574 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
8575 ));
8576 if (lo12 > 0 or hi12 == 0) try isel.emit(.sub(ptr_ra.x(), base_ra.x(), .{ .immediate = lo12 }));
8577 } else {
8578 try isel.emit(.add(ptr_ra.x(), base_ra.x(), .{ .register = ptr_ra.x() }));
8579 try isel.movImmediate(ptr_ra.x(), @truncate(@as(u65, @bitCast(offset))));
8580 }
8581}
8582
8583const DomInt = u8;
8584
8585pub const Value = struct {
8586 refs: u32,
8587 flags: Flags,
8588 offset_from_parent: u64,
8589 parent_payload: Parent.Payload,
8590 location_payload: Location.Payload,
8591 parts: Value.Index,
8592
8593 /// Must be at least 16 to compute call abi.
8594 /// Must be at least 16, the largest hardware alignment.
8595 pub const max_parts = 16;
8596 pub const PartsLen = std.math.IntFittingRange(0, Value.max_parts);
8597
8598 comptime {
8599 if (!std.debug.runtime_safety) assert(@sizeOf(Value) == 32);
8600 }
8601
8602 pub const Flags = packed struct(u32) {
8603 alignment: InternPool.Alignment,
8604 parent_tag: Parent.Tag,
8605 location_tag: Location.Tag,
8606 parts_len_minus_one: std.math.IntFittingRange(0, Value.max_parts - 1),
8607 unused: u18 = 0,
8608 };
8609
8610 pub const Parent = union(enum(u3)) {
8611 unallocated: void,
8612 stack_slot: Indirect,
8613 address: Value.Index,
8614 value: Value.Index,
8615 constant: Constant,
8616
8617 pub const Tag = @typeInfo(Parent).@"union".tag_type.?;
8618 pub const Payload = @Type(.{ .@"union" = .{
8619 .layout = .auto,
8620 .tag_type = null,
8621 .fields = @typeInfo(Parent).@"union".fields,
8622 .decls = &.{},
8623 } });
8624 };
8625
8626 pub const Location = union(enum(u1)) {
8627 large: struct {
8628 size: u64,
8629 },
8630 small: struct {
8631 size: u5,
8632 signedness: std.builtin.Signedness,
8633 is_vector: bool,
8634 hint: Register.Alias,
8635 register: Register.Alias,
8636 },
8637
8638 pub const Tag = @typeInfo(Location).@"union".tag_type.?;
8639 pub const Payload = @Type(.{ .@"union" = .{
8640 .layout = .auto,
8641 .tag_type = null,
8642 .fields = @typeInfo(Location).@"union".fields,
8643 .decls = &.{},
8644 } });
8645 };
8646
8647 pub const Indirect = packed struct(u32) {
8648 base: Register.Alias,
8649 offset: i25,
8650
8651 pub fn withOffset(ind: Indirect, offset: i25) Indirect {
8652 return .{
8653 .base = ind.base,
8654 .offset = ind.offset + offset,
8655 };
8656 }
8657 };
8658
8659 pub const Index = enum(u32) {
8660 allocating = std.math.maxInt(u32) - 1,
8661 free = std.math.maxInt(u32) - 0,
8662 _,
8663
8664 fn get(vi: Value.Index, isel: *Select) *Value {
8665 return &isel.values.items[@intFromEnum(vi)];
8666 }
8667
8668 fn setAlignment(vi: Value.Index, isel: *Select, new_alignment: InternPool.Alignment) void {
8669 vi.get(isel).flags.alignment = new_alignment;
8670 }
8671
8672 pub fn alignment(vi: Value.Index, isel: *Select) InternPool.Alignment {
8673 return vi.get(isel).flags.alignment;
8674 }
8675
8676 pub fn setParent(vi: Value.Index, isel: *Select, new_parent: Parent) void {
8677 const value = vi.get(isel);
8678 assert(value.flags.parent_tag == .unallocated);
8679 value.flags.parent_tag = new_parent;
8680 value.parent_payload = switch (new_parent) {
8681 .unallocated => unreachable,
8682 inline else => |payload, tag| @unionInit(Parent.Payload, @tagName(tag), payload),
8683 };
8684 if (value.refs > 0) switch (new_parent) {
8685 .unallocated => unreachable,
8686 .stack_slot, .constant => {},
8687 .address, .value => |parent_vi| _ = parent_vi.ref(isel),
8688 };
8689 }
8690
8691 pub fn changeStackSlot(vi: Value.Index, isel: *Select, new_stack_slot: Indirect) void {
8692 const value = vi.get(isel);
8693 assert(value.flags.parent_tag == .stack_slot);
8694 value.flags.parent_tag = .unallocated;
8695 vi.setParent(isel, .{ .stack_slot = new_stack_slot });
8696 }
8697
8698 pub fn parent(vi: Value.Index, isel: *Select) Parent {
8699 const value = vi.get(isel);
8700 return switch (value.flags.parent_tag) {
8701 inline else => |tag| @unionInit(
8702 Parent,
8703 @tagName(tag),
8704 @field(value.parent_payload, @tagName(tag)),
8705 ),
8706 };
8707 }
8708
8709 pub fn valueParent(initial_vi: Value.Index, isel: *Select) struct { u64, Value.Index } {
8710 var offset: u64 = 0;
8711 var vi = initial_vi;
8712 parent: switch (vi.parent(isel)) {
8713 else => return .{ offset, vi },
8714 .value => |parent_vi| {
8715 offset += vi.position(isel)[0];
8716 vi = parent_vi;
8717 continue :parent parent_vi.parent(isel);
8718 },
8719 }
8720 }
8721
8722 pub fn location(vi: Value.Index, isel: *Select) Location {
8723 const value = vi.get(isel);
8724 return switch (value.flags.location_tag) {
8725 inline else => |tag| @unionInit(
8726 Location,
8727 @tagName(tag),
8728 @field(value.location_payload, @tagName(tag)),
8729 ),
8730 };
8731 }
8732
8733 pub fn position(vi: Value.Index, isel: *Select) struct { u64, u64 } {
8734 return .{ vi.get(isel).offset_from_parent, vi.size(isel) };
8735 }
8736
8737 pub fn size(vi: Value.Index, isel: *Select) u64 {
8738 return switch (vi.location(isel)) {
8739 inline else => |loc| loc.size,
8740 };
8741 }
8742
8743 fn setHint(vi: Value.Index, isel: *Select, new_hint: Register.Alias) void {
8744 vi.get(isel).location_payload.small.hint = new_hint;
8745 }
8746
8747 pub fn hint(vi: Value.Index, isel: *Select) ?Register.Alias {
8748 return switch (vi.location(isel)) {
8749 .large => null,
8750 .small => |loc| switch (loc.hint) {
8751 .zr => null,
8752 else => |hint_reg| hint_reg,
8753 },
8754 };
8755 }
8756
8757 fn setSignedness(vi: Value.Index, isel: *Select, new_signedness: std.builtin.Signedness) void {
8758 const value = vi.get(isel);
8759 assert(value.location_payload.small.size <= 2);
8760 value.location_payload.small.signedness = new_signedness;
8761 }
8762
8763 pub fn signedness(vi: Value.Index, isel: *Select) std.builtin.Signedness {
8764 const value = vi.get(isel);
8765 return switch (value.flags.location_tag) {
8766 .large => .unsigned,
8767 .small => value.location_payload.small.signedness,
8768 };
8769 }
8770
8771 fn setIsVector(vi: Value.Index, isel: *Select) void {
8772 const is_vector = &vi.get(isel).location_payload.small.is_vector;
8773 assert(!is_vector.*);
8774 is_vector.* = true;
8775 }
8776
8777 pub fn isVector(vi: Value.Index, isel: *Select) bool {
8778 const value = vi.get(isel);
8779 return switch (value.flags.location_tag) {
8780 .large => false,
8781 .small => value.location_payload.small.is_vector,
8782 };
8783 }
8784
8785 pub fn register(vi: Value.Index, isel: *Select) ?Register.Alias {
8786 return switch (vi.location(isel)) {
8787 .large => null,
8788 .small => |loc| switch (loc.register) {
8789 .zr => null,
8790 else => |reg| reg,
8791 },
8792 };
8793 }
8794
8795 pub fn isUsed(vi: Value.Index, isel: *Select) bool {
8796 return vi.valueParent(isel)[1].parent(isel) != .unallocated or vi.hasRegisterRecursive(isel);
8797 }
8798
8799 fn hasRegisterRecursive(vi: Value.Index, isel: *Select) bool {
8800 if (vi.register(isel)) |_| return true;
8801 var part_it = vi.parts(isel);
8802 if (part_it.only() == null) while (part_it.next()) |part_vi| if (part_vi.hasRegisterRecursive(isel)) return true;
8803 return false;
8804 }
8805
8806 fn setParts(vi: Value.Index, isel: *Select, parts_len: Value.PartsLen) void {
8807 assert(parts_len > 1);
8808 const value = vi.get(isel);
8809 assert(value.flags.parts_len_minus_one == 0);
8810 value.parts = @enumFromInt(isel.values.items.len);
8811 value.flags.parts_len_minus_one = @intCast(parts_len - 1);
8812 }
8813
8814 fn addPart(vi: Value.Index, isel: *Select, part_offset: u64, part_size: u64) Value.Index {
8815 const part_vi = isel.initValueAdvanced(vi.alignment(isel), part_offset, part_size);
8816 tracking_log.debug("${d} <- ${d}[{d}]", .{
8817 @intFromEnum(part_vi),
8818 @intFromEnum(vi),
8819 part_offset,
8820 });
8821 part_vi.setParent(isel, .{ .value = vi });
8822 return part_vi;
8823 }
8824
8825 pub fn parts(vi: Value.Index, isel: *Select) Value.PartIterator {
8826 const value = vi.get(isel);
8827 return switch (value.flags.parts_len_minus_one) {
8828 0 => .initOne(vi),
8829 else => |parts_len_minus_one| .{
8830 .vi = value.parts,
8831 .remaining = @as(Value.PartsLen, parts_len_minus_one) + 1,
8832 },
8833 };
8834 }
8835
8836 fn containingParts(vi: Value.Index, isel: *Select, part_offset: u64, part_size: u64) Value.PartIterator {
8837 const start_vi = vi.partAtOffset(isel, part_offset);
8838 const start_offset, const start_size = start_vi.position(isel);
8839 if (part_offset >= start_offset and part_size <= start_size) return .initOne(start_vi);
8840 const end_vi = vi.partAtOffset(isel, part_size - 1 + part_offset);
8841 return .{
8842 .vi = start_vi,
8843 .remaining = @intCast(@intFromEnum(end_vi) - @intFromEnum(start_vi) + 1),
8844 };
8845 }
8846 comptime {
8847 _ = containingParts;
8848 }
8849
8850 fn partAtOffset(vi: Value.Index, isel: *Select, offset: u64) Value.Index {
8851 const SearchPartIndex = std.math.IntFittingRange(0, Value.max_parts * 2 - 1);
8852 const value = vi.get(isel);
8853 var last: SearchPartIndex = value.flags.parts_len_minus_one;
8854 if (last == 0) return vi;
8855 var first: SearchPartIndex = 0;
8856 last += 1;
8857 while (true) {
8858 const mid = (first + last) / 2;
8859 const mid_vi: Value.Index = @enumFromInt(@intFromEnum(value.parts) + mid);
8860 if (mid == first) return mid_vi;
8861 if (offset < mid_vi.get(isel).offset_from_parent) last = mid else first = mid;
8862 }
8863 }
8864
8865 fn field(
8866 vi: Value.Index,
8867 ty: ZigType,
8868 field_offset: u64,
8869 field_size: u64,
8870 ) Value.FieldPartIterator {
8871 assert(field_size > 0);
8872 return .{
8873 .vi = vi,
8874 .ty = ty,
8875 .field_offset = field_offset,
8876 .field_size = field_size,
8877 .next_offset = 0,
8878 };
8879 }
8880
8881 fn ref(initial_vi: Value.Index, isel: *Select) Value.Index {
8882 var vi = initial_vi;
8883 while (true) {
8884 const refs = &vi.get(isel).refs;
8885 refs.* += 1;
8886 if (refs.* > 1) return initial_vi;
8887 switch (vi.parent(isel)) {
8888 .unallocated, .stack_slot, .constant => {},
8889 .address, .value => |parent_vi| {
8890 vi = parent_vi;
8891 continue;
8892 },
8893 }
8894 return initial_vi;
8895 }
8896 }
8897
8898 pub fn deref(initial_vi: Value.Index, isel: *Select) void {
8899 var vi = initial_vi;
8900 while (true) {
8901 const refs = &vi.get(isel).refs;
8902 refs.* -= 1;
8903 if (refs.* > 0) return;
8904 switch (vi.parent(isel)) {
8905 .unallocated, .constant => {},
8906 .stack_slot => {
8907 // reuse stack slot
8908 },
8909 .address, .value => |parent_vi| {
8910 vi = parent_vi;
8911 continue;
8912 },
8913 }
8914 return;
8915 }
8916 }
8917
8918 fn move(dst_vi: Value.Index, isel: *Select, src_ref: Air.Inst.Ref) !void {
8919 try dst_vi.copy(
8920 isel,
8921 isel.air.typeOf(src_ref, &isel.pt.zcu.intern_pool),
8922 try isel.use(src_ref),
8923 );
8924 }
8925
8926 fn copy(dst_vi: Value.Index, isel: *Select, ty: ZigType, src_vi: Value.Index) !void {
8927 try dst_vi.copyAdvanced(isel, src_vi, .{
8928 .ty = ty,
8929 .dst_vi = dst_vi,
8930 .dst_offset = 0,
8931 .src_vi = src_vi,
8932 .src_offset = 0,
8933 });
8934 }
8935
8936 fn copyAdvanced(dst_vi: Value.Index, isel: *Select, src_vi: Value.Index, root: struct {
8937 ty: ZigType,
8938 dst_vi: Value.Index,
8939 dst_offset: u64,
8940 src_vi: Value.Index,
8941 src_offset: u64,
8942 }) !void {
8943 if (dst_vi == src_vi) return;
8944 var dst_part_it = dst_vi.parts(isel);
8945 if (dst_part_it.only()) |dst_part_vi| {
8946 var src_part_it = src_vi.parts(isel);
8947 if (src_part_it.only()) |src_part_vi| {
8948 try src_part_vi.liveOut(isel, try dst_part_vi.defReg(isel) orelse return);
8949 } else while (src_part_it.next()) |src_part_vi| {
8950 const src_part_offset, const src_part_size = src_part_vi.position(isel);
8951 var dst_field_it = root.dst_vi.field(root.ty, root.dst_offset + src_part_offset, src_part_size);
8952 const dst_field_vi = try dst_field_it.only(isel);
8953 try dst_field_vi.?.copyAdvanced(isel, src_part_vi, .{
8954 .ty = root.ty,
8955 .dst_vi = root.dst_vi,
8956 .dst_offset = root.dst_offset + src_part_offset,
8957 .src_vi = root.src_vi,
8958 .src_offset = root.src_offset + src_part_offset,
8959 });
8960 }
8961 } else while (dst_part_it.next()) |dst_part_vi| {
8962 const dst_part_offset, const dst_part_size = dst_part_vi.position(isel);
8963 var src_field_it = root.src_vi.field(root.ty, root.src_offset + dst_part_offset, dst_part_size);
8964 const src_part_vi = try src_field_it.only(isel);
8965 try dst_part_vi.copyAdvanced(isel, src_part_vi.?, .{
8966 .ty = root.ty,
8967 .dst_vi = root.dst_vi,
8968 .dst_offset = root.dst_offset + dst_part_offset,
8969 .src_vi = root.src_vi,
8970 .src_offset = root.src_offset + dst_part_offset,
8971 });
8972 }
8973 }
8974
8975 const AddOrSubtractOptions = struct {
8976 overflow: Overflow,
8977
8978 const Overflow = union(enum) {
8979 @"unreachable",
8980 panic: Zcu.SimplePanicId,
8981 wrap,
8982 ra: Register.Alias,
8983
8984 fn defCond(overflow: Overflow, isel: *Select, cond: codegen.aarch64.encoding.ConditionCode) !void {
8985 switch (overflow) {
8986 .@"unreachable" => unreachable,
8987 .panic => |panic_id| {
8988 const skip_label = isel.instructions.items.len;
8989 try isel.emitPanic(panic_id);
8990 try isel.emit(.@"b."(
8991 cond.invert(),
8992 @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
8993 ));
8994 },
8995 .wrap => {},
8996 .ra => |overflow_ra| try isel.emit(.csinc(overflow_ra.w(), .wzr, .wzr, cond.invert())),
8997 }
8998 }
8999 };
9000 };
9001 fn addOrSubtract(
9002 res_vi: Value.Index,
9003 isel: *Select,
9004 ty: ZigType,
9005 lhs_vi: Value.Index,
9006 op: codegen.aarch64.encoding.Instruction.AddSubtractOp,
9007 rhs_vi: Value.Index,
9008 opts: AddOrSubtractOptions,
9009 ) !void {
9010 const zcu = isel.pt.zcu;
9011 if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(op), isel.fmtType(ty) });
9012 const int_info = ty.intInfo(zcu);
9013 if (int_info.bits > 128) return isel.fail("too big {s} {f}", .{ @tagName(op), isel.fmtType(ty) });
9014 var part_offset = res_vi.size(isel);
9015 var need_wrap = switch (opts.overflow) {
9016 .@"unreachable" => false,
9017 .panic, .wrap, .ra => true,
9018 };
9019 var need_carry = switch (opts.overflow) {
9020 .@"unreachable", .wrap => false,
9021 .panic, .ra => true,
9022 };
9023 while (part_offset > 0) : (need_wrap = false) {
9024 const part_size = @min(part_offset, 8);
9025 part_offset -= part_size;
9026 var wrapped_res_part_it = res_vi.field(ty, part_offset, part_size);
9027 const wrapped_res_part_vi = try wrapped_res_part_it.only(isel);
9028 const wrapped_res_part_ra = try wrapped_res_part_vi.?.defReg(isel) orelse if (need_carry) .zr else continue;
9029 const unwrapped_res_part_ra = unwrapped_res_part_ra: {
9030 if (!need_wrap) break :unwrapped_res_part_ra wrapped_res_part_ra;
9031 if (int_info.bits % 32 == 0) {
9032 try opts.overflow.defCond(isel, switch (int_info.signedness) {
9033 .signed => .vs,
9034 .unsigned => switch (op) {
9035 .add => .cs,
9036 .sub => .cc,
9037 },
9038 });
9039 break :unwrapped_res_part_ra wrapped_res_part_ra;
9040 }
9041 need_carry = false;
9042 const wrapped_part_ra, const unwrapped_part_ra = part_ra: switch (opts.overflow) {
9043 .@"unreachable" => unreachable,
9044 .panic, .ra => switch (int_info.signedness) {
9045 .signed => {
9046 try opts.overflow.defCond(isel, .ne);
9047 const wrapped_part_ra = switch (wrapped_res_part_ra) {
9048 else => |res_part_ra| res_part_ra,
9049 .zr => try isel.allocIntReg(),
9050 };
9051 errdefer if (wrapped_part_ra != wrapped_res_part_ra) isel.freeReg(wrapped_part_ra);
9052 const unwrapped_part_ra = unwrapped_part_ra: {
9053 const wrapped_res_part_lock: RegLock = switch (wrapped_res_part_ra) {
9054 else => |res_part_ra| isel.lockReg(res_part_ra),
9055 .zr => .empty,
9056 };
9057 defer wrapped_res_part_lock.unlock(isel);
9058 break :unwrapped_part_ra try isel.allocIntReg();
9059 };
9060 errdefer isel.freeReg(unwrapped_part_ra);
9061 switch (part_size) {
9062 else => unreachable,
9063 1...4 => try isel.emit(.subs(.wzr, wrapped_part_ra.w(), .{ .register = unwrapped_part_ra.w() })),
9064 5...8 => try isel.emit(.subs(.xzr, wrapped_part_ra.x(), .{ .register = unwrapped_part_ra.x() })),
9065 }
9066 break :part_ra .{ wrapped_part_ra, unwrapped_part_ra };
9067 },
9068 .unsigned => {
9069 const unwrapped_part_ra = unwrapped_part_ra: {
9070 const wrapped_res_part_lock: RegLock = switch (wrapped_res_part_ra) {
9071 else => |res_part_ra| isel.lockReg(res_part_ra),
9072 .zr => .empty,
9073 };
9074 defer wrapped_res_part_lock.unlock(isel);
9075 break :unwrapped_part_ra try isel.allocIntReg();
9076 };
9077 errdefer isel.freeReg(unwrapped_part_ra);
9078 const bit: u6 = @truncate(int_info.bits);
9079 switch (opts.overflow) {
9080 .@"unreachable", .wrap => unreachable,
9081 .panic => |panic_id| {
9082 const skip_label = isel.instructions.items.len;
9083 try isel.emitPanic(panic_id);
9084 try isel.emit(.tbz(
9085 switch (bit) {
9086 0, 32 => unreachable,
9087 1...31 => unwrapped_part_ra.w(),
9088 33...63 => unwrapped_part_ra.x(),
9089 },
9090 bit,
9091 @intCast((isel.instructions.items.len + 1 - skip_label) << 2),
9092 ));
9093 },
9094 .ra => |overflow_ra| try isel.emit(switch (bit) {
9095 0, 32 => unreachable,
9096 1...31 => .ubfm(overflow_ra.w(), unwrapped_part_ra.w(), .{
9097 .N = .word,
9098 .immr = bit,
9099 .imms = bit,
9100 }),
9101 33...63 => .ubfm(overflow_ra.x(), unwrapped_part_ra.x(), .{
9102 .N = .doubleword,
9103 .immr = bit,
9104 .imms = bit,
9105 }),
9106 }),
9107 }
9108 break :part_ra .{ wrapped_res_part_ra, unwrapped_part_ra };
9109 },
9110 },
9111 .wrap => .{ wrapped_res_part_ra, wrapped_res_part_ra },
9112 };
9113 defer if (wrapped_part_ra != wrapped_res_part_ra) isel.freeReg(wrapped_part_ra);
9114 errdefer if (unwrapped_part_ra != wrapped_res_part_ra) isel.freeReg(unwrapped_part_ra);
9115 if (wrapped_part_ra != .zr) try isel.emit(switch (part_size) {
9116 else => unreachable,
9117 1...4 => switch (int_info.signedness) {
9118 .signed => .sbfm(wrapped_part_ra.w(), unwrapped_part_ra.w(), .{
9119 .N = .word,
9120 .immr = 0,
9121 .imms = @truncate(int_info.bits - 1),
9122 }),
9123 .unsigned => .ubfm(wrapped_part_ra.w(), unwrapped_part_ra.w(), .{
9124 .N = .word,
9125 .immr = 0,
9126 .imms = @truncate(int_info.bits - 1),
9127 }),
9128 },
9129 5...8 => switch (int_info.signedness) {
9130 .signed => .sbfm(wrapped_part_ra.x(), unwrapped_part_ra.x(), .{
9131 .N = .doubleword,
9132 .immr = 0,
9133 .imms = @truncate(int_info.bits - 1),
9134 }),
9135 .unsigned => .ubfm(wrapped_part_ra.x(), unwrapped_part_ra.x(), .{
9136 .N = .doubleword,
9137 .immr = 0,
9138 .imms = @truncate(int_info.bits - 1),
9139 }),
9140 },
9141 });
9142 break :unwrapped_res_part_ra unwrapped_part_ra;
9143 };
9144 defer if (unwrapped_res_part_ra != wrapped_res_part_ra) isel.freeReg(unwrapped_res_part_ra);
9145 var lhs_part_it = lhs_vi.field(ty, part_offset, part_size);
9146 const lhs_part_vi = try lhs_part_it.only(isel);
9147 const lhs_part_mat = try lhs_part_vi.?.matReg(isel);
9148 var rhs_part_it = rhs_vi.field(ty, part_offset, part_size);
9149 const rhs_part_vi = try rhs_part_it.only(isel);
9150 const rhs_part_mat = try rhs_part_vi.?.matReg(isel);
9151 try isel.emit(switch (part_size) {
9152 else => unreachable,
9153 1...4 => switch (op) {
9154 .add => switch (part_offset) {
9155 0 => switch (need_carry) {
9156 false => .add(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }),
9157 true => .adds(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }),
9158 },
9159 else => switch (need_carry) {
9160 false => .adc(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), rhs_part_mat.ra.w()),
9161 true => .adcs(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), rhs_part_mat.ra.w()),
9162 },
9163 },
9164 .sub => switch (part_offset) {
9165 0 => switch (need_carry) {
9166 false => .sub(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }),
9167 true => .subs(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }),
9168 },
9169 else => switch (need_carry) {
9170 false => .sbc(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), rhs_part_mat.ra.w()),
9171 true => .sbcs(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), rhs_part_mat.ra.w()),
9172 },
9173 },
9174 },
9175 5...8 => switch (op) {
9176 .add => switch (part_offset) {
9177 0 => switch (need_carry) {
9178 false => .add(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }),
9179 true => .adds(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }),
9180 },
9181 else => switch (need_carry) {
9182 false => .adc(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), rhs_part_mat.ra.x()),
9183 true => .adcs(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), rhs_part_mat.ra.x()),
9184 },
9185 },
9186 .sub => switch (part_offset) {
9187 0 => switch (need_carry) {
9188 false => .sub(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }),
9189 true => .subs(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }),
9190 },
9191 else => switch (need_carry) {
9192 false => .sbc(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), rhs_part_mat.ra.x()),
9193 true => .sbcs(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), rhs_part_mat.ra.x()),
9194 },
9195 },
9196 },
9197 });
9198 try rhs_part_mat.finish(isel);
9199 try lhs_part_mat.finish(isel);
9200 need_carry = true;
9201 }
9202 }
9203
9204 const MemoryAccessOptions = struct {
9205 root_vi: Value.Index = .free,
9206 offset: u64 = 0,
9207 @"volatile": bool = false,
9208 split: bool = true,
9209 wrap: ?std.builtin.Type.Int = null,
9210 expected_live_registers: *const LiveRegisters = &.initFill(.free),
9211 };
9212
9213 fn load(
9214 vi: Value.Index,
9215 isel: *Select,
9216 root_ty: ZigType,
9217 base_ra: Register.Alias,
9218 opts: MemoryAccessOptions,
9219 ) !bool {
9220 const root_vi = switch (opts.root_vi) {
9221 _ => |root_vi| root_vi,
9222 .allocating => unreachable,
9223 .free => vi,
9224 };
9225 var part_it = vi.parts(isel);
9226 if (part_it.only()) |part_vi| only: {
9227 const part_size = part_vi.size(isel);
9228 const part_is_vector = part_vi.isVector(isel);
9229 if (part_size > @as(@TypeOf(part_size), if (part_is_vector) 16 else 8)) {
9230 if (!opts.split) return false;
9231 var subpart_it = root_vi.field(root_ty, opts.offset, part_size - 1);
9232 _ = try subpart_it.next(isel);
9233 part_it = vi.parts(isel);
9234 assert(part_it.only() == null);
9235 break :only;
9236 }
9237 const part_ra = if (try part_vi.defReg(isel)) |part_ra|
9238 part_ra
9239 else if (opts.@"volatile")
9240 .zr
9241 else
9242 return false;
9243 if (part_ra != .zr) {
9244 const live_vi = isel.live_registers.getPtr(part_ra);
9245 assert(live_vi.* == .free);
9246 live_vi.* = .allocating;
9247 }
9248 if (opts.wrap) |int_info| switch (int_info.bits) {
9249 else => unreachable,
9250 1...7, 9...15, 17...31 => |bits| try isel.emit(switch (int_info.signedness) {
9251 .signed => .sbfm(part_ra.w(), part_ra.w(), .{
9252 .N = .word,
9253 .immr = 0,
9254 .imms = @intCast(bits - 1),
9255 }),
9256 .unsigned => .ubfm(part_ra.w(), part_ra.w(), .{
9257 .N = .word,
9258 .immr = 0,
9259 .imms = @intCast(bits - 1),
9260 }),
9261 }),
9262 8, 16, 32 => {},
9263 33...63 => |bits| try isel.emit(switch (int_info.signedness) {
9264 .signed => .sbfm(part_ra.x(), part_ra.x(), .{
9265 .N = .doubleword,
9266 .immr = 0,
9267 .imms = @intCast(bits - 1),
9268 }),
9269 .unsigned => .ubfm(part_ra.x(), part_ra.x(), .{
9270 .N = .doubleword,
9271 .immr = 0,
9272 .imms = @intCast(bits - 1),
9273 }),
9274 }),
9275 64 => {},
9276 };
9277 try isel.loadReg(part_ra, part_size, part_vi.signedness(isel), base_ra, opts.offset);
9278 if (part_ra != .zr) {
9279 const live_vi = isel.live_registers.getPtr(part_ra);
9280 assert(live_vi.* == .allocating);
9281 switch (opts.expected_live_registers.get(part_ra)) {
9282 _ => {},
9283 .allocating => unreachable,
9284 .free => live_vi.* = .free,
9285 }
9286 }
9287 return true;
9288 }
9289 var used = false;
9290 while (part_it.next()) |part_vi| used |= try part_vi.load(isel, root_ty, base_ra, .{
9291 .root_vi = root_vi,
9292 .offset = opts.offset + part_vi.get(isel).offset_from_parent,
9293 .@"volatile" = opts.@"volatile",
9294 .split = opts.split,
9295 .wrap = switch (part_it.remaining) {
9296 else => null,
9297 0 => if (opts.wrap) |wrap| .{
9298 .signedness = wrap.signedness,
9299 .bits = @intCast(wrap.bits - 8 * part_vi.position(isel)[0]),
9300 } else null,
9301 },
9302 .expected_live_registers = opts.expected_live_registers,
9303 });
9304 return used;
9305 }
9306
9307 fn store(
9308 vi: Value.Index,
9309 isel: *Select,
9310 root_ty: ZigType,
9311 base_ra: Register.Alias,
9312 opts: MemoryAccessOptions,
9313 ) !void {
9314 const root_vi = switch (opts.root_vi) {
9315 _ => |root_vi| root_vi,
9316 .allocating => unreachable,
9317 .free => vi,
9318 };
9319 var part_it = vi.parts(isel);
9320 if (part_it.only()) |part_vi| only: {
9321 const part_size = part_vi.size(isel);
9322 const part_is_vector = part_vi.isVector(isel);
9323 if (part_size > @as(@TypeOf(part_size), if (part_is_vector) 16 else 8)) {
9324 if (!opts.split) return;
9325 var subpart_it = root_vi.field(root_ty, opts.offset, part_size - 1);
9326 _ = try subpart_it.next(isel);
9327 part_it = vi.parts(isel);
9328 assert(part_it.only() == null);
9329 break :only;
9330 }
9331 const part_mat = try part_vi.matReg(isel);
9332 try isel.storeReg(part_mat.ra, part_size, base_ra, opts.offset);
9333 return part_mat.finish(isel);
9334 }
9335 while (part_it.next()) |part_vi| try part_vi.store(isel, root_ty, base_ra, .{
9336 .root_vi = root_vi,
9337 .offset = opts.offset + part_vi.get(isel).offset_from_parent,
9338 .@"volatile" = opts.@"volatile",
9339 .split = opts.split,
9340 .wrap = switch (part_it.remaining) {
9341 else => null,
9342 0 => if (opts.wrap) |wrap| .{
9343 .signedness = wrap.signedness,
9344 .bits = @intCast(wrap.bits - 8 * part_vi.position(isel)[0]),
9345 } else null,
9346 },
9347 .expected_live_registers = opts.expected_live_registers,
9348 });
9349 }
9350
9351 fn mat(vi: Value.Index, isel: *Select) !void {
9352 if (false) {
9353 var part_it: Value.PartIterator = if (vi.size(isel) > 8) vi.parts(isel) else .initOne(vi);
9354 if (part_it.only()) |part_vi| only: {
9355 const mat_ra = mat_ra: {
9356 if (part_vi.register(isel)) |mat_ra| {
9357 part_vi.get(isel).location_payload.small.register = .zr;
9358 const live_vi = isel.live_registers.getPtr(mat_ra);
9359 assert(live_vi.* == part_vi);
9360 live_vi.* = .allocating;
9361 break :mat_ra mat_ra;
9362 }
9363 if (part_vi.hint(isel)) |hint_ra| {
9364 const live_vi = isel.live_registers.getPtr(hint_ra);
9365 if (live_vi.* == .free) {
9366 live_vi.* = .allocating;
9367 isel.saved_registers.insert(hint_ra);
9368 break :mat_ra hint_ra;
9369 }
9370 }
9371 const part_size = part_vi.size(isel);
9372 const part_is_vector = part_vi.isVector(isel);
9373 if (part_size <= @as(@TypeOf(part_size), if (part_is_vector) 16 else 8))
9374 switch (if (part_is_vector) isel.tryAllocVecReg() else isel.tryAllocIntReg()) {
9375 .allocated => |ra| break :mat_ra ra,
9376 .fill_candidate, .out_of_registers => {},
9377 };
9378 _, const parent_vi = vi.valueParent(isel);
9379 switch (parent_vi.parent(isel)) {
9380 .unallocated => parent_vi.setParent(isel, .{ .stack_slot = parent_vi.allocStackSlot(isel) }),
9381 else => {},
9382 }
9383 break :only;
9384 };
9385 assert(isel.live_registers.get(mat_ra) == .allocating);
9386 try Value.Materialize.finish(.{ .vi = part_vi, .ra = mat_ra }, isel);
9387 } else while (part_it.next()) |part_vi| try part_vi.mat(isel);
9388 } else {
9389 _, const parent_vi = vi.valueParent(isel);
9390 switch (parent_vi.parent(isel)) {
9391 .unallocated => parent_vi.setParent(isel, .{ .stack_slot = parent_vi.allocStackSlot(isel) }),
9392 else => {},
9393 }
9394 }
9395 }
9396
9397 fn matReg(vi: Value.Index, isel: *Select) !Value.Materialize {
9398 const mat_ra = mat_ra: {
9399 if (vi.register(isel)) |mat_ra| {
9400 vi.get(isel).location_payload.small.register = .zr;
9401 const live_vi = isel.live_registers.getPtr(mat_ra);
9402 assert(live_vi.* == vi);
9403 live_vi.* = .allocating;
9404 break :mat_ra mat_ra;
9405 }
9406 if (vi.hint(isel)) |hint_ra| {
9407 const live_vi = isel.live_registers.getPtr(hint_ra);
9408 if (live_vi.* == .free) {
9409 live_vi.* = .allocating;
9410 isel.saved_registers.insert(hint_ra);
9411 break :mat_ra hint_ra;
9412 }
9413 }
9414 break :mat_ra if (vi.isVector(isel)) try isel.allocVecReg() else try isel.allocIntReg();
9415 };
9416 assert(isel.live_registers.get(mat_ra) == .allocating);
9417 return .{ .vi = vi, .ra = mat_ra };
9418 }
9419
9420 fn defAddr(
9421 def_vi: Value.Index,
9422 isel: *Select,
9423 def_ty: ZigType,
9424 wrap: ?std.builtin.Type.Int,
9425 expected_live_registers: *const LiveRegisters,
9426 ) !?void {
9427 if (!def_vi.isUsed(isel)) return null;
9428 const offset_from_parent: i65, const parent_vi = def_vi.valueParent(isel);
9429 const stack_slot, const allocated = switch (parent_vi.parent(isel)) {
9430 .unallocated => .{ parent_vi.allocStackSlot(isel), true },
9431 .stack_slot => |stack_slot| .{ stack_slot, false },
9432 else => unreachable,
9433 };
9434 _ = try def_vi.load(isel, def_ty, stack_slot.base, .{
9435 .offset = @intCast(stack_slot.offset + offset_from_parent),
9436 .split = false,
9437 .wrap = wrap,
9438 .expected_live_registers = expected_live_registers,
9439 });
9440 if (allocated) parent_vi.setParent(isel, .{ .stack_slot = stack_slot });
9441 }
9442
9443 fn defReg(def_vi: Value.Index, isel: *Select) !?Register.Alias {
9444 var vi = def_vi;
9445 var offset: i65 = 0;
9446 var def_ra: ?Register.Alias = null;
9447 while (true) {
9448 if (vi.register(isel)) |ra| {
9449 vi.get(isel).location_payload.small.register = .zr;
9450 const live_vi = isel.live_registers.getPtr(ra);
9451 assert(live_vi.* == vi);
9452 if (def_ra == null and vi != def_vi) {
9453 var part_it = vi.parts(isel);
9454 assert(part_it.only() == null);
9455
9456 const first_part_vi = part_it.next().?;
9457 const first_part_value = first_part_vi.get(isel);
9458 assert(first_part_value.offset_from_parent == 0);
9459 first_part_value.location_payload.small.register = ra;
9460 live_vi.* = first_part_vi;
9461
9462 const vi_size = vi.size(isel);
9463 while (part_it.next()) |part_vi| {
9464 const part_offset, const part_size = part_vi.position(isel);
9465 const part_mat = try part_vi.matReg(isel);
9466 try isel.emit(if (part_vi.isVector(isel)) emit: {
9467 assert(part_offset == 0 and part_size == vi_size);
9468 break :emit size: switch (vi_size) {
9469 else => unreachable,
9470 2 => if (isel.target.cpu.has(.aarch64, .fullfp16))
9471 .fmov(ra.h(), .{ .register = part_mat.ra.h() })
9472 else
9473 continue :size 4,
9474 4 => .fmov(ra.s(), .{ .register = part_mat.ra.s() }),
9475 8 => .fmov(ra.d(), .{ .register = part_mat.ra.d() }),
9476 16 => .orr(ra.@"16b"(), part_mat.ra.@"16b"(), .{ .register = part_mat.ra.@"16b"() }),
9477 };
9478 } else switch (vi_size) {
9479 else => unreachable,
9480 1...4 => .bfm(ra.w(), part_mat.ra.w(), .{
9481 .N = .word,
9482 .immr = @as(u5, @truncate(32 - 8 * part_offset)),
9483 .imms = @intCast(8 * part_size - 1),
9484 }),
9485 5...8 => .bfm(ra.x(), part_mat.ra.x(), .{
9486 .N = .doubleword,
9487 .immr = @as(u6, @truncate(64 - 8 * part_offset)),
9488 .imms = @intCast(8 * part_size - 1),
9489 }),
9490 });
9491 try part_mat.finish(isel);
9492 }
9493 vi = def_vi;
9494 offset = 0;
9495 continue;
9496 }
9497 live_vi.* = .free;
9498 def_ra = ra;
9499 }
9500 offset += vi.get(isel).offset_from_parent;
9501 switch (vi.parent(isel)) {
9502 else => unreachable,
9503 .unallocated => return def_ra,
9504 .stack_slot => |stack_slot| {
9505 offset += stack_slot.offset;
9506 const def_is_vector = def_vi.isVector(isel);
9507 const ra = def_ra orelse if (def_is_vector) try isel.allocVecReg() else try isel.allocIntReg();
9508 defer if (def_ra == null) isel.freeReg(ra);
9509 try isel.storeReg(ra, def_vi.size(isel), stack_slot.base, offset);
9510 return ra;
9511 },
9512 .value => |parent_vi| vi = parent_vi,
9513 }
9514 }
9515 }
9516
9517 pub fn liveIn(
9518 vi: Value.Index,
9519 isel: *Select,
9520 src_ra: Register.Alias,
9521 expected_live_registers: *const LiveRegisters,
9522 ) !void {
9523 const src_live_vi = isel.live_registers.getPtr(src_ra);
9524 if (vi.register(isel)) |dst_ra| {
9525 const dst_live_vi = isel.live_registers.getPtr(dst_ra);
9526 assert(dst_live_vi.* == vi);
9527 if (dst_ra == src_ra) {
9528 src_live_vi.* = .allocating;
9529 return;
9530 }
9531 dst_live_vi.* = .allocating;
9532 if (try isel.fill(src_ra)) {
9533 assert(src_live_vi.* == .free);
9534 src_live_vi.* = .allocating;
9535 }
9536 assert(src_live_vi.* == .allocating);
9537 try isel.emit(switch (dst_ra.isVector()) {
9538 false => switch (src_ra.isVector()) {
9539 false => switch (vi.size(isel)) {
9540 else => unreachable,
9541 1...4 => .orr(dst_ra.w(), .wzr, .{ .register = src_ra.w() }),
9542 5...8 => .orr(dst_ra.x(), .xzr, .{ .register = src_ra.x() }),
9543 },
9544 true => switch (vi.size(isel)) {
9545 else => unreachable,
9546 2 => .fmov(dst_ra.w(), .{ .register = src_ra.h() }),
9547 4 => .fmov(dst_ra.w(), .{ .register = src_ra.s() }),
9548 8 => .fmov(dst_ra.x(), .{ .register = src_ra.d() }),
9549 },
9550 },
9551 true => switch (src_ra.isVector()) {
9552 false => switch (vi.size(isel)) {
9553 else => unreachable,
9554 2 => .fmov(dst_ra.h(), .{ .register = src_ra.w() }),
9555 4 => .fmov(dst_ra.s(), .{ .register = src_ra.w() }),
9556 8 => .fmov(dst_ra.d(), .{ .register = src_ra.x() }),
9557 },
9558 true => switch (vi.size(isel)) {
9559 else => unreachable,
9560 2 => .fmov(dst_ra.h(), .{ .register = src_ra.h() }),
9561 4 => .fmov(dst_ra.s(), .{ .register = src_ra.s() }),
9562 8 => .fmov(dst_ra.d(), .{ .register = src_ra.d() }),
9563 16 => .orr(dst_ra.@"16b"(), src_ra.@"16b"(), .{ .register = src_ra.@"16b"() }),
9564 },
9565 },
9566 });
9567 assert(dst_live_vi.* == .allocating);
9568 dst_live_vi.* = switch (expected_live_registers.get(dst_ra)) {
9569 _ => .allocating,
9570 .allocating => .allocating,
9571 .free => .free,
9572 };
9573 } else if (try isel.fill(src_ra)) {
9574 assert(src_live_vi.* == .free);
9575 src_live_vi.* = .allocating;
9576 }
9577 assert(src_live_vi.* == .allocating);
9578 vi.get(isel).location_payload.small.register = src_ra;
9579 }
9580
9581 pub fn defLiveIn(
9582 vi: Value.Index,
9583 isel: *Select,
9584 src_ra: Register.Alias,
9585 expected_live_registers: *const LiveRegisters,
9586 ) !void {
9587 try vi.liveIn(isel, src_ra, expected_live_registers);
9588 const offset_from_parent, const parent_vi = vi.valueParent(isel);
9589 switch (parent_vi.parent(isel)) {
9590 .unallocated => {},
9591 .stack_slot => |stack_slot| if (stack_slot.base != Register.Alias.fp) try isel.storeReg(
9592 src_ra,
9593 vi.size(isel),
9594 stack_slot.base,
9595 @as(i65, stack_slot.offset) + offset_from_parent,
9596 ),
9597 else => unreachable,
9598 }
9599 try vi.spillReg(isel, src_ra, 0, expected_live_registers);
9600 }
9601
9602 fn spillReg(
9603 vi: Value.Index,
9604 isel: *Select,
9605 src_ra: Register.Alias,
9606 start_offset: u64,
9607 expected_live_registers: *const LiveRegisters,
9608 ) !void {
9609 assert(isel.live_registers.get(src_ra) == .allocating);
9610 var part_it = vi.parts(isel);
9611 if (part_it.only()) |part_vi| {
9612 const dst_ra = part_vi.register(isel) orelse return;
9613 if (dst_ra == src_ra) return;
9614 const part_size = part_vi.size(isel);
9615 const part_ra = if (part_vi.isVector(isel)) try isel.allocIntReg() else dst_ra;
9616 defer if (part_ra != dst_ra) isel.freeReg(part_ra);
9617 if (part_ra != dst_ra) try isel.emit(switch (part_size) {
9618 else => unreachable,
9619 2 => .fmov(dst_ra.h(), .{ .register = part_ra.w() }),
9620 4 => .fmov(dst_ra.s(), .{ .register = part_ra.w() }),
9621 8 => .fmov(dst_ra.d(), .{ .register = part_ra.x() }),
9622 });
9623 try isel.emit(switch (start_offset + part_size) {
9624 else => unreachable,
9625 1...4 => |end_offset| switch (part_vi.signedness(isel)) {
9626 .signed => .sbfm(part_ra.w(), src_ra.w(), .{
9627 .N = .word,
9628 .immr = @intCast(8 * start_offset),
9629 .imms = @intCast(8 * end_offset - 1),
9630 }),
9631 .unsigned => .ubfm(part_ra.w(), src_ra.w(), .{
9632 .N = .word,
9633 .immr = @intCast(8 * start_offset),
9634 .imms = @intCast(8 * end_offset - 1),
9635 }),
9636 },
9637 5...8 => |end_offset| switch (part_vi.signedness(isel)) {
9638 .signed => .sbfm(part_ra.x(), src_ra.x(), .{
9639 .N = .doubleword,
9640 .immr = @intCast(8 * start_offset),
9641 .imms = @intCast(8 * end_offset - 1),
9642 }),
9643 .unsigned => .ubfm(part_ra.x(), src_ra.x(), .{
9644 .N = .doubleword,
9645 .immr = @intCast(8 * start_offset),
9646 .imms = @intCast(8 * end_offset - 1),
9647 }),
9648 },
9649 });
9650 const value_ra = &part_vi.get(isel).location_payload.small.register;
9651 assert(value_ra.* == dst_ra);
9652 value_ra.* = .zr;
9653 const dst_live_vi = isel.live_registers.getPtr(dst_ra);
9654 assert(dst_live_vi.* == part_vi);
9655 dst_live_vi.* = switch (expected_live_registers.get(dst_ra)) {
9656 _ => .allocating,
9657 .allocating => unreachable,
9658 .free => .free,
9659 };
9660 } else while (part_it.next()) |part_vi| try part_vi.spillReg(
9661 isel,
9662 src_ra,
9663 start_offset + part_vi.get(isel).offset_from_parent,
9664 expected_live_registers,
9665 );
9666 }
9667
9668 fn liveOut(vi: Value.Index, isel: *Select, ra: Register.Alias) !void {
9669 assert(try isel.fill(ra));
9670 const live_vi = isel.live_registers.getPtr(ra);
9671 assert(live_vi.* == .free);
9672 live_vi.* = .allocating;
9673 try Value.Materialize.finish(.{ .vi = vi, .ra = ra }, isel);
9674 }
9675
9676 fn allocStackSlot(vi: Value.Index, isel: *Select) Value.Indirect {
9677 const offset = vi.alignment(isel).forward(isel.stack_size);
9678 isel.stack_size = @intCast(offset + vi.size(isel));
9679 tracking_log.debug("${d} -> [sp, #0x{x}]", .{ @intFromEnum(vi), @abs(offset) });
9680 return .{
9681 .base = .sp,
9682 .offset = @intCast(offset),
9683 };
9684 }
9685
9686 fn address(initial_vi: Value.Index, isel: *Select, initial_offset: u64, ptr_ra: Register.Alias) !void {
9687 var vi = initial_vi;
9688 var offset: i65 = vi.get(isel).offset_from_parent + initial_offset;
9689 parent: switch (vi.parent(isel)) {
9690 .unallocated => {
9691 const stack_slot = vi.allocStackSlot(isel);
9692 vi.setParent(isel, .{ .stack_slot = stack_slot });
9693 continue :parent .{ .stack_slot = stack_slot };
9694 },
9695 .stack_slot => |stack_slot| {
9696 offset += stack_slot.offset;
9697 const lo12: u12 = @truncate(@abs(offset) >> 0);
9698 const hi12: u12 = @intCast(@abs(offset) >> 12);
9699 if (hi12 > 0) try isel.emit(if (offset >= 0) .add(
9700 ptr_ra.x(),
9701 if (lo12 > 0) ptr_ra.x() else stack_slot.base.x(),
9702 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
9703 ) else .sub(
9704 ptr_ra.x(),
9705 if (lo12 > 0) ptr_ra.x() else stack_slot.base.x(),
9706 .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } },
9707 ));
9708 if (lo12 > 0 or hi12 == 0) try isel.emit(if (offset >= 0) .add(
9709 ptr_ra.x(),
9710 stack_slot.base.x(),
9711 .{ .immediate = lo12 },
9712 ) else .sub(
9713 ptr_ra.x(),
9714 stack_slot.base.x(),
9715 .{ .immediate = lo12 },
9716 ));
9717 },
9718 .address => |address_vi| try address_vi.liveOut(isel, ptr_ra),
9719 .value => |parent_vi| {
9720 vi = parent_vi;
9721 offset += vi.get(isel).offset_from_parent;
9722 continue :parent vi.parent(isel);
9723 },
9724 .constant => |constant| {
9725 const pt = isel.pt;
9726 const zcu = pt.zcu;
9727 switch (true) {
9728 false => {
9729 try isel.uav_relocs.append(zcu.gpa, .{
9730 .uav = .{
9731 .val = constant.toIntern(),
9732 .orig_ty = (try pt.singleConstPtrType(constant.typeOf(zcu))).toIntern(),
9733 },
9734 .reloc = .{
9735 .label = @intCast(isel.instructions.items.len),
9736 .addend = @intCast(offset),
9737 },
9738 });
9739 try isel.emit(.adr(ptr_ra.x(), 0));
9740 },
9741 true => {
9742 try isel.uav_relocs.append(zcu.gpa, .{
9743 .uav = .{
9744 .val = constant.toIntern(),
9745 .orig_ty = (try pt.singleConstPtrType(constant.typeOf(zcu))).toIntern(),
9746 },
9747 .reloc = .{
9748 .label = @intCast(isel.instructions.items.len),
9749 .addend = @intCast(offset),
9750 },
9751 });
9752 try isel.emit(.add(ptr_ra.x(), ptr_ra.x(), .{ .immediate = 0 }));
9753 try isel.uav_relocs.append(zcu.gpa, .{
9754 .uav = .{
9755 .val = constant.toIntern(),
9756 .orig_ty = (try pt.singleConstPtrType(constant.typeOf(zcu))).toIntern(),
9757 },
9758 .reloc = .{
9759 .label = @intCast(isel.instructions.items.len),
9760 .addend = @intCast(offset),
9761 },
9762 });
9763 try isel.emit(.adrp(ptr_ra.x(), 0));
9764 },
9765 }
9766 },
9767 }
9768 }
9769 };
9770
9771 pub const PartIterator = struct {
9772 vi: Value.Index,
9773 remaining: Value.PartsLen,
9774
9775 fn initOne(vi: Value.Index) PartIterator {
9776 return .{ .vi = vi, .remaining = 1 };
9777 }
9778
9779 pub fn next(it: *PartIterator) ?Value.Index {
9780 if (it.remaining == 0) return null;
9781 it.remaining -= 1;
9782 defer it.vi = @enumFromInt(@intFromEnum(it.vi) + 1);
9783 return it.vi;
9784 }
9785
9786 pub fn peek(it: PartIterator) ?Value.Index {
9787 var it_mut = it;
9788 return it_mut.next();
9789 }
9790
9791 pub fn only(it: PartIterator) ?Value.Index {
9792 return if (it.remaining == 1) it.vi else null;
9793 }
9794 };
9795
9796 const FieldPartIterator = struct {
9797 vi: Value.Index,
9798 ty: ZigType,
9799 field_offset: u64,
9800 field_size: u64,
9801 next_offset: u64,
9802
9803 fn next(it: *FieldPartIterator, isel: *Select) !?struct { offset: u64, vi: Value.Index } {
9804 const next_offset = it.next_offset;
9805 const next_part_size = it.field_size - next_offset;
9806 if (next_part_size == 0) return null;
9807 var next_part_offset = it.field_offset + next_offset;
9808
9809 const zcu = isel.pt.zcu;
9810 const ip = &zcu.intern_pool;
9811 var vi = it.vi;
9812 var ty = it.ty;
9813 var ty_size = vi.size(isel);
9814 assert(ty_size == ty.abiSize(zcu));
9815 var offset: u64 = 0;
9816 var size = ty_size;
9817 assert(next_part_offset + next_part_size <= size);
9818 while (next_part_offset > 0 or next_part_size < size) {
9819 const part_vi = vi.partAtOffset(isel, next_part_offset);
9820 if (part_vi != vi) {
9821 vi = part_vi;
9822 const part_offset, size = part_vi.position(isel);
9823 assert(part_offset <= next_part_offset and part_offset + size > next_part_offset);
9824 offset += part_offset;
9825 next_part_offset -= part_offset;
9826 continue;
9827 }
9828 try isel.values.ensureUnusedCapacity(zcu.gpa, Value.max_parts);
9829 type_key: switch (ip.indexToKey(ty.toIntern())) {
9830 else => return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}),
9831 .int_type => |int_type| switch (int_type.bits) {
9832 0 => unreachable,
9833 1...64 => unreachable,
9834 65...256 => |bits| if (offset == 0 and size == ty_size) {
9835 const parts_len = std.math.divCeil(u16, bits, 64) catch unreachable;
9836 vi.setParts(isel, @intCast(parts_len));
9837 for (0..parts_len) |part_index| _ = vi.addPart(isel, 8 * part_index, 8);
9838 },
9839 else => return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}),
9840 },
9841 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
9842 .one, .many, .c => unreachable,
9843 .slice => if (offset == 0 and size == ty_size) {
9844 vi.setParts(isel, 2);
9845 _ = vi.addPart(isel, 0, 8);
9846 _ = vi.addPart(isel, 8, 8);
9847 } else unreachable,
9848 },
9849 .opt_type => |child_type| if (ty.optionalReprIsPayload(zcu))
9850 continue :type_key ip.indexToKey(child_type)
9851 else switch (ZigType.fromInterned(child_type).abiSize(zcu)) {
9852 0...8, 16 => |child_size| if (offset == 0 and size == ty_size) {
9853 vi.setParts(isel, 2);
9854 _ = vi.addPart(isel, 0, child_size);
9855 _ = vi.addPart(isel, child_size, 1);
9856 } else unreachable,
9857 9...15 => |child_size| if (offset == 0 and size == ty_size) {
9858 vi.setParts(isel, 2);
9859 _ = vi.addPart(isel, 0, 8);
9860 _ = vi.addPart(isel, 8, ty_size - 8);
9861 } else if (offset == 8 and size == ty_size - 8) {
9862 vi.setParts(isel, 2);
9863 _ = vi.addPart(isel, 0, child_size - 8);
9864 _ = vi.addPart(isel, child_size - 8, 1);
9865 } else unreachable,
9866 else => return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}),
9867 },
9868 .array_type => |array_type| {
9869 const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0;
9870 const array_len = array_type.lenIncludingSentinel();
9871 if (array_len > Value.max_parts and
9872 (std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts)
9873 return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)});
9874 const alignment = vi.alignment(isel);
9875 const Part = struct { offset: u64, size: u64 };
9876 var parts: [Value.max_parts]Part = undefined;
9877 var parts_len: Value.PartsLen = 0;
9878 const elem_ty: ZigType = .fromInterned(array_type.child);
9879 const elem_size = elem_ty.abiSize(zcu);
9880 const elem_signedness = if (ty.isAbiInt(zcu)) elem_signedness: {
9881 const elem_int_info = elem_ty.intInfo(zcu);
9882 break :elem_signedness if (elem_int_info.bits <= 16) elem_int_info.signedness else null;
9883 } else null;
9884 const elem_is_vector = elem_size <= 16 and
9885 CallAbiIterator.homogeneousAggregateBaseType(zcu, elem_ty.toIntern()) != null;
9886 var elem_end: u64 = 0;
9887 for (0..@intCast(array_len)) |_| {
9888 const elem_begin = elem_end;
9889 if (elem_begin >= offset + size) break;
9890 elem_end = elem_begin + elem_size;
9891 if (elem_end <= offset) continue;
9892 if (offset >= elem_begin and offset + size <= elem_begin + elem_size) {
9893 ty = elem_ty;
9894 ty_size = elem_size;
9895 offset -= elem_begin;
9896 continue :type_key ip.indexToKey(elem_ty.toIntern());
9897 }
9898 if (parts_len > 0) combine: {
9899 const prev_part = &parts[parts_len - 1];
9900 const combined_size = elem_end - prev_part.offset;
9901 if (combined_size > @as(u64, 1) << @min(
9902 min_part_log2_stride,
9903 alignment.toLog2Units(),
9904 @ctz(prev_part.offset),
9905 )) break :combine;
9906 prev_part.size = combined_size;
9907 continue;
9908 }
9909 parts[parts_len] = .{ .offset = elem_begin, .size = elem_size };
9910 parts_len += 1;
9911 }
9912 vi.setParts(isel, parts_len);
9913 for (parts[0..parts_len]) |part| {
9914 const subpart_vi = vi.addPart(isel, part.offset - offset, part.size);
9915 if (elem_signedness) |signedness| subpart_vi.setSignedness(isel, signedness);
9916 if (elem_is_vector) subpart_vi.setIsVector(isel);
9917 }
9918 },
9919 .anyframe_type => unreachable,
9920 .error_union_type => |error_union_type| {
9921 const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0;
9922 if ((std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts)
9923 return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)});
9924 const alignment = vi.alignment(isel);
9925 const payload_ty: ZigType = .fromInterned(error_union_type.payload_type);
9926 const error_set_offset = codegen.errUnionErrorOffset(payload_ty, zcu);
9927 const payload_offset = codegen.errUnionPayloadOffset(payload_ty, zcu);
9928 const Part = struct { offset: u64, size: u64, signedness: ?std.builtin.Signedness, is_vector: bool };
9929 var parts: [2]Part = undefined;
9930 var parts_len: Value.PartsLen = 0;
9931 var field_end: u64 = 0;
9932 for (0..2) |field_index| {
9933 const field_ty: ZigType, const field_begin = switch (@as(enum { error_set, payload }, switch (field_index) {
9934 0 => if (error_set_offset < payload_offset) .error_set else .payload,
9935 1 => if (error_set_offset < payload_offset) .payload else .error_set,
9936 else => unreachable,
9937 })) {
9938 .error_set => .{ .fromInterned(error_union_type.error_set_type), error_set_offset },
9939 .payload => .{ payload_ty, payload_offset },
9940 };
9941 if (field_begin >= offset + size) break;
9942 const field_size = field_ty.abiSize(zcu);
9943 if (field_size == 0) continue;
9944 field_end = field_begin + field_size;
9945 if (field_end <= offset) continue;
9946 if (offset >= field_begin and offset + size <= field_begin + field_size) {
9947 ty = field_ty;
9948 ty_size = field_size;
9949 offset -= field_begin;
9950 continue :type_key ip.indexToKey(field_ty.toIntern());
9951 }
9952 const field_signedness = if (field_ty.isAbiInt(zcu)) field_signedness: {
9953 const field_int_info = field_ty.intInfo(zcu);
9954 break :field_signedness if (field_int_info.bits <= 16) field_int_info.signedness else null;
9955 } else null;
9956 const field_is_vector = field_size <= 16 and
9957 CallAbiIterator.homogeneousAggregateBaseType(zcu, field_ty.toIntern()) != null;
9958 if (parts_len > 0) combine: {
9959 const prev_part = &parts[parts_len - 1];
9960 const combined_size = field_end - prev_part.offset;
9961 if (combined_size > @as(u64, 1) << @min(
9962 min_part_log2_stride,
9963 alignment.toLog2Units(),
9964 @ctz(prev_part.offset),
9965 )) break :combine;
9966 prev_part.size = combined_size;
9967 prev_part.signedness = null;
9968 prev_part.is_vector &= field_is_vector;
9969 continue;
9970 }
9971 parts[parts_len] = .{
9972 .offset = field_begin,
9973 .size = field_size,
9974 .signedness = field_signedness,
9975 .is_vector = field_is_vector,
9976 };
9977 parts_len += 1;
9978 }
9979 vi.setParts(isel, parts_len);
9980 for (parts[0..parts_len]) |part| {
9981 const subpart_vi = vi.addPart(isel, part.offset - offset, part.size);
9982 if (part.signedness) |signedness| subpart_vi.setSignedness(isel, signedness);
9983 if (part.is_vector) subpart_vi.setIsVector(isel);
9984 }
9985 },
9986 .simple_type => |simple_type| switch (simple_type) {
9987 .f16, .f32, .f64, .f128, .c_longdouble => return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}),
9988 .f80 => continue :type_key .{ .int_type = .{ .signedness = .unsigned, .bits = 80 } },
9989 .usize,
9990 .isize,
9991 .c_char,
9992 .c_short,
9993 .c_ushort,
9994 .c_int,
9995 .c_uint,
9996 .c_long,
9997 .c_ulong,
9998 .c_longlong,
9999 .c_ulonglong,
10000 => continue :type_key .{ .int_type = ty.intInfo(zcu) },
10001 .anyopaque,
10002 .void,
10003 .type,
10004 .comptime_int,
10005 .comptime_float,
10006 .noreturn,
10007 .null,
10008 .undefined,
10009 .enum_literal,
10010 .adhoc_inferred_error_set,
10011 .generic_poison,
10012 => unreachable,
10013 .bool => continue :type_key .{ .int_type = .{ .signedness = .unsigned, .bits = 1 } },
10014 .anyerror => continue :type_key .{ .int_type = .{
10015 .signedness = .unsigned,
10016 .bits = zcu.errorSetBits(),
10017 } },
10018 },
10019 .struct_type => {
10020 const loaded_struct = ip.loadStructType(ty.toIntern());
10021 switch (loaded_struct.layout) {
10022 .auto, .@"extern" => {},
10023 .@"packed" => continue :type_key .{
10024 .int_type = ip.indexToKey(loaded_struct.backingIntTypeUnordered(ip)).int_type,
10025 },
10026 }
10027 const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0;
10028 if (loaded_struct.field_types.len > Value.max_parts and
10029 (std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts)
10030 return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)});
10031 const alignment = vi.alignment(isel);
10032 const Part = struct { offset: u64, size: u64, signedness: ?std.builtin.Signedness, is_vector: bool };
10033 var parts: [Value.max_parts]Part = undefined;
10034 var parts_len: Value.PartsLen = 0;
10035 var field_end: u64 = 0;
10036 var field_it = loaded_struct.iterateRuntimeOrder(ip);
10037 while (field_it.next()) |field_index| {
10038 const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
10039 const field_begin = switch (loaded_struct.fieldAlign(ip, field_index)) {
10040 .none => field_ty.abiAlignment(zcu),
10041 else => |field_align| field_align,
10042 }.forward(field_end);
10043 if (field_begin >= offset + size) break;
10044 const field_size = field_ty.abiSize(zcu);
10045 field_end = field_begin + field_size;
10046 if (field_end <= offset) continue;
10047 if (offset >= field_begin and offset + size <= field_begin + field_size) {
10048 ty = field_ty;
10049 ty_size = field_size;
10050 offset -= field_begin;
10051 continue :type_key ip.indexToKey(field_ty.toIntern());
10052 }
10053 const field_signedness = if (field_ty.isAbiInt(zcu)) field_signedness: {
10054 const field_int_info = field_ty.intInfo(zcu);
10055 break :field_signedness if (field_int_info.bits <= 16) field_int_info.signedness else null;
10056 } else null;
10057 const field_is_vector = field_size <= 16 and
10058 CallAbiIterator.homogeneousAggregateBaseType(zcu, field_ty.toIntern()) != null;
10059 if (parts_len > 0) combine: {
10060 const prev_part = &parts[parts_len - 1];
10061 const combined_size = field_end - prev_part.offset;
10062 if (combined_size > @as(u64, 1) << @min(
10063 min_part_log2_stride,
10064 alignment.toLog2Units(),
10065 @ctz(prev_part.offset),
10066 )) break :combine;
10067 prev_part.size = combined_size;
10068 prev_part.signedness = null;
10069 prev_part.is_vector &= field_is_vector;
10070 continue;
10071 }
10072 parts[parts_len] = .{
10073 .offset = field_begin,
10074 .size = field_size,
10075 .signedness = field_signedness,
10076 .is_vector = field_is_vector,
10077 };
10078 parts_len += 1;
10079 }
10080 vi.setParts(isel, parts_len);
10081 for (parts[0..parts_len]) |part| {
10082 const subpart_vi = vi.addPart(isel, part.offset - offset, part.size);
10083 if (part.signedness) |signedness| subpart_vi.setSignedness(isel, signedness);
10084 if (part.is_vector) subpart_vi.setIsVector(isel);
10085 }
10086 },
10087 .tuple_type => |tuple_type| {
10088 const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0;
10089 if (tuple_type.types.len > Value.max_parts and
10090 (std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts)
10091 return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)});
10092 const alignment = vi.alignment(isel);
10093 const Part = struct { offset: u64, size: u64, is_vector: bool };
10094 var parts: [Value.max_parts]Part = undefined;
10095 var parts_len: Value.PartsLen = 0;
10096 var field_end: u64 = 0;
10097 for (tuple_type.types.get(ip), tuple_type.values.get(ip)) |field_type, field_value| {
10098 if (field_value != .none) continue;
10099 const field_ty: ZigType = .fromInterned(field_type);
10100 const field_begin = field_ty.abiAlignment(zcu).forward(field_end);
10101 if (field_begin >= offset + size) break;
10102 const field_size = field_ty.abiSize(zcu);
10103 if (field_size == 0) continue;
10104 field_end = field_begin + field_size;
10105 if (field_end <= offset) continue;
10106 if (offset >= field_begin and offset + size <= field_begin + field_size) {
10107 ty = field_ty;
10108 ty_size = field_size;
10109 offset -= field_begin;
10110 continue :type_key ip.indexToKey(field_ty.toIntern());
10111 }
10112 const field_is_vector = field_size <= 16 and
10113 CallAbiIterator.homogeneousAggregateBaseType(zcu, field_ty.toIntern()) != null;
10114 if (parts_len > 0) combine: {
10115 const prev_part = &parts[parts_len - 1];
10116 const combined_size = field_end - prev_part.offset;
10117 if (combined_size > @as(u64, 1) << @min(
10118 min_part_log2_stride,
10119 alignment.toLog2Units(),
10120 @ctz(prev_part.offset),
10121 )) break :combine;
10122 prev_part.size = combined_size;
10123 prev_part.is_vector &= field_is_vector;
10124 continue;
10125 }
10126 parts[parts_len] = .{ .offset = field_begin, .size = field_size, .is_vector = field_is_vector };
10127 parts_len += 1;
10128 }
10129 vi.setParts(isel, parts_len);
10130 for (parts[0..parts_len]) |part| {
10131 const subpart_vi = vi.addPart(isel, part.offset - offset, part.size);
10132 if (part.is_vector) subpart_vi.setIsVector(isel);
10133 }
10134 },
10135 .union_type => {
10136 const loaded_union = ip.loadUnionType(ty.toIntern());
10137 switch (loaded_union.flagsUnordered(ip).layout) {
10138 .auto, .@"extern" => {},
10139 .@"packed" => continue :type_key .{ .int_type = .{
10140 .signedness = .unsigned,
10141 .bits = @intCast(ty.bitSize(zcu)),
10142 } },
10143 }
10144 const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0;
10145 if ((std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts)
10146 return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)});
10147 const union_layout = ZigType.getUnionLayout(loaded_union, zcu);
10148 const alignment = vi.alignment(isel);
10149 const tag_offset = union_layout.tagOffset();
10150 const payload_offset = union_layout.payloadOffset();
10151 const Part = struct { offset: u64, size: u64, signedness: ?std.builtin.Signedness };
10152 var parts: [2]Part = undefined;
10153 var parts_len: Value.PartsLen = 0;
10154 var field_end: u64 = 0;
10155 for (0..2) |field_index| {
10156 const field: enum { tag, payload } = switch (field_index) {
10157 0 => if (tag_offset < payload_offset) .tag else .payload,
10158 1 => if (tag_offset < payload_offset) .payload else .tag,
10159 else => unreachable,
10160 };
10161 const field_size, const field_begin = switch (field) {
10162 .tag => .{ union_layout.tag_size, tag_offset },
10163 .payload => .{ union_layout.payload_size, payload_offset },
10164 };
10165 if (field_begin >= offset + size) break;
10166 if (field_size == 0) continue;
10167 field_end = field_begin + field_size;
10168 if (field_end <= offset) continue;
10169 const field_signedness = field_signedness: switch (field) {
10170 .tag => {
10171 if (offset >= field_begin and offset + size <= field_begin + field_size) {
10172 ty = .fromInterned(loaded_union.enum_tag_ty);
10173 ty_size = field_size;
10174 offset -= field_begin;
10175 continue :type_key ip.indexToKey(loaded_union.enum_tag_ty);
10176 }
10177 break :field_signedness ip.indexToKey(loaded_union.loadTagType(ip).tag_ty).int_type.signedness;
10178 },
10179 .payload => null,
10180 };
10181 if (parts_len > 0) combine: {
10182 const prev_part = &parts[parts_len - 1];
10183 const combined_size = field_end - prev_part.offset;
10184 if (combined_size > @as(u64, 1) << @min(
10185 min_part_log2_stride,
10186 alignment.toLog2Units(),
10187 @ctz(prev_part.offset),
10188 )) break :combine;
10189 prev_part.size = combined_size;
10190 prev_part.signedness = null;
10191 continue;
10192 }
10193 parts[parts_len] = .{
10194 .offset = field_begin,
10195 .size = field_size,
10196 .signedness = field_signedness,
10197 };
10198 parts_len += 1;
10199 }
10200 vi.setParts(isel, parts_len);
10201 for (parts[0..parts_len]) |part| {
10202 const subpart_vi = vi.addPart(isel, part.offset - offset, part.size);
10203 if (part.signedness) |signedness| subpart_vi.setSignedness(isel, signedness);
10204 }
10205 },
10206 .opaque_type, .func_type => continue :type_key .{ .simple_type = .anyopaque },
10207 .enum_type => continue :type_key ip.indexToKey(ip.loadEnumType(ty.toIntern()).tag_ty),
10208 .error_set_type,
10209 .inferred_error_set_type,
10210 => continue :type_key .{ .simple_type = .anyerror },
10211 .undef,
10212 .simple_value,
10213 .variable,
10214 .@"extern",
10215 .func,
10216 .int,
10217 .err,
10218 .error_union,
10219 .enum_literal,
10220 .enum_tag,
10221 .empty_enum_value,
10222 .float,
10223 .ptr,
10224 .slice,
10225 .opt,
10226 .aggregate,
10227 .un,
10228 .memoized_call,
10229 => unreachable, // values, not types
10230 }
10231 }
10232 it.next_offset = next_offset + size;
10233 return .{ .offset = next_part_offset - next_offset, .vi = vi };
10234 }
10235
10236 fn only(it: *FieldPartIterator, isel: *Select) !?Value.Index {
10237 const part = try it.next(isel);
10238 assert(part.?.offset == 0);
10239 return if (try it.next(isel)) |_| null else part.?.vi;
10240 }
10241 };
10242
10243 const Materialize = struct {
10244 vi: Value.Index,
10245 ra: Register.Alias,
10246
10247 fn finish(mat: Value.Materialize, isel: *Select) error{ OutOfMemory, CodegenFail }!void {
10248 const live_vi = isel.live_registers.getPtr(mat.ra);
10249 assert(live_vi.* == .allocating);
10250 var vi = mat.vi;
10251 var offset: u64 = 0;
10252 const size = mat.vi.size(isel);
10253 free: while (true) {
10254 if (vi.register(isel)) |ra| {
10255 if (ra != mat.ra) break :free try isel.emit(if (vi == mat.vi) if (mat.ra.isVector()) switch (size) {
10256 else => unreachable,
10257 2 => .fmov(mat.ra.h(), .{ .register = ra.h() }),
10258 4 => .fmov(mat.ra.s(), .{ .register = ra.s() }),
10259 8 => .fmov(mat.ra.d(), .{ .register = ra.d() }),
10260 16 => .orr(mat.ra.@"16b"(), ra.@"16b"(), .{ .register = ra.@"16b"() }),
10261 } else switch (size) {
10262 else => unreachable,
10263 1...4 => .orr(mat.ra.w(), .wzr, .{ .register = ra.w() }),
10264 5...8 => .orr(mat.ra.x(), .xzr, .{ .register = ra.x() }),
10265 } else switch (offset + size) {
10266 else => unreachable,
10267 1...4 => |end_offset| switch (mat.vi.signedness(isel)) {
10268 .signed => .sbfm(mat.ra.w(), ra.w(), .{
10269 .N = .word,
10270 .immr = @intCast(8 * offset),
10271 .imms = @intCast(8 * end_offset - 1),
10272 }),
10273 .unsigned => .ubfm(mat.ra.w(), ra.w(), .{
10274 .N = .word,
10275 .immr = @intCast(8 * offset),
10276 .imms = @intCast(8 * end_offset - 1),
10277 }),
10278 },
10279 5...8 => |end_offset| switch (mat.vi.signedness(isel)) {
10280 .signed => .sbfm(mat.ra.x(), ra.x(), .{
10281 .N = .doubleword,
10282 .immr = @intCast(8 * offset),
10283 .imms = @intCast(8 * end_offset - 1),
10284 }),
10285 .unsigned => .ubfm(mat.ra.x(), ra.x(), .{
10286 .N = .doubleword,
10287 .immr = @intCast(8 * offset),
10288 .imms = @intCast(8 * end_offset - 1),
10289 }),
10290 },
10291 });
10292 mat.vi.get(isel).location_payload.small.register = mat.ra;
10293 live_vi.* = mat.vi;
10294 return;
10295 }
10296 offset += vi.get(isel).offset_from_parent;
10297 switch (vi.parent(isel)) {
10298 .unallocated => {
10299 mat.vi.get(isel).location_payload.small.register = mat.ra;
10300 live_vi.* = mat.vi;
10301 return;
10302 },
10303 .stack_slot => |stack_slot| break :free try isel.loadReg(
10304 mat.ra,
10305 size,
10306 mat.vi.signedness(isel),
10307 stack_slot.base,
10308 @as(i65, stack_slot.offset) + offset,
10309 ),
10310 .address => |base_vi| {
10311 const base_mat = try base_vi.matReg(isel);
10312 try isel.loadReg(mat.ra, size, mat.vi.signedness(isel), base_mat.ra, offset);
10313 break :free try base_mat.finish(isel);
10314 },
10315 .value => |parent_vi| vi = parent_vi,
10316 .constant => |initial_constant| {
10317 const zcu = isel.pt.zcu;
10318 const ip = &zcu.intern_pool;
10319 var constant = initial_constant.toIntern();
10320 var constant_key = ip.indexToKey(constant);
10321 while (true) {
10322 constant_key: switch (constant_key) {
10323 .int_type,
10324 .ptr_type,
10325 .array_type,
10326 .vector_type,
10327 .opt_type,
10328 .anyframe_type,
10329 .error_union_type,
10330 .simple_type,
10331 .struct_type,
10332 .tuple_type,
10333 .union_type,
10334 .opaque_type,
10335 .enum_type,
10336 .func_type,
10337 .error_set_type,
10338 .inferred_error_set_type,
10339
10340 .enum_literal,
10341 .empty_enum_value,
10342 .memoized_call,
10343 => unreachable, // not a runtime value
10344 .undef => break :free try isel.emit(if (mat.ra.isVector()) .movi(switch (size) {
10345 else => unreachable,
10346 1...8 => mat.ra.@"8b"(),
10347 9...16 => mat.ra.@"16b"(),
10348 }, 0xaa, .{ .lsl = 0 }) else switch (size) {
10349 else => unreachable,
10350 1...4 => .orr(mat.ra.w(), .wzr, .{ .immediate = .{
10351 .N = .word,
10352 .immr = 0b000001,
10353 .imms = 0b111100,
10354 } }),
10355 5...8 => .orr(mat.ra.x(), .xzr, .{ .immediate = .{
10356 .N = .word,
10357 .immr = 0b000001,
10358 .imms = 0b111100,
10359 } }),
10360 }),
10361 .simple_value => |simple_value| switch (simple_value) {
10362 .undefined, .void, .null, .empty_tuple, .@"unreachable" => unreachable,
10363 .true => continue :constant_key .{ .int = .{
10364 .ty = .bool_type,
10365 .storage = .{ .u64 = 1 },
10366 } },
10367 .false => continue :constant_key .{ .int = .{
10368 .ty = .bool_type,
10369 .storage = .{ .u64 = 0 },
10370 } },
10371 },
10372 .int => |int| break :free storage: switch (int.storage) {
10373 .u64 => |imm| try isel.movImmediate(switch (size) {
10374 else => unreachable,
10375 1...4 => mat.ra.w(),
10376 5...8 => mat.ra.x(),
10377 }, @bitCast(std.math.shr(u64, imm, 8 * offset))),
10378 .i64 => |imm| switch (size) {
10379 else => unreachable,
10380 1...4 => try isel.movImmediate(mat.ra.w(), @as(u32, @bitCast(@as(i32, @truncate(std.math.shr(i64, imm, 8 * offset)))))),
10381 5...8 => try isel.movImmediate(mat.ra.x(), @bitCast(std.math.shr(i64, imm, 8 * offset))),
10382 },
10383 .big_int => |big_int| {
10384 assert(size == 8);
10385 var imm: u64 = 0;
10386 const limb_bits = @bitSizeOf(std.math.big.Limb);
10387 const limbs = @divExact(64, limb_bits);
10388 var limb_index: usize = @intCast(@divExact(offset, @divExact(limb_bits, 8)) + limbs);
10389 for (0..limbs) |_| {
10390 limb_index -= 1;
10391 if (limb_index >= big_int.limbs.len) continue;
10392 if (limb_bits < 64) imm <<= limb_bits;
10393 imm |= big_int.limbs[limb_index];
10394 }
10395 if (!big_int.positive) {
10396 limb_index = @min(limb_index, big_int.limbs.len);
10397 imm = while (limb_index > 0) {
10398 limb_index -= 1;
10399 if (big_int.limbs[limb_index] != 0) break ~imm;
10400 } else -%imm;
10401 }
10402 try isel.movImmediate(mat.ra.x(), imm);
10403 },
10404 .lazy_align => |ty| continue :storage .{
10405 .u64 = ZigType.fromInterned(ty).abiAlignment(zcu).toByteUnits().?,
10406 },
10407 .lazy_size => |ty| continue :storage .{
10408 .u64 = ZigType.fromInterned(ty).abiSize(zcu),
10409 },
10410 },
10411 .err => |err| continue :constant_key .{ .int = .{
10412 .ty = err.ty,
10413 .storage = .{ .u64 = ip.getErrorValueIfExists(err.name).? },
10414 } },
10415 .error_union => |error_union| {
10416 const error_union_type = ip.indexToKey(error_union.ty).error_union_type;
10417 const error_set_ty: ZigType = .fromInterned(error_union_type.error_set_type);
10418 const payload_ty: ZigType = .fromInterned(error_union_type.payload_type);
10419 const error_set_offset = codegen.errUnionErrorOffset(payload_ty, zcu);
10420 const error_set_size = error_set_ty.abiSize(zcu);
10421 if (offset >= error_set_offset and offset + size <= error_set_offset + error_set_size) {
10422 offset -= error_set_offset;
10423 continue :constant_key switch (error_union.val) {
10424 .err_name => |err_name| .{ .err = .{
10425 .ty = error_union_type.error_set_type,
10426 .name = err_name,
10427 } },
10428 .payload => .{ .int = .{
10429 .ty = error_union_type.error_set_type,
10430 .storage = .{ .u64 = 0 },
10431 } },
10432 };
10433 }
10434 const payload_offset = codegen.errUnionPayloadOffset(payload_ty, zcu);
10435 const payload_size = payload_ty.abiSize(zcu);
10436 if (offset >= payload_offset and offset + size <= payload_offset + payload_size) {
10437 offset -= payload_offset;
10438 switch (error_union.val) {
10439 .err_name => continue :constant_key .{ .undef = error_union_type.payload_type },
10440 .payload => |payload| {
10441 constant = payload;
10442 constant_key = ip.indexToKey(payload);
10443 continue :constant_key constant_key;
10444 },
10445 }
10446 }
10447 },
10448 .enum_tag => |enum_tag| continue :constant_key .{ .int = ip.indexToKey(enum_tag.int).int },
10449 .float => |float| storage: switch (float.storage) {
10450 .f16 => |imm| {
10451 if (!mat.ra.isVector()) continue :constant_key .{ .int = .{
10452 .ty = .u16_type,
10453 .storage = .{ .u64 = @as(u16, @bitCast(imm)) },
10454 } };
10455 const feat_fp16 = isel.target.cpu.has(.aarch64, .fullfp16);
10456 if (feat_fp16) {
10457 const Repr = std.math.FloatRepr(f16);
10458 const repr: Repr = @bitCast(imm);
10459 if (repr.mantissa & std.math.maxInt(Repr.Mantissa) >> 5 == 0 and switch (repr.exponent) {
10460 .denormal, .infinite => false,
10461 else => std.math.cast(i3, repr.exponent.unbias() - 1) != null,
10462 }) break :free try isel.emit(.fmov(mat.ra.h(), .{ .immediate = imm }));
10463 }
10464 const bits: u16 = @bitCast(imm);
10465 if (bits == 0) break :free try isel.emit(.movi(mat.ra.d(), 0b00000000, .replicate));
10466 if (bits & std.math.maxInt(u8) == 0) break :free try isel.emit(.movi(
10467 mat.ra.@"4h"(),
10468 @intCast(@shrExact(bits, 8)),
10469 .{ .lsl = 8 },
10470 ));
10471 const temp_ra = try isel.allocIntReg();
10472 defer isel.freeReg(temp_ra);
10473 try isel.emit(.fmov(if (feat_fp16) mat.ra.h() else mat.ra.s(), .{ .register = temp_ra.w() }));
10474 break :free try isel.movImmediate(temp_ra.w(), bits);
10475 },
10476 .f32 => |imm| {
10477 if (!mat.ra.isVector()) continue :constant_key .{ .int = .{
10478 .ty = .u32_type,
10479 .storage = .{ .u64 = @as(u32, @bitCast(imm)) },
10480 } };
10481 const Repr = std.math.FloatRepr(f32);
10482 const repr: Repr = @bitCast(imm);
10483 if (repr.mantissa & std.math.maxInt(Repr.Mantissa) >> 5 == 0 and switch (repr.exponent) {
10484 .denormal, .infinite => false,
10485 else => std.math.cast(i3, repr.exponent.unbias() - 1) != null,
10486 }) break :free try isel.emit(.fmov(mat.ra.s(), .{ .immediate = @floatCast(imm) }));
10487 const bits: u32 = @bitCast(imm);
10488 if (bits == 0) break :free try isel.emit(.movi(mat.ra.d(), 0b00000000, .replicate));
10489 if (bits & std.math.maxInt(u24) == 0) break :free try isel.emit(.movi(
10490 mat.ra.@"2s"(),
10491 @intCast(@shrExact(bits, 24)),
10492 .{ .lsl = 24 },
10493 ));
10494 const temp_ra = try isel.allocIntReg();
10495 defer isel.freeReg(temp_ra);
10496 try isel.emit(.fmov(mat.ra.s(), .{ .register = temp_ra.w() }));
10497 break :free try isel.movImmediate(temp_ra.w(), bits);
10498 },
10499 .f64 => |imm| {
10500 if (!mat.ra.isVector()) continue :constant_key .{ .int = .{
10501 .ty = .u64_type,
10502 .storage = .{ .u64 = @as(u64, @bitCast(imm)) },
10503 } };
10504 const Repr = std.math.FloatRepr(f64);
10505 const repr: Repr = @bitCast(imm);
10506 if (repr.mantissa & std.math.maxInt(Repr.Mantissa) >> 5 == 0 and switch (repr.exponent) {
10507 .denormal, .infinite => false,
10508 else => std.math.cast(i3, repr.exponent.unbias() - 1) != null,
10509 }) break :free try isel.emit(.fmov(mat.ra.d(), .{ .immediate = @floatCast(imm) }));
10510 const bits: u64 = @bitCast(imm);
10511 if (bits == 0) break :free try isel.emit(.movi(mat.ra.d(), 0b00000000, .replicate));
10512 const temp_ra = try isel.allocIntReg();
10513 defer isel.freeReg(temp_ra);
10514 try isel.emit(.fmov(mat.ra.d(), .{ .register = temp_ra.x() }));
10515 break :free try isel.movImmediate(temp_ra.x(), bits);
10516 },
10517 .f80 => |imm| break :free try isel.movImmediate(
10518 mat.ra.x(),
10519 @truncate(std.math.shr(u80, @bitCast(imm), 8 * offset)),
10520 ),
10521 .f128 => |imm| switch (ZigType.fromInterned(float.ty).floatBits(isel.target)) {
10522 else => unreachable,
10523 16 => continue :storage .{ .f16 = @floatCast(imm) },
10524 32 => continue :storage .{ .f32 = @floatCast(imm) },
10525 64 => continue :storage .{ .f64 = @floatCast(imm) },
10526 128 => {
10527 const bits: u128 = @bitCast(imm);
10528 const hi64: u64 = @intCast(bits >> 64);
10529 const lo64: u64 = @truncate(bits >> 0);
10530 const temp_ra = try isel.allocIntReg();
10531 defer isel.freeReg(temp_ra);
10532 switch (hi64) {
10533 0 => {},
10534 else => {
10535 try isel.emit(.fmov(mat.ra.@"d[]"(1), .{ .register = temp_ra.x() }));
10536 try isel.movImmediate(temp_ra.x(), hi64);
10537 },
10538 }
10539 break :free switch (lo64) {
10540 0 => try isel.emit(.movi(switch (hi64) {
10541 else => mat.ra.d(),
10542 0 => mat.ra.@"2d"(),
10543 }, 0b00000000, .replicate)),
10544 else => {
10545 try isel.emit(.fmov(mat.ra.d(), .{ .register = temp_ra.x() }));
10546 try isel.movImmediate(temp_ra.x(), lo64);
10547 },
10548 };
10549 },
10550 },
10551 },
10552 .ptr => |ptr| {
10553 assert(offset == 0 and size == 8);
10554 break :free switch (ptr.base_addr) {
10555 .nav => |nav| if (ZigType.fromInterned(ip.getNav(nav).typeOf(ip)).isFnOrHasRuntimeBits(zcu)) switch (true) {
10556 false => {
10557 try isel.nav_relocs.append(zcu.gpa, .{
10558 .nav = nav,
10559 .reloc = .{
10560 .label = @intCast(isel.instructions.items.len),
10561 .addend = ptr.byte_offset,
10562 },
10563 });
10564 try isel.emit(.adr(mat.ra.x(), 0));
10565 },
10566 true => {
10567 try isel.nav_relocs.append(zcu.gpa, .{
10568 .nav = nav,
10569 .reloc = .{
10570 .label = @intCast(isel.instructions.items.len),
10571 .addend = ptr.byte_offset,
10572 },
10573 });
10574 try isel.emit(.add(mat.ra.x(), mat.ra.x(), .{ .immediate = 0 }));
10575 try isel.nav_relocs.append(zcu.gpa, .{
10576 .nav = nav,
10577 .reloc = .{
10578 .label = @intCast(isel.instructions.items.len),
10579 .addend = ptr.byte_offset,
10580 },
10581 });
10582 try isel.emit(.adrp(mat.ra.x(), 0));
10583 },
10584 } else continue :constant_key .{ .int = .{
10585 .ty = .usize_type,
10586 .storage = .{ .u64 = isel.pt.navAlignment(nav).forward(0xaaaaaaaaaaaaaaaa) },
10587 } },
10588 .uav => |uav| if (ZigType.fromInterned(ip.typeOf(uav.val)).isFnOrHasRuntimeBits(zcu)) switch (true) {
10589 false => {
10590 try isel.uav_relocs.append(zcu.gpa, .{
10591 .uav = uav,
10592 .reloc = .{
10593 .label = @intCast(isel.instructions.items.len),
10594 .addend = ptr.byte_offset,
10595 },
10596 });
10597 try isel.emit(.adr(mat.ra.x(), 0));
10598 },
10599 true => {
10600 try isel.uav_relocs.append(zcu.gpa, .{
10601 .uav = uav,
10602 .reloc = .{
10603 .label = @intCast(isel.instructions.items.len),
10604 .addend = ptr.byte_offset,
10605 },
10606 });
10607 try isel.emit(.add(mat.ra.x(), mat.ra.x(), .{ .immediate = 0 }));
10608 try isel.uav_relocs.append(zcu.gpa, .{
10609 .uav = uav,
10610 .reloc = .{
10611 .label = @intCast(isel.instructions.items.len),
10612 .addend = ptr.byte_offset,
10613 },
10614 });
10615 try isel.emit(.adrp(mat.ra.x(), 0));
10616 },
10617 } else continue :constant_key .{ .int = .{
10618 .ty = .usize_type,
10619 .storage = .{ .u64 = ZigType.fromInterned(uav.orig_ty).ptrAlignment(zcu).forward(0xaaaaaaaaaaaaaaaa) },
10620 } },
10621 .int => continue :constant_key .{ .int = .{
10622 .ty = .usize_type,
10623 .storage = .{ .u64 = ptr.byte_offset },
10624 } },
10625 .eu_payload => |base| {
10626 var base_ptr = ip.indexToKey(base).ptr;
10627 const eu_ty = ip.indexToKey(base_ptr.ty).ptr_type.child;
10628 const payload_ty = ip.indexToKey(eu_ty).error_union_type.payload_type;
10629 base_ptr.byte_offset += codegen.errUnionPayloadOffset(.fromInterned(payload_ty), zcu) + ptr.byte_offset;
10630 continue :constant_key .{ .ptr = base_ptr };
10631 },
10632 .opt_payload => |base| {
10633 var base_ptr = ip.indexToKey(base).ptr;
10634 base_ptr.byte_offset += ptr.byte_offset;
10635 continue :constant_key .{ .ptr = base_ptr };
10636 },
10637 .field => |field| {
10638 var base_ptr = ip.indexToKey(field.base).ptr;
10639 const agg_ty: ZigType = .fromInterned(ip.indexToKey(base_ptr.ty).ptr_type.child);
10640 base_ptr.byte_offset += agg_ty.structFieldOffset(@intCast(field.index), zcu) + ptr.byte_offset;
10641 continue :constant_key .{ .ptr = base_ptr };
10642 },
10643 .comptime_alloc, .comptime_field, .arr_elem => unreachable,
10644 };
10645 },
10646 .slice => |slice| switch (offset) {
10647 0 => continue :constant_key switch (ip.indexToKey(slice.ptr)) {
10648 else => unreachable,
10649 .undef => |undef| .{ .undef = undef },
10650 .ptr => |ptr| .{ .ptr = ptr },
10651 },
10652 else => {
10653 assert(offset == @divExact(isel.target.ptrBitWidth(), 8));
10654 offset = 0;
10655 continue :constant_key .{ .int = ip.indexToKey(slice.len).int };
10656 },
10657 },
10658 .opt => |opt| {
10659 const child_ty = ip.indexToKey(opt.ty).opt_type;
10660 const child_size = ZigType.fromInterned(child_ty).abiSize(zcu);
10661 if (offset == child_size and size == 1) {
10662 offset = 0;
10663 continue :constant_key .{ .simple_value = switch (opt.val) {
10664 .none => .false,
10665 else => .true,
10666 } };
10667 }
10668 const opt_ty: ZigType = .fromInterned(opt.ty);
10669 if (offset + size <= child_size) continue :constant_key switch (opt.val) {
10670 .none => if (opt_ty.optionalReprIsPayload(zcu)) .{ .int = .{
10671 .ty = opt.ty,
10672 .storage = .{ .u64 = 0 },
10673 } } else .{ .undef = child_ty },
10674 else => |child| {
10675 constant = child;
10676 constant_key = ip.indexToKey(child);
10677 continue :constant_key constant_key;
10678 },
10679 };
10680 },
10681 .aggregate => |aggregate| switch (ip.indexToKey(aggregate.ty)) {
10682 else => unreachable,
10683 .array_type => |array_type| {
10684 const elem_size = ZigType.fromInterned(array_type.child).abiSize(zcu);
10685 const elem_offset = @mod(offset, elem_size);
10686 if (size <= elem_size - elem_offset) {
10687 defer offset = elem_offset;
10688 continue :constant_key switch (aggregate.storage) {
10689 .bytes => |bytes| .{ .int = .{ .ty = .u8_type, .storage = .{
10690 .u64 = bytes.toSlice(array_type.lenIncludingSentinel(), ip)[@intCast(@divFloor(offset, elem_size))],
10691 } } },
10692 .elems => |elems| {
10693 constant = elems[@intCast(@divFloor(offset, elem_size))];
10694 constant_key = ip.indexToKey(constant);
10695 continue :constant_key constant_key;
10696 },
10697 .repeated_elem => |repeated_elem| {
10698 constant = repeated_elem;
10699 constant_key = ip.indexToKey(repeated_elem);
10700 continue :constant_key constant_key;
10701 },
10702 };
10703 }
10704 },
10705 .vector_type => {},
10706 .struct_type => {
10707 const loaded_struct = ip.loadStructType(aggregate.ty);
10708 switch (loaded_struct.layout) {
10709 .auto => {
10710 var field_offset: u64 = 0;
10711 var field_it = loaded_struct.iterateRuntimeOrder(ip);
10712 while (field_it.next()) |field_index| {
10713 if (loaded_struct.fieldIsComptime(ip, field_index)) continue;
10714 const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
10715 field_offset = field_ty.structFieldAlignment(
10716 loaded_struct.fieldAlign(ip, field_index),
10717 loaded_struct.layout,
10718 zcu,
10719 ).forward(field_offset);
10720 const field_size = field_ty.abiSize(zcu);
10721 if (offset >= field_offset and offset + size <= field_offset + field_size) {
10722 offset -= field_offset;
10723 constant = switch (aggregate.storage) {
10724 .bytes => unreachable,
10725 .elems => |elems| elems[field_index],
10726 .repeated_elem => |repeated_elem| repeated_elem,
10727 };
10728 constant_key = ip.indexToKey(constant);
10729 continue :constant_key constant_key;
10730 }
10731 field_offset += field_size;
10732 }
10733 },
10734 .@"extern", .@"packed" => {},
10735 }
10736 },
10737 .tuple_type => |tuple_type| {
10738 var field_offset: u64 = 0;
10739 for (tuple_type.types.get(ip), tuple_type.values.get(ip), 0..) |field_type, field_value, field_index| {
10740 if (field_value != .none) continue;
10741 const field_ty: ZigType = .fromInterned(field_type);
10742 field_offset = field_ty.abiAlignment(zcu).forward(field_offset);
10743 const field_size = field_ty.abiSize(zcu);
10744 if (offset >= field_offset and offset + size <= field_offset + field_size) {
10745 offset -= field_offset;
10746 constant = switch (aggregate.storage) {
10747 .bytes => unreachable,
10748 .elems => |elems| elems[field_index],
10749 .repeated_elem => |repeated_elem| repeated_elem,
10750 };
10751 constant_key = ip.indexToKey(constant);
10752 continue :constant_key constant_key;
10753 }
10754 field_offset += field_size;
10755 }
10756 },
10757 },
10758 else => {},
10759 }
10760 var buffer: [16]u8 = @splat(0);
10761 if (ZigType.fromInterned(constant_key.typeOf()).abiSize(zcu) <= buffer.len and
10762 try isel.writeToMemory(.fromInterned(constant), &buffer))
10763 {
10764 constant_key = if (mat.ra.isVector()) .{ .float = switch (size) {
10765 else => unreachable,
10766 2 => .{ .ty = .f16_type, .storage = .{ .f16 = @bitCast(std.mem.readInt(
10767 u16,
10768 buffer[@intCast(offset)..][0..2],
10769 isel.target.cpu.arch.endian(),
10770 )) } },
10771 4 => .{ .ty = .f32_type, .storage = .{ .f32 = @bitCast(std.mem.readInt(
10772 u32,
10773 buffer[@intCast(offset)..][0..4],
10774 isel.target.cpu.arch.endian(),
10775 )) } },
10776 8 => .{ .ty = .f64_type, .storage = .{ .f64 = @bitCast(std.mem.readInt(
10777 u64,
10778 buffer[@intCast(offset)..][0..8],
10779 isel.target.cpu.arch.endian(),
10780 )) } },
10781 16 => .{ .ty = .f128_type, .storage = .{ .f128 = @bitCast(std.mem.readInt(
10782 u128,
10783 buffer[@intCast(offset)..][0..16],
10784 isel.target.cpu.arch.endian(),
10785 )) } },
10786 } } else .{ .int = .{
10787 .ty = .u64_type,
10788 .storage = .{ .u64 = switch (size) {
10789 else => unreachable,
10790 inline 1...8 => |ct_size| std.mem.readInt(
10791 @Type(.{ .int = .{ .signedness = .unsigned, .bits = 8 * ct_size } }),
10792 buffer[@intCast(offset)..][0..ct_size],
10793 isel.target.cpu.arch.endian(),
10794 ),
10795 } },
10796 } };
10797 offset = 0;
10798 continue;
10799 }
10800 return isel.fail("unsupported value <{f}, {f}>", .{
10801 isel.fmtType(.fromInterned(constant_key.typeOf())),
10802 isel.fmtConstant(.fromInterned(constant)),
10803 });
10804 }
10805 },
10806 }
10807 }
10808 live_vi.* = .free;
10809 }
10810 };
10811};
10812fn initValue(isel: *Select, ty: ZigType) Value.Index {
10813 const zcu = isel.pt.zcu;
10814 return isel.initValueAdvanced(ty.abiAlignment(zcu), 0, ty.abiSize(zcu));
10815}
10816fn initValueAdvanced(
10817 isel: *Select,
10818 parent_alignment: InternPool.Alignment,
10819 offset_from_parent: u64,
10820 size: u64,
10821) Value.Index {
10822 defer isel.values.addOneAssumeCapacity().* = .{
10823 .refs = 0,
10824 .flags = .{
10825 .alignment = .fromLog2Units(@min(parent_alignment.toLog2Units(), @ctz(offset_from_parent))),
10826 .parent_tag = .unallocated,
10827 .location_tag = if (size > 16) .large else .small,
10828 .parts_len_minus_one = 0,
10829 },
10830 .offset_from_parent = offset_from_parent,
10831 .parent_payload = .{ .unallocated = {} },
10832 .location_payload = if (size > 16) .{ .large = .{
10833 .size = size,
10834 } } else .{ .small = .{
10835 .size = @intCast(size),
10836 .signedness = .unsigned,
10837 .is_vector = false,
10838 .hint = .zr,
10839 .register = .zr,
10840 } },
10841 .parts = undefined,
10842 };
10843 return @enumFromInt(isel.values.items.len);
10844}
10845pub fn dumpValues(isel: *Select, which: enum { only_referenced, all }) void {
10846 errdefer |err| @panic(@errorName(err));
10847 const stderr = std.debug.lockStderrWriter(&.{});
10848 defer std.debug.unlockStderrWriter();
10849
10850 const zcu = isel.pt.zcu;
10851 const gpa = zcu.gpa;
10852 const ip = &zcu.intern_pool;
10853 const nav = ip.getNav(isel.nav_index);
10854
10855 var reverse_live_values: std.AutoArrayHashMapUnmanaged(Value.Index, std.ArrayListUnmanaged(Air.Inst.Index)) = .empty;
10856 defer {
10857 for (reverse_live_values.values()) |*list| list.deinit(gpa);
10858 reverse_live_values.deinit(gpa);
10859 }
10860 {
10861 try reverse_live_values.ensureTotalCapacity(gpa, isel.live_values.count());
10862 var live_val_it = isel.live_values.iterator();
10863 while (live_val_it.next()) |live_val_entry| switch (live_val_entry.value_ptr.*) {
10864 _ => {
10865 const gop = reverse_live_values.getOrPutAssumeCapacity(live_val_entry.value_ptr.*);
10866 if (!gop.found_existing) gop.value_ptr.* = .empty;
10867 try gop.value_ptr.append(gpa, live_val_entry.key_ptr.*);
10868 },
10869 .allocating, .free => unreachable,
10870 };
10871 }
10872
10873 var reverse_live_registers: std.AutoHashMapUnmanaged(Value.Index, Register.Alias) = .empty;
10874 defer reverse_live_registers.deinit(gpa);
10875 {
10876 try reverse_live_registers.ensureTotalCapacity(gpa, @typeInfo(Register.Alias).@"enum".fields.len);
10877 var live_reg_it = isel.live_registers.iterator();
10878 while (live_reg_it.next()) |live_reg_entry| switch (live_reg_entry.value.*) {
10879 _ => reverse_live_registers.putAssumeCapacityNoClobber(live_reg_entry.value.*, live_reg_entry.key),
10880 .allocating, .free => {},
10881 };
10882 }
10883
10884 var roots: std.AutoArrayHashMapUnmanaged(Value.Index, u32) = .empty;
10885 defer roots.deinit(gpa);
10886 {
10887 try roots.ensureTotalCapacity(gpa, isel.values.items.len);
10888 var vi: Value.Index = @enumFromInt(isel.values.items.len);
10889 while (@intFromEnum(vi) > 0) {
10890 vi = @enumFromInt(@intFromEnum(vi) - 1);
10891 if (which == .only_referenced and vi.get(isel).refs == 0) continue;
10892 while (true) switch (vi.parent(isel)) {
10893 .unallocated, .stack_slot, .constant => break,
10894 .value => |parent_vi| vi = parent_vi,
10895 .address => |address_vi| break roots.putAssumeCapacity(address_vi, 0),
10896 };
10897 roots.putAssumeCapacity(vi, 0);
10898 }
10899 }
10900
10901 try stderr.print("# Begin {s} Value Dump: {f}:\n", .{ @typeName(Select), nav.fqn.fmt(ip) });
10902 while (roots.pop()) |root_entry| {
10903 const vi = root_entry.key;
10904 const value = vi.get(isel);
10905 try stderr.splatByteAll(' ', 2 * (@as(usize, 1) + root_entry.value));
10906 try stderr.print("${d}", .{@intFromEnum(vi)});
10907 {
10908 var first = true;
10909 if (reverse_live_values.get(vi)) |aiis| for (aiis.items) |aii| {
10910 if (aii == Block.main) {
10911 try stderr.print("{s}%main", .{if (first) " <- " else ", "});
10912 } else {
10913 try stderr.print("{s}%{d}", .{ if (first) " <- " else ", ", @intFromEnum(aii) });
10914 }
10915 first = false;
10916 };
10917 if (reverse_live_registers.get(vi)) |ra| {
10918 try stderr.print("{s}{s}", .{ if (first) " <- " else ", ", @tagName(ra) });
10919 first = false;
10920 }
10921 }
10922 try stderr.writeByte(':');
10923 switch (value.flags.parent_tag) {
10924 .unallocated => if (value.offset_from_parent != 0) try stderr.print(" +0x{x}", .{value.offset_from_parent}),
10925 .stack_slot => {
10926 try stderr.print(" [{s}, #{s}0x{x}", .{
10927 @tagName(value.parent_payload.stack_slot.base),
10928 if (value.parent_payload.stack_slot.offset < 0) "-" else "",
10929 @abs(value.parent_payload.stack_slot.offset),
10930 });
10931 if (value.offset_from_parent != 0) try stderr.print("+0x{x}", .{value.offset_from_parent});
10932 try stderr.writeByte(']');
10933 },
10934 .value => try stderr.print(" ${d}+0x{x}", .{ @intFromEnum(value.parent_payload.value), value.offset_from_parent }),
10935 .address => try stderr.print(" ${d}[0x{x}]", .{ @intFromEnum(value.parent_payload.address), value.offset_from_parent }),
10936 .constant => try stderr.print(" <{f}, {f}>", .{
10937 isel.fmtType(value.parent_payload.constant.typeOf(zcu)),
10938 isel.fmtConstant(value.parent_payload.constant),
10939 }),
10940 }
10941 try stderr.print(" align({s})", .{@tagName(value.flags.alignment)});
10942 switch (value.flags.location_tag) {
10943 .large => try stderr.print(" size=0x{x} large", .{value.location_payload.large.size}),
10944 .small => {
10945 const loc = value.location_payload.small;
10946 try stderr.print(" size=0x{x}", .{loc.size});
10947 switch (loc.signedness) {
10948 .unsigned => {},
10949 .signed => try stderr.writeAll(" signed"),
10950 }
10951 if (loc.hint != .zr) try stderr.print(" hint={s}", .{@tagName(loc.hint)});
10952 if (loc.register != .zr) try stderr.print(" loc={s}", .{@tagName(loc.register)});
10953 },
10954 }
10955 try stderr.print(" refs={d}\n", .{value.refs});
10956
10957 var part_index = value.flags.parts_len_minus_one;
10958 if (part_index > 0) while (true) : (part_index -= 1) {
10959 roots.putAssumeCapacityNoClobber(
10960 @enumFromInt(@intFromEnum(value.parts) + part_index),
10961 root_entry.value + 1,
10962 );
10963 if (part_index == 0) break;
10964 };
10965 }
10966 try stderr.print("# End {s} Value Dump: {f}\n\n", .{ @typeName(Select), nav.fqn.fmt(ip) });
10967}
10968
10969fn hasRepeatedByteRepr(isel: *Select, constant: Constant) error{OutOfMemory}!?u8 {
10970 const zcu = isel.pt.zcu;
10971 const ty = constant.typeOf(zcu);
10972 const abi_size = std.math.cast(usize, ty.abiSize(zcu)) orelse return null;
10973 const byte_buffer = try zcu.gpa.alloc(u8, abi_size);
10974 defer zcu.gpa.free(byte_buffer);
10975 return if (try isel.writeToMemory(constant, byte_buffer) and
10976 std.mem.allEqual(u8, byte_buffer[1..], byte_buffer[0])) byte_buffer[0] else null;
10977}
10978
10979fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMemory}!bool {
10980 const zcu = isel.pt.zcu;
10981 const ip = &zcu.intern_pool;
10982 if (try isel.writeKeyToMemory(ip.indexToKey(constant.toIntern()), buffer)) return true;
10983 constant.writeToMemory(isel.pt, buffer) catch |err| switch (err) {
10984 error.OutOfMemory => return error.OutOfMemory,
10985 error.ReinterpretDeclRef, error.Unimplemented, error.IllDefinedMemoryLayout => return false,
10986 };
10987 return true;
10988}
10989fn writeKeyToMemory(isel: *Select, constant_key: InternPool.Key, buffer: []u8) error{OutOfMemory}!bool {
10990 const zcu = isel.pt.zcu;
10991 const ip = &zcu.intern_pool;
10992 switch (constant_key) {
10993 .int_type,
10994 .ptr_type,
10995 .array_type,
10996 .vector_type,
10997 .opt_type,
10998 .anyframe_type,
10999 .error_union_type,
11000 .simple_type,
11001 .struct_type,
11002 .tuple_type,
11003 .union_type,
11004 .opaque_type,
11005 .enum_type,
11006 .func_type,
11007 .error_set_type,
11008 .inferred_error_set_type,
11009
11010 .enum_literal,
11011 .empty_enum_value,
11012 .memoized_call,
11013 => unreachable, // not a runtime value
11014 .err => |err| {
11015 const error_int = ip.getErrorValueIfExists(err.name).?;
11016 switch (buffer.len) {
11017 else => unreachable,
11018 inline 1...4 => |size| std.mem.writeInt(
11019 @Type(.{ .int = .{ .signedness = .unsigned, .bits = 8 * size } }),
11020 buffer[0..size],
11021 @intCast(error_int),
11022 isel.target.cpu.arch.endian(),
11023 ),
11024 }
11025 },
11026 .error_union => |error_union| {
11027 const error_union_type = ip.indexToKey(error_union.ty).error_union_type;
11028 const error_set_ty: ZigType = .fromInterned(error_union_type.error_set_type);
11029 const payload_ty: ZigType = .fromInterned(error_union_type.payload_type);
11030 const error_set = buffer[@intCast(codegen.errUnionErrorOffset(payload_ty, zcu))..][0..@intCast(error_set_ty.abiSize(zcu))];
11031 switch (error_union.val) {
11032 .err_name => |err_name| if (!try isel.writeKeyToMemory(.{ .err = .{
11033 .ty = error_set_ty.toIntern(),
11034 .name = err_name,
11035 } }, error_set)) return false,
11036 .payload => |payload| {
11037 if (!try isel.writeToMemory(
11038 .fromInterned(payload),
11039 buffer[@intCast(codegen.errUnionPayloadOffset(payload_ty, zcu))..][0..@intCast(payload_ty.abiSize(zcu))],
11040 )) return false;
11041 @memset(error_set, 0);
11042 },
11043 }
11044 },
11045 .opt => |opt| {
11046 const child_size: usize = @intCast(ZigType.fromInterned(ip.indexToKey(opt.ty).opt_type).abiSize(zcu));
11047 switch (opt.val) {
11048 .none => if (!ZigType.fromInterned(opt.ty).optionalReprIsPayload(zcu)) {
11049 buffer[child_size] = @intFromBool(false);
11050 } else @memset(buffer[0..child_size], 0x00),
11051 else => |child_constant| {
11052 if (!try isel.writeToMemory(.fromInterned(child_constant), buffer[0..child_size])) return false;
11053 if (!ZigType.fromInterned(opt.ty).optionalReprIsPayload(zcu)) buffer[child_size] = @intFromBool(true);
11054 },
11055 }
11056 },
11057 .aggregate => |aggregate| switch (ip.indexToKey(aggregate.ty)) {
11058 else => unreachable,
11059 .array_type => |array_type| {
11060 var elem_offset: usize = 0;
11061 const elem_size: usize = @intCast(ZigType.fromInterned(array_type.child).abiSize(zcu));
11062 const len_including_sentinel: usize = @intCast(array_type.lenIncludingSentinel());
11063 switch (aggregate.storage) {
11064 .bytes => |bytes| @memcpy(buffer[0..len_including_sentinel], bytes.toSlice(len_including_sentinel, ip)),
11065 .elems => |elems| for (elems) |elem| {
11066 if (!try isel.writeToMemory(.fromInterned(elem), buffer[elem_offset..][0..elem_size])) return false;
11067 elem_offset += elem_size;
11068 },
11069 .repeated_elem => |repeated_elem| for (0..len_including_sentinel) |_| {
11070 if (!try isel.writeToMemory(.fromInterned(repeated_elem), buffer[elem_offset..][0..elem_size])) return false;
11071 elem_offset += elem_size;
11072 },
11073 }
11074 },
11075 .vector_type => return false,
11076 .struct_type => {
11077 const loaded_struct = ip.loadStructType(aggregate.ty);
11078 switch (loaded_struct.layout) {
11079 .auto => {
11080 var field_offset: u64 = 0;
11081 var field_it = loaded_struct.iterateRuntimeOrder(ip);
11082 while (field_it.next()) |field_index| {
11083 if (loaded_struct.fieldIsComptime(ip, field_index)) continue;
11084 const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
11085 field_offset = field_ty.structFieldAlignment(
11086 loaded_struct.fieldAlign(ip, field_index),
11087 loaded_struct.layout,
11088 zcu,
11089 ).forward(field_offset);
11090 const field_size = field_ty.abiSize(zcu);
11091 if (!try isel.writeToMemory(.fromInterned(switch (aggregate.storage) {
11092 .bytes => unreachable,
11093 .elems => |elems| elems[field_index],
11094 .repeated_elem => |repeated_elem| repeated_elem,
11095 }), buffer[@intCast(field_offset)..][0..@intCast(field_size)])) return false;
11096 field_offset += field_size;
11097 }
11098 },
11099 .@"extern", .@"packed" => return false,
11100 }
11101 },
11102 .tuple_type => |tuple_type| {
11103 var field_offset: u64 = 0;
11104 for (tuple_type.types.get(ip), tuple_type.values.get(ip), 0..) |field_type, field_value, field_index| {
11105 if (field_value != .none) continue;
11106 const field_ty: ZigType = .fromInterned(field_type);
11107 field_offset = field_ty.abiAlignment(zcu).forward(field_offset);
11108 const field_size = field_ty.abiSize(zcu);
11109 if (!try isel.writeToMemory(.fromInterned(switch (aggregate.storage) {
11110 .bytes => unreachable,
11111 .elems => |elems| elems[field_index],
11112 .repeated_elem => |repeated_elem| repeated_elem,
11113 }), buffer[@intCast(field_offset)..][0..@intCast(field_size)])) return false;
11114 field_offset += field_size;
11115 }
11116 },
11117 },
11118 else => return false,
11119 }
11120 return true;
11121}
11122
11123const TryAllocRegResult = union(enum) {
11124 allocated: Register.Alias,
11125 fill_candidate: Register.Alias,
11126 out_of_registers,
11127};
11128
11129fn tryAllocIntReg(isel: *Select) TryAllocRegResult {
11130 var failed_result: TryAllocRegResult = .out_of_registers;
11131 var ra: Register.Alias = .r0;
11132 while (true) : (ra = @enumFromInt(@intFromEnum(ra) + 1)) {
11133 if (ra == .r18) continue; // The Platform Register
11134 if (ra == Register.Alias.fp) continue;
11135 const live_vi = isel.live_registers.getPtr(ra);
11136 switch (live_vi.*) {
11137 _ => switch (failed_result) {
11138 .allocated => unreachable,
11139 .fill_candidate => {},
11140 .out_of_registers => failed_result = .{ .fill_candidate = ra },
11141 },
11142 .allocating => {},
11143 .free => {
11144 live_vi.* = .allocating;
11145 isel.saved_registers.insert(ra);
11146 return .{ .allocated = ra };
11147 },
11148 }
11149 if (ra == Register.Alias.lr) return failed_result;
11150 }
11151}
11152
11153fn allocIntReg(isel: *Select) !Register.Alias {
11154 switch (isel.tryAllocIntReg()) {
11155 .allocated => |ra| return ra,
11156 .fill_candidate => |ra| {
11157 assert(try isel.fillMemory(ra));
11158 const live_vi = isel.live_registers.getPtr(ra);
11159 assert(live_vi.* == .free);
11160 live_vi.* = .allocating;
11161 return ra;
11162 },
11163 .out_of_registers => return isel.fail("ran out of registers", .{}),
11164 }
11165}
11166
11167fn tryAllocVecReg(isel: *Select) TryAllocRegResult {
11168 var failed_result: TryAllocRegResult = .out_of_registers;
11169 var ra: Register.Alias = .v0;
11170 while (true) : (ra = @enumFromInt(@intFromEnum(ra) + 1)) {
11171 const live_vi = isel.live_registers.getPtr(ra);
11172 switch (live_vi.*) {
11173 _ => switch (failed_result) {
11174 .allocated => unreachable,
11175 .fill_candidate => {},
11176 .out_of_registers => failed_result = .{ .fill_candidate = ra },
11177 },
11178 .allocating => {},
11179 .free => {
11180 live_vi.* = .allocating;
11181 isel.saved_registers.insert(ra);
11182 return .{ .allocated = ra };
11183 },
11184 }
11185 if (ra == Register.Alias.v31) return failed_result;
11186 }
11187}
11188
11189fn allocVecReg(isel: *Select) !Register.Alias {
11190 switch (isel.tryAllocVecReg()) {
11191 .allocated => |ra| return ra,
11192 .fill_candidate => |ra| {
11193 assert(try isel.fillMemory(ra));
11194 return ra;
11195 },
11196 .out_of_registers => return isel.fail("ran out of registers", .{}),
11197 }
11198}
11199
11200const RegLock = struct {
11201 ra: Register.Alias,
11202 const empty: RegLock = .{ .ra = .zr };
11203 fn unlock(lock: RegLock, isel: *Select) void {
11204 switch (lock.ra) {
11205 else => |ra| isel.freeReg(ra),
11206 .zr => {},
11207 }
11208 }
11209};
11210fn lockReg(isel: *Select, ra: Register.Alias) RegLock {
11211 assert(ra != .zr);
11212 const live_vi = isel.live_registers.getPtr(ra);
11213 assert(live_vi.* == .free);
11214 live_vi.* = .allocating;
11215 return .{ .ra = ra };
11216}
11217fn tryLockReg(isel: *Select, ra: Register.Alias) RegLock {
11218 assert(ra != .zr);
11219 const live_vi = isel.live_registers.getPtr(ra);
11220 switch (live_vi.*) {
11221 _ => unreachable,
11222 .allocating => return .{ .ra = .zr },
11223 .free => {
11224 live_vi.* = .allocating;
11225 return .{ .ra = ra };
11226 },
11227 }
11228}
11229
11230fn freeReg(isel: *Select, ra: Register.Alias) void {
11231 assert(ra != .zr);
11232 const live_vi = isel.live_registers.getPtr(ra);
11233 assert(live_vi.* == .allocating);
11234 live_vi.* = .free;
11235}
11236
11237fn use(isel: *Select, air_ref: Air.Inst.Ref) !Value.Index {
11238 const zcu = isel.pt.zcu;
11239 const ip = &zcu.intern_pool;
11240 try isel.values.ensureUnusedCapacity(zcu.gpa, 1);
11241 const vi, const ty = if (air_ref.toIndex()) |air_inst_index| vi_ty: {
11242 const live_gop = try isel.live_values.getOrPut(zcu.gpa, air_inst_index);
11243 if (live_gop.found_existing) return live_gop.value_ptr.*;
11244 const ty = isel.air.typeOf(air_ref, ip);
11245 const vi = isel.initValue(ty);
11246 tracking_log.debug("${d} <- %{d}", .{
11247 @intFromEnum(vi),
11248 @intFromEnum(air_inst_index),
11249 });
11250 live_gop.value_ptr.* = vi.ref(isel);
11251 break :vi_ty .{ vi, ty };
11252 } else vi_ty: {
11253 const constant: Constant = .fromInterned(air_ref.toInterned().?);
11254 const ty = constant.typeOf(zcu);
11255 const vi = isel.initValue(ty);
11256 tracking_log.debug("${d} <- <{f}, {f}>", .{
11257 @intFromEnum(vi),
11258 isel.fmtType(ty),
11259 isel.fmtConstant(constant),
11260 });
11261 vi.setParent(isel, .{ .constant = constant });
11262 break :vi_ty .{ vi, ty };
11263 };
11264 if (ty.isAbiInt(zcu)) {
11265 const int_info = ty.intInfo(zcu);
11266 if (int_info.bits <= 16) vi.setSignedness(isel, int_info.signedness);
11267 } else if (vi.size(isel) <= 16 and
11268 CallAbiIterator.homogeneousAggregateBaseType(zcu, ty.toIntern()) != null) vi.setIsVector(isel);
11269 return vi;
11270}
11271
11272fn fill(isel: *Select, dst_ra: Register.Alias) error{ OutOfMemory, CodegenFail }!bool {
11273 switch (dst_ra) {
11274 else => {},
11275 Register.Alias.fp, .zr, .sp, .pc, .fpcr, .fpsr, .ffr => return false,
11276 }
11277 const dst_live_vi = isel.live_registers.getPtr(dst_ra);
11278 const dst_vi = switch (dst_live_vi.*) {
11279 _ => |dst_vi| dst_vi,
11280 .allocating => return false,
11281 .free => return true,
11282 };
11283 const src_ra = src_ra: {
11284 if (dst_vi.hint(isel)) |hint_ra| {
11285 assert(dst_live_vi.* == dst_vi);
11286 dst_live_vi.* = .allocating;
11287 defer dst_live_vi.* = dst_vi;
11288 if (try isel.fill(hint_ra)) {
11289 isel.saved_registers.insert(hint_ra);
11290 break :src_ra hint_ra;
11291 }
11292 }
11293 switch (if (dst_vi.isVector(isel)) isel.tryAllocVecReg() else isel.tryAllocIntReg()) {
11294 .allocated => |ra| break :src_ra ra,
11295 .fill_candidate, .out_of_registers => return isel.fillMemory(dst_ra),
11296 }
11297 };
11298 try dst_vi.liveIn(isel, src_ra, comptime &.initFill(.free));
11299 const src_live_vi = isel.live_registers.getPtr(src_ra);
11300 assert(src_live_vi.* == .allocating);
11301 src_live_vi.* = dst_vi;
11302 return true;
11303}
11304
11305fn fillMemory(isel: *Select, dst_ra: Register.Alias) error{ OutOfMemory, CodegenFail }!bool {
11306 const dst_live_vi = isel.live_registers.getPtr(dst_ra);
11307 const dst_vi = switch (dst_live_vi.*) {
11308 _ => |dst_vi| dst_vi,
11309 .allocating => return false,
11310 .free => return true,
11311 };
11312 const dst_vi_ra = &dst_vi.get(isel).location_payload.small.register;
11313 assert(dst_vi_ra.* == dst_ra);
11314 const base_ra = if (dst_ra.isVector()) try isel.allocIntReg() else dst_ra;
11315 defer if (base_ra != dst_ra) isel.freeReg(base_ra);
11316 try isel.emit(switch (dst_vi.size(isel)) {
11317 else => unreachable,
11318 1 => if (dst_ra.isVector())
11319 .ldr(dst_ra.b(), .{ .base = base_ra.x() })
11320 else switch (dst_vi.signedness(isel)) {
11321 .signed => .ldrsb(dst_ra.w(), .{ .base = base_ra.x() }),
11322 .unsigned => .ldrb(dst_ra.w(), .{ .base = base_ra.x() }),
11323 },
11324 2 => if (dst_ra.isVector())
11325 .ldr(dst_ra.h(), .{ .base = base_ra.x() })
11326 else switch (dst_vi.signedness(isel)) {
11327 .signed => .ldrsh(dst_ra.w(), .{ .base = base_ra.x() }),
11328 .unsigned => .ldrh(dst_ra.w(), .{ .base = base_ra.x() }),
11329 },
11330 4 => .ldr(if (dst_ra.isVector()) dst_ra.s() else dst_ra.w(), .{ .base = base_ra.x() }),
11331 8 => .ldr(if (dst_ra.isVector()) dst_ra.d() else dst_ra.x(), .{ .base = base_ra.x() }),
11332 16 => .ldr(dst_ra.q(), .{ .base = base_ra.x() }),
11333 });
11334 dst_vi_ra.* = .zr;
11335 try dst_vi.address(isel, 0, base_ra);
11336 dst_live_vi.* = .free;
11337 return true;
11338}
11339
11340/// Merges possibly differing value tracking into a consistent state.
11341///
11342/// At a conditional branch, if a value is expected in the same register on both
11343/// paths, or only expected in a register on only one path, tracking is updated:
11344///
11345/// $0 -> r0 // final state is now consistent with both paths
11346/// b.cond else
11347/// then:
11348/// $0 -> r0 // updated if not already consistent with else
11349/// ...
11350/// b end
11351/// else:
11352/// $0 -> r0
11353/// ...
11354/// end:
11355///
11356/// At a conditional branch, if a value is expected in different registers on
11357/// each path, mov instructions are emitted:
11358///
11359/// $0 -> r0 // final state is now consistent with both paths
11360/// b.cond else
11361/// then:
11362/// $0 -> r0 // updated to be consistent with else
11363/// mov x1, x0 // emitted to merge the inconsistent states
11364/// $0 -> r1
11365/// ...
11366/// b end
11367/// else:
11368/// $0 -> r0
11369/// ...
11370/// end:
11371///
11372/// At a loop, a value that is expected in a register at the repeats is updated:
11373///
11374/// $0 -> r0 // final state is now consistent with all paths
11375/// loop:
11376/// $0 -> r0 // updated to be consistent with the repeats
11377/// ...
11378/// $0 -> r0
11379/// b.cond loop
11380/// ...
11381/// $0 -> r0
11382/// b loop
11383///
11384/// At a loop, a value that is expected in a register at the top is filled:
11385///
11386/// $0 -> [sp, #A] // final state is now consistent with all paths
11387/// loop:
11388/// $0 -> [sp, #A] // updated to be consistent with the repeats
11389/// ldr x0, [sp, #A] // emitted to merge the inconsistent states
11390/// $0 -> r0
11391/// ...
11392/// $0 -> [sp, #A]
11393/// b.cond loop
11394/// ...
11395/// $0 -> [sp, #A]
11396/// b loop
11397///
11398/// At a loop, if a value that is expected in different registers on each path,
11399/// mov instructions are emitted:
11400///
11401/// $0 -> r0 // final state is now consistent with all paths
11402/// loop:
11403/// $0 -> r0 // updated to be consistent with the repeats
11404/// mov x1, x0 // emitted to merge the inconsistent states
11405/// $0 -> r1
11406/// ...
11407/// $0 -> r0
11408/// b.cond loop
11409/// ...
11410/// $0 -> r0
11411/// b loop
11412fn merge(
11413 isel: *Select,
11414 expected_live_registers: *const LiveRegisters,
11415 comptime opts: struct { fill_extra: bool = false },
11416) !void {
11417 var live_reg_it = isel.live_registers.iterator();
11418 while (live_reg_it.next()) |live_reg_entry| {
11419 const ra = live_reg_entry.key;
11420 const actual_vi = live_reg_entry.value;
11421 const expected_vi = expected_live_registers.get(ra);
11422 switch (expected_vi) {
11423 else => switch (actual_vi.*) {
11424 _ => {},
11425 .allocating => unreachable,
11426 .free => actual_vi.* = .allocating,
11427 },
11428 .free => {},
11429 }
11430 }
11431 live_reg_it = isel.live_registers.iterator();
11432 while (live_reg_it.next()) |live_reg_entry| {
11433 const ra = live_reg_entry.key;
11434 const actual_vi = live_reg_entry.value;
11435 const expected_vi = expected_live_registers.get(ra);
11436 switch (expected_vi) {
11437 _ => {
11438 switch (actual_vi.*) {
11439 _ => _ = if (opts.fill_extra) {
11440 assert(try isel.fillMemory(ra));
11441 assert(actual_vi.* == .free);
11442 },
11443 .allocating => actual_vi.* = .free,
11444 .free => unreachable,
11445 }
11446 try expected_vi.liveIn(isel, ra, expected_live_registers);
11447 },
11448 .allocating => if (if (opts.fill_extra) try isel.fillMemory(ra) else try isel.fill(ra)) {
11449 assert(actual_vi.* == .free);
11450 actual_vi.* = .allocating;
11451 },
11452 .free => if (opts.fill_extra) assert(try isel.fillMemory(ra) and actual_vi.* == .free),
11453 }
11454 }
11455 live_reg_it = isel.live_registers.iterator();
11456 while (live_reg_it.next()) |live_reg_entry| {
11457 const ra = live_reg_entry.key;
11458 const actual_vi = live_reg_entry.value;
11459 const expected_vi = expected_live_registers.get(ra);
11460 switch (expected_vi) {
11461 _ => {
11462 assert(actual_vi.* == .allocating and expected_vi.register(isel) == ra);
11463 actual_vi.* = expected_vi;
11464 },
11465 .allocating => assert(actual_vi.* == .allocating),
11466 .free => if (opts.fill_extra) assert(actual_vi.* == .free),
11467 }
11468 }
11469}
11470
11471const call = struct {
11472 const param_reg: Value.Index = @enumFromInt(@intFromEnum(Value.Index.allocating) - 2);
11473 const callee_clobbered_reg: Value.Index = @enumFromInt(@intFromEnum(Value.Index.allocating) - 1);
11474 const caller_saved_regs: LiveRegisters = .init(.{
11475 .r0 = param_reg,
11476 .r1 = param_reg,
11477 .r2 = param_reg,
11478 .r3 = param_reg,
11479 .r4 = param_reg,
11480 .r5 = param_reg,
11481 .r6 = param_reg,
11482 .r7 = param_reg,
11483 .r8 = param_reg,
11484 .r9 = callee_clobbered_reg,
11485 .r10 = callee_clobbered_reg,
11486 .r11 = callee_clobbered_reg,
11487 .r12 = callee_clobbered_reg,
11488 .r13 = callee_clobbered_reg,
11489 .r14 = callee_clobbered_reg,
11490 .r15 = callee_clobbered_reg,
11491 .r16 = callee_clobbered_reg,
11492 .r17 = callee_clobbered_reg,
11493 .r18 = callee_clobbered_reg,
11494 .r19 = .free,
11495 .r20 = .free,
11496 .r21 = .free,
11497 .r22 = .free,
11498 .r23 = .free,
11499 .r24 = .free,
11500 .r25 = .free,
11501 .r26 = .free,
11502 .r27 = .free,
11503 .r28 = .free,
11504 .r29 = .free,
11505 .r30 = callee_clobbered_reg,
11506 .zr = .free,
11507 .sp = .free,
11508
11509 .pc = .free,
11510
11511 .v0 = param_reg,
11512 .v1 = param_reg,
11513 .v2 = param_reg,
11514 .v3 = param_reg,
11515 .v4 = param_reg,
11516 .v5 = param_reg,
11517 .v6 = param_reg,
11518 .v7 = param_reg,
11519 .v8 = .free,
11520 .v9 = .free,
11521 .v10 = .free,
11522 .v11 = .free,
11523 .v12 = .free,
11524 .v13 = .free,
11525 .v14 = .free,
11526 .v15 = .free,
11527 .v16 = callee_clobbered_reg,
11528 .v17 = callee_clobbered_reg,
11529 .v18 = callee_clobbered_reg,
11530 .v19 = callee_clobbered_reg,
11531 .v20 = callee_clobbered_reg,
11532 .v21 = callee_clobbered_reg,
11533 .v22 = callee_clobbered_reg,
11534 .v23 = callee_clobbered_reg,
11535 .v24 = callee_clobbered_reg,
11536 .v25 = callee_clobbered_reg,
11537 .v26 = callee_clobbered_reg,
11538 .v27 = callee_clobbered_reg,
11539 .v28 = callee_clobbered_reg,
11540 .v29 = callee_clobbered_reg,
11541 .v30 = callee_clobbered_reg,
11542 .v31 = callee_clobbered_reg,
11543
11544 .fpcr = .free,
11545 .fpsr = .free,
11546
11547 .p0 = callee_clobbered_reg,
11548 .p1 = callee_clobbered_reg,
11549 .p2 = callee_clobbered_reg,
11550 .p3 = callee_clobbered_reg,
11551 .p4 = callee_clobbered_reg,
11552 .p5 = callee_clobbered_reg,
11553 .p6 = callee_clobbered_reg,
11554 .p7 = callee_clobbered_reg,
11555 .p8 = callee_clobbered_reg,
11556 .p9 = callee_clobbered_reg,
11557 .p10 = callee_clobbered_reg,
11558 .p11 = callee_clobbered_reg,
11559 .p12 = callee_clobbered_reg,
11560 .p13 = callee_clobbered_reg,
11561 .p14 = callee_clobbered_reg,
11562 .p15 = callee_clobbered_reg,
11563
11564 .ffr = .free,
11565 });
11566 fn prepareReturn(isel: *Select) !void {
11567 var live_reg_it = isel.live_registers.iterator();
11568 while (live_reg_it.next()) |live_reg_entry| switch (caller_saved_regs.get(live_reg_entry.key)) {
11569 else => unreachable,
11570 param_reg, callee_clobbered_reg => switch (live_reg_entry.value.*) {
11571 _ => {},
11572 .allocating => unreachable,
11573 .free => live_reg_entry.value.* = .allocating,
11574 },
11575 .free => {},
11576 };
11577 }
11578 fn returnFill(isel: *Select, ra: Register.Alias) !void {
11579 const live_vi = isel.live_registers.getPtr(ra);
11580 if (try isel.fill(ra)) {
11581 assert(live_vi.* == .free);
11582 live_vi.* = .allocating;
11583 }
11584 assert(live_vi.* == .allocating);
11585 }
11586 fn returnLiveIn(isel: *Select, vi: Value.Index, ra: Register.Alias) !void {
11587 try vi.defLiveIn(isel, ra, &caller_saved_regs);
11588 }
11589 fn finishReturn(isel: *Select) !void {
11590 var live_reg_it = isel.live_registers.iterator();
11591 while (live_reg_it.next()) |live_reg_entry| {
11592 switch (live_reg_entry.value.*) {
11593 _ => |live_vi| switch (live_vi.size(isel)) {
11594 else => unreachable,
11595 1, 2, 4, 8 => {},
11596 16 => {
11597 assert(try isel.fillMemory(live_reg_entry.key));
11598 assert(live_reg_entry.value.* == .free);
11599 switch (caller_saved_regs.get(live_reg_entry.key)) {
11600 else => unreachable,
11601 param_reg, callee_clobbered_reg => live_reg_entry.value.* = .allocating,
11602 .free => {},
11603 }
11604 continue;
11605 },
11606 },
11607 .allocating, .free => {},
11608 }
11609 switch (caller_saved_regs.get(live_reg_entry.key)) {
11610 else => unreachable,
11611 param_reg, callee_clobbered_reg => switch (live_reg_entry.value.*) {
11612 _ => {
11613 assert(try isel.fill(live_reg_entry.key));
11614 assert(live_reg_entry.value.* == .free);
11615 live_reg_entry.value.* = .allocating;
11616 },
11617 .allocating => {},
11618 .free => unreachable,
11619 },
11620 .free => {},
11621 }
11622 }
11623 }
11624 fn prepareCallee(isel: *Select) !void {
11625 var live_reg_it = isel.live_registers.iterator();
11626 while (live_reg_it.next()) |live_reg_entry| switch (caller_saved_regs.get(live_reg_entry.key)) {
11627 else => unreachable,
11628 param_reg => assert(live_reg_entry.value.* == .allocating),
11629 callee_clobbered_reg => isel.freeReg(live_reg_entry.key),
11630 .free => {},
11631 };
11632 }
11633 fn finishCallee(_: *Select) !void {}
11634 fn prepareParams(_: *Select) !void {}
11635 fn paramLiveOut(isel: *Select, vi: Value.Index, ra: Register.Alias) !void {
11636 isel.freeReg(ra);
11637 try vi.liveOut(isel, ra);
11638 const live_vi = isel.live_registers.getPtr(ra);
11639 if (live_vi.* == .free) live_vi.* = .allocating;
11640 }
11641 fn paramAddress(isel: *Select, vi: Value.Index, ra: Register.Alias) !void {
11642 isel.freeReg(ra);
11643 try vi.address(isel, 0, ra);
11644 const live_vi = isel.live_registers.getPtr(ra);
11645 if (live_vi.* == .free) live_vi.* = .allocating;
11646 }
11647 fn finishParams(isel: *Select) !void {
11648 var live_reg_it = isel.live_registers.iterator();
11649 while (live_reg_it.next()) |live_reg_entry| switch (caller_saved_regs.get(live_reg_entry.key)) {
11650 else => unreachable,
11651 param_reg => switch (live_reg_entry.value.*) {
11652 _ => {},
11653 .allocating => live_reg_entry.value.* = .free,
11654 .free => unreachable,
11655 },
11656 callee_clobbered_reg, .free => {},
11657 };
11658 }
11659};
11660
11661pub const CallAbiIterator = struct {
11662 /// Next General-purpose Register Number
11663 ngrn: Register.Alias,
11664 /// Next SIMD and Floating-point Register Number
11665 nsrn: Register.Alias,
11666 /// next stacked argument address
11667 nsaa: u24,
11668
11669 pub const ngrn_start: Register.Alias = .r0;
11670 pub const ngrn_end: Register.Alias = .r8;
11671 pub const nsrn_start: Register.Alias = .v0;
11672 pub const nsrn_end: Register.Alias = .v8;
11673 pub const nsaa_start: u42 = 0;
11674
11675 pub const init: CallAbiIterator = .{
11676 // A.1
11677 .ngrn = ngrn_start,
11678 // A.2
11679 .nsrn = nsrn_start,
11680 // A.3
11681 .nsaa = nsaa_start,
11682 };
11683
11684 pub fn param(it: *CallAbiIterator, isel: *Select, ty: ZigType) !?Value.Index {
11685 const zcu = isel.pt.zcu;
11686 const ip = &zcu.intern_pool;
11687
11688 if (ty.isNoReturn(zcu) or !ty.hasRuntimeBitsIgnoreComptime(zcu)) return null;
11689 try isel.values.ensureUnusedCapacity(zcu.gpa, Value.max_parts);
11690 const wip_vi = isel.initValue(ty);
11691 type_key: switch (ip.indexToKey(ty.toIntern())) {
11692 else => return isel.fail("CallAbiIterator.param({f})", .{isel.fmtType(ty)}),
11693 .int_type => |int_type| switch (int_type.bits) {
11694 0 => unreachable,
11695 1...16 => {
11696 wip_vi.setSignedness(isel, int_type.signedness);
11697 // C.7
11698 it.integer(isel, wip_vi);
11699 },
11700 // C.7
11701 17...64 => it.integer(isel, wip_vi),
11702 // C.9
11703 65...128 => it.integers(isel, wip_vi, @splat(@divExact(wip_vi.size(isel), 2))),
11704 else => it.indirect(isel, wip_vi),
11705 },
11706 .array_type => switch (wip_vi.size(isel)) {
11707 0 => unreachable,
11708 1...8 => it.integer(isel, wip_vi),
11709 9...16 => |size| it.integers(isel, wip_vi, .{ 8, size - 8 }),
11710 else => it.indirect(isel, wip_vi),
11711 },
11712 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
11713 .one, .many, .c => continue :type_key .{ .int_type = .{
11714 .signedness = .unsigned,
11715 .bits = 64,
11716 } },
11717 .slice => it.integers(isel, wip_vi, @splat(8)),
11718 },
11719 .opt_type => |child_type| if (ty.optionalReprIsPayload(zcu))
11720 continue :type_key ip.indexToKey(child_type)
11721 else switch (ZigType.fromInterned(child_type).abiSize(zcu)) {
11722 0 => continue :type_key .{ .simple_type = .bool },
11723 1...7 => it.integer(isel, wip_vi),
11724 8...15 => |child_size| it.integers(isel, wip_vi, .{ 8, child_size - 7 }),
11725 else => return isel.fail("CallAbiIterator.param({f})", .{isel.fmtType(ty)}),
11726 },
11727 .anyframe_type => unreachable,
11728 .error_union_type => |error_union_type| switch (wip_vi.size(isel)) {
11729 0 => unreachable,
11730 1...8 => it.integer(isel, wip_vi),
11731 9...16 => {
11732 var sizes: [2]u64 = @splat(0);
11733 const payload_ty: ZigType = .fromInterned(error_union_type.payload_type);
11734 {
11735 const error_set_ty: ZigType = .fromInterned(error_union_type.error_set_type);
11736 const offset = codegen.errUnionErrorOffset(payload_ty, zcu);
11737 const end = offset % 8 + error_set_ty.abiSize(zcu);
11738 const part_index: usize = @intCast(offset / 8);
11739 sizes[part_index] = @max(sizes[part_index], @min(end, 8));
11740 if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8);
11741 }
11742 {
11743 const offset = codegen.errUnionPayloadOffset(payload_ty, zcu);
11744 const end = offset % 8 + payload_ty.abiSize(zcu);
11745 const part_index: usize = @intCast(offset / 8);
11746 sizes[part_index] = @max(sizes[part_index], @min(end, 8));
11747 if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8);
11748 }
11749 it.integers(isel, wip_vi, sizes);
11750 },
11751 else => it.indirect(isel, wip_vi),
11752 },
11753 .simple_type => |simple_type| switch (simple_type) {
11754 .f16, .f32, .f64, .f128, .c_longdouble => it.vector(isel, wip_vi),
11755 .f80 => continue :type_key .{ .int_type = .{ .signedness = .unsigned, .bits = 80 } },
11756 .usize,
11757 .isize,
11758 .c_char,
11759 .c_short,
11760 .c_ushort,
11761 .c_int,
11762 .c_uint,
11763 .c_long,
11764 .c_ulong,
11765 .c_longlong,
11766 .c_ulonglong,
11767 => continue :type_key .{ .int_type = ty.intInfo(zcu) },
11768 // B.1
11769 .anyopaque => it.indirect(isel, wip_vi),
11770 .bool => continue :type_key .{ .int_type = .{ .signedness = .unsigned, .bits = 1 } },
11771 .anyerror => continue :type_key .{ .int_type = .{
11772 .signedness = .unsigned,
11773 .bits = zcu.errorSetBits(),
11774 } },
11775 .void,
11776 .type,
11777 .comptime_int,
11778 .comptime_float,
11779 .noreturn,
11780 .null,
11781 .undefined,
11782 .enum_literal,
11783 .adhoc_inferred_error_set,
11784 .generic_poison,
11785 => unreachable,
11786 },
11787 .struct_type => {
11788 const loaded_struct = ip.loadStructType(ty.toIntern());
11789 switch (loaded_struct.layout) {
11790 .auto, .@"extern" => {},
11791 .@"packed" => continue :type_key .{
11792 .int_type = ip.indexToKey(loaded_struct.backingIntTypeUnordered(ip)).int_type,
11793 },
11794 }
11795 const size = wip_vi.size(isel);
11796 if (size <= 16 * 4) homogeneous_aggregate: {
11797 const fdt = homogeneousStructBaseType(zcu, &loaded_struct) orelse break :homogeneous_aggregate;
11798 const parts_len = @shrExact(size, fdt.log2Size());
11799 if (parts_len > 4) break :homogeneous_aggregate;
11800 it.vectors(isel, wip_vi, fdt, @intCast(parts_len));
11801 break :type_key;
11802 }
11803 switch (size) {
11804 0 => unreachable,
11805 1...8 => it.integer(isel, wip_vi),
11806 9...16 => {
11807 var part_offset: u64 = 0;
11808 var part_sizes: [2]u64 = undefined;
11809 var parts_len: Value.PartsLen = 0;
11810 var next_field_end: u64 = 0;
11811 var field_it = loaded_struct.iterateRuntimeOrder(ip);
11812 while (part_offset < size) {
11813 const field_end = next_field_end;
11814 const next_field_begin = if (field_it.next()) |field_index| next_field_begin: {
11815 const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
11816 const next_field_begin = switch (loaded_struct.fieldAlign(ip, field_index)) {
11817 .none => field_ty.abiAlignment(zcu),
11818 else => |field_align| field_align,
11819 }.forward(field_end);
11820 next_field_end = next_field_begin + field_ty.abiSize(zcu);
11821 break :next_field_begin next_field_begin;
11822 } else std.mem.alignForward(u64, size, 8);
11823 while (next_field_begin - part_offset >= 8) {
11824 const part_size = field_end - part_offset;
11825 part_sizes[parts_len] = part_size;
11826 assert(part_offset + part_size <= size);
11827 parts_len += 1;
11828 part_offset = next_field_begin;
11829 }
11830 }
11831 assert(parts_len == part_sizes.len);
11832 it.integers(isel, wip_vi, part_sizes);
11833 },
11834 else => it.indirect(isel, wip_vi),
11835 }
11836 },
11837 .tuple_type => |tuple_type| {
11838 const size = wip_vi.size(isel);
11839 if (size <= 16 * 4) homogeneous_aggregate: {
11840 const fdt = homogeneousTupleBaseType(zcu, tuple_type) orelse break :homogeneous_aggregate;
11841 const parts_len = @shrExact(size, fdt.log2Size());
11842 if (parts_len > 4) break :homogeneous_aggregate;
11843 it.vectors(isel, wip_vi, fdt, @intCast(parts_len));
11844 break :type_key;
11845 }
11846 switch (size) {
11847 0 => unreachable,
11848 1...8 => it.integer(isel, wip_vi),
11849 9...16 => {
11850 var part_offset: u64 = 0;
11851 var part_sizes: [2]u64 = undefined;
11852 var parts_len: Value.PartsLen = 0;
11853 var next_field_end: u64 = 0;
11854 var field_index: usize = 0;
11855 while (part_offset < size) {
11856 const field_end = next_field_end;
11857 const next_field_begin = while (field_index < tuple_type.types.len) {
11858 defer field_index += 1;
11859 if (tuple_type.values.get(ip)[field_index] != .none) continue;
11860 const field_ty: ZigType = .fromInterned(tuple_type.types.get(ip)[field_index]);
11861 const next_field_begin = field_ty.abiAlignment(zcu).forward(field_end);
11862 next_field_end = next_field_begin + field_ty.abiSize(zcu);
11863 break next_field_begin;
11864 } else std.mem.alignForward(u64, size, 8);
11865 while (next_field_begin - part_offset >= 8) {
11866 const part_size = @min(field_end - part_offset, 8);
11867 part_sizes[parts_len] = part_size;
11868 assert(part_offset + part_size <= size);
11869 parts_len += 1;
11870 part_offset += part_size;
11871 if (part_offset >= field_end) part_offset = next_field_begin;
11872 }
11873 }
11874 assert(parts_len == part_sizes.len);
11875 it.integers(isel, wip_vi, part_sizes);
11876 },
11877 else => it.indirect(isel, wip_vi),
11878 }
11879 },
11880 .union_type => {
11881 const loaded_union = ip.loadUnionType(ty.toIntern());
11882 switch (loaded_union.flagsUnordered(ip).layout) {
11883 .auto, .@"extern" => {},
11884 .@"packed" => continue :type_key .{ .int_type = .{
11885 .signedness = .unsigned,
11886 .bits = @intCast(ty.bitSize(zcu)),
11887 } },
11888 }
11889 switch (wip_vi.size(isel)) {
11890 0 => unreachable,
11891 1...8 => it.integer(isel, wip_vi),
11892 9...16 => {
11893 const union_layout = ZigType.getUnionLayout(loaded_union, zcu);
11894 var sizes: [2]u64 = @splat(0);
11895 {
11896 const offset = union_layout.tagOffset();
11897 const end = offset % 8 + union_layout.tag_size;
11898 const part_index: usize = @intCast(offset / 8);
11899 sizes[part_index] = @max(sizes[part_index], @min(end, 8));
11900 if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8);
11901 }
11902 {
11903 const offset = union_layout.payloadOffset();
11904 const end = offset % 8 + union_layout.payload_size;
11905 const part_index: usize = @intCast(offset / 8);
11906 sizes[part_index] = @max(sizes[part_index], @min(end, 8));
11907 if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8);
11908 }
11909 it.integers(isel, wip_vi, sizes);
11910 },
11911 else => it.indirect(isel, wip_vi),
11912 }
11913 },
11914 .opaque_type, .func_type => continue :type_key .{ .simple_type = .anyopaque },
11915 .enum_type => continue :type_key ip.indexToKey(ip.loadEnumType(ty.toIntern()).tag_ty),
11916 .error_set_type,
11917 .inferred_error_set_type,
11918 => continue :type_key .{ .simple_type = .anyerror },
11919 .undef,
11920 .simple_value,
11921 .variable,
11922 .@"extern",
11923 .func,
11924 .int,
11925 .err,
11926 .error_union,
11927 .enum_literal,
11928 .enum_tag,
11929 .empty_enum_value,
11930 .float,
11931 .ptr,
11932 .slice,
11933 .opt,
11934 .aggregate,
11935 .un,
11936 .memoized_call,
11937 => unreachable, // values, not types
11938 }
11939 return wip_vi.ref(isel);
11940 }
11941
11942 pub fn nonSysvVarArg(it: *CallAbiIterator, isel: *Select, ty: ZigType) !?Value.Index {
11943 const ngrn = it.ngrn;
11944 defer it.ngrn = ngrn;
11945 it.ngrn = ngrn_end;
11946 const nsrn = it.nsrn;
11947 defer it.nsrn = nsrn;
11948 it.nsrn = nsrn_end;
11949 return it.param(isel, ty);
11950 }
11951
11952 pub fn ret(it: *CallAbiIterator, isel: *Select, ty: ZigType) !?Value.Index {
11953 const wip_vi = try it.param(isel, ty) orelse return null;
11954 switch (wip_vi.parent(isel)) {
11955 .unallocated, .stack_slot => {},
11956 .value, .constant => unreachable,
11957 .address => |address_vi| {
11958 assert(address_vi.hint(isel) == ngrn_start);
11959 address_vi.setHint(isel, ngrn_end);
11960 },
11961 }
11962 return wip_vi;
11963 }
11964
11965 pub const FundamentalDataType = enum {
11966 half,
11967 single,
11968 double,
11969 quad,
11970 vector64,
11971 vector128,
11972 fn log2Size(fdt: FundamentalDataType) u3 {
11973 return switch (fdt) {
11974 .half => 1,
11975 .single => 2,
11976 .double, .vector64 => 3,
11977 .quad, .vector128 => 4,
11978 };
11979 }
11980 fn size(fdt: FundamentalDataType) u64 {
11981 return @as(u64, 1) << fdt.log2Size();
11982 }
11983 };
11984 fn homogeneousAggregateBaseType(zcu: *Zcu, initial_ty: InternPool.Index) ?FundamentalDataType {
11985 const ip = &zcu.intern_pool;
11986 var ty = initial_ty;
11987 return type_key: switch (ip.indexToKey(ty)) {
11988 else => null,
11989 .array_type => |array_type| {
11990 ty = array_type.child;
11991 continue :type_key ip.indexToKey(ty);
11992 },
11993 .vector_type => switch (ZigType.fromInterned(ty).abiSize(zcu)) {
11994 else => null,
11995 8 => .vector64,
11996 16 => .vector128,
11997 },
11998 .simple_type => |simple_type| switch (simple_type) {
11999 .f16 => .half,
12000 .f32 => .single,
12001 .f64 => .double,
12002 .f128 => .quad,
12003 .c_longdouble => switch (zcu.getTarget().cTypeBitSize(.longdouble)) {
12004 else => unreachable,
12005 16 => .half,
12006 32 => .single,
12007 64 => .double,
12008 80 => null,
12009 128 => .quad,
12010 },
12011 else => null,
12012 },
12013 .struct_type => homogeneousStructBaseType(zcu, &ip.loadStructType(ty)),
12014 .tuple_type => |tuple_type| homogeneousTupleBaseType(zcu, tuple_type),
12015 };
12016 }
12017 fn homogeneousStructBaseType(zcu: *Zcu, loaded_struct: *const InternPool.LoadedStructType) ?FundamentalDataType {
12018 const ip = &zcu.intern_pool;
12019 var common_fdt: ?FundamentalDataType = null;
12020 for (0.., loaded_struct.field_types.get(ip)) |field_index, field_ty| {
12021 if (loaded_struct.fieldIsComptime(ip, field_index)) continue;
12022 if (loaded_struct.fieldAlign(ip, field_index) != .none) return null;
12023 if (!ZigType.fromInterned(field_ty).hasRuntimeBits(zcu)) continue;
12024 const fdt = homogeneousAggregateBaseType(zcu, field_ty);
12025 if (common_fdt == null) common_fdt = fdt else if (fdt != common_fdt) return null;
12026 }
12027 return common_fdt;
12028 }
12029 fn homogeneousTupleBaseType(zcu: *Zcu, tuple_type: InternPool.Key.TupleType) ?FundamentalDataType {
12030 const ip = &zcu.intern_pool;
12031 var common_fdt: ?FundamentalDataType = null;
12032 for (tuple_type.values.get(ip), tuple_type.types.get(ip)) |field_val, field_ty| {
12033 if (field_val != .none) continue;
12034 const fdt = homogeneousAggregateBaseType(zcu, field_ty);
12035 if (common_fdt == null) common_fdt = fdt else if (fdt != common_fdt) return null;
12036 }
12037 return common_fdt;
12038 }
12039
12040 const Spec = struct {
12041 offset: u64,
12042 size: u64,
12043 };
12044
12045 fn stack(it: *CallAbiIterator, isel: *Select, wip_vi: Value.Index) void {
12046 // C.12
12047 it.nsaa = @intCast(wip_vi.alignment(isel).forward(it.nsaa));
12048 const parent_vi = switch (wip_vi.parent(isel)) {
12049 .unallocated, .stack_slot => wip_vi,
12050 .address, .constant => unreachable,
12051 .value => |parent_vi| parent_vi,
12052 };
12053 switch (parent_vi.parent(isel)) {
12054 .unallocated => parent_vi.setParent(isel, .{ .stack_slot = .{
12055 .base = .sp,
12056 .offset = it.nsaa,
12057 } }),
12058 .stack_slot => {},
12059 .address, .value, .constant => unreachable,
12060 }
12061 it.nsaa += @intCast(wip_vi.size(isel));
12062 }
12063
12064 fn integer(it: *CallAbiIterator, isel: *Select, wip_vi: Value.Index) void {
12065 assert(wip_vi.size(isel) <= 8);
12066 const natural_alignment = wip_vi.alignment(isel);
12067 assert(natural_alignment.order(.@"16").compare(.lte));
12068 wip_vi.setAlignment(isel, natural_alignment.maxStrict(.@"8"));
12069 if (it.ngrn == ngrn_end) return it.stack(isel, wip_vi);
12070 wip_vi.setHint(isel, it.ngrn);
12071 it.ngrn = @enumFromInt(@intFromEnum(it.ngrn) + 1);
12072 }
12073
12074 fn integers(it: *CallAbiIterator, isel: *Select, wip_vi: Value.Index, part_sizes: [2]u64) void {
12075 assert(wip_vi.size(isel) <= 16);
12076 const natural_alignment = wip_vi.alignment(isel);
12077 assert(natural_alignment.order(.@"16").compare(.lte));
12078 wip_vi.setAlignment(isel, natural_alignment.maxStrict(.@"8"));
12079 // C.8
12080 if (natural_alignment == .@"16") it.ngrn = @enumFromInt(std.mem.alignForward(
12081 @typeInfo(Register.Alias).@"enum".tag_type,
12082 @intFromEnum(it.ngrn),
12083 2,
12084 ));
12085 if (it.ngrn == ngrn_end) return it.stack(isel, wip_vi);
12086 wip_vi.setParts(isel, part_sizes.len);
12087 for (0.., part_sizes) |part_index, part_size|
12088 it.integer(isel, wip_vi.addPart(isel, 8 * part_index, part_size));
12089 }
12090
12091 fn vector(it: *CallAbiIterator, isel: *Select, wip_vi: Value.Index) void {
12092 assert(wip_vi.size(isel) <= 16);
12093 const natural_alignment = wip_vi.alignment(isel);
12094 assert(natural_alignment.order(.@"16").compare(.lte));
12095 wip_vi.setAlignment(isel, natural_alignment.maxStrict(.@"8"));
12096 wip_vi.setIsVector(isel);
12097 if (it.nsrn == nsrn_end) return it.stack(isel, wip_vi);
12098 wip_vi.setHint(isel, it.nsrn);
12099 it.nsrn = @enumFromInt(@intFromEnum(it.nsrn) + 1);
12100 }
12101
12102 fn vectors(
12103 it: *CallAbiIterator,
12104 isel: *Select,
12105 wip_vi: Value.Index,
12106 fdt: FundamentalDataType,
12107 parts_len: Value.PartsLen,
12108 ) void {
12109 const fdt_log2_size = fdt.log2Size();
12110 assert(wip_vi.size(isel) == @shlExact(@as(u9, parts_len), fdt_log2_size));
12111 const natural_alignment = wip_vi.alignment(isel);
12112 assert(natural_alignment.order(.@"16").compare(.lte));
12113 wip_vi.setAlignment(isel, natural_alignment.maxStrict(.@"8"));
12114 if (@intFromEnum(it.nsrn) > @intFromEnum(nsrn_end) - parts_len) return it.stack(isel, wip_vi);
12115 if (parts_len == 1) return it.vector(isel, wip_vi);
12116 wip_vi.setParts(isel, parts_len);
12117 const fdt_size = @as(u64, 1) << fdt_log2_size;
12118 for (0..parts_len) |part_index|
12119 it.vector(isel, wip_vi.addPart(isel, part_index << fdt_log2_size, fdt_size));
12120 }
12121
12122 fn indirect(it: *CallAbiIterator, isel: *Select, wip_vi: Value.Index) void {
12123 const wip_address_vi = isel.initValue(.usize);
12124 wip_vi.setParent(isel, .{ .address = wip_address_vi });
12125 it.integer(isel, wip_address_vi);
12126 }
12127};
12128
12129const Air = @import("../../Air.zig");
12130const assert = std.debug.assert;
12131const codegen = @import("../../codegen.zig");
12132const Constant = @import("../../Value.zig");
12133const InternPool = @import("../../InternPool.zig");
12134const Package = @import("../../Package.zig");
12135const Register = codegen.aarch64.encoding.Register;
12136const Select = @This();
12137const std = @import("std");
12138const tracking_log = std.log.scoped(.tracking);
12139const wip_mir_log = std.log.scoped(.@"wip-mir");
12140const Zcu = @import("../../Zcu.zig");
12141const ZigType = @import("../../Type.zig");
src/codegen/aarch64/abi.zig+4-16
...@@ -1,7 +1,5 @@...@@ -1,7 +1,5 @@
1const assert = @import("std").debug.assert;
1const std = @import("std");2const std = @import("std");
2const builtin = @import("builtin");
3const bits = @import("../../arch/aarch64/bits.zig");
4const Register = bits.Register;
5const Type = @import("../../Type.zig");3const Type = @import("../../Type.zig");
6const Zcu = @import("../../Zcu.zig");4const Zcu = @import("../../Zcu.zig");
75
...@@ -15,7 +13,7 @@ pub const Class = union(enum) {...@@ -15,7 +13,7 @@ pub const Class = union(enum) {
1513
16/// For `float_array` the second element will be the amount of floats.14/// For `float_array` the second element will be the amount of floats.
17pub fn classifyType(ty: Type, zcu: *Zcu) Class {15pub fn classifyType(ty: Type, zcu: *Zcu) Class {
18 std.debug.assert(ty.hasRuntimeBitsIgnoreComptime(zcu));16 assert(ty.hasRuntimeBitsIgnoreComptime(zcu));
1917
20 var maybe_float_bits: ?u16 = null;18 var maybe_float_bits: ?u16 = null;
21 switch (ty.zigTypeTag(zcu)) {19 switch (ty.zigTypeTag(zcu)) {
...@@ -47,11 +45,11 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class {...@@ -47,11 +45,11 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class {
47 return .byval;45 return .byval;
48 },46 },
49 .optional => {47 .optional => {
50 std.debug.assert(ty.isPtrLikeOptional(zcu));48 assert(ty.isPtrLikeOptional(zcu));
51 return .byval;49 return .byval;
52 },50 },
53 .pointer => {51 .pointer => {
54 std.debug.assert(!ty.isSlice(zcu));52 assert(!ty.isSlice(zcu));
55 return .byval;53 return .byval;
56 },54 },
57 .error_union,55 .error_union,
...@@ -138,13 +136,3 @@ pub fn getFloatArrayType(ty: Type, zcu: *Zcu) ?Type {...@@ -138,13 +136,3 @@ pub fn getFloatArrayType(ty: Type, zcu: *Zcu) ?Type {
138 else => return null,136 else => return null,
139 }137 }
140}138}
141
142pub const callee_preserved_regs = [_]Register{
143 .x19, .x20, .x21, .x22, .x23,
144 .x24, .x25, .x26, .x27, .x28,
145};
146
147pub const c_abi_int_param_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 };
148pub const c_abi_int_return_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 };
149
150const allocatable_registers = callee_preserved_regs;
src/codegen/aarch64/encoding.zig created+12194
...@@ -0,0 +1,12194 @@
1/// B1.2 Registers in AArch64 Execution state
2pub const Register = struct {
3 alias: Alias,
4 format: Format,
5
6 pub const Format = union(enum) {
7 alias,
8 integer: IntegerSize,
9 scalar: VectorSize,
10 vector: Arrangement,
11 element: struct { size: VectorSize, index: u4 },
12 };
13
14 pub const IntegerSize = enum(u1) {
15 word = 0b0,
16 doubleword = 0b1,
17
18 pub fn prefix(is: IntegerSize) u8 {
19 return (comptime std.enums.EnumArray(IntegerSize, u8).init(.{
20 .word = 'w',
21 .doubleword = 'x',
22 })).get(is);
23 }
24 };
25
26 pub const VectorSize = enum(u3) {
27 byte = 0,
28 half = 1,
29 single = 2,
30 double = 3,
31 quad = 4,
32 scalable,
33 predicate,
34
35 pub fn prefix(vs: VectorSize) u8 {
36 return (comptime std.enums.EnumArray(VectorSize, u8).init(.{
37 .byte = 'b',
38 .half = 'h',
39 .single = 's',
40 .double = 'd',
41 .quad = 'q',
42 .scalable = 'z',
43 .predicate = 'p',
44 })).get(vs);
45 }
46 };
47
48 pub const Arrangement = enum {
49 @"2d",
50 @"4s",
51 @"8h",
52 @"16b",
53
54 @"1d",
55 @"2s",
56 @"4h",
57 @"8b",
58
59 pub fn len(arrangement: Arrangement) u5 {
60 return switch (arrangement) {
61 .@"1d" => 1,
62 .@"2d", .@"2s" => 2,
63 .@"4s", .@"4h" => 4,
64 .@"8h", .@"8b" => 8,
65 .@"16b" => 16,
66 };
67 }
68
69 pub fn size(arrangement: Arrangement) Instruction.DataProcessingVector.Q {
70 return switch (arrangement) {
71 .@"2d", .@"4s", .@"8h", .@"16b" => .quad,
72 .@"1d", .@"2s", .@"4h", .@"8b" => .double,
73 };
74 }
75
76 pub fn elemSize(arrangement: Arrangement) Instruction.DataProcessingVector.Size {
77 return switch (arrangement) {
78 .@"2d", .@"1d" => .double,
79 .@"4s", .@"2s" => .single,
80 .@"8h", .@"4h" => .half,
81 .@"16b", .@"8b" => .byte,
82 };
83 }
84 };
85
86 pub const x0: Register = .{ .alias = .r0, .format = .{ .integer = .doubleword } };
87 pub const x1: Register = .{ .alias = .r1, .format = .{ .integer = .doubleword } };
88 pub const x2: Register = .{ .alias = .r2, .format = .{ .integer = .doubleword } };
89 pub const x3: Register = .{ .alias = .r3, .format = .{ .integer = .doubleword } };
90 pub const x4: Register = .{ .alias = .r4, .format = .{ .integer = .doubleword } };
91 pub const x5: Register = .{ .alias = .r5, .format = .{ .integer = .doubleword } };
92 pub const x6: Register = .{ .alias = .r6, .format = .{ .integer = .doubleword } };
93 pub const x7: Register = .{ .alias = .r7, .format = .{ .integer = .doubleword } };
94 pub const x8: Register = .{ .alias = .r8, .format = .{ .integer = .doubleword } };
95 pub const x9: Register = .{ .alias = .r9, .format = .{ .integer = .doubleword } };
96 pub const x10: Register = .{ .alias = .r10, .format = .{ .integer = .doubleword } };
97 pub const x11: Register = .{ .alias = .r11, .format = .{ .integer = .doubleword } };
98 pub const x12: Register = .{ .alias = .r12, .format = .{ .integer = .doubleword } };
99 pub const x13: Register = .{ .alias = .r13, .format = .{ .integer = .doubleword } };
100 pub const x14: Register = .{ .alias = .r14, .format = .{ .integer = .doubleword } };
101 pub const x15: Register = .{ .alias = .r15, .format = .{ .integer = .doubleword } };
102 pub const x16: Register = .{ .alias = .r16, .format = .{ .integer = .doubleword } };
103 pub const x17: Register = .{ .alias = .r17, .format = .{ .integer = .doubleword } };
104 pub const x18: Register = .{ .alias = .r18, .format = .{ .integer = .doubleword } };
105 pub const x19: Register = .{ .alias = .r19, .format = .{ .integer = .doubleword } };
106 pub const x20: Register = .{ .alias = .r20, .format = .{ .integer = .doubleword } };
107 pub const x21: Register = .{ .alias = .r21, .format = .{ .integer = .doubleword } };
108 pub const x22: Register = .{ .alias = .r22, .format = .{ .integer = .doubleword } };
109 pub const x23: Register = .{ .alias = .r23, .format = .{ .integer = .doubleword } };
110 pub const x24: Register = .{ .alias = .r24, .format = .{ .integer = .doubleword } };
111 pub const x25: Register = .{ .alias = .r25, .format = .{ .integer = .doubleword } };
112 pub const x26: Register = .{ .alias = .r26, .format = .{ .integer = .doubleword } };
113 pub const x27: Register = .{ .alias = .r27, .format = .{ .integer = .doubleword } };
114 pub const x28: Register = .{ .alias = .r28, .format = .{ .integer = .doubleword } };
115 pub const x29: Register = .{ .alias = .r29, .format = .{ .integer = .doubleword } };
116 pub const x30: Register = .{ .alias = .r30, .format = .{ .integer = .doubleword } };
117 pub const xzr: Register = .{ .alias = .zr, .format = .{ .integer = .doubleword } };
118 pub const sp: Register = .{ .alias = .sp, .format = .{ .integer = .doubleword } };
119
120 pub const w0: Register = .{ .alias = .r0, .format = .{ .integer = .word } };
121 pub const w1: Register = .{ .alias = .r1, .format = .{ .integer = .word } };
122 pub const w2: Register = .{ .alias = .r2, .format = .{ .integer = .word } };
123 pub const w3: Register = .{ .alias = .r3, .format = .{ .integer = .word } };
124 pub const w4: Register = .{ .alias = .r4, .format = .{ .integer = .word } };
125 pub const w5: Register = .{ .alias = .r5, .format = .{ .integer = .word } };
126 pub const w6: Register = .{ .alias = .r6, .format = .{ .integer = .word } };
127 pub const w7: Register = .{ .alias = .r7, .format = .{ .integer = .word } };
128 pub const w8: Register = .{ .alias = .r8, .format = .{ .integer = .word } };
129 pub const w9: Register = .{ .alias = .r9, .format = .{ .integer = .word } };
130 pub const w10: Register = .{ .alias = .r10, .format = .{ .integer = .word } };
131 pub const w11: Register = .{ .alias = .r11, .format = .{ .integer = .word } };
132 pub const w12: Register = .{ .alias = .r12, .format = .{ .integer = .word } };
133 pub const w13: Register = .{ .alias = .r13, .format = .{ .integer = .word } };
134 pub const w14: Register = .{ .alias = .r14, .format = .{ .integer = .word } };
135 pub const w15: Register = .{ .alias = .r15, .format = .{ .integer = .word } };
136 pub const w16: Register = .{ .alias = .r16, .format = .{ .integer = .word } };
137 pub const w17: Register = .{ .alias = .r17, .format = .{ .integer = .word } };
138 pub const w18: Register = .{ .alias = .r18, .format = .{ .integer = .word } };
139 pub const w19: Register = .{ .alias = .r19, .format = .{ .integer = .word } };
140 pub const w20: Register = .{ .alias = .r20, .format = .{ .integer = .word } };
141 pub const w21: Register = .{ .alias = .r21, .format = .{ .integer = .word } };
142 pub const w22: Register = .{ .alias = .r22, .format = .{ .integer = .word } };
143 pub const w23: Register = .{ .alias = .r23, .format = .{ .integer = .word } };
144 pub const w24: Register = .{ .alias = .r24, .format = .{ .integer = .word } };
145 pub const w25: Register = .{ .alias = .r25, .format = .{ .integer = .word } };
146 pub const w26: Register = .{ .alias = .r26, .format = .{ .integer = .word } };
147 pub const w27: Register = .{ .alias = .r27, .format = .{ .integer = .word } };
148 pub const w28: Register = .{ .alias = .r28, .format = .{ .integer = .word } };
149 pub const w29: Register = .{ .alias = .r29, .format = .{ .integer = .word } };
150 pub const w30: Register = .{ .alias = .r30, .format = .{ .integer = .word } };
151 pub const wzr: Register = .{ .alias = .zr, .format = .{ .integer = .word } };
152 pub const wsp: Register = .{ .alias = .sp, .format = .{ .integer = .word } };
153
154 pub const ip = x16;
155 pub const ip0 = x16;
156 pub const ip1 = x17;
157 pub const fp = x29;
158 pub const lr = x30;
159 pub const pc: Register = .{ .alias = .pc, .format = .{ .integer = .doubleword } };
160
161 pub const q0: Register = .{ .alias = .v0, .format = .{ .scalar = .quad } };
162 pub const q1: Register = .{ .alias = .v1, .format = .{ .scalar = .quad } };
163 pub const q2: Register = .{ .alias = .v2, .format = .{ .scalar = .quad } };
164 pub const q3: Register = .{ .alias = .v3, .format = .{ .scalar = .quad } };
165 pub const q4: Register = .{ .alias = .v4, .format = .{ .scalar = .quad } };
166 pub const q5: Register = .{ .alias = .v5, .format = .{ .scalar = .quad } };
167 pub const q6: Register = .{ .alias = .v6, .format = .{ .scalar = .quad } };
168 pub const q7: Register = .{ .alias = .v7, .format = .{ .scalar = .quad } };
169 pub const q8: Register = .{ .alias = .v8, .format = .{ .scalar = .quad } };
170 pub const q9: Register = .{ .alias = .v9, .format = .{ .scalar = .quad } };
171 pub const q10: Register = .{ .alias = .v10, .format = .{ .scalar = .quad } };
172 pub const q11: Register = .{ .alias = .v11, .format = .{ .scalar = .quad } };
173 pub const q12: Register = .{ .alias = .v12, .format = .{ .scalar = .quad } };
174 pub const q13: Register = .{ .alias = .v13, .format = .{ .scalar = .quad } };
175 pub const q14: Register = .{ .alias = .v14, .format = .{ .scalar = .quad } };
176 pub const q15: Register = .{ .alias = .v15, .format = .{ .scalar = .quad } };
177 pub const q16: Register = .{ .alias = .v16, .format = .{ .scalar = .quad } };
178 pub const q17: Register = .{ .alias = .v17, .format = .{ .scalar = .quad } };
179 pub const q18: Register = .{ .alias = .v18, .format = .{ .scalar = .quad } };
180 pub const q19: Register = .{ .alias = .v19, .format = .{ .scalar = .quad } };
181 pub const q20: Register = .{ .alias = .v20, .format = .{ .scalar = .quad } };
182 pub const q21: Register = .{ .alias = .v21, .format = .{ .scalar = .quad } };
183 pub const q22: Register = .{ .alias = .v22, .format = .{ .scalar = .quad } };
184 pub const q23: Register = .{ .alias = .v23, .format = .{ .scalar = .quad } };
185 pub const q24: Register = .{ .alias = .v24, .format = .{ .scalar = .quad } };
186 pub const q25: Register = .{ .alias = .v25, .format = .{ .scalar = .quad } };
187 pub const q26: Register = .{ .alias = .v26, .format = .{ .scalar = .quad } };
188 pub const q27: Register = .{ .alias = .v27, .format = .{ .scalar = .quad } };
189 pub const q28: Register = .{ .alias = .v28, .format = .{ .scalar = .quad } };
190 pub const q29: Register = .{ .alias = .v29, .format = .{ .scalar = .quad } };
191 pub const q30: Register = .{ .alias = .v30, .format = .{ .scalar = .quad } };
192 pub const q31: Register = .{ .alias = .v31, .format = .{ .scalar = .quad } };
193
194 pub const d0: Register = .{ .alias = .v0, .format = .{ .scalar = .double } };
195 pub const d1: Register = .{ .alias = .v1, .format = .{ .scalar = .double } };
196 pub const d2: Register = .{ .alias = .v2, .format = .{ .scalar = .double } };
197 pub const d3: Register = .{ .alias = .v3, .format = .{ .scalar = .double } };
198 pub const d4: Register = .{ .alias = .v4, .format = .{ .scalar = .double } };
199 pub const d5: Register = .{ .alias = .v5, .format = .{ .scalar = .double } };
200 pub const d6: Register = .{ .alias = .v6, .format = .{ .scalar = .double } };
201 pub const d7: Register = .{ .alias = .v7, .format = .{ .scalar = .double } };
202 pub const d8: Register = .{ .alias = .v8, .format = .{ .scalar = .double } };
203 pub const d9: Register = .{ .alias = .v9, .format = .{ .scalar = .double } };
204 pub const d10: Register = .{ .alias = .v10, .format = .{ .scalar = .double } };
205 pub const d11: Register = .{ .alias = .v11, .format = .{ .scalar = .double } };
206 pub const d12: Register = .{ .alias = .v12, .format = .{ .scalar = .double } };
207 pub const d13: Register = .{ .alias = .v13, .format = .{ .scalar = .double } };
208 pub const d14: Register = .{ .alias = .v14, .format = .{ .scalar = .double } };
209 pub const d15: Register = .{ .alias = .v15, .format = .{ .scalar = .double } };
210 pub const d16: Register = .{ .alias = .v16, .format = .{ .scalar = .double } };
211 pub const d17: Register = .{ .alias = .v17, .format = .{ .scalar = .double } };
212 pub const d18: Register = .{ .alias = .v18, .format = .{ .scalar = .double } };
213 pub const d19: Register = .{ .alias = .v19, .format = .{ .scalar = .double } };
214 pub const d20: Register = .{ .alias = .v20, .format = .{ .scalar = .double } };
215 pub const d21: Register = .{ .alias = .v21, .format = .{ .scalar = .double } };
216 pub const d22: Register = .{ .alias = .v22, .format = .{ .scalar = .double } };
217 pub const d23: Register = .{ .alias = .v23, .format = .{ .scalar = .double } };
218 pub const d24: Register = .{ .alias = .v24, .format = .{ .scalar = .double } };
219 pub const d25: Register = .{ .alias = .v25, .format = .{ .scalar = .double } };
220 pub const d26: Register = .{ .alias = .v26, .format = .{ .scalar = .double } };
221 pub const d27: Register = .{ .alias = .v27, .format = .{ .scalar = .double } };
222 pub const d28: Register = .{ .alias = .v28, .format = .{ .scalar = .double } };
223 pub const d29: Register = .{ .alias = .v29, .format = .{ .scalar = .double } };
224 pub const d30: Register = .{ .alias = .v30, .format = .{ .scalar = .double } };
225 pub const d31: Register = .{ .alias = .v31, .format = .{ .scalar = .double } };
226
227 pub const s0: Register = .{ .alias = .v0, .format = .{ .scalar = .single } };
228 pub const s1: Register = .{ .alias = .v1, .format = .{ .scalar = .single } };
229 pub const s2: Register = .{ .alias = .v2, .format = .{ .scalar = .single } };
230 pub const s3: Register = .{ .alias = .v3, .format = .{ .scalar = .single } };
231 pub const s4: Register = .{ .alias = .v4, .format = .{ .scalar = .single } };
232 pub const s5: Register = .{ .alias = .v5, .format = .{ .scalar = .single } };
233 pub const s6: Register = .{ .alias = .v6, .format = .{ .scalar = .single } };
234 pub const s7: Register = .{ .alias = .v7, .format = .{ .scalar = .single } };
235 pub const s8: Register = .{ .alias = .v8, .format = .{ .scalar = .single } };
236 pub const s9: Register = .{ .alias = .v9, .format = .{ .scalar = .single } };
237 pub const s10: Register = .{ .alias = .v10, .format = .{ .scalar = .single } };
238 pub const s11: Register = .{ .alias = .v11, .format = .{ .scalar = .single } };
239 pub const s12: Register = .{ .alias = .v12, .format = .{ .scalar = .single } };
240 pub const s13: Register = .{ .alias = .v13, .format = .{ .scalar = .single } };
241 pub const s14: Register = .{ .alias = .v14, .format = .{ .scalar = .single } };
242 pub const s15: Register = .{ .alias = .v15, .format = .{ .scalar = .single } };
243 pub const s16: Register = .{ .alias = .v16, .format = .{ .scalar = .single } };
244 pub const s17: Register = .{ .alias = .v17, .format = .{ .scalar = .single } };
245 pub const s18: Register = .{ .alias = .v18, .format = .{ .scalar = .single } };
246 pub const s19: Register = .{ .alias = .v19, .format = .{ .scalar = .single } };
247 pub const s20: Register = .{ .alias = .v20, .format = .{ .scalar = .single } };
248 pub const s21: Register = .{ .alias = .v21, .format = .{ .scalar = .single } };
249 pub const s22: Register = .{ .alias = .v22, .format = .{ .scalar = .single } };
250 pub const s23: Register = .{ .alias = .v23, .format = .{ .scalar = .single } };
251 pub const s24: Register = .{ .alias = .v24, .format = .{ .scalar = .single } };
252 pub const s25: Register = .{ .alias = .v25, .format = .{ .scalar = .single } };
253 pub const s26: Register = .{ .alias = .v26, .format = .{ .scalar = .single } };
254 pub const s27: Register = .{ .alias = .v27, .format = .{ .scalar = .single } };
255 pub const s28: Register = .{ .alias = .v28, .format = .{ .scalar = .single } };
256 pub const s29: Register = .{ .alias = .v29, .format = .{ .scalar = .single } };
257 pub const s30: Register = .{ .alias = .v30, .format = .{ .scalar = .single } };
258 pub const s31: Register = .{ .alias = .v31, .format = .{ .scalar = .single } };
259
260 pub const h0: Register = .{ .alias = .v0, .format = .{ .scalar = .half } };
261 pub const h1: Register = .{ .alias = .v1, .format = .{ .scalar = .half } };
262 pub const h2: Register = .{ .alias = .v2, .format = .{ .scalar = .half } };
263 pub const h3: Register = .{ .alias = .v3, .format = .{ .scalar = .half } };
264 pub const h4: Register = .{ .alias = .v4, .format = .{ .scalar = .half } };
265 pub const h5: Register = .{ .alias = .v5, .format = .{ .scalar = .half } };
266 pub const h6: Register = .{ .alias = .v6, .format = .{ .scalar = .half } };
267 pub const h7: Register = .{ .alias = .v7, .format = .{ .scalar = .half } };
268 pub const h8: Register = .{ .alias = .v8, .format = .{ .scalar = .half } };
269 pub const h9: Register = .{ .alias = .v9, .format = .{ .scalar = .half } };
270 pub const h10: Register = .{ .alias = .v10, .format = .{ .scalar = .half } };
271 pub const h11: Register = .{ .alias = .v11, .format = .{ .scalar = .half } };
272 pub const h12: Register = .{ .alias = .v12, .format = .{ .scalar = .half } };
273 pub const h13: Register = .{ .alias = .v13, .format = .{ .scalar = .half } };
274 pub const h14: Register = .{ .alias = .v14, .format = .{ .scalar = .half } };
275 pub const h15: Register = .{ .alias = .v15, .format = .{ .scalar = .half } };
276 pub const h16: Register = .{ .alias = .v16, .format = .{ .scalar = .half } };
277 pub const h17: Register = .{ .alias = .v17, .format = .{ .scalar = .half } };
278 pub const h18: Register = .{ .alias = .v18, .format = .{ .scalar = .half } };
279 pub const h19: Register = .{ .alias = .v19, .format = .{ .scalar = .half } };
280 pub const h20: Register = .{ .alias = .v20, .format = .{ .scalar = .half } };
281 pub const h21: Register = .{ .alias = .v21, .format = .{ .scalar = .half } };
282 pub const h22: Register = .{ .alias = .v22, .format = .{ .scalar = .half } };
283 pub const h23: Register = .{ .alias = .v23, .format = .{ .scalar = .half } };
284 pub const h24: Register = .{ .alias = .v24, .format = .{ .scalar = .half } };
285 pub const h25: Register = .{ .alias = .v25, .format = .{ .scalar = .half } };
286 pub const h26: Register = .{ .alias = .v26, .format = .{ .scalar = .half } };
287 pub const h27: Register = .{ .alias = .v27, .format = .{ .scalar = .half } };
288 pub const h28: Register = .{ .alias = .v28, .format = .{ .scalar = .half } };
289 pub const h29: Register = .{ .alias = .v29, .format = .{ .scalar = .half } };
290 pub const h30: Register = .{ .alias = .v30, .format = .{ .scalar = .half } };
291 pub const h31: Register = .{ .alias = .v31, .format = .{ .scalar = .half } };
292
293 pub const b0: Register = .{ .alias = .v0, .format = .{ .scalar = .byte } };
294 pub const b1: Register = .{ .alias = .v1, .format = .{ .scalar = .byte } };
295 pub const b2: Register = .{ .alias = .v2, .format = .{ .scalar = .byte } };
296 pub const b3: Register = .{ .alias = .v3, .format = .{ .scalar = .byte } };
297 pub const b4: Register = .{ .alias = .v4, .format = .{ .scalar = .byte } };
298 pub const b5: Register = .{ .alias = .v5, .format = .{ .scalar = .byte } };
299 pub const b6: Register = .{ .alias = .v6, .format = .{ .scalar = .byte } };
300 pub const b7: Register = .{ .alias = .v7, .format = .{ .scalar = .byte } };
301 pub const b8: Register = .{ .alias = .v8, .format = .{ .scalar = .byte } };
302 pub const b9: Register = .{ .alias = .v9, .format = .{ .scalar = .byte } };
303 pub const b10: Register = .{ .alias = .v10, .format = .{ .scalar = .byte } };
304 pub const b11: Register = .{ .alias = .v11, .format = .{ .scalar = .byte } };
305 pub const b12: Register = .{ .alias = .v12, .format = .{ .scalar = .byte } };
306 pub const b13: Register = .{ .alias = .v13, .format = .{ .scalar = .byte } };
307 pub const b14: Register = .{ .alias = .v14, .format = .{ .scalar = .byte } };
308 pub const b15: Register = .{ .alias = .v15, .format = .{ .scalar = .byte } };
309 pub const b16: Register = .{ .alias = .v16, .format = .{ .scalar = .byte } };
310 pub const b17: Register = .{ .alias = .v17, .format = .{ .scalar = .byte } };
311 pub const b18: Register = .{ .alias = .v18, .format = .{ .scalar = .byte } };
312 pub const b19: Register = .{ .alias = .v19, .format = .{ .scalar = .byte } };
313 pub const b20: Register = .{ .alias = .v20, .format = .{ .scalar = .byte } };
314 pub const b21: Register = .{ .alias = .v21, .format = .{ .scalar = .byte } };
315 pub const b22: Register = .{ .alias = .v22, .format = .{ .scalar = .byte } };
316 pub const b23: Register = .{ .alias = .v23, .format = .{ .scalar = .byte } };
317 pub const b24: Register = .{ .alias = .v24, .format = .{ .scalar = .byte } };
318 pub const b25: Register = .{ .alias = .v25, .format = .{ .scalar = .byte } };
319 pub const b26: Register = .{ .alias = .v26, .format = .{ .scalar = .byte } };
320 pub const b27: Register = .{ .alias = .v27, .format = .{ .scalar = .byte } };
321 pub const b28: Register = .{ .alias = .v28, .format = .{ .scalar = .byte } };
322 pub const b29: Register = .{ .alias = .v29, .format = .{ .scalar = .byte } };
323 pub const b30: Register = .{ .alias = .v30, .format = .{ .scalar = .byte } };
324 pub const b31: Register = .{ .alias = .v31, .format = .{ .scalar = .byte } };
325
326 pub const fpcr: Register = .{ .alias = .fpcr, .format = .{ .integer = .doubleword } };
327 pub const fpsr: Register = .{ .alias = .fpsr, .format = .{ .integer = .doubleword } };
328
329 pub const z0: Register = .{ .alias = .v0, .format = .{ .scalar = .scalable } };
330 pub const z1: Register = .{ .alias = .v1, .format = .{ .scalar = .scalable } };
331 pub const z2: Register = .{ .alias = .v2, .format = .{ .scalar = .scalable } };
332 pub const z3: Register = .{ .alias = .v3, .format = .{ .scalar = .scalable } };
333 pub const z4: Register = .{ .alias = .v4, .format = .{ .scalar = .scalable } };
334 pub const z5: Register = .{ .alias = .v5, .format = .{ .scalar = .scalable } };
335 pub const z6: Register = .{ .alias = .v6, .format = .{ .scalar = .scalable } };
336 pub const z7: Register = .{ .alias = .v7, .format = .{ .scalar = .scalable } };
337 pub const z8: Register = .{ .alias = .v8, .format = .{ .scalar = .scalable } };
338 pub const z9: Register = .{ .alias = .v9, .format = .{ .scalar = .scalable } };
339 pub const z10: Register = .{ .alias = .v10, .format = .{ .scalar = .scalable } };
340 pub const z11: Register = .{ .alias = .v11, .format = .{ .scalar = .scalable } };
341 pub const z12: Register = .{ .alias = .v12, .format = .{ .scalar = .scalable } };
342 pub const z13: Register = .{ .alias = .v13, .format = .{ .scalar = .scalable } };
343 pub const z14: Register = .{ .alias = .v14, .format = .{ .scalar = .scalable } };
344 pub const z15: Register = .{ .alias = .v15, .format = .{ .scalar = .scalable } };
345 pub const z16: Register = .{ .alias = .v16, .format = .{ .scalar = .scalable } };
346 pub const z17: Register = .{ .alias = .v17, .format = .{ .scalar = .scalable } };
347 pub const z18: Register = .{ .alias = .v18, .format = .{ .scalar = .scalable } };
348 pub const z19: Register = .{ .alias = .v19, .format = .{ .scalar = .scalable } };
349 pub const z20: Register = .{ .alias = .v20, .format = .{ .scalar = .scalable } };
350 pub const z21: Register = .{ .alias = .v21, .format = .{ .scalar = .scalable } };
351 pub const z22: Register = .{ .alias = .v22, .format = .{ .scalar = .scalable } };
352 pub const z23: Register = .{ .alias = .v23, .format = .{ .scalar = .scalable } };
353 pub const z24: Register = .{ .alias = .v24, .format = .{ .scalar = .scalable } };
354 pub const z25: Register = .{ .alias = .v25, .format = .{ .scalar = .scalable } };
355 pub const z26: Register = .{ .alias = .v26, .format = .{ .scalar = .scalable } };
356 pub const z27: Register = .{ .alias = .v27, .format = .{ .scalar = .scalable } };
357 pub const z28: Register = .{ .alias = .v28, .format = .{ .scalar = .scalable } };
358 pub const z29: Register = .{ .alias = .v29, .format = .{ .scalar = .scalable } };
359 pub const z30: Register = .{ .alias = .v30, .format = .{ .scalar = .scalable } };
360 pub const z31: Register = .{ .alias = .v31, .format = .{ .scalar = .scalable } };
361
362 pub const p0: Register = .{ .alias = .v0, .format = .{ .scalar = .predicate } };
363 pub const p1: Register = .{ .alias = .v1, .format = .{ .scalar = .predicate } };
364 pub const p2: Register = .{ .alias = .v2, .format = .{ .scalar = .predicate } };
365 pub const p3: Register = .{ .alias = .v3, .format = .{ .scalar = .predicate } };
366 pub const p4: Register = .{ .alias = .v4, .format = .{ .scalar = .predicate } };
367 pub const p5: Register = .{ .alias = .v5, .format = .{ .scalar = .predicate } };
368 pub const p6: Register = .{ .alias = .v6, .format = .{ .scalar = .predicate } };
369 pub const p7: Register = .{ .alias = .v7, .format = .{ .scalar = .predicate } };
370 pub const p8: Register = .{ .alias = .v8, .format = .{ .scalar = .predicate } };
371 pub const p9: Register = .{ .alias = .v9, .format = .{ .scalar = .predicate } };
372 pub const p10: Register = .{ .alias = .v10, .format = .{ .scalar = .predicate } };
373 pub const p11: Register = .{ .alias = .v11, .format = .{ .scalar = .predicate } };
374 pub const p12: Register = .{ .alias = .v12, .format = .{ .scalar = .predicate } };
375 pub const p13: Register = .{ .alias = .v13, .format = .{ .scalar = .predicate } };
376 pub const p14: Register = .{ .alias = .v14, .format = .{ .scalar = .predicate } };
377 pub const p15: Register = .{ .alias = .v15, .format = .{ .scalar = .predicate } };
378
379 pub const ffr: Register = .{ .alias = .ffr, .format = .{ .integer = .doubleword } };
380
381 pub const Encoded = enum(u5) {
382 _,
383
384 pub fn decodeInteger(enc: Encoded, sf_enc: IntegerSize, opts: struct { sp: bool = false }) Register {
385 return switch (sf_enc) {
386 .word => switch (@intFromEnum(enc)) {
387 0 => .w0,
388 1 => .w1,
389 2 => .w2,
390 3 => .w3,
391 4 => .w4,
392 5 => .w5,
393 6 => .w6,
394 7 => .w7,
395 8 => .w8,
396 9 => .w9,
397 10 => .w10,
398 11 => .w11,
399 12 => .w12,
400 13 => .w13,
401 14 => .w14,
402 15 => .w15,
403 16 => .w16,
404 17 => .w17,
405 18 => .w18,
406 19 => .w19,
407 20 => .w20,
408 21 => .w21,
409 22 => .w22,
410 23 => .w23,
411 24 => .w24,
412 25 => .w25,
413 26 => .w26,
414 27 => .w27,
415 28 => .w28,
416 29 => .w29,
417 30 => .w30,
418 31 => if (opts.sp) .wsp else .wzr,
419 },
420 .doubleword => switch (@intFromEnum(enc)) {
421 0 => .x0,
422 1 => .x1,
423 2 => .x2,
424 3 => .x3,
425 4 => .x4,
426 5 => .x5,
427 6 => .x6,
428 7 => .x7,
429 8 => .x8,
430 9 => .x9,
431 10 => .x10,
432 11 => .x11,
433 12 => .x12,
434 13 => .x13,
435 14 => .x14,
436 15 => .x15,
437 16 => .x16,
438 17 => .x17,
439 18 => .x18,
440 19 => .x19,
441 20 => .x20,
442 21 => .x21,
443 22 => .x22,
444 23 => .x23,
445 24 => .x24,
446 25 => .x25,
447 26 => .x26,
448 27 => .x27,
449 28 => .x28,
450 29 => .x29,
451 30 => .x30,
452 31 => if (opts.sp) .sp else .xzr,
453 },
454 };
455 }
456
457 pub fn decodeVector(enc: Encoded, vs_enc: VectorSize) Register {
458 return switch (vs_enc) {
459 .byte => switch (@intFromEnum(enc)) {
460 0 => .b0,
461 1 => .b1,
462 2 => .b2,
463 3 => .b3,
464 4 => .b4,
465 5 => .b5,
466 6 => .b6,
467 7 => .b7,
468 8 => .b8,
469 9 => .b9,
470 10 => .b10,
471 11 => .b11,
472 12 => .b12,
473 13 => .b13,
474 14 => .b14,
475 15 => .b15,
476 16 => .b16,
477 17 => .b17,
478 18 => .b18,
479 19 => .b19,
480 20 => .b20,
481 21 => .b21,
482 22 => .b22,
483 23 => .b23,
484 24 => .b24,
485 25 => .b25,
486 26 => .b26,
487 27 => .b27,
488 28 => .b28,
489 29 => .b29,
490 30 => .b30,
491 31 => .b31,
492 },
493 .half => switch (@intFromEnum(enc)) {
494 0 => .h0,
495 1 => .h1,
496 2 => .h2,
497 3 => .h3,
498 4 => .h4,
499 5 => .h5,
500 6 => .h6,
501 7 => .h7,
502 8 => .h8,
503 9 => .h9,
504 10 => .h10,
505 11 => .h11,
506 12 => .h12,
507 13 => .h13,
508 14 => .h14,
509 15 => .h15,
510 16 => .h16,
511 17 => .h17,
512 18 => .h18,
513 19 => .h19,
514 20 => .h20,
515 21 => .h21,
516 22 => .h22,
517 23 => .h23,
518 24 => .h24,
519 25 => .h25,
520 26 => .h26,
521 27 => .h27,
522 28 => .h28,
523 29 => .h29,
524 30 => .h30,
525 31 => .h31,
526 },
527 .single => switch (@intFromEnum(enc)) {
528 0 => .s0,
529 1 => .s1,
530 2 => .s2,
531 3 => .s3,
532 4 => .s4,
533 5 => .s5,
534 6 => .s6,
535 7 => .s7,
536 8 => .s8,
537 9 => .s9,
538 10 => .s10,
539 11 => .s11,
540 12 => .s12,
541 13 => .s13,
542 14 => .s14,
543 15 => .s15,
544 16 => .s16,
545 17 => .s17,
546 18 => .s18,
547 19 => .s19,
548 20 => .s20,
549 21 => .s21,
550 22 => .s22,
551 23 => .s23,
552 24 => .s24,
553 25 => .s25,
554 26 => .s26,
555 27 => .s27,
556 28 => .s28,
557 29 => .s29,
558 30 => .s30,
559 31 => .s31,
560 },
561 .double => switch (@intFromEnum(enc)) {
562 0 => .d0,
563 1 => .d1,
564 2 => .d2,
565 3 => .d3,
566 4 => .d4,
567 5 => .d5,
568 6 => .d6,
569 7 => .d7,
570 8 => .d8,
571 9 => .d9,
572 10 => .d10,
573 11 => .d11,
574 12 => .d12,
575 13 => .d13,
576 14 => .d14,
577 15 => .d15,
578 16 => .d16,
579 17 => .d17,
580 18 => .d18,
581 19 => .d19,
582 20 => .d20,
583 21 => .d21,
584 22 => .d22,
585 23 => .d23,
586 24 => .d24,
587 25 => .d25,
588 26 => .d26,
589 27 => .d27,
590 28 => .d28,
591 29 => .d29,
592 30 => .d30,
593 31 => .d31,
594 },
595 .quad => switch (@intFromEnum(enc)) {
596 0 => .q0,
597 1 => .q1,
598 2 => .q2,
599 3 => .q3,
600 4 => .q4,
601 5 => .q5,
602 6 => .q6,
603 7 => .q7,
604 8 => .q8,
605 9 => .q9,
606 10 => .q10,
607 11 => .q11,
608 12 => .q12,
609 13 => .q13,
610 14 => .q14,
611 15 => .q15,
612 16 => .q16,
613 17 => .q17,
614 18 => .q18,
615 19 => .q19,
616 20 => .q20,
617 21 => .q21,
618 22 => .q22,
619 23 => .q23,
620 24 => .q24,
621 25 => .q25,
622 26 => .q26,
623 27 => .q27,
624 28 => .q28,
625 29 => .q29,
626 30 => .q30,
627 31 => .q31,
628 },
629 .scalable => switch (@intFromEnum(enc)) {
630 0 => .z0,
631 1 => .z1,
632 2 => .z2,
633 3 => .z3,
634 4 => .z4,
635 5 => .z5,
636 6 => .z6,
637 7 => .z7,
638 8 => .z8,
639 9 => .z9,
640 10 => .z10,
641 11 => .z11,
642 12 => .z12,
643 13 => .z13,
644 14 => .z14,
645 15 => .z15,
646 16 => .z16,
647 17 => .z17,
648 18 => .z18,
649 19 => .z19,
650 20 => .z20,
651 21 => .z21,
652 22 => .z22,
653 23 => .z23,
654 24 => .z24,
655 25 => .z25,
656 26 => .z26,
657 27 => .z27,
658 28 => .z28,
659 29 => .z29,
660 30 => .z30,
661 31 => .z31,
662 },
663 .predicate => switch (@as(u4, @intCast(@intFromEnum(enc)))) {
664 0 => .p0,
665 1 => .p1,
666 2 => .p2,
667 3 => .p3,
668 4 => .p4,
669 5 => .p5,
670 6 => .p6,
671 7 => .p7,
672 8 => .p8,
673 9 => .p9,
674 10 => .p10,
675 11 => .p11,
676 12 => .p12,
677 13 => .p13,
678 14 => .p14,
679 15 => .p15,
680 },
681 };
682 }
683 };
684
685 /// One tag per set of aliasing registers.
686 pub const Alias = enum(u7) {
687 r0,
688 r1,
689 r2,
690 r3,
691 r4,
692 r5,
693 r6,
694 r7,
695 r8,
696 r9,
697 r10,
698 r11,
699 r12,
700 r13,
701 r14,
702 r15,
703 r16,
704 r17,
705 r18,
706 r19,
707 r20,
708 r21,
709 r22,
710 r23,
711 r24,
712 r25,
713 r26,
714 r27,
715 r28,
716 r29,
717 r30,
718 zr,
719 sp,
720
721 pc,
722
723 v0,
724 v1,
725 v2,
726 v3,
727 v4,
728 v5,
729 v6,
730 v7,
731 v8,
732 v9,
733 v10,
734 v11,
735 v12,
736 v13,
737 v14,
738 v15,
739 v16,
740 v17,
741 v18,
742 v19,
743 v20,
744 v21,
745 v22,
746 v23,
747 v24,
748 v25,
749 v26,
750 v27,
751 v28,
752 v29,
753 v30,
754 v31,
755
756 fpcr,
757 fpsr,
758
759 p0,
760 p1,
761 p2,
762 p3,
763 p4,
764 p5,
765 p6,
766 p7,
767 p8,
768 p9,
769 p10,
770 p11,
771 p12,
772 p13,
773 p14,
774 p15,
775
776 ffr,
777
778 pub const ip: Alias = .r16;
779 pub const ip0: Alias = .r16;
780 pub const ip1: Alias = .r17;
781 pub const fp: Alias = .r29;
782 pub const lr: Alias = .r30;
783
784 pub fn r(ra: Alias) Register {
785 assert(@intFromEnum(ra) >= @intFromEnum(Alias.r0) and @intFromEnum(ra) <= @intFromEnum(Alias.pc));
786 return .{ .alias = ra, .format = .alias };
787 }
788 pub fn x(ra: Alias) Register {
789 assert(@intFromEnum(ra) >= @intFromEnum(Alias.r0) and @intFromEnum(ra) <= @intFromEnum(Alias.sp));
790 return .{ .alias = ra, .format = .{ .integer = .doubleword } };
791 }
792 pub fn w(ra: Alias) Register {
793 assert(@intFromEnum(ra) >= @intFromEnum(Alias.r0) and @intFromEnum(ra) <= @intFromEnum(Alias.sp));
794 return .{ .alias = ra, .format = .{ .integer = .word } };
795 }
796 pub fn v(ra: Alias) Register {
797 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
798 return .{ .alias = ra, .format = .alias };
799 }
800 pub fn q(ra: Alias) Register {
801 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
802 return .{ .alias = ra, .format = .{ .scalar = .quad } };
803 }
804 pub fn d(ra: Alias) Register {
805 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
806 return .{ .alias = ra, .format = .{ .scalar = .double } };
807 }
808 pub fn s(ra: Alias) Register {
809 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
810 return .{ .alias = ra, .format = .{ .scalar = .single } };
811 }
812 pub fn h(ra: Alias) Register {
813 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
814 return .{ .alias = ra, .format = .{ .scalar = .half } };
815 }
816 pub fn b(ra: Alias) Register {
817 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
818 return .{ .alias = ra, .format = .{ .scalar = .byte } };
819 }
820 pub fn z(ra: Alias) Register {
821 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
822 return .{ .alias = ra, .format = .{ .scalar = .scalable } };
823 }
824 pub fn p(ra: Alias) Register {
825 assert(@intFromEnum(ra) >= @intFromEnum(Alias.p0) and @intFromEnum(ra) <= @intFromEnum(Alias.p15));
826 return .{ .alias = ra, .format = .{ .scalar = .predicate } };
827 }
828 pub fn @"2d"(ra: Alias) Register {
829 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
830 return .{ .alias = ra, .format = .{ .vector = .@"2d" } };
831 }
832 pub fn @"4s"(ra: Alias) Register {
833 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
834 return .{ .alias = ra, .format = .{ .vector = .@"4s" } };
835 }
836 pub fn @"8h"(ra: Alias) Register {
837 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
838 return .{ .alias = ra, .format = .{ .vector = .@"8h" } };
839 }
840 pub fn @"16b"(ra: Alias) Register {
841 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
842 return .{ .alias = ra, .format = .{ .vector = .@"16b" } };
843 }
844 pub fn @"1d"(ra: Alias) Register {
845 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
846 return .{ .alias = ra, .format = .{ .vector = .@"1d" } };
847 }
848 pub fn @"2s"(ra: Alias) Register {
849 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
850 return .{ .alias = ra, .format = .{ .vector = .@"2s" } };
851 }
852 pub fn @"4h"(ra: Alias) Register {
853 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
854 return .{ .alias = ra, .format = .{ .vector = .@"4h" } };
855 }
856 pub fn @"8b"(ra: Alias) Register {
857 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
858 return .{ .alias = ra, .format = .{ .vector = .@"8b" } };
859 }
860 pub fn @"d[]"(ra: Alias, index: u1) Register {
861 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
862 return .{ .alias = ra, .format = .{ .element = .{ .size = .double, .index = index } } };
863 }
864 pub fn @"s[]"(ra: Alias, index: u2) Register {
865 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
866 return .{ .alias = ra, .format = .{ .element = .{ .size = .single, .index = index } } };
867 }
868 pub fn @"h[]"(ra: Alias, index: u3) Register {
869 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
870 return .{ .alias = ra, .format = .{ .element = .{ .size = .half, .index = index } } };
871 }
872 pub fn @"b[]"(ra: Alias, index: u4) Register {
873 assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31));
874 return .{ .alias = ra, .format = .{ .element = .{ .size = .byte, .index = index } } };
875 }
876
877 pub fn isVector(ra: Alias) bool {
878 return switch (ra) {
879 .r0,
880 .r1,
881 .r2,
882 .r3,
883 .r4,
884 .r5,
885 .r6,
886 .r7,
887 .r8,
888 .r9,
889 .r10,
890 .r11,
891 .r12,
892 .r13,
893 .r14,
894 .r15,
895 .r16,
896 .r17,
897 .r18,
898 .r19,
899 .r20,
900 .r21,
901 .r22,
902 .r23,
903 .r24,
904 .r25,
905 .r26,
906 .r27,
907 .r28,
908 .r29,
909 .r30,
910 .zr,
911 .sp,
912
913 .pc,
914
915 .fpcr,
916 .fpsr,
917
918 .ffr,
919 => false,
920
921 .v0,
922 .v1,
923 .v2,
924 .v3,
925 .v4,
926 .v5,
927 .v6,
928 .v7,
929 .v8,
930 .v9,
931 .v10,
932 .v11,
933 .v12,
934 .v13,
935 .v14,
936 .v15,
937 .v16,
938 .v17,
939 .v18,
940 .v19,
941 .v20,
942 .v21,
943 .v22,
944 .v23,
945 .v24,
946 .v25,
947 .v26,
948 .v27,
949 .v28,
950 .v29,
951 .v30,
952 .v31,
953
954 .p0,
955 .p1,
956 .p2,
957 .p3,
958 .p4,
959 .p5,
960 .p6,
961 .p7,
962 .p8,
963 .p9,
964 .p10,
965 .p11,
966 .p12,
967 .p13,
968 .p14,
969 .p15,
970 => true,
971 };
972 }
973
974 pub fn encode(ra: Alias, comptime opts: struct { sp: bool = false, V: bool = false }) Encoded {
975 return @enumFromInt(@as(u5, switch (ra) {
976 .r0 => if (opts.V) unreachable else 0,
977 .r1 => if (opts.V) unreachable else 1,
978 .r2 => if (opts.V) unreachable else 2,
979 .r3 => if (opts.V) unreachable else 3,
980 .r4 => if (opts.V) unreachable else 4,
981 .r5 => if (opts.V) unreachable else 5,
982 .r6 => if (opts.V) unreachable else 6,
983 .r7 => if (opts.V) unreachable else 7,
984 .r8 => if (opts.V) unreachable else 8,
985 .r9 => if (opts.V) unreachable else 9,
986 .r10 => if (opts.V) unreachable else 10,
987 .r11 => if (opts.V) unreachable else 11,
988 .r12 => if (opts.V) unreachable else 12,
989 .r13 => if (opts.V) unreachable else 13,
990 .r14 => if (opts.V) unreachable else 14,
991 .r15 => if (opts.V) unreachable else 15,
992 .r16 => if (opts.V) unreachable else 16,
993 .r17 => if (opts.V) unreachable else 17,
994 .r18 => if (opts.V) unreachable else 18,
995 .r19 => if (opts.V) unreachable else 19,
996 .r20 => if (opts.V) unreachable else 20,
997 .r21 => if (opts.V) unreachable else 21,
998 .r22 => if (opts.V) unreachable else 22,
999 .r23 => if (opts.V) unreachable else 23,
1000 .r24 => if (opts.V) unreachable else 24,
1001 .r25 => if (opts.V) unreachable else 25,
1002 .r26 => if (opts.V) unreachable else 26,
1003 .r27 => if (opts.V) unreachable else 27,
1004 .r28 => if (opts.V) unreachable else 28,
1005 .r29 => if (opts.V) unreachable else 29,
1006 .r30 => if (opts.V) unreachable else 30,
1007 .zr => if (opts.sp or opts.V) unreachable else 31,
1008 .sp => if (opts.sp and !opts.V) 31 else unreachable,
1009 .pc => unreachable,
1010 .v0 => if (opts.V) 0 else unreachable,
1011 .v1 => if (opts.V) 1 else unreachable,
1012 .v2 => if (opts.V) 2 else unreachable,
1013 .v3 => if (opts.V) 3 else unreachable,
1014 .v4 => if (opts.V) 4 else unreachable,
1015 .v5 => if (opts.V) 5 else unreachable,
1016 .v6 => if (opts.V) 6 else unreachable,
1017 .v7 => if (opts.V) 7 else unreachable,
1018 .v8 => if (opts.V) 8 else unreachable,
1019 .v9 => if (opts.V) 9 else unreachable,
1020 .v10 => if (opts.V) 10 else unreachable,
1021 .v11 => if (opts.V) 11 else unreachable,
1022 .v12 => if (opts.V) 12 else unreachable,
1023 .v13 => if (opts.V) 13 else unreachable,
1024 .v14 => if (opts.V) 14 else unreachable,
1025 .v15 => if (opts.V) 15 else unreachable,
1026 .v16 => if (opts.V) 16 else unreachable,
1027 .v17 => if (opts.V) 17 else unreachable,
1028 .v18 => if (opts.V) 18 else unreachable,
1029 .v19 => if (opts.V) 19 else unreachable,
1030 .v20 => if (opts.V) 20 else unreachable,
1031 .v21 => if (opts.V) 21 else unreachable,
1032 .v22 => if (opts.V) 22 else unreachable,
1033 .v23 => if (opts.V) 23 else unreachable,
1034 .v24 => if (opts.V) 24 else unreachable,
1035 .v25 => if (opts.V) 25 else unreachable,
1036 .v26 => if (opts.V) 26 else unreachable,
1037 .v27 => if (opts.V) 27 else unreachable,
1038 .v28 => if (opts.V) 28 else unreachable,
1039 .v29 => if (opts.V) 29 else unreachable,
1040 .v30 => if (opts.V) 30 else unreachable,
1041 .v31 => if (opts.V) 31 else unreachable,
1042 .fpcr, .fpsr => unreachable,
1043 .p0, .p1, .p2, .p3, .p4, .p5, .p6, .p7, .p8, .p9, .p10, .p11, .p12, .p13, .p14, .p15 => unreachable,
1044 .ffr => unreachable,
1045 }));
1046 }
1047 };
1048
1049 pub fn isVector(reg: Register) bool {
1050 return reg.alias.isVector();
1051 }
1052
1053 pub fn size(reg: Register) ?u5 {
1054 return format: switch (reg.format) {
1055 .alias => unreachable,
1056 .integer => |sf| switch (sf) {
1057 .word => 4,
1058 .doubleword => 8,
1059 },
1060 .vector => |vs| switch (vs) {
1061 .byte => 1,
1062 .word => 2,
1063 .single => 4,
1064 .double => 8,
1065 .quad => 16,
1066 .scalable, .predicate => null,
1067 },
1068 .arrangement => |arrangement| switch (arrangement) {
1069 .@"2d", .@"4s", .@"8h", .@"16b" => 16,
1070 .@"1d", .@"2s", .@"4h", .@"8b" => 8,
1071 },
1072 .element => |element| continue :format .{ .vector = element.size },
1073 };
1074 }
1075
1076 pub fn parse(reg: []const u8) ?Register {
1077 return if (reg.len == 0) null else switch (std.ascii.toLower(reg[0])) {
1078 else => null,
1079 'r' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| switch (n) {
1080 0...30 => .{
1081 .alias = @enumFromInt(@intFromEnum(Alias.r0) + n),
1082 .format = .alias,
1083 },
1084 31 => null,
1085 } else |_| null,
1086 'x' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| switch (n) {
1087 0...30 => .{
1088 .alias = @enumFromInt(@intFromEnum(Alias.r0) + n),
1089 .format = .{ .integer = .doubleword },
1090 },
1091 31 => null,
1092 } else |_| if (toLowerEqlAssertLower(reg, "xzr")) .xzr else null,
1093 'w' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| switch (n) {
1094 0...30 => .{
1095 .alias = @enumFromInt(@intFromEnum(Alias.r0) + n),
1096 .format = .{ .integer = .word },
1097 },
1098 31 => null,
1099 } else |_| if (toLowerEqlAssertLower(reg, "wzr"))
1100 .wzr
1101 else if (toLowerEqlAssertLower(reg, "wsp"))
1102 .wsp
1103 else
1104 null,
1105 'i' => return if (toLowerEqlAssertLower(reg, "ip") or toLowerEqlAssertLower(reg, "ip0"))
1106 .ip0
1107 else if (toLowerEqlAssertLower(reg, "ip1"))
1108 .ip1
1109 else
1110 null,
1111 'f' => return if (toLowerEqlAssertLower(reg, "fp")) .fp else null,
1112 'p' => return if (toLowerEqlAssertLower(reg, "pc")) .pc else null,
1113 'v' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{
1114 .alias = @enumFromInt(@intFromEnum(Alias.v0) + n),
1115 .format = .alias,
1116 } else |_| null,
1117 'q' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{
1118 .alias = @enumFromInt(@intFromEnum(Alias.v0) + n),
1119 .format = .{ .scalar = .quad },
1120 } else |_| null,
1121 'd' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{
1122 .alias = @enumFromInt(@intFromEnum(Alias.v0) + n),
1123 .format = .{ .scalar = .double },
1124 } else |_| null,
1125 's' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{
1126 .alias = @enumFromInt(@intFromEnum(Alias.v0) + n),
1127 .format = .{ .scalar = .single },
1128 } else |_| if (toLowerEqlAssertLower(reg, "sp")) .sp else null,
1129 'h' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{
1130 .alias = @enumFromInt(@intFromEnum(Alias.v0) + n),
1131 .format = .{ .scalar = .half },
1132 } else |_| null,
1133 'b' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{
1134 .alias = @enumFromInt(@intFromEnum(Alias.v0) + n),
1135 .format = .{ .scalar = .byte },
1136 } else |_| null,
1137 };
1138 }
1139
1140 pub fn fmt(reg: Register) aarch64.Disassemble.RegisterFormatter {
1141 return reg.fmtCase(.lower);
1142 }
1143 pub fn fmtCase(reg: Register, case: aarch64.Disassemble.Case) aarch64.Disassemble.RegisterFormatter {
1144 return .{ .reg = reg, .case = case };
1145 }
1146
1147 pub const System = packed struct(u16) {
1148 op2: u3,
1149 CRm: u4,
1150 CRn: u4,
1151 op1: u3,
1152 op0: u2,
1153
1154 // D19.2 General system control registers
1155 /// D19.2.1 ACCDATA_EL1, Accelerator Data
1156 pub const accdata_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b101 };
1157 /// D19.2.2 ACTLR_EL1, Auxiliary Control Register (EL1)
1158 pub const actlr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b001 };
1159 /// D19.2.3 ACTLR_EL2, Auxiliary Control Register (EL2)
1160 pub const actlr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b001 };
1161 /// D19.2.4 ACTLR_EL3, Auxiliary Control Register (EL3)
1162 pub const actlr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b001 };
1163 /// D19.2.5 AFSR0_EL1, Auxiliary Fault Status Register 0 (EL1)
1164 pub const afsr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b000 };
1165 /// D19.2.5 AFSR0_EL12, Auxiliary Fault Status Register 0 (EL12)
1166 pub const afsr0_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b000 };
1167 /// D19.2.6 AFSR0_EL2, Auxiliary Fault Status Register 0 (EL2)
1168 pub const afsr0_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b000 };
1169 /// D19.2.7 AFSR0_EL3, Auxiliary Fault Status Register 0 (EL3)
1170 pub const afsr0_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b000 };
1171 /// D19.2.8 AFSR1_EL1, Auxiliary Fault Status Register 1 (EL1)
1172 pub const afsr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b001 };
1173 /// D19.2.8 AFSR1_EL12, Auxiliary Fault Status Register 1 (EL12)
1174 pub const afsr1_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b001 };
1175 /// D19.2.9 AFSR1_EL2, Auxiliary Fault Status Register 1 (EL2)
1176 pub const afsr1_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b001 };
1177 /// D19.2.10 AFSR1_EL3, Auxiliary Fault Status Register 1 (EL3)
1178 pub const afsr1_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b001 };
1179 /// D19.2.11 AIDR_EL1, Auxiliary ID Register
1180 pub const aidr_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b111 };
1181 /// D19.2.12 AMAIR_EL1, Auxiliary Memory Attribute Indirection Register (EL1)
1182 pub const amair_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0011, .op2 = 0b000 };
1183 /// D19.2.12 AMAIR_EL12, Auxiliary Memory Attribute Indirection Register (EL12)
1184 pub const amair_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1010, .CRm = 0b0011, .op2 = 0b000 };
1185 /// D19.2.13 AMAIR_EL2, Auxiliary Memory Attribute Indirection Register (EL2)
1186 pub const amair_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1010, .CRm = 0b0011, .op2 = 0b000 };
1187 /// D19.2.14 AMAIR_EL3, Auxiliary Memory Attribute Indirection Register (EL3)
1188 pub const amair_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1010, .CRm = 0b0011, .op2 = 0b000 };
1189 /// D19.2.15 APDAKeyHi_EL1, Pointer Authentication Key A for Data (bits[127:64])
1190 pub const apdakeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b001 };
1191 /// D19.2.16 APDAKeyLo_EL1, Pointer Authentication Key A for Data (bits[63:0])
1192 pub const apdakeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b000 };
1193 /// D19.2.17 APDBKeyHi_EL1, Pointer Authentication Key B for Data (bits[127:64])
1194 pub const apdbkeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b011 };
1195 /// D19.2.18 APDAKeyHi_EL1, Pointer Authentication Key B for Data (bits[63:0])
1196 pub const apdbkeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b010 };
1197 /// D19.2.19 APGAKeyHi_EL1, Pointer Authentication Key A for Code (bits[127:64])
1198 pub const apgakeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0011, .op2 = 0b001 };
1199 /// D19.2.20 APGAKeyLo_EL1, Pointer Authentication Key A for Code (bits[63:0])
1200 pub const apgakeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0011, .op2 = 0b000 };
1201 /// D19.2.21 APIAKeyHi_EL1, Pointer Authentication Key A for Instruction (bits[127:64])
1202 pub const apiakeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b001 };
1203 /// D19.2.22 APIAKeyLo_EL1, Pointer Authentication Key A for Instruction (bits[63:0])
1204 pub const apiakeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b000 };
1205 /// D19.2.23 APIBKeyHi_EL1, Pointer Authentication Key B for Instruction (bits[127:64])
1206 pub const apibkeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b011 };
1207 /// D19.2.24 APIBKeyLo_EL1, Pointer Authentication Key B for Instruction (bits[63:0])
1208 pub const apibkeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b010 };
1209 /// D19.2.25 CCSIDR2_EL1, Current Cache Size ID Register 2
1210 pub const ccsidr2_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b010 };
1211 /// D19.2.26 CCSIDR_EL1, Current Cache Size ID Register
1212 pub const ccsidr_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b000 };
1213 /// D19.2.27 CLIDR_EL1, Cache Level ID Register
1214 pub const clidr_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b001 };
1215 /// D19.2.28 CONTEXTIDR_EL1, Context ID Register (EL1)
1216 pub const contextidr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b001 };
1217 /// D19.2.28 CONTEXTIDR_EL12, Context ID Register (EL12)
1218 pub const contextidr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b001 };
1219 /// D19.2.29 CONTEXTIDR_EL2, Context ID Register (EL2)
1220 pub const contextidr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b001 };
1221 /// D19.2.30 CPACR_EL1, Architectural Feature Access Control Register
1222 pub const cpacr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b010 };
1223 /// D19.2.30 CPACR_EL12, Architectural Feature Access Control Register
1224 pub const cpacr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b010 };
1225 /// D19.2.31 CPACR_EL2, Architectural Feature Trap Register (EL2)
1226 pub const cptr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b010 };
1227 /// D19.2.32 CPACR_EL3, Architectural Feature Trap Register (EL3)
1228 pub const cptr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b010 };
1229 /// D19.2.33 CSSELR_EL1, Cache Size Selection Register
1230 pub const csselr_el1: System = .{ .op0 = 0b11, .op1 = 0b010, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b000 };
1231 /// D19.2.34 CTR_EL0, Cache Type Register
1232 pub const ctr_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b001 };
1233 /// D19.2.35 DACR32_EL2, Domain Access Control Register
1234 pub const dacr32_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0011, .CRm = 0b0000, .op2 = 0b000 };
1235 /// D19.2.36 DCZID_EL0, Data Cache Zero ID Register
1236 pub const dczid_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b111 };
1237 /// D19.2.37 ESR_EL1, Exception Syndrome Register (EL1)
1238 pub const esr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0010, .op2 = 0b000 };
1239 /// D19.2.37 ESR_EL12, Exception Syndrome Register (EL12)
1240 pub const esr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0101, .CRm = 0b0010, .op2 = 0b000 };
1241 /// D19.2.38 ESR_EL2, Exception Syndrome Register (EL2)
1242 pub const esr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0010, .op2 = 0b000 };
1243 /// D19.2.39 ESR_EL3, Exception Syndrome Register (EL3)
1244 pub const esr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0101, .CRm = 0b0010, .op2 = 0b000 };
1245 /// D19.2.40 FAR_EL1, Fault Address Register (EL1)
1246 pub const far_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b000 };
1247 /// D19.2.40 FAR_EL12, Fault Address Register (EL12)
1248 pub const far_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b000 };
1249 /// D19.2.41 FAR_EL2, Fault Address Register (EL2)
1250 pub const far_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b000 };
1251 /// D19.2.42 FAR_EL3, Fault Address Register (EL3)
1252 pub const far_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b000 };
1253 /// D19.2.43 FPEXC32_EL2, Floating-Point Exception Control Register
1254 pub const fpexc32_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0011, .op2 = 0b000 };
1255 /// D19.2.44 GCR_EL1, Tag Control Register
1256 pub const gcr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b110 };
1257 /// D19.2.45 GMID_EL1, Tag Control Register
1258 pub const gmid_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b100 };
1259 /// D19.2.46 HACR_EL2, Hypervisor Auxiliary Control Register
1260 pub const hacr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b111 };
1261 /// D19.2.47 HAFGRTR_EL2, Hypervisor Activity Monitors Fine-Grained Read Trap Register
1262 pub const hafgrtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0011, .CRm = 0b0001, .op2 = 0b110 };
1263 /// D19.2.48 HCR_EL2, Hypervisor Configuration Register
1264 pub const hcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b000 };
1265 /// D19.2.49 HCRX_EL2, Extended Hypervisor Configuration Register
1266 pub const hcrx_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b010 };
1267 /// D19.2.50 HDFGRTR_EL2, Hypervisor Debug Fine-Grained Read Trap Register
1268 pub const hdfgrtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0011, .CRm = 0b0001, .op2 = 0b100 };
1269 /// D19.2.51 HDFGWTR_EL2, Hypervisor Debug Fine-Grained Write Trap Register
1270 pub const hdfgwtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0011, .CRm = 0b0001, .op2 = 0b101 };
1271 /// D19.2.52 HFGITR_EL2, Hypervisor Fine-Grained Instruction Trap Register
1272 pub const hfgitr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b110 };
1273 /// D19.2.53 HFGRTR_EL2, Hypervisor Fine-Grained Read Trap Register
1274 pub const hfgrtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b100 };
1275 /// D19.2.54 HFGWTR_EL2, Hypervisor Fine-Grained Write Trap Register
1276 pub const hfgwtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b101 };
1277 /// D19.2.55 HPFAR_EL2, Hypervisor IPA Fault Address Register
1278 pub const hpfar_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b100 };
1279 /// D19.2.56 HSTR_EL2, Hypervisor System Trap Register
1280 pub const hstr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b011 };
1281 /// D19.2.57 ID_AA64AFR0_EL1, AArch64 Auxiliary Feature Register 0
1282 pub const id_aa64afr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0101, .op2 = 0b100 };
1283 /// D19.2.58 ID_AA64AFR1_EL1, AArch64 Auxiliary Feature Register 1
1284 pub const id_aa64afr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0101, .op2 = 0b101 };
1285 /// D19.2.59 ID_AA64DFR0_EL1, AArch64 Debug Feature Register 0
1286 pub const id_aa64dfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0101, .op2 = 0b000 };
1287 /// D19.2.60 ID_AA64DFR1_EL1, AArch64 Debug Feature Register 1
1288 pub const id_aa64dfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0101, .op2 = 0b001 };
1289 /// D19.2.61 ID_AA64ISAR0_EL1, AArch64 Instruction Set Attribute Register 0
1290 pub const id_aa64isar0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0110, .op2 = 0b000 };
1291 /// D19.2.62 ID_AA64ISAR1_EL1, AArch64 Instruction Set Attribute Register 1
1292 pub const id_aa64isar1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0110, .op2 = 0b001 };
1293 /// D19.2.63 ID_AA64ISAR2_EL1, AArch64 Instruction Set Attribute Register 2
1294 pub const id_aa64isar2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0110, .op2 = 0b010 };
1295 /// D19.2.64 ID_AA64MMFR0_EL1, AArch64 Memory Model Feature Register 0
1296 pub const id_aa64mmfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b000 };
1297 /// D19.2.65 ID_AA64MMFR1_EL1, AArch64 Memory Model Feature Register 1
1298 pub const id_aa64mmfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b001 };
1299 /// D19.2.66 ID_AA64MMFR2_EL1, AArch64 Memory Model Feature Register 2
1300 pub const id_aa64mmfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b010 };
1301 /// D19.2.67 ID_AA64MMFR3_EL1, AArch64 Memory Model Feature Register 3
1302 pub const id_aa64mmfr3_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b011 };
1303 /// D19.2.68 ID_AA64MMFR4_EL1, AArch64 Memory Model Feature Register 4
1304 pub const id_aa64mmfr4_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b100 };
1305 /// D19.2.69 ID_AA64PFR0_EL1, AArch64 Processor Feature Register 0
1306 pub const id_aa64pfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b000 };
1307 /// D19.2.70 ID_AA64PFR1_EL1, AArch64 Processor Feature Register 1
1308 pub const id_aa64pfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b001 };
1309 /// D19.2.71 ID_AA64PFR2_EL1, AArch64 Processor Feature Register 2
1310 pub const id_aa64pfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b010 };
1311 /// D19.2.72 ID_AA64SMFR0_EL1, SME Feature ID Register 0
1312 pub const id_aa64smfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b101 };
1313 /// D19.2.73 ID_AA64ZFR0_EL1, SVE Feature ID Register 0
1314 pub const id_aa64zfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b100 };
1315 /// D19.2.74 ID_AFR0_EL1, AArch32 Auxiliary Feature Register 0
1316 pub const id_afr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b011 };
1317 /// D19.2.75 ID_DFR0_EL1, AArch32 Debug Feature Register 0
1318 pub const id_dfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b010 };
1319 /// D19.2.76 ID_DFR1_EL1, AArch32 Debug Feature Register 1
1320 pub const id_dfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b101 };
1321 /// D19.2.77 ID_ISAR0_EL1, AArch32 Instruction Set Attribute Register 0
1322 pub const id_isar0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b000 };
1323 /// D19.2.78 ID_ISAR1_EL1, AArch32 Instruction Set Attribute Register 1
1324 pub const id_isar1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b001 };
1325 /// D19.2.79 ID_ISAR2_EL1, AArch32 Instruction Set Attribute Register 2
1326 pub const id_isar2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b010 };
1327 /// D19.2.80 ID_ISAR3_EL1, AArch32 Instruction Set Attribute Register 3
1328 pub const id_isar3_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b011 };
1329 /// D19.2.81 ID_ISAR4_EL1, AArch32 Instruction Set Attribute Register 4
1330 pub const id_isar4_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b100 };
1331 /// D19.2.82 ID_ISAR5_EL1, AArch32 Instruction Set Attribute Register 5
1332 pub const id_isar5_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b101 };
1333 /// D19.2.83 ID_ISAR6_EL1, AArch32 Instruction Set Attribute Register 6
1334 pub const id_isar6_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b111 };
1335 /// D19.2.84 ID_MMFR0_EL1, AArch32 Memory Model Feature Register 0
1336 pub const id_mmfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b100 };
1337 /// D19.2.85 ID_MMFR1_EL1, AArch32 Memory Model Feature Register 1
1338 pub const id_mmfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b101 };
1339 /// D19.2.86 ID_MMFR2_EL1, AArch32 Memory Model Feature Register 2
1340 pub const id_mmfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b110 };
1341 /// D19.2.87 ID_MMFR3_EL1, AArch32 Memory Model Feature Register 3
1342 pub const id_mmfr3_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b111 };
1343 /// D19.2.88 ID_MMFR4_EL1, AArch32 Memory Model Feature Register 4
1344 pub const id_mmfr4_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b110 };
1345 /// D19.2.89 ID_MMFR5_EL1, AArch32 Memory Model Feature Register 5
1346 pub const id_mmfr5_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b110 };
1347 /// D19.2.90 ID_PFR0_EL1, AArch32 Processor Feature Register 0
1348 pub const id_pfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b000 };
1349 /// D19.2.91 ID_PFR1_EL1, AArch32 Processor Feature Register 1
1350 pub const id_pfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b001 };
1351 /// D19.2.92 ID_PFR2_EL1, AArch32 Processor Feature Register 2
1352 pub const id_pfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b100 };
1353 /// D19.2.93 IFSR32_EL2, Instruction Fault Status Register (EL2)
1354 pub const ifsr32_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0000, .op2 = 0b001 };
1355 /// D19.2.94 ISR_EL1, Interrupt Status Register
1356 pub const isr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1100, .CRm = 0b0001, .op2 = 0b000 };
1357 /// D19.2.95 LORC_EL1, LORegion Control (EL1)
1358 pub const lorc_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b011 };
1359 /// D19.2.96 LOREA_EL1, LORegion End Address (EL1)
1360 pub const lorea_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b001 };
1361 /// D19.2.97 SORID_EL1, LORegionID (EL1)
1362 pub const lorid_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b111 };
1363 /// D19.2.98 LORN_EL1, LORegion Number (EL1)
1364 pub const lorn_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b010 };
1365 /// D19.2.99 LORSA_EL1, LORegion Start Address (EL1)
1366 pub const lorsa_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b000 };
1367 /// D19.2.100 MAIR_EL1, Memory Attribute Indirection Register (EL1)
1368 pub const mair_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0010, .op2 = 0b000 };
1369 /// D19.2.100 MAIR_EL12, Memory Attribute Indirection Register (EL12)
1370 pub const mair_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1010, .CRm = 0b0010, .op2 = 0b000 };
1371 /// D19.2.101 MAIR_EL2, Memory Attribute Indirection Register (EL2)
1372 pub const mair_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1010, .CRm = 0b0010, .op2 = 0b000 };
1373 /// D19.2.102 MAIR_EL3, Memory Attribute Indirection Register (EL3)
1374 pub const mair_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1010, .CRm = 0b0010, .op2 = 0b000 };
1375 /// D19.2.103 MIDR_EL1, Main ID Register
1376 pub const midr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b000 };
1377 /// D19.2.104 MPIDR_EL1, Multiprocessor Affinity Register
1378 pub const mpidr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b101 };
1379 /// D19.2.105 MVFR0_EL1, AArch32 Media and VFP Feature Register 0
1380 pub const mvfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b000 };
1381 /// D19.2.106 MVFR1_EL1, AArch32 Media and VFP Feature Register 1
1382 pub const mvfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b001 };
1383 /// D19.2.107 MVFR2_EL1, AArch32 Media and VFP Feature Register 2
1384 pub const mvfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b010 };
1385 /// D19.2.108 PAR_EL1, Physical Address Register
1386 pub const par_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0111, .CRm = 0b0100, .op2 = 0b000 };
1387 /// D19.2.109 REVIDR_EL1, Revision ID Register
1388 pub const revidr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b110 };
1389 /// D19.2.110 RGSR_EL1, Random Allocation Tag Seed Register
1390 pub const rgsr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b101 };
1391 /// D19.2.111 RMR_EL1, Reset Management Register (EL1)
1392 pub const rmr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b010 };
1393 /// D19.2.112 RMR_EL2, Reset Management Register (EL2)
1394 pub const rmr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b010 };
1395 /// D19.2.113 RMR_EL3, Reset Management Register (EL3)
1396 pub const rmr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b010 };
1397 /// D19.2.114 RNDR, Random Number
1398 pub const rndr: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b0010, .CRm = 0b0100, .op2 = 0b000 };
1399 /// D19.2.115 RNDRRS, Reseeded Random Number
1400 pub const rndrrs: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b0010, .CRm = 0b0100, .op2 = 0b001 };
1401 /// D19.2.116 RVBAR_EL1, Reset Vector Base Address Register (if EL2 and EL3 not implemented)
1402 pub const rvbar_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b001 };
1403 /// D19.2.117 RVBAR_EL2, Reset Vector Base Address Register (if EL3 not implemented)
1404 pub const rvbar_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b001 };
1405 /// D19.2.118 RVBAR_EL3, Reset Vector Base Address Register (if EL3 implemented)
1406 pub const rvbar_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b001 };
1407 /// D19.2.120 SCR_EL3, Secure Configuration Register
1408 pub const scr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b000 };
1409 /// D19.2.121 SCTLR2_EL1, System Control Register (EL1)
1410 pub const sctlr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b011 };
1411 /// D19.2.121 SCTLR2_EL12, System Control Register (EL12)
1412 pub const sctlr2_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b011 };
1413 /// D19.2.122 SCTLR2_EL2, System Control Register (EL2)
1414 pub const sctlr2_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b011 };
1415 /// D19.2.123 SCTLR2_EL3, System Control Register (EL3)
1416 pub const sctlr2_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b011 };
1417 /// D19.2.124 SCTLR_EL1, System Control Register (EL1)
1418 pub const sctlr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b000 };
1419 /// D19.2.124 SCTLR_EL12, System Control Register (EL12)
1420 pub const sctlr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b000 };
1421 /// D19.2.125 SCTLR_EL2, System Control Register (EL2)
1422 pub const sctlr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b000 };
1423 /// D19.2.126 SCTLR_EL3, System Control Register (EL3)
1424 pub const sctlr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b000 };
1425 /// D19.2.127 SCXTNUM_EL0, EL0 Read/Write Software Context Number
1426 pub const scxtnum_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 };
1427 /// D19.2.128 SCXTNUM_EL1, EL1 Read/Write Software Context Number
1428 pub const scxtnum_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 };
1429 /// D19.2.128 SCXTNUM_EL12, EL12 Read/Write Software Context Number
1430 pub const scxtnum_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 };
1431 /// D19.2.129 SCXTNUM_EL2, EL2 Read/Write Software Context Number
1432 pub const scxtnum_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 };
1433 /// D19.2.130 SCXTNUM_EL3, EL3 Read/Write Software Context Number
1434 pub const scxtnum_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 };
1435 /// D19.2.131 SMCR_EL1, SME Control Register (EL1)
1436 pub const smcr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b110 };
1437 /// D19.2.131 SMCR_EL12, SME Control Register (EL12)
1438 pub const smcr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b110 };
1439 /// D19.2.132 SMCR_EL2, SME Control Register (EL2)
1440 pub const smcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b110 };
1441 /// D19.2.133 SMCR_EL3, SME Control Register (EL3)
1442 pub const smcr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b110 };
1443 /// D19.2.134 SMIDR_EL1, Streaming Mode Identification Register
1444 pub const smidr_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b110 };
1445 /// D19.2.135 SMPRIMAP_EL2, Streaming Mode Priority Mapping Register
1446 pub const smprimap_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b101 };
1447 /// D19.2.136 SMPRI_EL1, Streaming Mode Priority Register
1448 pub const smpri_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b100 };
1449 /// D19.2.137 TCR2_EL1, Extended Translation Control Register (EL1)
1450 pub const tcr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b011 };
1451 /// D19.2.137 TCR2_EL12, Extended Translation Control Register (EL12)
1452 pub const tcr2_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b011 };
1453 /// D19.2.138 TCR2_EL2, Extended Translation Control Register (EL2)
1454 pub const tcr2_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b011 };
1455 /// D19.2.139 TCR_EL1, Translation Control Register (EL1)
1456 pub const tcr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b010 };
1457 /// D19.2.139 TCR_EL12, Translation Control Register (EL12)
1458 pub const tcr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b010 };
1459 /// D19.2.140 TCR_EL2, Translation Control Register (EL2)
1460 pub const tcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b010 };
1461 /// D19.2.141 TCR_EL3, Translation Control Register (EL3)
1462 pub const tcr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b010 };
1463 /// D19.2.142 TFSRE0_EL1, Tag Fault Status Register (EL0)
1464 pub const tfsre0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b001 };
1465 /// D19.2.143 TFSR_EL1, Tag Fault Status Register (EL1)
1466 pub const tfsr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b000 };
1467 /// D19.2.143 TFSR_EL12, Tag Fault Status Register (EL12)
1468 pub const tfsr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b000 };
1469 /// D19.2.144 TFSR_EL2, Tag Fault Status Register (EL2)
1470 pub const tfsr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b000 };
1471 /// D19.2.145 TFSR_EL3, Tag Fault Status Register (EL3)
1472 pub const tfsr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b000 };
1473 /// D19.2.146 TPIDR2_EL0, EL0 Read/Write Software Thread ID Register 2
1474 pub const tpidr2_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b101 };
1475 /// D19.2.147 TPIDR_EL0, EL0 Read/Write Software Thread ID Register
1476 pub const tpidr_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b010 };
1477 /// D19.2.148 TPIDR_EL1, EL1 Read/Write Software Thread ID Register
1478 pub const tpidr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b100 };
1479 /// D19.2.149 TPIDR_EL2, EL2 Read/Write Software Thread ID Register
1480 pub const tpidr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b010 };
1481 /// D19.2.150 TPIDR_EL3, EL3 Read/Write Software Thread ID Register
1482 pub const tpidr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b010 };
1483 /// D19.2.151 TPIDRRO_EL0, EL0 Read-Only Software Thread ID Register
1484 pub const tpidrro_el3: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b011 };
1485 /// D19.2.152 TTBR0_EL1, Translation Table Base Register 0 (EL1)
1486 pub const ttbr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b000 };
1487 /// D19.2.152 TTBR0_EL12, Translation Table Base Register 0 (EL12)
1488 pub const ttbr0_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b000 };
1489 /// D19.2.153 TTBR0_EL2, Translation Table Base Register 0 (EL2)
1490 pub const ttbr0_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b000 };
1491 /// D19.2.154 TTBR0_EL3, Translation Table Base Register 0 (EL3)
1492 pub const ttbr0_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b000 };
1493 /// D19.2.155 TTBR1_EL1, Translation Table Base Register 1 (EL1)
1494 pub const ttbr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b001 };
1495 /// D19.2.155 TTBR1_EL12, Translation Table Base Register 1 (EL12)
1496 pub const ttbr1_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b001 };
1497 /// D19.2.156 TTBR1_EL2, Translation Table Base Register 1 (EL2)
1498 pub const ttbr1_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b001 };
1499 /// D19.2.157 VBAR_EL1, Vector Base Address Register (EL1)
1500 pub const vbar_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b000 };
1501 /// D19.2.157 VBAR_EL12, Vector Base Address Register (EL12)
1502 pub const vbar_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b000 };
1503 /// D19.2.158 VBAR_EL2, Vector Base Address Register (EL2)
1504 pub const vbar_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b000 };
1505 /// D19.2.159 VBAR_EL3, Vector Base Address Register (EL3)
1506 pub const vbar_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b000 };
1507 /// D19.2.160 VMPIDR_EL2, Virtualization Multiprocessor ID Register
1508 pub const vmpidr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b101 };
1509 /// D19.2.161 VNCR_EL2, Virtual Nested Control Register
1510 pub const nvcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b000 };
1511 /// D19.2.162 VPIDR_EL2, Virtualization Processor ID Register
1512 pub const vpidr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b000 };
1513 /// D19.2.163 VSTCR_EL2, Virtualization Secure Translation Control Register
1514 pub const vstcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0110, .op2 = 0b010 };
1515 /// D19.2.164 VSTTBR_EL2, Virtualization Secure Translation Table Base Register
1516 pub const vsttbr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0110, .op2 = 0b000 };
1517 /// D19.2.165 VTCR_EL2, Virtualization Translation Control Register
1518 pub const vtcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b010 };
1519 /// D19.2.166 VTTBR_EL2, Virtualization Translation Table Base Register
1520 pub const vttbr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b000 };
1521 /// D19.2.167 ZCR_EL1, SVE Control Register (EL1)
1522 pub const zcr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b000 };
1523 /// D19.2.167 ZCR_EL12, SVE Control Register (EL12)
1524 pub const zcr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b000 };
1525 /// D19.2.168 ZCR_EL2, SVE Control Register (EL2)
1526 pub const zcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b000 };
1527 /// D19.2.169 ZCR_EL3, SVE Control Register (EL3)
1528 pub const zcr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b000 };
1529
1530 pub fn parse(reg: []const u8) ?System {
1531 if (reg.len >= 10 and std.ascii.toLower(reg[0]) == 's') encoded: {
1532 var symbol_it = std.mem.splitScalar(u8, reg[1..], '_');
1533 const op0 = std.fmt.parseInt(u2, symbol_it.next() orelse break :encoded, 10) catch break :encoded;
1534 if (op0 < 0b10) break :encoded;
1535 const op1 = std.fmt.parseInt(u3, symbol_it.next() orelse break :encoded, 10) catch break :encoded;
1536 const n = symbol_it.next() orelse break :encoded;
1537 if (n.len == 0 or std.ascii.toLower(n[0]) != 'c') break :encoded;
1538 const CRn = std.fmt.parseInt(u4, n[1..], 10) catch break :encoded;
1539 const m = symbol_it.next() orelse break :encoded;
1540 if (m.len == 0 or std.ascii.toLower(m[0]) != 'c') break :encoded;
1541 const CRm = std.fmt.parseInt(u4, m[1..], 10) catch break :encoded;
1542 const op2 = std.fmt.parseInt(u3, symbol_it.next() orelse break :encoded, 10) catch break :encoded;
1543 if (symbol_it.next() != null) break :encoded;
1544 return .{ .op0 = op0, .op1 = op1, .CRn = CRn, .CRm = CRm, .op2 = op2 };
1545 }
1546 inline for (@typeInfo(System).@"struct".decls) |decl| {
1547 if (@TypeOf(@field(System, decl.name)) != System) continue;
1548 if (toLowerEqlAssertLower(reg, decl.name)) return @field(System, decl.name);
1549 }
1550 return null;
1551 }
1552 };
1553
1554 fn toLowerEqlAssertLower(lhs: []const u8, rhs: []const u8) bool {
1555 if (lhs.len != rhs.len) return false;
1556 for (lhs, rhs) |l, r| {
1557 assert(!std.ascii.isUpper(r));
1558 if (std.ascii.toLower(l) != r) return false;
1559 }
1560 return true;
1561 }
1562};
1563
1564/// C1.2.4 Condition code
1565pub const ConditionCode = enum(u4) {
1566 /// integer: Equal
1567 /// floating-point: Equal
1568 /// Z == 1
1569 eq = 0b0000,
1570 /// integer: Not equal
1571 /// floating-point: Not equal or unordered
1572 /// Z == 0
1573 ne = 0b0001,
1574 /// integer: Unsigned higher or same
1575 /// floating-point: Greater than, equal, or unordered
1576 /// C == 1
1577 hs = 0b0010,
1578 /// integer: Unsigned lower
1579 /// floating-point: Less than
1580 /// C == 0
1581 lo = 0b0011,
1582 /// integer: Minus, negative
1583 /// floating-point: Less than
1584 /// N == 1
1585 mi = 0b0100,
1586 /// integer: Plus, positive or zero
1587 /// floating-point: Greater than, equal, or unordered
1588 /// N == 0
1589 pl = 0b0101,
1590 /// integer: Overflow
1591 /// floating-point: Unordered
1592 /// V == 1
1593 vs = 0b0110,
1594 /// integer: No overflow
1595 /// floating-point: Ordered
1596 /// V == 0
1597 vc = 0b0111,
1598 /// integer: Unsigned higher
1599 /// floating-point: Greater than, or unordered
1600 /// C == 1 and Z == 0
1601 hi = 0b1000,
1602 /// integer: Unsigned lower or same
1603 /// floating-point: Less than or equal
1604 /// C == 0 or Z == 1
1605 ls = 0b1001,
1606 /// integer: Signed greater than or equal
1607 /// floating-point: Greater than or equal
1608 /// N == V
1609 ge = 0b1010,
1610 /// integer: Signed less than
1611 /// floating-point: Less than, or unordered
1612 /// N != V
1613 lt = 0b1011,
1614 /// integer: Signed greater than
1615 /// floating-point: Greater than
1616 /// Z == 0 and N == V
1617 gt = 0b1100,
1618 /// integer: Signed less than or equal
1619 /// floating-point: Less than, equal, or unordered
1620 /// Z == 1 or N != V
1621 le = 0b1101,
1622 /// integer: Always
1623 /// floating-point: Always
1624 /// true
1625 al = 0b1110,
1626 /// integer: Always
1627 /// floating-point: Always
1628 /// true
1629 nv = 0b1111,
1630 /// Carry set
1631 /// C == 1
1632 pub const cs: ConditionCode = .hs;
1633 /// Carry clear
1634 /// C == 0
1635 pub const cc: ConditionCode = .lo;
1636
1637 pub fn invert(cond: ConditionCode) ConditionCode {
1638 return @enumFromInt(@intFromEnum(cond) ^ 0b0001);
1639 }
1640};
1641
1642/// C4.1 A64 instruction set encoding
1643pub const Instruction = packed union {
1644 group: Group,
1645 reserved: Reserved,
1646 sme: Sme,
1647 sve: Sve,
1648 data_processing_immediate: DataProcessingImmediate,
1649 branch_exception_generating_system: BranchExceptionGeneratingSystem,
1650 load_store: LoadStore,
1651 data_processing_register: DataProcessingRegister,
1652 data_processing_vector: DataProcessingVector,
1653
1654 /// Table C4-1 Main encoding table for the A64 instruction set
1655 pub const Group = packed struct {
1656 encoded0: u25,
1657 op1: u4,
1658 encoded29: u2,
1659 op0: u1,
1660 };
1661
1662 /// C4.1.1 Reserved
1663 pub const Reserved = packed union {
1664 group: @This().Group,
1665 udf: Udf,
1666
1667 /// Table C4-2 Encoding table for the Reserved group
1668 pub const Group = packed struct {
1669 encoded0: u16,
1670 op1: u9,
1671 decoded25: u4 = 0b0000,
1672 op0: u2,
1673 decoded31: u1 = 0b0,
1674 };
1675
1676 /// C6.2.387 UDF
1677 pub const Udf = packed struct {
1678 imm16: u16,
1679 decoded16: u16 = 0b0000000000000000,
1680 };
1681
1682 pub const Decoded = union(enum) {
1683 unallocated,
1684 udf: Udf,
1685 };
1686 pub fn decode(inst: @This()) @This().Decoded {
1687 return switch (inst.group.op0) {
1688 0b00 => switch (inst.group.op1) {
1689 0b000000000 => .{ .udf = inst.udf },
1690 else => .unallocated,
1691 },
1692 else => .unallocated,
1693 };
1694 }
1695 };
1696
1697 /// C4.1.2 SME encodings
1698 pub const Sme = packed union {
1699 group: @This().Group,
1700
1701 /// Table C4-3 Encodings table for the SME encodings group
1702 pub const Group = packed struct {
1703 encoded0: u2,
1704 op2: u3,
1705 encoded5: u5,
1706 op1: u15,
1707 decoded25: u4 = 0b0000,
1708 op0: u2,
1709 decoded31: u1 = 0b1,
1710 };
1711 };
1712
1713 /// C4.1.30 SVE encodings
1714 pub const Sve = packed union {
1715 group: @This().Group,
1716
1717 /// Table C4-31 Encoding table for the SVE encodings group
1718 pub const Group = packed struct {
1719 encoded0: u4,
1720 op2: u1,
1721 encoded5: u5,
1722 op1: u15,
1723 decoded25: u4 = 0b0010,
1724 op0: u3,
1725 };
1726 };
1727
1728 /// C4.1.86 Data Processing -- Immediate
1729 pub const DataProcessingImmediate = packed union {
1730 group: @This().Group,
1731 pc_relative_addressing: PcRelativeAddressing,
1732 add_subtract_immediate: AddSubtractImmediate,
1733 add_subtract_immediate_with_tags: AddSubtractImmediateWithTags,
1734 logical_immediate: LogicalImmediate,
1735 move_wide_immediate: MoveWideImmediate,
1736 bitfield: Bitfield,
1737 extract: Extract,
1738
1739 /// Table C4-87 Encoding table for the Data Processing -- Immediate group
1740 pub const Group = packed struct {
1741 encoded0: u23,
1742 op0: u3,
1743 decoded26: u3 = 0b100,
1744 encoded29: u3,
1745 };
1746
1747 /// PC-rel. addressing
1748 pub const PcRelativeAddressing = packed union {
1749 group: @This().Group,
1750 adr: Adr,
1751 adrp: Adrp,
1752
1753 pub const Group = packed struct {
1754 Rd: Register.Encoded,
1755 immhi: i19,
1756 decoded24: u5 = 0b10000,
1757 immlo: u2,
1758 op: Op,
1759 };
1760
1761 /// C6.2.10 ADR
1762 pub const Adr = packed struct {
1763 Rd: Register.Encoded,
1764 immhi: i19,
1765 decoded24: u5 = 0b10000,
1766 immlo: u2,
1767 op: Op = .adr,
1768 };
1769
1770 /// C6.2.11 ADRP
1771 pub const Adrp = packed struct {
1772 Rd: Register.Encoded,
1773 immhi: i19,
1774 decoded24: u5 = 0b10000,
1775 immlo: u2,
1776 op: Op = .adrp,
1777 };
1778
1779 pub const Op = enum(u1) {
1780 adr = 0b0,
1781 adrp = 0b1,
1782 };
1783 };
1784
1785 /// Add/subtract (immediate)
1786 pub const AddSubtractImmediate = packed union {
1787 group: @This().Group,
1788 add: Add,
1789 adds: Adds,
1790 sub: Sub,
1791 subs: Subs,
1792
1793 pub const Group = packed struct {
1794 Rd: Register.Encoded,
1795 Rn: Register.Encoded,
1796 imm12: u12,
1797 sh: Shift,
1798 decoded23: u6 = 0b100010,
1799 S: bool,
1800 op: AddSubtractOp,
1801 sf: Register.IntegerSize,
1802 };
1803
1804 /// C6.2.4 ADD (immediate)
1805 pub const Add = packed struct {
1806 Rd: Register.Encoded,
1807 Rn: Register.Encoded,
1808 imm12: u12,
1809 sh: Shift,
1810 decoded23: u6 = 0b100010,
1811 S: bool = false,
1812 op: AddSubtractOp = .add,
1813 sf: Register.IntegerSize,
1814 };
1815
1816 /// C6.2.8 ADDS (immediate)
1817 pub const Adds = packed struct {
1818 Rd: Register.Encoded,
1819 Rn: Register.Encoded,
1820 imm12: u12,
1821 sh: Shift,
1822 decoded23: u6 = 0b100010,
1823 S: bool = true,
1824 op: AddSubtractOp = .add,
1825 sf: Register.IntegerSize,
1826 };
1827
1828 /// C6.2.357 SUB (immediate)
1829 pub const Sub = packed struct {
1830 Rd: Register.Encoded,
1831 Rn: Register.Encoded,
1832 imm12: u12,
1833 sh: Shift,
1834 decoded23: u6 = 0b100010,
1835 S: bool = false,
1836 op: AddSubtractOp = .sub,
1837 sf: Register.IntegerSize,
1838 };
1839
1840 /// C6.2.363 SUBS (immediate)
1841 pub const Subs = packed struct {
1842 Rd: Register.Encoded,
1843 Rn: Register.Encoded,
1844 imm12: u12,
1845 sh: Shift,
1846 decoded23: u6 = 0b100010,
1847 S: bool = true,
1848 op: AddSubtractOp = .sub,
1849 sf: Register.IntegerSize,
1850 };
1851
1852 pub const Shift = enum(u1) {
1853 @"0" = 0b0,
1854 @"12" = 0b1,
1855 };
1856 };
1857
1858 /// Add/subtract (immediate, with tags)
1859 pub const AddSubtractImmediateWithTags = packed union {
1860 group: @This().Group,
1861
1862 pub const Group = packed struct {
1863 Rd: Register.Encoded,
1864 Rn: Register.Encoded,
1865 uimm4: u4,
1866 op3: u2,
1867 uimm6: u6,
1868 o2: u1,
1869 decoded23: u6 = 0b100011,
1870 S: bool,
1871 op: AddSubtractOp,
1872 sf: Register.IntegerSize,
1873 };
1874 };
1875
1876 /// Logical (immediate)
1877 pub const LogicalImmediate = packed union {
1878 group: @This().Group,
1879 @"and": And,
1880 orr: Orr,
1881 eor: Eor,
1882 ands: Ands,
1883
1884 pub const Group = packed struct {
1885 Rd: Register.Encoded,
1886 Rn: Register.Encoded,
1887 imm: Bitmask,
1888 decoded23: u6 = 0b100100,
1889 opc: LogicalOpc,
1890 sf: Register.IntegerSize,
1891 };
1892
1893 /// C6.2.12 AND (immediate)
1894 pub const And = packed struct {
1895 Rd: Register.Encoded,
1896 Rn: Register.Encoded,
1897 imm: Bitmask,
1898 decoded23: u6 = 0b100100,
1899 opc: LogicalOpc = .@"and",
1900 sf: Register.IntegerSize,
1901 };
1902
1903 /// C6.2.240 ORR (immediate)
1904 pub const Orr = packed struct {
1905 Rd: Register.Encoded,
1906 Rn: Register.Encoded,
1907 imm: Bitmask,
1908 decoded23: u6 = 0b100100,
1909 opc: LogicalOpc = .orr,
1910 sf: Register.IntegerSize,
1911 };
1912
1913 /// C6.2.119 EOR (immediate)
1914 pub const Eor = packed struct {
1915 Rd: Register.Encoded,
1916 Rn: Register.Encoded,
1917 imm: Bitmask,
1918 decoded23: u6 = 0b100100,
1919 opc: LogicalOpc = .eor,
1920 sf: Register.IntegerSize,
1921 };
1922
1923 /// C6.2.14 ANDS (immediate)
1924 pub const Ands = packed struct {
1925 Rd: Register.Encoded,
1926 Rn: Register.Encoded,
1927 imm: Bitmask,
1928 decoded23: u6 = 0b100100,
1929 opc: LogicalOpc = .ands,
1930 sf: Register.IntegerSize,
1931 };
1932
1933 pub const Decoded = union(enum) {
1934 unallocated,
1935 @"and": And,
1936 orr: Orr,
1937 eor: Eor,
1938 ands: Ands,
1939 };
1940 pub fn decode(inst: @This()) @This().Decoded {
1941 return if (!inst.group.imm.validImmediate(inst.group.sf))
1942 .unallocated
1943 else switch (inst.group.opc) {
1944 .@"and" => .{ .@"and" = inst.@"and" },
1945 .orr => .{ .orr = inst.orr },
1946 .eor => .{ .eor = inst.eor },
1947 .ands => .{ .ands = inst.ands },
1948 };
1949 }
1950 };
1951
1952 /// Move wide (immediate)
1953 pub const MoveWideImmediate = packed union {
1954 group: @This().Group,
1955 movn: Movn,
1956 movz: Movz,
1957 movk: Movk,
1958
1959 pub const Group = packed struct {
1960 Rd: Register.Encoded,
1961 imm16: u16,
1962 hw: Hw,
1963 decoded23: u6 = 0b100101,
1964 opc: Opc,
1965 sf: Register.IntegerSize,
1966 };
1967
1968 /// C6.2.226 MOVN
1969 pub const Movn = packed struct {
1970 Rd: Register.Encoded,
1971 imm16: u16,
1972 hw: Hw,
1973 decoded23: u6 = 0b100101,
1974 opc: Opc = .movn,
1975 sf: Register.IntegerSize,
1976 };
1977
1978 /// C6.2.227 MOVZ
1979 pub const Movz = packed struct {
1980 Rd: Register.Encoded,
1981 imm16: u16,
1982 hw: Hw,
1983 decoded23: u6 = 0b100101,
1984 opc: Opc = .movz,
1985 sf: Register.IntegerSize,
1986 };
1987
1988 /// C6.2.225 MOVK
1989 pub const Movk = packed struct {
1990 Rd: Register.Encoded,
1991 imm16: u16,
1992 hw: Hw,
1993 decoded23: u6 = 0b100101,
1994 opc: Opc = .movk,
1995 sf: Register.IntegerSize,
1996 };
1997
1998 pub const Hw = enum(u2) {
1999 @"0" = 0b00,
2000 @"16" = 0b01,
2001 @"32" = 0b10,
2002 @"48" = 0b11,
2003
2004 pub fn int(hw: Hw) u6 {
2005 return switch (hw) {
2006 .@"0" => 0,
2007 .@"16" => 16,
2008 .@"32" => 32,
2009 .@"48" => 48,
2010 };
2011 }
2012
2013 pub fn sf(hw: Hw) Register.IntegerSize {
2014 return switch (hw) {
2015 .@"0", .@"16" => .word,
2016 .@"32", .@"48" => .doubleword,
2017 };
2018 }
2019 };
2020
2021 pub const Opc = enum(u2) {
2022 movn = 0b00,
2023 movz = 0b10,
2024 movk = 0b11,
2025 _,
2026 };
2027
2028 pub const Decoded = union(enum) {
2029 unallocated,
2030 movn: Movn,
2031 movz: Movz,
2032 movk: Movk,
2033 };
2034 pub fn decode(inst: @This()) @This().Decoded {
2035 return if (inst.group.sf == .word and inst.group.hw.sf() == .doubleword)
2036 .unallocated
2037 else switch (inst.group.opc) {
2038 _ => .unallocated,
2039 .movn => .{ .movn = inst.movn },
2040 .movz => .{ .movz = inst.movz },
2041 .movk => .{ .movk = inst.movk },
2042 };
2043 }
2044 };
2045
2046 /// Bitfield
2047 pub const Bitfield = packed union {
2048 group: @This().Group,
2049 sbfm: Sbfm,
2050 bfm: Bfm,
2051 ubfm: Ubfm,
2052
2053 pub const Group = packed struct {
2054 Rd: Register.Encoded,
2055 Rn: Register.Encoded,
2056 imm: Bitmask,
2057 decoded23: u6 = 0b100110,
2058 opc: Opc,
2059 sf: Register.IntegerSize,
2060 };
2061
2062 pub const Sbfm = packed struct {
2063 Rd: Register.Encoded,
2064 Rn: Register.Encoded,
2065 imm: Bitmask,
2066 decoded23: u6 = 0b100110,
2067 opc: Opc = .sbfm,
2068 sf: Register.IntegerSize,
2069 };
2070
2071 pub const Bfm = packed struct {
2072 Rd: Register.Encoded,
2073 Rn: Register.Encoded,
2074 imm: Bitmask,
2075 decoded23: u6 = 0b100110,
2076 opc: Opc = .bfm,
2077 sf: Register.IntegerSize,
2078 };
2079
2080 pub const Ubfm = packed struct {
2081 Rd: Register.Encoded,
2082 Rn: Register.Encoded,
2083 imm: Bitmask,
2084 decoded23: u6 = 0b100110,
2085 opc: Opc = .ubfm,
2086 sf: Register.IntegerSize,
2087 };
2088
2089 pub const Opc = enum(u2) {
2090 sbfm = 0b00,
2091 bfm = 0b01,
2092 ubfm = 0b10,
2093 _,
2094 };
2095
2096 pub const Decoded = union(enum) {
2097 unallocated,
2098 sbfm: Sbfm,
2099 bfm: Bfm,
2100 ubfm: Ubfm,
2101 };
2102 pub fn decode(inst: @This()) @This().Decoded {
2103 return if (!inst.group.imm.validBitfield(inst.group.sf))
2104 .unallocated
2105 else switch (inst.group.opc) {
2106 _ => .unallocated,
2107 .sbfm => .{ .sbfm = inst.sbfm },
2108 .bfm => .{ .bfm = inst.bfm },
2109 .ubfm => .{ .ubfm = inst.ubfm },
2110 };
2111 }
2112 };
2113
2114 /// Extract
2115 pub const Extract = packed union {
2116 group: @This().Group,
2117 extr: Extr,
2118
2119 pub const Group = packed struct {
2120 Rd: Register.Encoded,
2121 Rn: Register.Encoded,
2122 imms: u6,
2123 Rm: Register.Encoded,
2124 o0: u1,
2125 N: Register.IntegerSize,
2126 decoded23: u6 = 0b100111,
2127 op21: u2,
2128 sf: Register.IntegerSize,
2129 };
2130
2131 pub const Extr = packed struct {
2132 Rd: Register.Encoded,
2133 Rn: Register.Encoded,
2134 imms: u6,
2135 Rm: Register.Encoded,
2136 o0: u1 = 0b0,
2137 N: Register.IntegerSize,
2138 decoded23: u6 = 0b100111,
2139 op21: u2 = 0b00,
2140 sf: Register.IntegerSize,
2141 };
2142
2143 pub const Decoded = union(enum) {
2144 unallocated,
2145 extr: Extr,
2146 };
2147 pub fn decode(inst: @This()) @This().Decoded {
2148 return switch (inst.group.op21) {
2149 0b01, 0b10...0b11 => .unallocated,
2150 0b00 => switch (inst.group.o0) {
2151 0b1 => .unallocated,
2152 0b0 => if ((inst.group.sf == .word and @as(u1, @truncate(inst.group.imms >> 5)) == 0b1) or
2153 inst.group.sf != inst.group.N)
2154 .unallocated
2155 else
2156 .{ .extr = inst.extr },
2157 },
2158 };
2159 }
2160 };
2161
2162 pub const Bitmask = packed struct {
2163 imms: u6,
2164 immr: u6,
2165 N: Register.IntegerSize,
2166
2167 fn lenHsb(bitmask: Bitmask) u7 {
2168 return @bitCast(packed struct {
2169 not_imms: u6,
2170 N: Register.IntegerSize,
2171 }{ .not_imms = ~bitmask.imms, .N = bitmask.N });
2172 }
2173
2174 fn validImmediate(bitmask: Bitmask, sf: Register.IntegerSize) bool {
2175 if (sf == .word and bitmask.N == .doubleword) return false;
2176 const len_hsb = bitmask.lenHsb();
2177 return (len_hsb -% 1) & len_hsb != 0b0_000000;
2178 }
2179
2180 fn validBitfield(bitmask: Bitmask, sf: Register.IntegerSize) bool {
2181 if (sf != bitmask.N) return false;
2182 if (sf == .word and (@as(u1, @truncate(bitmask.immr >> 5)) != 0b0 or
2183 @as(u1, @truncate(bitmask.imms >> 5)) != 0b0)) return false;
2184 const len_hsb = bitmask.lenHsb();
2185 return len_hsb >= 0b0_000010;
2186 }
2187
2188 fn decode(bitmask: Bitmask, sf: Register.IntegerSize) struct { u64, u64 } {
2189 const esize = @as(u7, 1 << 6) >> @clz(bitmask.lenHsb());
2190 const levels: u6 = @intCast(esize - 1);
2191 const s = bitmask.imms & levels;
2192 const r = bitmask.immr & levels;
2193 const d = (s -% r) & levels;
2194 const welem = @as(u64, std.math.maxInt(u64)) >> (63 - s);
2195 const telem = @as(u64, std.math.maxInt(u64)) >> (63 - d);
2196 const emask = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - esize);
2197 const rmask = @divExact(std.math.maxInt(u64), emask);
2198 const wmask = std.math.rotr(u64, welem * rmask, r);
2199 const tmask = telem * rmask;
2200 return switch (sf) {
2201 .word => .{ @as(u32, @truncate(wmask)), @as(u32, @truncate(tmask)) },
2202 .doubleword => .{ wmask, tmask },
2203 };
2204 }
2205
2206 pub fn decodeImmediate(bitmask: Bitmask, sf: Register.IntegerSize) u64 {
2207 assert(bitmask.validImmediate(sf));
2208 const imm, _ = bitmask.decode(sf);
2209 return imm;
2210 }
2211
2212 pub fn decodeBitfield(bitmask: Bitmask, sf: Register.IntegerSize) struct { u64, u64 } {
2213 assert(bitmask.validBitfield(sf));
2214 return bitmask.decode(sf);
2215 }
2216
2217 pub fn moveWidePreferred(bitmask: Bitmask, sf: Register.IntegerSize) bool {
2218 const s = bitmask.imms;
2219 const r = bitmask.immr;
2220 const width: u7 = switch (sf) {
2221 .word => 32,
2222 .doubleword => 64,
2223 };
2224 if (sf != bitmask.N) return false;
2225 if (sf == .word and @as(u1, @truncate(s >> 5)) != 0b0) return false;
2226 if (s < 16) return (-%r % 16) <= (15 - s);
2227 if (s >= width - 15) return (r % 16) <= (s - (width - 15));
2228 return false;
2229 }
2230 };
2231
2232 pub const Decoded = union(enum) {
2233 unallocated,
2234 pc_relative_addressing: PcRelativeAddressing,
2235 add_subtract_immediate: AddSubtractImmediate,
2236 add_subtract_immediate_with_tags: AddSubtractImmediateWithTags,
2237 logical_immediate: LogicalImmediate,
2238 move_wide_immediate: MoveWideImmediate,
2239 bitfield: Bitfield,
2240 extract: Extract,
2241 };
2242 pub fn decode(inst: @This()) @This().Decoded {
2243 return switch (inst.group.op0) {
2244 0b000, 0b001 => .{ .pc_relative_addressing = inst.pc_relative_addressing },
2245 0b010 => .{ .add_subtract_immediate = inst.add_subtract_immediate },
2246 0b011 => .{ .add_subtract_immediate_with_tags = inst.add_subtract_immediate_with_tags },
2247 0b100 => .{ .logical_immediate = inst.logical_immediate },
2248 0b101 => .{ .move_wide_immediate = inst.move_wide_immediate },
2249 0b110 => .{ .bitfield = inst.bitfield },
2250 0b111 => .{ .extract = inst.extract },
2251 };
2252 }
2253 };
2254
2255 /// C4.1.87 Branches, Exception Generating and System instructions
2256 pub const BranchExceptionGeneratingSystem = packed union {
2257 group: @This().Group,
2258 conditional_branch_immediate: ConditionalBranchImmediate,
2259 exception_generating: ExceptionGenerating,
2260 system_register_argument: SystemRegisterArgument,
2261 hints: Hints,
2262 barriers: Barriers,
2263 pstate: Pstate,
2264 system_result: SystemResult,
2265 system: System,
2266 system_register_move: SystemRegisterMove,
2267 unconditional_branch_register: UnconditionalBranchRegister,
2268 unconditional_branch_immediate: UnconditionalBranchImmediate,
2269 compare_branch_immediate: CompareBranchImmediate,
2270 test_branch_immediate: TestBranchImmediate,
2271
2272 /// Table C4-88 Encoding table for the Branches, Exception Generating and System instructions group
2273 pub const Group = packed struct {
2274 op2: u5,
2275 encoded5: u7,
2276 op1: u14,
2277 decoded26: u3 = 0b101,
2278 op0: u3,
2279 };
2280
2281 /// Conditional branch (immediate)
2282 pub const ConditionalBranchImmediate = packed union {
2283 group: @This().Group,
2284 b: B,
2285 bc: Bc,
2286
2287 pub const Group = packed struct {
2288 cond: ConditionCode,
2289 o0: u1,
2290 imm19: i19,
2291 o1: u1,
2292 decoded25: u7 = 0b0101010,
2293 };
2294
2295 /// C6.2.26 B.cond
2296 pub const B = packed struct {
2297 cond: ConditionCode,
2298 o0: u1 = 0b0,
2299 imm19: i19,
2300 o1: u1 = 0b0,
2301 decoded25: u7 = 0b0101010,
2302 };
2303
2304 /// C6.2.27 BC.cond
2305 pub const Bc = packed struct {
2306 cond: ConditionCode,
2307 o0: u1 = 0b1,
2308 imm19: i19,
2309 o1: u1 = 0b0,
2310 decoded25: u7 = 0b0101010,
2311 };
2312
2313 pub const Decoded = union(enum) {
2314 unallocated,
2315 b: B,
2316 bc: Bc,
2317 };
2318 pub fn decode(inst: @This()) @This().Decoded {
2319 return switch (inst.group.o1) {
2320 0b0 => switch (inst.group.o0) {
2321 0b0 => .{ .b = inst.b },
2322 0b1 => .{ .bc = inst.bc },
2323 },
2324 0b1 => .unallocated,
2325 };
2326 }
2327 };
2328
2329 /// Exception generating
2330 pub const ExceptionGenerating = packed union {
2331 group: @This().Group,
2332 svc: Svc,
2333 hvc: Hvc,
2334 smc: Smc,
2335 brk: Brk,
2336 hlt: Hlt,
2337 tcancel: Tcancel,
2338 dcps1: Dcps1,
2339 dcps2: Dcps2,
2340 dcps3: Dcps3,
2341
2342 pub const Group = packed struct {
2343 LL: u2,
2344 op2: u3,
2345 imm16: u16,
2346 opc: u3,
2347 decoded24: u8 = 0b11010100,
2348 };
2349
2350 /// C6.2.365 SVC
2351 pub const Svc = packed struct {
2352 decoded0: u2 = 0b01,
2353 decoded2: u3 = 0b000,
2354 imm16: u16,
2355 decoded21: u3 = 0b000,
2356 decoded24: u8 = 0b11010100,
2357 };
2358
2359 /// C6.2.128 HVC
2360 pub const Hvc = packed struct {
2361 decoded0: u2 = 0b10,
2362 decoded2: u3 = 0b000,
2363 imm16: u16,
2364 decoded21: u3 = 0b000,
2365 decoded24: u8 = 0b11010100,
2366 };
2367
2368 /// C6.2.283 SMC
2369 pub const Smc = packed struct {
2370 decoded0: u2 = 0b11,
2371 decoded2: u3 = 0b000,
2372 imm16: u16,
2373 decoded21: u3 = 0b000,
2374 decoded24: u8 = 0b11010100,
2375 };
2376
2377 /// C6.2.40 BRK
2378 pub const Brk = packed struct {
2379 decoded0: u2 = 0b00,
2380 decoded2: u3 = 0b000,
2381 imm16: u16,
2382 decoded21: u3 = 0b001,
2383 decoded24: u8 = 0b11010100,
2384 };
2385
2386 /// C6.2.127 HLT
2387 pub const Hlt = packed struct {
2388 decoded0: u2 = 0b00,
2389 decoded2: u3 = 0b000,
2390 imm16: u16,
2391 decoded21: u3 = 0b010,
2392 decoded24: u8 = 0b11010100,
2393 };
2394
2395 /// C6.2.376 TCANCEL
2396 pub const Tcancel = packed struct {
2397 decoded0: u2 = 0b00,
2398 decoded2: u3 = 0b000,
2399 imm16: u16,
2400 decoded21: u3 = 0b011,
2401 decoded24: u8 = 0b11010100,
2402 };
2403
2404 /// C6.2.110 DCPS1
2405 pub const Dcps1 = packed struct {
2406 LL: u2 = 0b01,
2407 decoded2: u3 = 0b000,
2408 imm16: u16,
2409 decoded21: u3 = 0b101,
2410 decoded24: u8 = 0b11010100,
2411 };
2412
2413 /// C6.2.110 DCPS2
2414 pub const Dcps2 = packed struct {
2415 LL: u2 = 0b10,
2416 decoded2: u3 = 0b000,
2417 imm16: u16,
2418 decoded21: u3 = 0b101,
2419 decoded24: u8 = 0b11010100,
2420 };
2421
2422 /// C6.2.110 DCPS3
2423 pub const Dcps3 = packed struct {
2424 LL: u2 = 0b11,
2425 decoded2: u3 = 0b000,
2426 imm16: u16,
2427 decoded21: u3 = 0b101,
2428 decoded24: u8 = 0b11010100,
2429 };
2430
2431 pub const Decoded = union(enum) {
2432 unallocated,
2433 svc: Svc,
2434 hvc: Hvc,
2435 smc: Smc,
2436 brk: Brk,
2437 hlt: Hlt,
2438 tcancel: Tcancel,
2439 dcps1: Dcps1,
2440 dcps2: Dcps2,
2441 dcps3: Dcps3,
2442 };
2443 pub fn decode(inst: @This()) @This().Decoded {
2444 return switch (inst.group.op2) {
2445 0b001 => .unallocated,
2446 0b010...0b011 => .unallocated,
2447 0b100...0b111 => .unallocated,
2448 0b000 => switch (inst.group.opc) {
2449 0b000 => switch (inst.group.LL) {
2450 0b00 => .unallocated,
2451 0b01 => .{ .svc = inst.svc },
2452 0b10 => .{ .hvc = inst.hvc },
2453 0b11 => .{ .smc = inst.smc },
2454 },
2455 0b001 => switch (inst.group.LL) {
2456 0b01 => .unallocated,
2457 0b00 => .{ .brk = inst.brk },
2458 0b10...0b11 => .unallocated,
2459 },
2460 0b010 => switch (inst.group.LL) {
2461 0b01 => .unallocated,
2462 0b00 => .{ .hlt = inst.hlt },
2463 0b10...0b11 => .unallocated,
2464 },
2465 0b011 => switch (inst.group.LL) {
2466 0b00 => .{ .tcancel = inst.tcancel },
2467 0b01 => .unallocated,
2468 0b10...0b11 => .unallocated,
2469 },
2470 0b100 => .unallocated,
2471 0b101 => switch (inst.group.LL) {
2472 0b00 => .unallocated,
2473 0b01 => .{ .dcps1 = inst.dcps1 },
2474 0b10 => .{ .dcps2 = inst.dcps2 },
2475 0b11 => .{ .dcps3 = inst.dcps3 },
2476 },
2477 0b110 => .unallocated,
2478 0b111 => .unallocated,
2479 },
2480 };
2481 }
2482 };
2483
2484 /// System instructions with register argument
2485 pub const SystemRegisterArgument = packed struct {
2486 Rt: Register.Encoded,
2487 op2: u3,
2488 CRm: u4,
2489 decoded12: u20 = 0b11010101000000110001,
2490 };
2491
2492 /// Hints
2493 pub const Hints = packed union {
2494 group: @This().Group,
2495 hint: Hint,
2496 nop: Nop,
2497 yield: Yield,
2498 wfe: Wfe,
2499 wfi: Wfi,
2500 sev: Sev,
2501 sevl: Sevl,
2502
2503 pub const Group = packed struct {
2504 decoded0: u5 = 0b11111,
2505 op2: u3,
2506 CRm: u4,
2507 decoded12: u20 = 0b11010101000000110010,
2508 };
2509
2510 /// C6.2.126 HINT
2511 pub const Hint = packed struct {
2512 decoded0: u5 = 0b11111,
2513 op2: u3,
2514 CRm: u4,
2515 decoded12: u4 = 0b0010,
2516 decoded16: u3 = 0b011,
2517 decoded19: u2 = 0b00,
2518 decoded21: u1 = 0b0,
2519 decoded22: u10 = 0b1101010100,
2520 };
2521
2522 /// C6.2.238 NOP
2523 pub const Nop = packed struct {
2524 decoded0: u5 = 0b11111,
2525 op2: u3 = 0b000,
2526 CRm: u4 = 0b0000,
2527 decoded12: u4 = 0b0010,
2528 decoded16: u3 = 0b011,
2529 decoded19: u2 = 0b00,
2530 decoded21: u1 = 0b0,
2531 decoded22: u10 = 0b1101010100,
2532 };
2533
2534 /// C6.2.402 YIELD
2535 pub const Yield = packed struct {
2536 decoded0: u5 = 0b11111,
2537 op2: u3 = 0b001,
2538 CRm: u4 = 0b0000,
2539 decoded12: u4 = 0b0010,
2540 decoded16: u3 = 0b011,
2541 decoded19: u2 = 0b00,
2542 decoded21: u1 = 0b0,
2543 decoded22: u10 = 0b1101010100,
2544 };
2545
2546 /// C6.2.396 WFE
2547 pub const Wfe = packed struct {
2548 decoded0: u5 = 0b11111,
2549 op2: u3 = 0b010,
2550 CRm: u4 = 0b0000,
2551 decoded12: u4 = 0b0010,
2552 decoded16: u3 = 0b011,
2553 decoded19: u2 = 0b00,
2554 decoded21: u1 = 0b0,
2555 decoded22: u10 = 0b1101010100,
2556 };
2557
2558 /// C6.2.398 WFI
2559 pub const Wfi = packed struct {
2560 decoded0: u5 = 0b11111,
2561 op2: u3 = 0b011,
2562 CRm: u4 = 0b0000,
2563 decoded12: u4 = 0b0010,
2564 decoded16: u3 = 0b011,
2565 decoded19: u2 = 0b00,
2566 decoded21: u1 = 0b0,
2567 decoded22: u10 = 0b1101010100,
2568 };
2569
2570 /// C6.2.280 SEV
2571 pub const Sev = packed struct {
2572 decoded0: u5 = 0b11111,
2573 op2: u3 = 0b100,
2574 CRm: u4 = 0b0000,
2575 decoded12: u4 = 0b0010,
2576 decoded16: u3 = 0b011,
2577 decoded19: u2 = 0b00,
2578 decoded21: u1 = 0b0,
2579 decoded22: u10 = 0b1101010100,
2580 };
2581
2582 /// C6.2.280 SEVL
2583 pub const Sevl = packed struct {
2584 decoded0: u5 = 0b11111,
2585 op2: u3 = 0b101,
2586 CRm: u4 = 0b0000,
2587 decoded12: u4 = 0b0010,
2588 decoded16: u3 = 0b011,
2589 decoded19: u2 = 0b00,
2590 decoded21: u1 = 0b0,
2591 decoded22: u10 = 0b1101010100,
2592 };
2593
2594 pub const Decoded = union(enum) {
2595 hint: Hint,
2596 nop: Nop,
2597 yield: Yield,
2598 wfe: Wfe,
2599 wfi: Wfi,
2600 sev: Sev,
2601 sevl: Sevl,
2602 };
2603 pub fn decode(inst: @This()) @This().Decoded {
2604 return switch (inst.group.CRm) {
2605 else => .{ .hint = inst.hint },
2606 0b0000 => switch (inst.group.op2) {
2607 else => .{ .hint = inst.hint },
2608 0b000 => .{ .nop = inst.nop },
2609 0b001 => .{ .yield = inst.yield },
2610 0b010 => .{ .wfe = inst.wfe },
2611 0b011 => .{ .wfi = inst.wfi },
2612 0b100 => .{ .sev = inst.sev },
2613 0b101 => .{ .sevl = inst.sevl },
2614 },
2615 };
2616 }
2617 };
2618
2619 /// Barriers
2620 pub const Barriers = packed union {
2621 group: @This().Group,
2622 clrex: Clrex,
2623 dsb: Dsb,
2624 dmb: Dmb,
2625 isb: Isb,
2626 sb: Sb,
2627
2628 pub const Group = packed struct {
2629 Rt: Register.Encoded,
2630 op2: u3,
2631 CRm: u4,
2632 decoded12: u4 = 0b0011,
2633 decoded16: u3 = 0b011,
2634 decoded19: u2 = 0b00,
2635 decoded21: u1 = 0b0,
2636 decoded22: u10 = 0b1101010100,
2637 };
2638
2639 /// C6.2.56 CLREX
2640 pub const Clrex = packed struct {
2641 Rt: Register.Encoded = @enumFromInt(0b11111),
2642 op2: u3 = 0b010,
2643 CRm: u4,
2644 decoded12: u4 = 0b0011,
2645 decoded16: u3 = 0b011,
2646 decoded19: u2 = 0b00,
2647 decoded21: u1 = 0b0,
2648 decoded22: u10 = 0b1101010100,
2649 };
2650
2651 /// C6.2.116 DSB
2652 pub const Dsb = packed struct {
2653 Rt: Register.Encoded = @enumFromInt(0b11111),
2654 opc: u2 = 0b00,
2655 decoded7: u1 = 0b1,
2656 CRm: Option,
2657 decoded12: u4 = 0b0011,
2658 decoded16: u3 = 0b011,
2659 decoded19: u2 = 0b00,
2660 decoded21: u1 = 0b0,
2661 decoded22: u10 = 0b1101010100,
2662 };
2663
2664 /// C6.2.114 DMB
2665 pub const Dmb = packed struct {
2666 Rt: Register.Encoded = @enumFromInt(0b11111),
2667 opc: u2 = 0b01,
2668 decoded7: u1 = 0b1,
2669 CRm: Option,
2670 decoded12: u4 = 0b0011,
2671 decoded16: u3 = 0b011,
2672 decoded19: u2 = 0b00,
2673 decoded21: u1 = 0b0,
2674 decoded22: u10 = 0b1101010100,
2675 };
2676
2677 /// C6.2.131 ISB
2678 pub const Isb = packed struct {
2679 Rt: Register.Encoded = @enumFromInt(0b11111),
2680 opc: u2 = 0b10,
2681 decoded7: u1 = 0b1,
2682 CRm: Option,
2683 decoded12: u4 = 0b0011,
2684 decoded16: u3 = 0b011,
2685 decoded19: u2 = 0b00,
2686 decoded21: u1 = 0b0,
2687 decoded22: u10 = 0b1101010100,
2688 };
2689
2690 /// C6.2.264 SB
2691 pub const Sb = packed struct {
2692 Rt: Register.Encoded = @enumFromInt(0b11111),
2693 opc: u2 = 0b11,
2694 decoded7: u1 = 0b1,
2695 CRm: u4 = 0b0000,
2696 decoded12: u4 = 0b0011,
2697 decoded16: u3 = 0b011,
2698 decoded19: u2 = 0b00,
2699 decoded21: u1 = 0b0,
2700 decoded22: u10 = 0b1101010100,
2701 };
2702
2703 pub const Option = enum(u4) {
2704 oshld = 0b0001,
2705 oshst = 0b0010,
2706 osh = 0b0011,
2707 nshld = 0b0101,
2708 nshst = 0b0110,
2709 nsh = 0b0111,
2710 ishld = 0b1001,
2711 ishst = 0b1010,
2712 ish = 0b1011,
2713 ld = 0b1101,
2714 st = 0b1110,
2715 sy = 0b1111,
2716 _,
2717 };
2718 };
2719
2720 /// PSTATE
2721 pub const Pstate = packed struct {
2722 Rt: Register.Encoded,
2723 op2: u3,
2724 CRm: u4,
2725 decoded12: u4 = 0b0100,
2726 op1: u3,
2727 decoded19: u13 = 0b1101010100000,
2728 };
2729
2730 /// System with result
2731 pub const SystemResult = packed struct {
2732 Rt: Register.Encoded,
2733 op2: u3,
2734 CRm: u4,
2735 CRn: u4,
2736 op1: u3,
2737 decoded19: u13 = 0b1101010100100,
2738 };
2739
2740 /// System instructions
2741 pub const System = packed union {
2742 group: @This().Group,
2743 sys: Sys,
2744 sysl: Sysl,
2745
2746 pub const Group = packed struct {
2747 Rt: Register.Encoded,
2748 op2: u3,
2749 CRm: u4,
2750 CRn: u4,
2751 op1: u3,
2752 decoded19: u2 = 0b01,
2753 L: L,
2754 decoded22: u10 = 0b1101010100,
2755 };
2756
2757 /// C6.2.372 SYS
2758 pub const Sys = packed struct {
2759 Rt: Register.Encoded,
2760 op2: u3,
2761 CRm: u4,
2762 CRn: u4,
2763 op1: u3,
2764 decoded19: u2 = 0b01,
2765 L: L = .sys,
2766 decoded22: u10 = 0b1101010100,
2767 };
2768
2769 /// C6.2.373 SYSL
2770 pub const Sysl = packed struct {
2771 Rt: Register.Encoded,
2772 op2: u3,
2773 CRm: u4,
2774 CRn: u4,
2775 op1: u3,
2776 decoded19: u2 = 0b01,
2777 L: L = .sysl,
2778 decoded22: u10 = 0b1101010100,
2779 };
2780
2781 const L = enum(u1) {
2782 sys = 0b0,
2783 sysl = 0b1,
2784 };
2785
2786 pub const Decoded = union(enum) {
2787 sys: Sys,
2788 sysl: Sysl,
2789 };
2790 pub fn decode(inst: @This()) @This().Decoded {
2791 return switch (inst.group.L) {
2792 .sys => .{ .sys = inst.sys },
2793 .sysl => .{ .sysl = inst.sysl },
2794 };
2795 }
2796 };
2797
2798 /// System register move
2799 pub const SystemRegisterMove = packed union {
2800 group: @This().Group,
2801 msr: Msr,
2802 mrs: Mrs,
2803
2804 pub const Group = packed struct {
2805 Rt: Register.Encoded,
2806 systemreg: Register.System,
2807 L: L,
2808 decoded22: u10 = 0b1101010100,
2809 };
2810
2811 /// C6.2.230 MSR (register)
2812 pub const Msr = packed struct {
2813 Rt: Register.Encoded,
2814 systemreg: Register.System,
2815 L: L = .msr,
2816 decoded22: u10 = 0b1101010100,
2817 };
2818
2819 /// C6.2.228 MRS
2820 pub const Mrs = packed struct {
2821 Rt: Register.Encoded,
2822 systemreg: Register.System,
2823 L: L = .mrs,
2824 decoded22: u10 = 0b1101010100,
2825 };
2826
2827 pub const L = enum(u1) {
2828 msr = 0b0,
2829 mrs = 0b1,
2830 };
2831
2832 pub const Decoded = union(enum) {
2833 msr: Msr,
2834 mrs: Mrs,
2835 };
2836 pub fn decode(inst: @This()) @This().Decoded {
2837 return switch (inst.group.L) {
2838 .msr => .{ .msr = inst.msr },
2839 .mrs => .{ .mrs = inst.mrs },
2840 };
2841 }
2842 };
2843
2844 /// Unconditional branch (register)
2845 pub const UnconditionalBranchRegister = packed union {
2846 group: @This().Group,
2847 br: Br,
2848 blr: Blr,
2849 ret: Ret,
2850
2851 pub const Group = packed struct {
2852 op4: u5,
2853 Rn: Register.Encoded,
2854 op3: u6,
2855 op2: u5,
2856 opc: u4,
2857 decoded25: u7 = 0b1101011,
2858 };
2859
2860 /// C6.2.37 BR
2861 pub const Br = packed struct {
2862 Rm: Register.Encoded = @enumFromInt(0),
2863 Rn: Register.Encoded,
2864 M: bool = false,
2865 A: bool = false,
2866 decoded12: u4 = 0b0000,
2867 decoded16: u5 = 0b11111,
2868 op: u2 = 0b00,
2869 decoded23: u1 = 0b0,
2870 Z: bool = false,
2871 decoded25: u7 = 0b1101011,
2872 };
2873
2874 /// C6.2.35 BLR
2875 pub const Blr = packed struct {
2876 Rm: Register.Encoded = @enumFromInt(0),
2877 Rn: Register.Encoded,
2878 M: bool = false,
2879 A: bool = false,
2880 decoded12: u4 = 0b0000,
2881 decoded16: u5 = 0b11111,
2882 op: u2 = 0b01,
2883 decoded23: u1 = 0b0,
2884 Z: bool = false,
2885 decoded25: u7 = 0b1101011,
2886 };
2887
2888 /// C6.2.254 RET
2889 pub const Ret = packed struct {
2890 Rm: Register.Encoded = @enumFromInt(0),
2891 Rn: Register.Encoded,
2892 M: bool = false,
2893 A: bool = false,
2894 decoded12: u4 = 0b0000,
2895 decoded16: u5 = 0b11111,
2896 op: u2 = 0b10,
2897 decoded23: u1 = 0b0,
2898 Z: bool = false,
2899 decoded25: u7 = 0b1101011,
2900 };
2901
2902 pub const Decoded = union(enum) {
2903 unallocated,
2904 br: Br,
2905 blr: Blr,
2906 ret: Ret,
2907 };
2908 pub fn decode(inst: @This()) @This().Decoded {
2909 return switch (inst.group.op2) {
2910 else => .unallocated,
2911 0b11111 => switch (inst.group.opc) {
2912 0b0000 => switch (inst.group.op4) {
2913 else => .unallocated,
2914 0b00000 => .{ .br = inst.br },
2915 },
2916 0b0001 => switch (inst.group.op4) {
2917 else => .unallocated,
2918 0b00000 => .{ .blr = inst.blr },
2919 },
2920 0b0010 => switch (inst.group.op4) {
2921 else => .unallocated,
2922 0b00000 => .{ .ret = inst.ret },
2923 },
2924 else => .unallocated,
2925 },
2926 };
2927 }
2928 };
2929
2930 /// Unconditional branch (immediate)
2931 pub const UnconditionalBranchImmediate = packed union {
2932 group: @This().Group,
2933 b: B,
2934 bl: Bl,
2935
2936 pub const Group = packed struct {
2937 imm26: i26,
2938 decoded26: u5 = 0b00101,
2939 op: Op,
2940 };
2941
2942 /// C6.2.25 B
2943 pub const B = packed struct {
2944 imm26: i26,
2945 decoded26: u5 = 0b00101,
2946 op: Op = .b,
2947 };
2948
2949 /// C6.2.34 BL
2950 pub const Bl = packed struct {
2951 imm26: i26,
2952 decoded26: u5 = 0b00101,
2953 op: Op = .bl,
2954 };
2955
2956 pub const Op = enum(u1) {
2957 b = 0b0,
2958 bl = 0b1,
2959 };
2960 };
2961
2962 /// Compare and branch (immediate)
2963 pub const CompareBranchImmediate = packed union {
2964 group: @This().Group,
2965 cbz: Cbz,
2966 cbnz: Cbnz,
2967
2968 pub const Group = packed struct {
2969 Rt: Register.Encoded,
2970 imm19: i19,
2971 op: Op,
2972 decoded25: u6 = 0b011010,
2973 sf: Register.IntegerSize,
2974 };
2975
2976 /// C6.2.47 CBZ
2977 pub const Cbz = packed struct {
2978 Rt: Register.Encoded,
2979 imm19: i19,
2980 op: Op = .cbz,
2981 decoded25: u6 = 0b011010,
2982 sf: Register.IntegerSize,
2983 };
2984
2985 /// C6.2.46 CBNZ
2986 pub const Cbnz = packed struct {
2987 Rt: Register.Encoded,
2988 imm19: i19,
2989 op: Op = .cbnz,
2990 decoded25: u6 = 0b011010,
2991 sf: Register.IntegerSize,
2992 };
2993
2994 pub const Op = enum(u1) {
2995 cbz = 0b0,
2996 cbnz = 0b1,
2997 };
2998 };
2999
3000 /// Test and branch (immediate)
3001 pub const TestBranchImmediate = packed union {
3002 group: @This().Group,
3003 tbz: Tbz,
3004 tbnz: Tbnz,
3005
3006 pub const Group = packed struct {
3007 Rt: Register.Encoded,
3008 imm14: i14,
3009 b40: u5,
3010 op: Op,
3011 decoded25: u6 = 0b011011,
3012 b5: u1,
3013 };
3014
3015 /// C6.2.375 TBZ
3016 pub const Tbz = packed struct {
3017 Rt: Register.Encoded,
3018 imm14: i14,
3019 b40: u5,
3020 op: Op = .tbz,
3021 decoded25: u6 = 0b011011,
3022 b5: u1,
3023 };
3024
3025 /// C6.2.374 TBNZ
3026 pub const Tbnz = packed struct {
3027 Rt: Register.Encoded,
3028 imm14: i14,
3029 b40: u5,
3030 op: Op = .tbnz,
3031 decoded25: u6 = 0b011011,
3032 b5: u1,
3033 };
3034
3035 pub const Op = enum(u1) {
3036 tbz = 0b0,
3037 tbnz = 0b1,
3038 };
3039 };
3040
3041 pub const Decoded = union(enum) {
3042 unallocated,
3043 conditional_branch_immediate: ConditionalBranchImmediate,
3044 exception_generating: ExceptionGenerating,
3045 system_register_argument: SystemRegisterArgument,
3046 hints: Hints,
3047 barriers: Barriers,
3048 pstate: Pstate,
3049 system_result: SystemResult,
3050 system: System,
3051 system_register_move: SystemRegisterMove,
3052 unconditional_branch_register: UnconditionalBranchRegister,
3053 unconditional_branch_immediate: UnconditionalBranchImmediate,
3054 compare_branch_immediate: CompareBranchImmediate,
3055 test_branch_immediate: TestBranchImmediate,
3056 };
3057 pub fn decode(inst: @This()) @This().Decoded {
3058 return switch (inst.group.op0) {
3059 0b010 => switch (inst.group.op1) {
3060 0b000000000000000...0b01111111111111 => .{ .conditional_branch_immediate = inst.conditional_branch_immediate },
3061 else => .unallocated,
3062 },
3063 0b110 => switch (inst.group.op1) {
3064 0b00000000000000...0b00111111111111 => .{ .exception_generating = inst.exception_generating },
3065 0b01000000110001 => .{ .system_register_argument = inst.system_register_argument },
3066 0b01000000110010 => switch (inst.group.op2) {
3067 0b11111 => .{ .hints = inst.hints },
3068 else => .unallocated,
3069 },
3070 0b01000000110011 => .{ .barriers = inst.barriers },
3071 0b01000000000100,
3072 0b01000000010100,
3073 0b01000000100100,
3074 0b01000000110100,
3075 0b01000001000100,
3076 0b01000001010100,
3077 0b01000001100100,
3078 0b01000001110100,
3079 => .{ .pstate = inst.pstate },
3080 0b01001000000000...0b01001001111111 => .{ .system_result = inst.system_result },
3081 0b01000010000000...0b01000011111111, 0b01001010000000...0b01001011111111 => .{ .system = inst.system },
3082 0b01000100000000...0b01000111111111, 0b01001100000000...0b01001111111111 => .{ .system_register_move = inst.system_register_move },
3083 0b10000000000000...0b11111111111111 => .{ .unconditional_branch_register = inst.unconditional_branch_register },
3084 else => .unallocated,
3085 },
3086 0b000, 0b100 => .{ .unconditional_branch_immediate = inst.unconditional_branch_immediate },
3087 0b001, 0b101 => switch (inst.group.op1) {
3088 0b00000000000000...0b01111111111111 => .{ .compare_branch_immediate = inst.compare_branch_immediate },
3089 0b10000000000000...0b11111111111111 => .{ .test_branch_immediate = inst.test_branch_immediate },
3090 },
3091 else => .unallocated,
3092 };
3093 }
3094 };
3095
3096 /// C4.1.88 Loads and Stores
3097 pub const LoadStore = packed union {
3098 group: @This().Group,
3099 register_literal: RegisterLiteral,
3100 memory: Memory,
3101 no_allocate_pair_offset: NoAllocatePairOffset,
3102 register_pair_post_indexed: RegisterPairPostIndexed,
3103 register_pair_offset: RegisterPairOffset,
3104 register_pair_pre_indexed: RegisterPairPreIndexed,
3105 register_unscaled_immediate: RegisterUnscaledImmediate,
3106 register_immediate_post_indexed: RegisterImmediatePostIndexed,
3107 register_unprivileged: RegisterUnprivileged,
3108 register_immediate_pre_indexed: RegisterImmediatePreIndexed,
3109 register_register_offset: RegisterRegisterOffset,
3110 register_unsigned_immediate: RegisterUnsignedImmediate,
3111
3112 /// Table C4-89 Encoding table for the Loads and Stores group
3113 pub const Group = packed struct {
3114 encoded0: u10,
3115 op4: u2,
3116 encoded12: u4,
3117 op3: u6,
3118 encoded22: u1,
3119 op2: u2,
3120 decoded25: u1 = 0b0,
3121 op1: bool,
3122 decoded27: u1 = 0b1,
3123 op0: u4,
3124 };
3125
3126 /// Load register (literal)
3127 pub const RegisterLiteral = packed union {
3128 group: @This().Group,
3129 integer: Integer,
3130 vector: Vector,
3131
3132 pub const Group = packed struct {
3133 Rt: Register.Encoded,
3134 imm19: i19,
3135 decoded24: u2 = 0b00,
3136 V: bool,
3137 decoded27: u3 = 0b011,
3138 opc: u2,
3139 };
3140
3141 pub const Integer = packed union {
3142 group: @This().Group,
3143 ldr: Ldr,
3144 ldrsw: Ldrsw,
3145 prfm: Prfm,
3146
3147 pub const Group = packed struct {
3148 Rt: Register.Encoded,
3149 imm19: i19,
3150 decoded24: u2 = 0b00,
3151 V: bool = false,
3152 decoded27: u3 = 0b011,
3153 opc: u2,
3154 };
3155
3156 /// C6.2.167 LDR (literal)
3157 pub const Ldr = packed struct {
3158 Rt: Register.Encoded,
3159 imm19: i19,
3160 decoded24: u2 = 0b00,
3161 V: bool = false,
3162 decoded27: u3 = 0b011,
3163 sf: Register.IntegerSize,
3164 opc1: u1 = 0b0,
3165 };
3166
3167 /// C6.2.179 LDRSW (literal)
3168 pub const Ldrsw = packed struct {
3169 Rt: Register.Encoded,
3170 imm19: i19,
3171 decoded24: u2 = 0b00,
3172 V: bool = false,
3173 decoded27: u3 = 0b011,
3174 opc: u2 = 0b10,
3175 };
3176
3177 /// C6.2.248 PRFM (literal)
3178 pub const Prfm = packed struct {
3179 prfop: PrfOp,
3180 imm19: i19,
3181 decoded24: u2 = 0b00,
3182 V: bool = false,
3183 decoded27: u3 = 0b011,
3184 opc: u2 = 0b11,
3185 };
3186 };
3187
3188 pub const Vector = packed union {
3189 group: @This().Group,
3190 ldr: Ldr,
3191
3192 pub const Group = packed struct {
3193 Rt: Register.Encoded,
3194 imm19: i19,
3195 decoded24: u2 = 0b00,
3196 V: bool = true,
3197 decoded27: u3 = 0b011,
3198 opc: VectorSize,
3199 };
3200
3201 /// C7.2.192 LDR (literal, SIMD&FP)
3202 pub const Ldr = packed struct {
3203 Rt: Register.Encoded,
3204 imm19: i19,
3205 decoded24: u2 = 0b00,
3206 V: bool = true,
3207 decoded27: u3 = 0b011,
3208 opc: VectorSize,
3209 };
3210 };
3211
3212 pub const Decoded = union(enum) {
3213 integer: Integer,
3214 vector: Vector,
3215 };
3216 pub fn decode(inst: @This()) @This().Decoded {
3217 return switch (inst.group.V) {
3218 false => .{ .integer = inst.integer },
3219 true => .{ .vector = inst.vector },
3220 };
3221 }
3222 };
3223
3224 /// Memory Copy and Memory Set
3225 pub const Memory = packed struct {
3226 Rd: Register.Encoded,
3227 Rn: Register.Encoded,
3228 decoded10: u2 = 0b01,
3229 op2: u4,
3230 Rs: Register.Encoded,
3231 decoded21: u1 = 0b0,
3232 op1: u2,
3233 decoded24: u2 = 0b01,
3234 o0: u1,
3235 decoded27: u3 = 0b011,
3236 size: IntegerSize,
3237 };
3238
3239 /// Load/store no-allocate pair (offset)
3240 pub const NoAllocatePairOffset = packed struct {
3241 Rt: Register.Encoded,
3242 Rn: Register.Encoded,
3243 Rt2: Register.Encoded,
3244 imm7: i7,
3245 L: L,
3246 decoded23: u3 = 0b000,
3247 V: bool,
3248 decoded27: u3 = 0b101,
3249 opc: u2,
3250 };
3251
3252 /// Load/store register pair (post-indexed)
3253 pub const RegisterPairPostIndexed = packed union {
3254 group: @This().Group,
3255 integer: Integer,
3256 vector: Vector,
3257
3258 pub const Group = packed struct {
3259 Rt: Register.Encoded,
3260 Rn: Register.Encoded,
3261 Rt2: Register.Encoded,
3262 imm7: i7,
3263 L: L,
3264 decoded23: u3 = 0b001,
3265 V: bool,
3266 decoded27: u3 = 0b101,
3267 opc: u2,
3268 };
3269
3270 pub const Integer = packed union {
3271 group: @This().Group,
3272 stp: Stp,
3273 ldp: Ldp,
3274 ldpsw: Ldpsw,
3275
3276 pub const Group = packed struct {
3277 Rt: Register.Encoded,
3278 Rn: Register.Encoded,
3279 Rt2: Register.Encoded,
3280 imm7: i7,
3281 L: L,
3282 decoded23: u3 = 0b001,
3283 V: bool = false,
3284 decoded27: u3 = 0b101,
3285 opc: u2,
3286 };
3287
3288 /// C6.2.321 STP
3289 pub const Stp = packed struct {
3290 Rt: Register.Encoded,
3291 Rn: Register.Encoded,
3292 Rt2: Register.Encoded,
3293 imm7: i7,
3294 L: L = .store,
3295 decoded23: u3 = 0b001,
3296 V: bool = false,
3297 decoded27: u3 = 0b101,
3298 opc0: u1 = 0b0,
3299 sf: Register.IntegerSize,
3300 };
3301
3302 /// C6.2.164 LDP
3303 pub const Ldp = packed struct {
3304 Rt: Register.Encoded,
3305 Rn: Register.Encoded,
3306 Rt2: Register.Encoded,
3307 imm7: i7,
3308 L: L = .load,
3309 decoded23: u3 = 0b001,
3310 V: bool = false,
3311 decoded27: u3 = 0b101,
3312 opc0: u1 = 0b0,
3313 sf: Register.IntegerSize,
3314 };
3315
3316 /// C6.2.165 LDPSW
3317 pub const Ldpsw = packed struct {
3318 Rt: Register.Encoded,
3319 Rn: Register.Encoded,
3320 Rt2: Register.Encoded,
3321 imm7: i7,
3322 L: L = .load,
3323 decoded23: u3 = 0b001,
3324 V: bool = false,
3325 decoded27: u3 = 0b101,
3326 opc: u2 = 0b01,
3327 };
3328
3329 pub const Decoded = union(enum) {
3330 unallocated,
3331 stp: Stp,
3332 ldp: Ldp,
3333 ldpsw: Ldpsw,
3334 };
3335 pub fn decode(inst: @This()) @This().Decoded {
3336 return switch (inst.group.opc) {
3337 0b00, 0b10 => switch (inst.group.L) {
3338 .store => .{ .stp = inst.stp },
3339 .load => .{ .ldp = inst.ldp },
3340 },
3341 0b01 => switch (inst.group.L) {
3342 else => .unallocated,
3343 .load => .{ .ldpsw = inst.ldpsw },
3344 },
3345 else => .unallocated,
3346 };
3347 }
3348 };
3349
3350 pub const Vector = packed union {
3351 group: @This().Group,
3352 stp: Stp,
3353 ldp: Ldp,
3354
3355 pub const Group = packed struct {
3356 Rt: Register.Encoded,
3357 Rn: Register.Encoded,
3358 Rt2: Register.Encoded,
3359 imm7: i7,
3360 L: L,
3361 decoded23: u3 = 0b001,
3362 V: bool = true,
3363 decoded27: u3 = 0b101,
3364 opc: VectorSize,
3365 };
3366
3367 /// C7.2.330 STP (SIMD&FP)
3368 pub const Stp = packed struct {
3369 Rt: Register.Encoded,
3370 Rn: Register.Encoded,
3371 Rt2: Register.Encoded,
3372 imm7: i7,
3373 L: L = .store,
3374 decoded23: u3 = 0b001,
3375 V: bool = true,
3376 decoded27: u3 = 0b101,
3377 opc: VectorSize,
3378 };
3379
3380 /// C7.2.190 LDP (SIMD&FP)
3381 pub const Ldp = packed struct {
3382 Rt: Register.Encoded,
3383 Rn: Register.Encoded,
3384 Rt2: Register.Encoded,
3385 imm7: i7,
3386 L: L = .load,
3387 decoded23: u3 = 0b001,
3388 V: bool = true,
3389 decoded27: u3 = 0b101,
3390 opc: VectorSize,
3391 };
3392
3393 pub const Decoded = union(enum) {
3394 unallocated,
3395 stp: Stp,
3396 ldp: Ldp,
3397 };
3398 pub fn decode(inst: @This()) @This().Decoded {
3399 return switch (inst.group.opc) {
3400 .single, .double, .quad => switch (inst.group.L) {
3401 .store => .{ .stp = inst.stp },
3402 .load => .{ .ldp = inst.ldp },
3403 },
3404 _ => .unallocated,
3405 };
3406 }
3407 };
3408
3409 pub const Decoded = union(enum) {
3410 integer: Integer,
3411 vector: Vector,
3412 };
3413 pub fn decode(inst: @This()) @This().Decoded {
3414 return switch (inst.group.V) {
3415 false => .{ .integer = inst.integer },
3416 true => .{ .vector = inst.vector },
3417 };
3418 }
3419 };
3420
3421 /// Load/store register pair (offset)
3422 pub const RegisterPairOffset = packed union {
3423 group: @This().Group,
3424 integer: Integer,
3425 vector: Vector,
3426
3427 pub const Group = packed struct {
3428 Rt: Register.Encoded,
3429 Rn: Register.Encoded,
3430 Rt2: Register.Encoded,
3431 imm7: i7,
3432 L: L,
3433 decoded23: u3 = 0b010,
3434 V: bool,
3435 decoded27: u3 = 0b101,
3436 opc: u2,
3437 };
3438
3439 pub const Integer = packed union {
3440 group: @This().Group,
3441 stp: Stp,
3442 ldp: Ldp,
3443 ldpsw: Ldpsw,
3444
3445 pub const Group = packed struct {
3446 Rt: Register.Encoded,
3447 Rn: Register.Encoded,
3448 Rt2: Register.Encoded,
3449 imm7: i7,
3450 L: L,
3451 decoded23: u3 = 0b010,
3452 V: bool = false,
3453 decoded27: u3 = 0b101,
3454 opc: u2,
3455 };
3456
3457 /// C6.2.321 STP
3458 pub const Stp = packed struct {
3459 Rt: Register.Encoded,
3460 Rn: Register.Encoded,
3461 Rt2: Register.Encoded,
3462 imm7: i7,
3463 L: L = .store,
3464 decoded23: u3 = 0b010,
3465 V: bool = false,
3466 decoded27: u3 = 0b101,
3467 opc0: u1 = 0b0,
3468 sf: Register.IntegerSize,
3469 };
3470
3471 /// C6.2.164 LDP
3472 pub const Ldp = packed struct {
3473 Rt: Register.Encoded,
3474 Rn: Register.Encoded,
3475 Rt2: Register.Encoded,
3476 imm7: i7,
3477 L: L = .load,
3478 decoded23: u3 = 0b010,
3479 V: bool = false,
3480 decoded27: u3 = 0b101,
3481 opc0: u1 = 0b0,
3482 sf: Register.IntegerSize,
3483 };
3484
3485 /// C6.2.165 LDPSW
3486 pub const Ldpsw = packed struct {
3487 Rt: Register.Encoded,
3488 Rn: Register.Encoded,
3489 Rt2: Register.Encoded,
3490 imm7: i7,
3491 L: L = .load,
3492 decoded23: u3 = 0b010,
3493 V: bool = false,
3494 decoded27: u3 = 0b101,
3495 opc: u2 = 0b01,
3496 };
3497
3498 pub const Decoded = union(enum) {
3499 unallocated,
3500 stp: Stp,
3501 ldp: Ldp,
3502 ldpsw: Ldpsw,
3503 };
3504 pub fn decode(inst: @This()) @This().Decoded {
3505 return switch (inst.group.opc) {
3506 0b00, 0b10 => switch (inst.group.L) {
3507 .store => .{ .stp = inst.stp },
3508 .load => .{ .ldp = inst.ldp },
3509 },
3510 0b01 => switch (inst.group.L) {
3511 else => .unallocated,
3512 .load => .{ .ldpsw = inst.ldpsw },
3513 },
3514 else => .unallocated,
3515 };
3516 }
3517 };
3518
3519 pub const Vector = packed union {
3520 group: @This().Group,
3521 stp: Stp,
3522 ldp: Ldp,
3523
3524 pub const Group = packed struct {
3525 Rt: Register.Encoded,
3526 Rn: Register.Encoded,
3527 Rt2: Register.Encoded,
3528 imm7: i7,
3529 L: L,
3530 decoded23: u3 = 0b010,
3531 V: bool = true,
3532 decoded27: u3 = 0b101,
3533 opc: VectorSize,
3534 };
3535
3536 /// C7.2.330 STP (SIMD&FP)
3537 pub const Stp = packed struct {
3538 Rt: Register.Encoded,
3539 Rn: Register.Encoded,
3540 Rt2: Register.Encoded,
3541 imm7: i7,
3542 L: L = .store,
3543 decoded23: u3 = 0b010,
3544 V: bool = true,
3545 decoded27: u3 = 0b101,
3546 opc: VectorSize,
3547 };
3548
3549 /// C7.2.190 LDP (SIMD&FP)
3550 pub const Ldp = packed struct {
3551 Rt: Register.Encoded,
3552 Rn: Register.Encoded,
3553 Rt2: Register.Encoded,
3554 imm7: i7,
3555 L: L = .load,
3556 decoded23: u3 = 0b010,
3557 V: bool = true,
3558 decoded27: u3 = 0b101,
3559 opc: VectorSize,
3560 };
3561
3562 pub const Decoded = union(enum) {
3563 unallocated,
3564 stp: Stp,
3565 ldp: Ldp,
3566 };
3567 pub fn decode(inst: @This()) @This().Decoded {
3568 return switch (inst.group.opc) {
3569 .single, .double, .quad => switch (inst.group.L) {
3570 .store => .{ .stp = inst.stp },
3571 .load => .{ .ldp = inst.ldp },
3572 },
3573 _ => .unallocated,
3574 };
3575 }
3576 };
3577
3578 pub const Decoded = union(enum) {
3579 integer: Integer,
3580 vector: Vector,
3581 };
3582 pub fn decode(inst: @This()) @This().Decoded {
3583 return switch (inst.group.V) {
3584 false => .{ .integer = inst.integer },
3585 true => .{ .vector = inst.vector },
3586 };
3587 }
3588 };
3589
3590 /// Load/store register pair (pre-indexed)
3591 pub const RegisterPairPreIndexed = packed union {
3592 group: @This().Group,
3593 integer: Integer,
3594 vector: Vector,
3595
3596 pub const Group = packed struct {
3597 Rt: Register.Encoded,
3598 Rn: Register.Encoded,
3599 Rt2: Register.Encoded,
3600 imm7: i7,
3601 L: L,
3602 decoded23: u3 = 0b011,
3603 V: bool,
3604 decoded27: u3 = 0b101,
3605 opc: u2,
3606 };
3607
3608 pub const Integer = packed union {
3609 group: @This().Group,
3610 stp: Stp,
3611 ldp: Ldp,
3612 ldpsw: Ldpsw,
3613
3614 pub const Group = packed struct {
3615 Rt: Register.Encoded,
3616 Rn: Register.Encoded,
3617 Rt2: Register.Encoded,
3618 imm7: i7,
3619 L: L,
3620 decoded23: u3 = 0b011,
3621 V: bool = false,
3622 decoded27: u3 = 0b101,
3623 opc: u2,
3624 };
3625
3626 /// C6.2.321 STP
3627 pub const Stp = packed struct {
3628 Rt: Register.Encoded,
3629 Rn: Register.Encoded,
3630 Rt2: Register.Encoded,
3631 imm7: i7,
3632 L: L = .store,
3633 decoded23: u3 = 0b011,
3634 V: bool = false,
3635 decoded27: u3 = 0b101,
3636 opc0: u1 = 0b0,
3637 sf: Register.IntegerSize,
3638 };
3639
3640 /// C6.2.164 LDP
3641 pub const Ldp = packed struct {
3642 Rt: Register.Encoded,
3643 Rn: Register.Encoded,
3644 Rt2: Register.Encoded,
3645 imm7: i7,
3646 L: L = .load,
3647 decoded23: u3 = 0b011,
3648 V: bool = false,
3649 decoded27: u3 = 0b101,
3650 opc0: u1 = 0b0,
3651 sf: Register.IntegerSize,
3652 };
3653
3654 /// C6.2.165 LDPSW
3655 pub const Ldpsw = packed struct {
3656 Rt: Register.Encoded,
3657 Rn: Register.Encoded,
3658 Rt2: Register.Encoded,
3659 imm7: i7,
3660 L: L = .load,
3661 decoded23: u3 = 0b011,
3662 V: bool = false,
3663 decoded27: u3 = 0b101,
3664 opc0: u2 = 0b01,
3665 };
3666
3667 pub const Decoded = union(enum) {
3668 unallocated,
3669 stp: Stp,
3670 ldp: Ldp,
3671 ldpsw: Ldpsw,
3672 };
3673 pub fn decode(inst: @This()) @This().Decoded {
3674 return switch (inst.group.opc) {
3675 0b00, 0b10 => switch (inst.group.L) {
3676 .store => .{ .stp = inst.stp },
3677 .load => .{ .ldp = inst.ldp },
3678 },
3679 0b01 => switch (inst.group.L) {
3680 else => .unallocated,
3681 .load => .{ .ldpsw = inst.ldpsw },
3682 },
3683 else => .unallocated,
3684 };
3685 }
3686 };
3687
3688 pub const Vector = packed union {
3689 group: @This().Group,
3690 stp: Stp,
3691 ldp: Ldp,
3692
3693 pub const Group = packed struct {
3694 Rt: Register.Encoded,
3695 Rn: Register.Encoded,
3696 Rt2: Register.Encoded,
3697 imm7: i7,
3698 L: L,
3699 decoded23: u3 = 0b011,
3700 V: bool = true,
3701 decoded27: u3 = 0b101,
3702 opc: VectorSize,
3703 };
3704
3705 /// C7.2.330 STP (SIMD&FP)
3706 pub const Stp = packed struct {
3707 Rt: Register.Encoded,
3708 Rn: Register.Encoded,
3709 Rt2: Register.Encoded,
3710 imm7: i7,
3711 L: L = .store,
3712 decoded23: u3 = 0b011,
3713 V: bool = true,
3714 decoded27: u3 = 0b101,
3715 opc: VectorSize,
3716 };
3717
3718 /// C7.2.190 LDP (SIMD&FP)
3719 pub const Ldp = packed struct {
3720 Rt: Register.Encoded,
3721 Rn: Register.Encoded,
3722 Rt2: Register.Encoded,
3723 imm7: i7,
3724 L: L = .load,
3725 decoded23: u3 = 0b011,
3726 V: bool = true,
3727 decoded27: u3 = 0b101,
3728 opc: VectorSize,
3729 };
3730
3731 pub const Decoded = union(enum) {
3732 unallocated,
3733 stp: Stp,
3734 ldp: Ldp,
3735 };
3736 pub fn decode(inst: @This()) @This().Decoded {
3737 return switch (inst.group.opc) {
3738 .single, .double, .quad => switch (inst.group.L) {
3739 .store => .{ .stp = inst.stp },
3740 .load => .{ .ldp = inst.ldp },
3741 },
3742 _ => .unallocated,
3743 };
3744 }
3745 };
3746
3747 pub const Decoded = union(enum) {
3748 integer: Integer,
3749 vector: Vector,
3750 };
3751 pub fn decode(inst: @This()) @This().Decoded {
3752 return switch (inst.group.V) {
3753 false => .{ .integer = inst.integer },
3754 true => .{ .vector = inst.vector },
3755 };
3756 }
3757 };
3758
3759 /// Load/store register (unscaled immediate)
3760 pub const RegisterUnscaledImmediate = packed union {
3761 group: @This().Group,
3762 integer: Integer,
3763 vector: Vector,
3764
3765 pub const Group = packed struct {
3766 Rt: Register.Encoded,
3767 Rn: Register.Encoded,
3768 decoded10: u2 = 0b00,
3769 imm9: i9,
3770 decoded21: u1 = 0b0,
3771 opc: u2,
3772 decoded24: u2 = 0b00,
3773 V: bool,
3774 decoded27: u3 = 0b111,
3775 size: u2,
3776 };
3777
3778 pub const Integer = packed union {
3779 group: @This().Group,
3780 sturb: Sturb,
3781 ldurb: Ldurb,
3782 ldursb: Ldursb,
3783 sturh: Sturh,
3784 ldurh: Ldurh,
3785 ldursh: Ldursh,
3786 stur: Stur,
3787 ldur: Ldur,
3788 ldursw: Ldursw,
3789 prfum: Prfum,
3790
3791 pub const Group = packed struct {
3792 Rt: Register.Encoded,
3793 Rn: Register.Encoded,
3794 decoded10: u2 = 0b00,
3795 imm9: i9,
3796 decoded21: u1 = 0b0,
3797 opc: u2,
3798 decoded24: u2 = 0b00,
3799 V: bool = false,
3800 decoded27: u3 = 0b111,
3801 size: IntegerSize,
3802 };
3803
3804 /// C6.2.347 STURB
3805 pub const Sturb = packed struct {
3806 Rt: Register.Encoded,
3807 Rn: Register.Encoded,
3808 decoded10: u2 = 0b00,
3809 imm9: i9,
3810 decoded21: u1 = 0b0,
3811 opc: u2 = 0b00,
3812 decoded24: u2 = 0b00,
3813 V: bool = false,
3814 decoded27: u3 = 0b111,
3815 size: IntegerSize = .byte,
3816 };
3817
3818 /// C6.2.203 LDURB
3819 pub const Ldurb = packed struct {
3820 Rt: Register.Encoded,
3821 Rn: Register.Encoded,
3822 decoded10: u2 = 0b00,
3823 imm9: i9,
3824 decoded21: u1 = 0b0,
3825 opc: u2 = 0b01,
3826 decoded24: u2 = 0b00,
3827 V: bool = false,
3828 decoded27: u3 = 0b111,
3829 size: IntegerSize = .byte,
3830 };
3831
3832 /// C6.2.205 LDURSB
3833 pub const Ldursb = packed struct {
3834 Rt: Register.Encoded,
3835 Rn: Register.Encoded,
3836 decoded10: u2 = 0b00,
3837 imm9: i9,
3838 decoded21: u1 = 0b0,
3839 opc0: u1,
3840 opc1: u1 = 0b1,
3841 decoded24: u2 = 0b00,
3842 V: bool = false,
3843 decoded27: u3 = 0b111,
3844 size: IntegerSize = .byte,
3845 };
3846
3847 /// C6.2.348 STURH
3848 pub const Sturh = packed struct {
3849 Rt: Register.Encoded,
3850 Rn: Register.Encoded,
3851 decoded10: u2 = 0b00,
3852 imm9: i9,
3853 decoded21: u1 = 0b0,
3854 opc: u2 = 0b00,
3855 decoded24: u2 = 0b00,
3856 V: bool = false,
3857 decoded27: u3 = 0b111,
3858 size: IntegerSize = .halfword,
3859 };
3860
3861 /// C6.2.204 LDURH
3862 pub const Ldurh = packed struct {
3863 Rt: Register.Encoded,
3864 Rn: Register.Encoded,
3865 decoded10: u2 = 0b00,
3866 imm9: i9,
3867 decoded21: u1 = 0b0,
3868 opc: u2 = 0b01,
3869 decoded24: u2 = 0b00,
3870 V: bool = false,
3871 decoded27: u3 = 0b111,
3872 size: IntegerSize = .halfword,
3873 };
3874
3875 /// C6.2.206 LDURSH
3876 pub const Ldursh = packed struct {
3877 Rt: Register.Encoded,
3878 Rn: Register.Encoded,
3879 decoded10: u2 = 0b00,
3880 imm9: i9,
3881 decoded21: u1 = 0b0,
3882 opc0: u1,
3883 opc1: u1 = 0b1,
3884 decoded24: u2 = 0b00,
3885 V: bool = false,
3886 decoded27: u3 = 0b111,
3887 size: IntegerSize = .halfword,
3888 };
3889
3890 /// C6.2.346 STUR
3891 pub const Stur = packed struct {
3892 Rt: Register.Encoded,
3893 Rn: Register.Encoded,
3894 decoded10: u2 = 0b00,
3895 imm9: i9,
3896 decoded21: u1 = 0b0,
3897 opc: u2 = 0b00,
3898 decoded24: u2 = 0b00,
3899 V: bool = false,
3900 decoded27: u3 = 0b111,
3901 sf: Register.IntegerSize,
3902 size1: u1 = 0b1,
3903 };
3904
3905 /// C6.2.202 LDUR
3906 pub const Ldur = packed struct {
3907 Rt: Register.Encoded,
3908 Rn: Register.Encoded,
3909 decoded10: u2 = 0b00,
3910 imm9: i9,
3911 decoded21: u1 = 0b0,
3912 opc: u2 = 0b01,
3913 decoded24: u2 = 0b00,
3914 V: bool = false,
3915 decoded27: u3 = 0b111,
3916 sf: Register.IntegerSize,
3917 size1: u1 = 0b1,
3918 };
3919
3920 /// C6.2.207 LDURSW
3921 pub const Ldursw = packed struct {
3922 Rt: Register.Encoded,
3923 Rn: Register.Encoded,
3924 decoded10: u2 = 0b00,
3925 imm9: i9,
3926 decoded21: u1 = 0b0,
3927 opc: u2 = 0b10,
3928 decoded24: u2 = 0b00,
3929 V: bool = false,
3930 decoded27: u3 = 0b111,
3931 size: IntegerSize = .word,
3932 };
3933
3934 /// C6.2.250 PRFUM
3935 pub const Prfum = packed struct {
3936 prfop: PrfOp,
3937 Rn: Register.Encoded,
3938 decoded10: u2 = 0b00,
3939 imm9: i9,
3940 decoded21: u1 = 0b0,
3941 opc: u2 = 0b10,
3942 decoded24: u2 = 0b00,
3943 V: bool = false,
3944 decoded27: u3 = 0b111,
3945 size: IntegerSize = .doubleword,
3946 };
3947
3948 pub const Decoded = union(enum) {
3949 unallocated,
3950 sturb: Sturb,
3951 ldurb: Ldurb,
3952 ldursb: Ldursb,
3953 sturh: Sturh,
3954 ldurh: Ldurh,
3955 ldursh: Ldursh,
3956 stur: Stur,
3957 ldur: Ldur,
3958 ldursw: Ldursw,
3959 prfum: Prfum,
3960 };
3961 pub fn decode(inst: @This()) @This().Decoded {
3962 return switch (inst.group.size) {
3963 .byte => switch (inst.group.V) {
3964 false => switch (inst.group.opc) {
3965 0b00 => .{ .sturb = inst.sturb },
3966 0b01 => .{ .ldurb = inst.ldurb },
3967 0b10, 0b11 => .{ .ldursb = inst.ldursb },
3968 },
3969 true => .unallocated,
3970 },
3971 .halfword => switch (inst.group.V) {
3972 false => switch (inst.group.opc) {
3973 0b00 => .{ .sturh = inst.sturh },
3974 0b01 => .{ .ldurh = inst.ldurh },
3975 0b10, 0b11 => .{ .ldursh = inst.ldursh },
3976 },
3977 true => .unallocated,
3978 },
3979 .word => switch (inst.group.V) {
3980 false => switch (inst.group.opc) {
3981 0b00 => .{ .stur = inst.stur },
3982 0b01 => .{ .ldur = inst.ldur },
3983 0b10 => .{ .ldursw = inst.ldursw },
3984 0b11 => .unallocated,
3985 },
3986 true => .unallocated,
3987 },
3988 .doubleword => switch (inst.group.V) {
3989 false => switch (inst.group.opc) {
3990 0b00 => .{ .stur = inst.stur },
3991 0b01 => .{ .ldur = inst.ldur },
3992 0b10 => .{ .prfum = inst.prfum },
3993 0b11 => .unallocated,
3994 },
3995 true => .unallocated,
3996 },
3997 };
3998 }
3999 };
4000
4001 pub const Vector = packed union {
4002 group: @This().Group,
4003 stur: Stur,
4004 ldur: Ldur,
4005
4006 pub const Group = packed struct {
4007 Rt: Register.Encoded,
4008 Rn: Register.Encoded,
4009 decoded10: u2 = 0b00,
4010 imm9: i9,
4011 decoded21: u1 = 0b0,
4012 opc0: L,
4013 opc1: Opc1,
4014 decoded24: u2 = 0b00,
4015 V: bool = true,
4016 decoded27: u3 = 0b111,
4017 size: Size,
4018 };
4019
4020 /// C7.2.333 STUR (SIMD&FP)
4021 pub const Stur = packed struct {
4022 Rt: Register.Encoded,
4023 Rn: Register.Encoded,
4024 decoded10: u2 = 0b00,
4025 imm9: i9,
4026 decoded21: u1 = 0b0,
4027 opc0: L = .store,
4028 opc1: Opc1,
4029 decoded24: u2 = 0b00,
4030 V: bool = true,
4031 decoded27: u3 = 0b111,
4032 size: Size,
4033 };
4034
4035 /// C7.2.194 LDUR (SIMD&FP)
4036 pub const Ldur = packed struct {
4037 Rt: Register.Encoded,
4038 Rn: Register.Encoded,
4039 decoded10: u2 = 0b00,
4040 imm9: i9,
4041 decoded21: u1 = 0b0,
4042 opc0: L = .load,
4043 opc1: Opc1,
4044 decoded24: u2 = 0b00,
4045 V: bool = true,
4046 decoded27: u3 = 0b111,
4047 size: Size,
4048 };
4049
4050 pub const Opc1 = packed struct {
4051 encoded: u1,
4052
4053 pub fn encode(vs: Register.VectorSize) Opc1 {
4054 return .{ .encoded = switch (vs) {
4055 .byte, .half, .single, .double => 0b0,
4056 .quad => 0b1,
4057 else => unreachable,
4058 } };
4059 }
4060
4061 pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize {
4062 return switch (enc_size.encoded) {
4063 0b00 => switch (enc_opc1.encoded) {
4064 0b0 => .byte,
4065 0b1 => .quad,
4066 },
4067 0b01 => switch (enc_opc1.encoded) {
4068 0b0 => .half,
4069 0b1 => unreachable,
4070 },
4071 0b10 => switch (enc_opc1.encoded) {
4072 0b0 => .single,
4073 0b1 => unreachable,
4074 },
4075 0b11 => switch (enc_opc1.encoded) {
4076 0b0 => .double,
4077 0b1 => unreachable,
4078 },
4079 };
4080 }
4081 };
4082
4083 pub const Size = packed struct {
4084 encoded: u2,
4085
4086 pub fn encode(vs: Register.VectorSize) Size {
4087 return .{ .encoded = switch (vs) {
4088 .byte, .quad => 0b00,
4089 .half => 0b01,
4090 .single => 0b10,
4091 .double => 0b11,
4092 else => unreachable,
4093 } };
4094 }
4095 };
4096
4097 pub const Decoded = union(enum) {
4098 unallocated,
4099 stur: Stur,
4100 ldur: Ldur,
4101 };
4102 pub fn decode(inst: @This()) @This().Decoded {
4103 return switch (inst.group.size.encoded) {
4104 0b00 => switch (inst.group.opc0) {
4105 .store => .{ .stur = inst.stur },
4106 .load => .{ .ldur = inst.ldur },
4107 },
4108 0b01, 0b10, 0b11 => switch (inst.group.opc1.encoded) {
4109 0b0 => switch (inst.group.opc0) {
4110 .store => .{ .stur = inst.stur },
4111 .load => .{ .ldur = inst.ldur },
4112 },
4113 0b1 => .unallocated,
4114 },
4115 };
4116 }
4117 };
4118
4119 pub const Decoded = union(enum) {
4120 integer: Integer,
4121 vector: Vector,
4122 };
4123 pub fn decode(inst: @This()) @This().Decoded {
4124 return switch (inst.group.V) {
4125 false => .{ .integer = inst.integer },
4126 true => .{ .vector = inst.vector },
4127 };
4128 }
4129 };
4130
4131 /// Load/store register (immediate post-indexed)
4132 pub const RegisterImmediatePostIndexed = packed union {
4133 group: @This().Group,
4134 integer: Integer,
4135 vector: Vector,
4136
4137 pub const Group = packed struct {
4138 Rt: Register.Encoded,
4139 Rn: Register.Encoded,
4140 decoded10: u2 = 0b01,
4141 imm9: i9,
4142 decoded21: u1 = 0b0,
4143 opc: u2,
4144 decoded24: u2 = 0b00,
4145 V: bool,
4146 decoded27: u3 = 0b111,
4147 size: u2,
4148 };
4149
4150 pub const Integer = packed union {
4151 group: @This().Group,
4152 strb: Strb,
4153 ldrb: Ldrb,
4154 ldrsb: Ldrsb,
4155 strh: Strh,
4156 ldrh: Ldrh,
4157 ldrsh: Ldrsh,
4158 str: Str,
4159 ldr: Ldr,
4160 ldrsw: Ldrsw,
4161
4162 pub const Group = packed struct {
4163 Rt: Register.Encoded,
4164 Rn: Register.Encoded,
4165 decoded10: u2 = 0b01,
4166 imm9: i9,
4167 decoded21: u1 = 0b0,
4168 opc: u2,
4169 decoded24: u2 = 0b00,
4170 V: bool = false,
4171 decoded27: u3 = 0b111,
4172 size: IntegerSize,
4173 };
4174
4175 /// C6.2.324 STRB (immediate)
4176 pub const Strb = packed struct {
4177 Rt: Register.Encoded,
4178 Rn: Register.Encoded,
4179 decoded10: u2 = 0b01,
4180 imm9: i9,
4181 decoded21: u1 = 0b0,
4182 opc: u2 = 0b00,
4183 decoded24: u2 = 0b00,
4184 V: bool = false,
4185 decoded27: u3 = 0b111,
4186 size: IntegerSize = .byte,
4187 };
4188
4189 /// C6.2.170 LDRB (immediate)
4190 pub const Ldrb = packed struct {
4191 Rt: Register.Encoded,
4192 Rn: Register.Encoded,
4193 decoded10: u2 = 0b01,
4194 imm9: i9,
4195 decoded21: u1 = 0b0,
4196 opc: u2 = 0b01,
4197 decoded24: u2 = 0b00,
4198 V: bool = false,
4199 decoded27: u3 = 0b111,
4200 size: IntegerSize = .byte,
4201 };
4202
4203 /// C6.2.174 LDRSB (immediate)
4204 pub const Ldrsb = packed struct {
4205 Rt: Register.Encoded,
4206 Rn: Register.Encoded,
4207 decoded10: u2 = 0b01,
4208 imm9: i9,
4209 decoded21: u1 = 0b0,
4210 opc0: u1,
4211 opc1: u1 = 0b1,
4212 decoded24: u2 = 0b00,
4213 V: bool = false,
4214 decoded27: u3 = 0b111,
4215 size: IntegerSize = .byte,
4216 };
4217
4218 /// C6.2.326 STRH (immediate)
4219 pub const Strh = packed struct {
4220 Rt: Register.Encoded,
4221 Rn: Register.Encoded,
4222 decoded10: u2 = 0b01,
4223 imm9: i9,
4224 decoded21: u1 = 0b0,
4225 opc: u2 = 0b00,
4226 decoded24: u2 = 0b00,
4227 V: bool = false,
4228 decoded27: u3 = 0b111,
4229 size: IntegerSize = .halfword,
4230 };
4231
4232 /// C6.2.172 LDRH (immediate)
4233 pub const Ldrh = packed struct {
4234 Rt: Register.Encoded,
4235 Rn: Register.Encoded,
4236 decoded10: u2 = 0b01,
4237 imm9: i9,
4238 decoded21: u1 = 0b0,
4239 opc: u2 = 0b01,
4240 decoded24: u2 = 0b00,
4241 V: bool = false,
4242 decoded27: u3 = 0b111,
4243 size: IntegerSize = .halfword,
4244 };
4245
4246 /// C6.2.176 LDRSH (immediate)
4247 pub const Ldrsh = packed struct {
4248 Rt: Register.Encoded,
4249 Rn: Register.Encoded,
4250 decoded10: u2 = 0b01,
4251 imm9: i9,
4252 decoded21: u1 = 0b0,
4253 opc0: u1,
4254 opc1: u1 = 0b1,
4255 decoded24: u2 = 0b00,
4256 V: bool = false,
4257 decoded27: u3 = 0b111,
4258 size: IntegerSize = .halfword,
4259 };
4260
4261 /// C6.2.322 STR (immediate)
4262 pub const Str = packed struct {
4263 Rt: Register.Encoded,
4264 Rn: Register.Encoded,
4265 decoded10: u2 = 0b01,
4266 imm9: i9,
4267 decoded21: u1 = 0b0,
4268 opc: u2 = 0b00,
4269 decoded24: u2 = 0b00,
4270 V: bool = false,
4271 decoded27: u3 = 0b111,
4272 sf: Register.IntegerSize,
4273 size1: u1 = 0b1,
4274 };
4275
4276 /// C6.2.166 LDR (immediate)
4277 pub const Ldr = packed struct {
4278 Rt: Register.Encoded,
4279 Rn: Register.Encoded,
4280 decoded10: u2 = 0b01,
4281 imm9: i9,
4282 decoded21: u1 = 0b0,
4283 opc: u2 = 0b01,
4284 decoded24: u2 = 0b00,
4285 V: bool = false,
4286 decoded27: u3 = 0b111,
4287 sf: Register.IntegerSize,
4288 size1: u1 = 0b1,
4289 };
4290
4291 /// C6.2.178 LDRSW (immediate)
4292 pub const Ldrsw = packed struct {
4293 Rt: Register.Encoded,
4294 Rn: Register.Encoded,
4295 decoded10: u2 = 0b01,
4296 imm9: i9,
4297 decoded21: u1 = 0b0,
4298 opc: u2 = 0b10,
4299 decoded24: u2 = 0b00,
4300 V: bool = false,
4301 decoded27: u3 = 0b111,
4302 size: IntegerSize = .word,
4303 };
4304
4305 pub const Decoded = union(enum) {
4306 unallocated,
4307 strb: Strb,
4308 ldrb: Ldrb,
4309 ldrsb: Ldrsb,
4310 strh: Strh,
4311 ldrh: Ldrh,
4312 ldrsh: Ldrsh,
4313 str: Str,
4314 ldr: Ldr,
4315 ldrsw: Ldrsw,
4316 };
4317 pub fn decode(inst: @This()) @This().Decoded {
4318 return switch (inst.group.size) {
4319 .byte => switch (inst.group.V) {
4320 false => switch (inst.group.opc) {
4321 0b00 => .{ .strb = inst.strb },
4322 0b01 => .{ .ldrb = inst.ldrb },
4323 0b10, 0b11 => .{ .ldrsb = inst.ldrsb },
4324 },
4325 true => .unallocated,
4326 },
4327 .halfword => switch (inst.group.V) {
4328 false => switch (inst.group.opc) {
4329 0b00 => .{ .strh = inst.strh },
4330 0b01 => .{ .ldrh = inst.ldrh },
4331 0b10, 0b11 => .{ .ldrsh = inst.ldrsh },
4332 },
4333 true => .unallocated,
4334 },
4335 .word => switch (inst.group.V) {
4336 false => switch (inst.group.opc) {
4337 0b00 => .{ .str = inst.str },
4338 0b01 => .{ .ldr = inst.ldr },
4339 0b10 => .{ .ldrsw = inst.ldrsw },
4340 0b11 => .unallocated,
4341 },
4342 true => .unallocated,
4343 },
4344 .doubleword => switch (inst.group.V) {
4345 false => switch (inst.group.opc) {
4346 0b00 => .{ .str = inst.str },
4347 0b01 => .{ .ldr = inst.ldr },
4348 0b10, 0b11 => .unallocated,
4349 },
4350 true => .unallocated,
4351 },
4352 };
4353 }
4354 };
4355
4356 pub const Vector = packed union {
4357 group: @This().Group,
4358 str: Str,
4359 ldr: Ldr,
4360
4361 pub const Group = packed struct {
4362 Rt: Register.Encoded,
4363 Rn: Register.Encoded,
4364 decoded10: u2 = 0b01,
4365 imm9: i9,
4366 decoded21: u1 = 0b0,
4367 opc0: L,
4368 opc1: Opc1,
4369 decoded24: u2 = 0b00,
4370 V: bool = true,
4371 decoded27: u3 = 0b111,
4372 size: Size,
4373 };
4374
4375 /// C7.2.331 STR (immediate, SIMD&FP)
4376 pub const Str = packed struct {
4377 Rt: Register.Encoded,
4378 Rn: Register.Encoded,
4379 decoded10: u2 = 0b01,
4380 imm9: i9,
4381 decoded21: u1 = 0b0,
4382 opc0: L = .store,
4383 opc1: Opc1,
4384 decoded24: u2 = 0b00,
4385 V: bool = true,
4386 decoded27: u3 = 0b111,
4387 size: Size,
4388 };
4389
4390 /// C7.2.191 LDR (immediate, SIMD&FP)
4391 pub const Ldr = packed struct {
4392 Rt: Register.Encoded,
4393 Rn: Register.Encoded,
4394 decoded10: u2 = 0b01,
4395 imm9: i9,
4396 decoded21: u1 = 0b0,
4397 opc0: L = .load,
4398 opc1: Opc1,
4399 decoded24: u2 = 0b00,
4400 V: bool = true,
4401 decoded27: u3 = 0b111,
4402 size: Size,
4403 };
4404
4405 pub const Opc1 = packed struct {
4406 encoded: u1,
4407
4408 pub fn encode(vs: Register.VectorSize) Opc1 {
4409 return .{ .encoded = switch (vs) {
4410 .byte, .half, .single, .double => 0b0,
4411 .quad => 0b1,
4412 else => unreachable,
4413 } };
4414 }
4415
4416 pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize {
4417 return switch (enc_size.encoded) {
4418 0b00 => switch (enc_opc1.encoded) {
4419 0b0 => .byte,
4420 0b1 => .quad,
4421 },
4422 0b01 => switch (enc_opc1.encoded) {
4423 0b0 => .half,
4424 0b1 => unreachable,
4425 },
4426 0b10 => switch (enc_opc1.encoded) {
4427 0b0 => .single,
4428 0b1 => unreachable,
4429 },
4430 0b11 => switch (enc_opc1.encoded) {
4431 0b0 => .double,
4432 0b1 => unreachable,
4433 },
4434 };
4435 }
4436 };
4437
4438 pub const Size = packed struct {
4439 encoded: u2,
4440
4441 pub fn encode(vs: Register.VectorSize) Size {
4442 return .{ .encoded = switch (vs) {
4443 .byte, .quad => 0b00,
4444 .half => 0b01,
4445 .single => 0b10,
4446 .double => 0b11,
4447 else => unreachable,
4448 } };
4449 }
4450 };
4451
4452 pub const Decoded = union(enum) {
4453 unallocated,
4454 str: Str,
4455 ldr: Ldr,
4456 };
4457 pub fn decode(inst: @This()) @This().Decoded {
4458 return switch (inst.group.size.encoded) {
4459 0b00 => switch (inst.group.opc0) {
4460 .store => .{ .str = inst.str },
4461 .load => .{ .ldr = inst.ldr },
4462 },
4463 0b01, 0b10, 0b11 => switch (inst.group.opc1.encoded) {
4464 0b0 => switch (inst.group.opc0) {
4465 .store => .{ .str = inst.str },
4466 .load => .{ .ldr = inst.ldr },
4467 },
4468 0b1 => .unallocated,
4469 },
4470 };
4471 }
4472 };
4473
4474 pub const Decoded = union(enum) {
4475 integer: Integer,
4476 vector: Vector,
4477 };
4478 pub fn decode(inst: @This()) @This().Decoded {
4479 return switch (inst.group.V) {
4480 false => .{ .integer = inst.integer },
4481 true => .{ .vector = inst.vector },
4482 };
4483 }
4484 };
4485
4486 /// Load/store register (unprivileged)
4487 pub const RegisterUnprivileged = packed struct {
4488 Rt: Register.Encoded,
4489 Rn: Register.Encoded,
4490 decoded10: u2 = 0b10,
4491 imm9: i9,
4492 decoded21: u1 = 0b0,
4493 opc: u2,
4494 decoded24: u2 = 0b00,
4495 V: bool,
4496 decoded27: u3 = 0b111,
4497 size: IntegerSize,
4498 };
4499
4500 /// Load/store register (immediate pre-indexed)
4501 pub const RegisterImmediatePreIndexed = packed union {
4502 group: @This().Group,
4503 integer: Integer,
4504 vector: Vector,
4505
4506 pub const Group = packed struct {
4507 Rt: Register.Encoded,
4508 Rn: Register.Encoded,
4509 decoded10: u2 = 0b11,
4510 imm9: i9,
4511 decoded21: u1 = 0b0,
4512 opc: u2,
4513 decoded24: u2 = 0b00,
4514 V: bool,
4515 decoded27: u3 = 0b111,
4516 size: u2,
4517 };
4518
4519 pub const Integer = packed union {
4520 group: @This().Group,
4521 strb: Strb,
4522 ldrb: Ldrb,
4523 ldrsb: Ldrsb,
4524 strh: Strh,
4525 ldrh: Ldrh,
4526 ldrsh: Ldrsh,
4527 str: Str,
4528 ldr: Ldr,
4529 ldrsw: Ldrsw,
4530
4531 pub const Group = packed struct {
4532 Rt: Register.Encoded,
4533 Rn: Register.Encoded,
4534 decoded10: u2 = 0b11,
4535 imm9: i9,
4536 decoded21: u1 = 0b0,
4537 opc: u2,
4538 decoded24: u2 = 0b00,
4539 V: bool = false,
4540 decoded27: u3 = 0b111,
4541 size: IntegerSize,
4542 };
4543
4544 /// C6.2.324 STRB (immediate)
4545 pub const Strb = packed struct {
4546 Rt: Register.Encoded,
4547 Rn: Register.Encoded,
4548 decoded10: u2 = 0b11,
4549 imm9: i9,
4550 decoded21: u1 = 0b0,
4551 opc: u2 = 0b00,
4552 decoded24: u2 = 0b00,
4553 V: bool = false,
4554 decoded27: u3 = 0b111,
4555 size: IntegerSize = .byte,
4556 };
4557
4558 /// C6.2.170 LDRB (immediate)
4559 pub const Ldrb = packed struct {
4560 Rt: Register.Encoded,
4561 Rn: Register.Encoded,
4562 decoded10: u2 = 0b11,
4563 imm9: i9,
4564 decoded21: u1 = 0b0,
4565 opc: u2 = 0b01,
4566 decoded24: u2 = 0b00,
4567 V: bool = false,
4568 decoded27: u3 = 0b111,
4569 size: IntegerSize = .byte,
4570 };
4571
4572 /// C6.2.174 LDRSB (immediate)
4573 pub const Ldrsb = packed struct {
4574 Rt: Register.Encoded,
4575 Rn: Register.Encoded,
4576 decoded10: u2 = 0b11,
4577 imm9: i9,
4578 decoded21: u1 = 0b0,
4579 opc0: u1,
4580 opc1: u1 = 0b1,
4581 decoded24: u2 = 0b00,
4582 V: bool = false,
4583 decoded27: u3 = 0b111,
4584 size: IntegerSize = .byte,
4585 };
4586
4587 /// C6.2.326 STRH (immediate)
4588 pub const Strh = packed struct {
4589 Rt: Register.Encoded,
4590 Rn: Register.Encoded,
4591 decoded10: u2 = 0b11,
4592 imm9: i9,
4593 decoded21: u1 = 0b0,
4594 opc: u2 = 0b00,
4595 decoded24: u2 = 0b00,
4596 V: bool = false,
4597 decoded27: u3 = 0b111,
4598 size: IntegerSize = .halfword,
4599 };
4600
4601 /// C6.2.172 LDRH (immediate)
4602 pub const Ldrh = packed struct {
4603 Rt: Register.Encoded,
4604 Rn: Register.Encoded,
4605 decoded10: u2 = 0b11,
4606 imm9: i9,
4607 decoded21: u1 = 0b0,
4608 opc: u2 = 0b01,
4609 decoded24: u2 = 0b00,
4610 V: bool = false,
4611 decoded27: u3 = 0b111,
4612 size: IntegerSize = .halfword,
4613 };
4614
4615 /// C6.2.176 LDRSH (immediate)
4616 pub const Ldrsh = packed struct {
4617 Rt: Register.Encoded,
4618 Rn: Register.Encoded,
4619 decoded10: u2 = 0b11,
4620 imm9: i9,
4621 decoded21: u1 = 0b0,
4622 opc0: u1,
4623 opc1: u1 = 0b1,
4624 decoded24: u2 = 0b00,
4625 V: bool = false,
4626 decoded27: u3 = 0b111,
4627 size: IntegerSize = .halfword,
4628 };
4629
4630 /// C6.2.322 STR (immediate)
4631 pub const Str = packed struct {
4632 Rt: Register.Encoded,
4633 Rn: Register.Encoded,
4634 decoded10: u2 = 0b11,
4635 imm9: i9,
4636 decoded21: u1 = 0b0,
4637 opc: u2 = 0b00,
4638 decoded24: u2 = 0b00,
4639 V: bool = false,
4640 decoded27: u3 = 0b111,
4641 sf: Register.IntegerSize,
4642 size1: u1 = 0b1,
4643 };
4644
4645 /// C6.2.166 LDR (immediate)
4646 pub const Ldr = packed struct {
4647 Rt: Register.Encoded,
4648 Rn: Register.Encoded,
4649 decoded10: u2 = 0b11,
4650 imm9: i9,
4651 decoded21: u1 = 0b0,
4652 opc: u2 = 0b01,
4653 decoded24: u2 = 0b00,
4654 V: bool = false,
4655 decoded27: u3 = 0b111,
4656 sf: Register.IntegerSize,
4657 size1: u1 = 0b1,
4658 };
4659
4660 /// C6.2.178 LDRSW (immediate)
4661 pub const Ldrsw = packed struct {
4662 Rt: Register.Encoded,
4663 Rn: Register.Encoded,
4664 decoded10: u2 = 0b11,
4665 imm9: i9,
4666 decoded21: u1 = 0b0,
4667 opc: u2 = 0b10,
4668 decoded24: u2 = 0b00,
4669 V: bool = false,
4670 decoded27: u3 = 0b111,
4671 size: IntegerSize = .word,
4672 };
4673
4674 pub const Decoded = union(enum) {
4675 unallocated,
4676 strb: Strb,
4677 ldrb: Ldrb,
4678 ldrsb: Ldrsb,
4679 strh: Strh,
4680 ldrh: Ldrh,
4681 ldrsh: Ldrsh,
4682 str: Str,
4683 ldr: Ldr,
4684 ldrsw: Ldrsw,
4685 };
4686 pub fn decode(inst: @This()) @This().Decoded {
4687 return switch (inst.group.size) {
4688 .byte => switch (inst.group.opc) {
4689 0b00 => .{ .strb = inst.strb },
4690 0b01 => .{ .ldrb = inst.ldrb },
4691 0b10, 0b11 => .{ .ldrsb = inst.ldrsb },
4692 },
4693 .halfword => switch (inst.group.opc) {
4694 0b00 => .{ .strh = inst.strh },
4695 0b01 => .{ .ldrh = inst.ldrh },
4696 0b10, 0b11 => .{ .ldrsh = inst.ldrsh },
4697 },
4698 .word => switch (inst.group.opc) {
4699 0b00 => .{ .str = inst.str },
4700 0b01 => .{ .ldr = inst.ldr },
4701 0b10 => .{ .ldrsw = inst.ldrsw },
4702 0b11 => .unallocated,
4703 },
4704 .doubleword => switch (inst.group.opc) {
4705 0b00 => .{ .str = inst.str },
4706 0b01 => .{ .ldr = inst.ldr },
4707 0b10, 0b11 => .unallocated,
4708 },
4709 };
4710 }
4711 };
4712
4713 pub const Vector = packed union {
4714 group: @This().Group,
4715 str: Str,
4716 ldr: Ldr,
4717
4718 pub const Group = packed struct {
4719 Rt: Register.Encoded,
4720 Rn: Register.Encoded,
4721 decoded10: u2 = 0b11,
4722 imm9: i9,
4723 decoded21: u1 = 0b0,
4724 opc0: L,
4725 opc1: Opc1,
4726 decoded24: u2 = 0b00,
4727 V: bool = true,
4728 decoded27: u3 = 0b111,
4729 size: Size,
4730 };
4731
4732 /// C7.2.331 STR (immediate, SIMD&FP)
4733 pub const Str = packed struct {
4734 Rt: Register.Encoded,
4735 Rn: Register.Encoded,
4736 decoded10: u2 = 0b11,
4737 imm9: i9,
4738 decoded21: u1 = 0b0,
4739 opc0: L = .store,
4740 opc1: Opc1,
4741 decoded24: u2 = 0b00,
4742 V: bool = true,
4743 decoded27: u3 = 0b111,
4744 size: Size,
4745 };
4746
4747 /// C7.2.191 LDR (immediate, SIMD&FP)
4748 pub const Ldr = packed struct {
4749 Rt: Register.Encoded,
4750 Rn: Register.Encoded,
4751 decoded10: u2 = 0b11,
4752 imm9: i9,
4753 decoded21: u1 = 0b0,
4754 opc0: L = .load,
4755 opc1: Opc1,
4756 decoded24: u2 = 0b00,
4757 V: bool = true,
4758 decoded27: u3 = 0b111,
4759 size: Size,
4760 };
4761
4762 pub const Opc1 = packed struct {
4763 encoded: u1,
4764
4765 pub fn encode(vs: Register.VectorSize) Opc1 {
4766 return .{ .encoded = switch (vs) {
4767 .byte, .half, .single, .double => 0b0,
4768 .quad => 0b1,
4769 else => unreachable,
4770 } };
4771 }
4772
4773 pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize {
4774 return switch (enc_size.encoded) {
4775 0b00 => switch (enc_opc1.encoded) {
4776 0b0 => .byte,
4777 0b1 => .quad,
4778 },
4779 0b01 => switch (enc_opc1.encoded) {
4780 0b0 => .half,
4781 0b1 => unreachable,
4782 },
4783 0b10 => switch (enc_opc1.encoded) {
4784 0b0 => .single,
4785 0b1 => unreachable,
4786 },
4787 0b11 => switch (enc_opc1.encoded) {
4788 0b0 => .double,
4789 0b1 => unreachable,
4790 },
4791 };
4792 }
4793 };
4794
4795 pub const Size = packed struct {
4796 encoded: u2,
4797
4798 pub fn encode(vs: Register.VectorSize) Size {
4799 return .{ .encoded = switch (vs) {
4800 .byte, .quad => 0b00,
4801 .half => 0b01,
4802 .single => 0b10,
4803 .double => 0b11,
4804 else => unreachable,
4805 } };
4806 }
4807 };
4808
4809 pub const Decoded = union(enum) {
4810 unallocated,
4811 str: Str,
4812 ldr: Ldr,
4813 };
4814 pub fn decode(inst: @This()) @This().Decoded {
4815 return switch (inst.group.size.encoded) {
4816 0b00 => switch (inst.group.opc0) {
4817 .store => .{ .str = inst.str },
4818 .load => .{ .ldr = inst.ldr },
4819 },
4820 0b01, 0b10, 0b11 => switch (inst.group.opc1.encoded) {
4821 0b0 => switch (inst.group.opc0) {
4822 .store => .{ .str = inst.str },
4823 .load => .{ .ldr = inst.ldr },
4824 },
4825 0b1 => .unallocated,
4826 },
4827 };
4828 }
4829 };
4830
4831 pub const Decoded = union(enum) {
4832 integer: Integer,
4833 vector: Vector,
4834 };
4835 pub fn decode(inst: @This()) @This().Decoded {
4836 return switch (inst.group.V) {
4837 false => .{ .integer = inst.integer },
4838 true => .{ .vector = inst.vector },
4839 };
4840 }
4841 };
4842
4843 /// Load/store register (register offset)
4844 pub const RegisterRegisterOffset = packed union {
4845 group: @This().Group,
4846 integer: Integer,
4847 vector: Vector,
4848
4849 pub const Group = packed struct {
4850 Rt: Register.Encoded,
4851 Rn: Register.Encoded,
4852 decoded10: u2 = 0b10,
4853 S: bool,
4854 option: Option,
4855 Rm: Register.Encoded,
4856 decoded21: u1 = 0b1,
4857 opc: u2,
4858 decoded24: u2 = 0b00,
4859 V: bool,
4860 decoded27: u3 = 0b111,
4861 size: u2,
4862 };
4863
4864 pub const Integer = packed union {
4865 group: @This().Group,
4866 strb: Strb,
4867 ldrb: Ldrb,
4868 ldrsb: Ldrsb,
4869 strh: Strh,
4870 ldrh: Ldrh,
4871 ldrsh: Ldrsh,
4872 str: Str,
4873 ldr: Ldr,
4874 ldrsw: Ldrsw,
4875 prfm: Prfm,
4876
4877 pub const Group = packed struct {
4878 Rt: Register.Encoded,
4879 Rn: Register.Encoded,
4880 decoded10: u2 = 0b10,
4881 S: bool,
4882 option: Option,
4883 Rm: Register.Encoded,
4884 decoded21: u1 = 0b1,
4885 opc: u2,
4886 decoded24: u2 = 0b00,
4887 V: bool = false,
4888 decoded27: u3 = 0b111,
4889 size: IntegerSize,
4890 };
4891
4892 /// C6.2.325 STRB (register)
4893 pub const Strb = packed struct {
4894 Rt: Register.Encoded,
4895 Rn: Register.Encoded,
4896 decoded10: u2 = 0b10,
4897 S: bool,
4898 option: Option,
4899 Rm: Register.Encoded,
4900 decoded21: u1 = 0b1,
4901 opc: u2 = 0b00,
4902 decoded24: u2 = 0b00,
4903 V: bool = false,
4904 decoded27: u3 = 0b111,
4905 size: IntegerSize = .byte,
4906 };
4907
4908 /// C6.2.171 LDRB (register)
4909 pub const Ldrb = packed struct {
4910 Rt: Register.Encoded,
4911 Rn: Register.Encoded,
4912 decoded10: u2 = 0b10,
4913 S: bool,
4914 option: Option,
4915 Rm: Register.Encoded,
4916 decoded21: u1 = 0b1,
4917 opc: u2 = 0b01,
4918 decoded24: u2 = 0b00,
4919 V: bool = false,
4920 decoded27: u3 = 0b111,
4921 size: IntegerSize = .byte,
4922 };
4923
4924 /// C6.2.175 LDRSB (register)
4925 pub const Ldrsb = packed struct {
4926 Rt: Register.Encoded,
4927 Rn: Register.Encoded,
4928 decoded10: u2 = 0b10,
4929 S: bool,
4930 option: Option,
4931 Rm: Register.Encoded,
4932 decoded21: u1 = 0b1,
4933 opc0: u1,
4934 opc1: u1 = 0b1,
4935 decoded24: u2 = 0b00,
4936 V: bool = false,
4937 decoded27: u3 = 0b111,
4938 size: IntegerSize = .byte,
4939 };
4940
4941 /// C6.2.327 STRH (register)
4942 pub const Strh = packed struct {
4943 Rt: Register.Encoded,
4944 Rn: Register.Encoded,
4945 decoded10: u2 = 0b10,
4946 S: bool,
4947 option: Option,
4948 Rm: Register.Encoded,
4949 decoded21: u1 = 0b1,
4950 opc: u2 = 0b00,
4951 decoded24: u2 = 0b00,
4952 V: bool = false,
4953 decoded27: u3 = 0b111,
4954 size: IntegerSize = .halfword,
4955 };
4956
4957 /// C6.2.173 LDRH (register)
4958 pub const Ldrh = packed struct {
4959 Rt: Register.Encoded,
4960 Rn: Register.Encoded,
4961 decoded10: u2 = 0b10,
4962 S: bool,
4963 option: Option,
4964 Rm: Register.Encoded,
4965 decoded21: u1 = 0b1,
4966 opc: u2 = 0b01,
4967 decoded24: u2 = 0b00,
4968 V: bool = false,
4969 decoded27: u3 = 0b111,
4970 size: IntegerSize = .halfword,
4971 };
4972
4973 /// C6.2.177 LDRSH (register)
4974 pub const Ldrsh = packed struct {
4975 Rt: Register.Encoded,
4976 Rn: Register.Encoded,
4977 decoded10: u2 = 0b10,
4978 S: bool,
4979 option: Option,
4980 Rm: Register.Encoded,
4981 decoded21: u1 = 0b1,
4982 opc0: u1,
4983 opc1: u1 = 0b1,
4984 decoded24: u2 = 0b00,
4985 V: bool = false,
4986 decoded27: u3 = 0b111,
4987 size: IntegerSize = .halfword,
4988 };
4989
4990 /// C6.2.323 STR (register)
4991 pub const Str = packed struct {
4992 Rt: Register.Encoded,
4993 Rn: Register.Encoded,
4994 decoded10: u2 = 0b10,
4995 S: bool,
4996 option: Option,
4997 Rm: Register.Encoded,
4998 decoded21: u1 = 0b1,
4999 opc: u2 = 0b00,
5000 decoded24: u2 = 0b00,
5001 V: bool = false,
5002 decoded27: u3 = 0b111,
5003 sf: Register.IntegerSize,
5004 size1: u1 = 0b1,
5005 };
5006
5007 /// C6.2.168 LDR (register)
5008 pub const Ldr = packed struct {
5009 Rt: Register.Encoded,
5010 Rn: Register.Encoded,
5011 decoded10: u2 = 0b10,
5012 S: bool,
5013 option: Option,
5014 Rm: Register.Encoded,
5015 decoded21: u1 = 0b1,
5016 opc: u2 = 0b01,
5017 decoded24: u2 = 0b00,
5018 V: bool = false,
5019 decoded27: u3 = 0b111,
5020 sf: Register.IntegerSize,
5021 size1: u1 = 0b1,
5022 };
5023
5024 /// C6.2.180 LDRSW (register)
5025 pub const Ldrsw = packed struct {
5026 Rt: Register.Encoded,
5027 Rn: Register.Encoded,
5028 decoded10: u2 = 0b10,
5029 S: bool,
5030 option: Option,
5031 Rm: Register.Encoded,
5032 decoded21: u1 = 0b1,
5033 opc: u2 = 0b10,
5034 decoded24: u2 = 0b00,
5035 V: bool = false,
5036 decoded27: u3 = 0b111,
5037 size: IntegerSize = .word,
5038 };
5039
5040 /// C6.2.249 PRFM (register)
5041 pub const Prfm = packed struct {
5042 prfop: PrfOp,
5043 Rn: Register.Encoded,
5044 decoded10: u2 = 0b10,
5045 S: bool,
5046 option: Option,
5047 Rm: Register.Encoded,
5048 decoded21: u1 = 0b1,
5049 opc: u2 = 0b10,
5050 decoded24: u2 = 0b00,
5051 V: bool = false,
5052 decoded27: u3 = 0b111,
5053 size: IntegerSize = .doubleword,
5054 };
5055
5056 pub const Decoded = union(enum) {
5057 unallocated,
5058 strb: Strb,
5059 ldrb: Ldrb,
5060 ldrsb: Ldrsb,
5061 strh: Strh,
5062 ldrh: Ldrh,
5063 ldrsh: Ldrsh,
5064 str: Str,
5065 ldr: Ldr,
5066 ldrsw: Ldrsw,
5067 prfm: Prfm,
5068 };
5069 pub fn decode(inst: @This()) @This().Decoded {
5070 return switch (inst.group.size) {
5071 .byte => switch (inst.group.V) {
5072 false => switch (inst.group.opc) {
5073 0b00 => .{ .strb = inst.strb },
5074 0b01 => .{ .ldrb = inst.ldrb },
5075 0b10, 0b11 => .{ .ldrsb = inst.ldrsb },
5076 },
5077 true => .unallocated,
5078 },
5079 .halfword => switch (inst.group.V) {
5080 false => switch (inst.group.opc) {
5081 0b00 => .{ .strh = inst.strh },
5082 0b01 => .{ .ldrh = inst.ldrh },
5083 0b10, 0b11 => .{ .ldrsh = inst.ldrsh },
5084 },
5085 true => .unallocated,
5086 },
5087 .word => switch (inst.group.V) {
5088 false => switch (inst.group.opc) {
5089 0b00 => .{ .str = inst.str },
5090 0b01 => .{ .ldr = inst.ldr },
5091 0b10 => .{ .ldrsw = inst.ldrsw },
5092 0b11 => .unallocated,
5093 },
5094 true => .unallocated,
5095 },
5096 .doubleword => switch (inst.group.V) {
5097 false => switch (inst.group.opc) {
5098 0b00 => .{ .str = inst.str },
5099 0b01 => .{ .ldr = inst.ldr },
5100 0b10 => .{ .prfm = inst.prfm },
5101 0b11 => .unallocated,
5102 },
5103 true => .unallocated,
5104 },
5105 };
5106 }
5107 };
5108
5109 pub const Vector = packed union {
5110 group: @This().Group,
5111 str: Str,
5112 ldr: Ldr,
5113
5114 pub const Group = packed struct {
5115 Rt: Register.Encoded,
5116 Rn: Register.Encoded,
5117 decoded10: u2 = 0b10,
5118 S: bool,
5119 option: Option,
5120 Rm: Register.Encoded,
5121 decoded21: u1 = 0b1,
5122 opc: u2,
5123 decoded24: u2 = 0b00,
5124 V: bool = true,
5125 decoded27: u3 = 0b111,
5126 size: Size,
5127 };
5128
5129 /// C7.2.332 STR (register, SIMD&FP)
5130 pub const Str = packed struct {
5131 Rt: Register.Encoded,
5132 Rn: Register.Encoded,
5133 decoded10: u2 = 0b10,
5134 S: bool,
5135 option: Option,
5136 Rm: Register.Encoded,
5137 decoded21: u1 = 0b1,
5138 opc0: L = .store,
5139 opc1: Opc1,
5140 decoded24: u2 = 0b00,
5141 V: bool = true,
5142 decoded27: u3 = 0b111,
5143 size: Size,
5144 };
5145
5146 /// C7.2.193 LDR (register, SIMD&FP)
5147 pub const Ldr = packed struct {
5148 Rt: Register.Encoded,
5149 Rn: Register.Encoded,
5150 decoded10: u2 = 0b10,
5151 S: bool,
5152 option: Option,
5153 Rm: Register.Encoded,
5154 decoded21: u1 = 0b1,
5155 opc0: L = .load,
5156 opc1: Opc1,
5157 decoded24: u2 = 0b00,
5158 V: bool = true,
5159 decoded27: u3 = 0b111,
5160 size: Size,
5161 };
5162
5163 pub const Opc1 = packed struct {
5164 encoded: u1,
5165
5166 pub fn encode(vs: Register.VectorSize) Opc1 {
5167 return .{ .encoded = switch (vs) {
5168 .byte, .half, .single, .double => 0b0,
5169 .quad => 0b1,
5170 else => unreachable,
5171 } };
5172 }
5173
5174 pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize {
5175 return switch (enc_size.encoded) {
5176 0b00 => switch (enc_opc1.encoded) {
5177 0b0 => .byte,
5178 0b1 => .quad,
5179 },
5180 0b01 => switch (enc_opc1.encoded) {
5181 0b0 => .half,
5182 0b1 => unreachable,
5183 },
5184 0b10 => switch (enc_opc1.encoded) {
5185 0b0 => .single,
5186 0b1 => unreachable,
5187 },
5188 0b11 => switch (enc_opc1.encoded) {
5189 0b0 => .double,
5190 0b1 => unreachable,
5191 },
5192 };
5193 }
5194 };
5195
5196 pub const Size = packed struct {
5197 encoded: u2,
5198
5199 pub fn encode(vs: Register.VectorSize) Size {
5200 return .{ .encoded = switch (vs) {
5201 .byte, .quad => 0b00,
5202 .half => 0b01,
5203 .single => 0b10,
5204 .double => 0b11,
5205 else => unreachable,
5206 } };
5207 }
5208 };
5209 };
5210
5211 pub const Option = enum(u3) {
5212 uxtw = 0b010,
5213 lsl = 0b011,
5214 sxtw = 0b110,
5215 sxtx = 0b111,
5216 _,
5217
5218 pub fn sf(option: Option) Register.IntegerSize {
5219 return switch (option) {
5220 .uxtw, .sxtw => .word,
5221 .lsl, .sxtx => .doubleword,
5222 _ => unreachable,
5223 };
5224 }
5225 };
5226
5227 pub const Extend = union(Option) {
5228 uxtw: Amount,
5229 lsl: Amount,
5230 sxtw: Amount,
5231 sxtx: Amount,
5232
5233 pub const Amount = u3;
5234 };
5235
5236 pub const Decoded = union(enum) {
5237 integer: Integer,
5238 vector: Vector,
5239 };
5240 pub fn decode(inst: @This()) @This().Decoded {
5241 return switch (inst.group.V) {
5242 false => .{ .integer = inst.integer },
5243 true => .{ .vector = inst.vector },
5244 };
5245 }
5246 };
5247
5248 /// Load/store register (unsigned immediate)
5249 pub const RegisterUnsignedImmediate = packed union {
5250 group: @This().Group,
5251 integer: Integer,
5252 vector: Vector,
5253
5254 pub const Group = packed struct {
5255 Rt: Register.Encoded,
5256 Rn: Register.Encoded,
5257 imm12: u12,
5258 opc: u2,
5259 decoded24: u2 = 0b01,
5260 V: bool,
5261 decoded27: u3 = 0b111,
5262 size: u2,
5263 };
5264
5265 pub const Integer = packed union {
5266 group: @This().Group,
5267 strb: Strb,
5268 ldrb: Ldrb,
5269 ldrsb: Ldrsb,
5270 strh: Strh,
5271 ldrh: Ldrh,
5272 ldrsh: Ldrsh,
5273 str: Str,
5274 ldr: Ldr,
5275 ldrsw: Ldrsw,
5276 prfm: Prfm,
5277
5278 pub const Group = packed struct {
5279 Rt: Register.Encoded,
5280 Rn: Register.Encoded,
5281 imm12: u12,
5282 opc: u2,
5283 decoded24: u2 = 0b01,
5284 V: bool = false,
5285 decoded27: u3 = 0b111,
5286 size: IntegerSize,
5287 };
5288
5289 /// C6.2.324 STRB (immediate)
5290 pub const Strb = packed struct {
5291 Rt: Register.Encoded,
5292 Rn: Register.Encoded,
5293 imm12: u12,
5294 opc: u2 = 0b00,
5295 decoded24: u2 = 0b01,
5296 V: bool = false,
5297 decoded27: u3 = 0b111,
5298 size: IntegerSize = .byte,
5299 };
5300
5301 /// C6.2.170 LDRB (immediate)
5302 pub const Ldrb = packed struct {
5303 Rt: Register.Encoded,
5304 Rn: Register.Encoded,
5305 imm12: u12,
5306 opc: u2 = 0b01,
5307 decoded24: u2 = 0b01,
5308 V: bool = false,
5309 decoded27: u3 = 0b111,
5310 size: IntegerSize = .byte,
5311 };
5312
5313 /// C6.2.174 LDRSB (immediate)
5314 pub const Ldrsb = packed struct {
5315 Rt: Register.Encoded,
5316 Rn: Register.Encoded,
5317 imm12: u12,
5318 opc0: u1,
5319 opc1: u1 = 0b1,
5320 decoded24: u2 = 0b01,
5321 V: bool = false,
5322 decoded27: u3 = 0b111,
5323 size: IntegerSize = .byte,
5324 };
5325
5326 /// C6.2.326 STRH (immediate)
5327 pub const Strh = packed struct {
5328 Rt: Register.Encoded,
5329 Rn: Register.Encoded,
5330 imm12: u12,
5331 opc: u2 = 0b00,
5332 decoded24: u2 = 0b01,
5333 V: bool = false,
5334 decoded27: u3 = 0b111,
5335 size: IntegerSize = .halfword,
5336 };
5337
5338 /// C6.2.172 LDRH (immediate)
5339 pub const Ldrh = packed struct {
5340 Rt: Register.Encoded,
5341 Rn: Register.Encoded,
5342 imm12: u12,
5343 opc: u2 = 0b01,
5344 decoded24: u2 = 0b01,
5345 V: bool = false,
5346 decoded27: u3 = 0b111,
5347 size: IntegerSize = .halfword,
5348 };
5349
5350 /// C6.2.176 LDRSH (immediate)
5351 pub const Ldrsh = packed struct {
5352 Rt: Register.Encoded,
5353 Rn: Register.Encoded,
5354 imm12: u12,
5355 opc0: u1,
5356 opc1: u1 = 0b1,
5357 decoded24: u2 = 0b01,
5358 V: bool = false,
5359 decoded27: u3 = 0b111,
5360 size: IntegerSize = .halfword,
5361 };
5362
5363 /// C6.2.322 STR (immediate)
5364 pub const Str = packed struct {
5365 Rt: Register.Encoded,
5366 Rn: Register.Encoded,
5367 imm12: u12,
5368 opc: u2 = 0b00,
5369 decoded24: u2 = 0b01,
5370 V: bool = false,
5371 decoded27: u3 = 0b111,
5372 sf: Register.IntegerSize,
5373 size1: u1 = 0b1,
5374 };
5375
5376 /// C6.2.166 LDR (immediate)
5377 pub const Ldr = packed struct {
5378 Rt: Register.Encoded,
5379 Rn: Register.Encoded,
5380 imm12: u12,
5381 opc: u2 = 0b01,
5382 decoded24: u2 = 0b01,
5383 V: bool = false,
5384 decoded27: u3 = 0b111,
5385 sf: Register.IntegerSize,
5386 size1: u1 = 0b1,
5387 };
5388
5389 /// C6.2.178 LDRSW (immediate)
5390 pub const Ldrsw = packed struct {
5391 Rt: Register.Encoded,
5392 Rn: Register.Encoded,
5393 imm12: u12,
5394 opc: u2 = 0b10,
5395 decoded24: u2 = 0b01,
5396 V: bool = false,
5397 decoded27: u3 = 0b111,
5398 size: IntegerSize = .word,
5399 };
5400
5401 /// C6.2.247 PRFM (immediate)
5402 pub const Prfm = packed struct {
5403 prfop: PrfOp,
5404 Rn: Register.Encoded,
5405 imm12: u12,
5406 opc: u2 = 0b10,
5407 decoded24: u2 = 0b01,
5408 V: bool = false,
5409 decoded27: u3 = 0b111,
5410 size: IntegerSize = .doubleword,
5411 };
5412
5413 pub const Decoded = union(enum) {
5414 unallocated,
5415 strb: Strb,
5416 ldrb: Ldrb,
5417 ldrsb: Ldrsb,
5418 strh: Strh,
5419 ldrh: Ldrh,
5420 ldrsh: Ldrsh,
5421 str: Str,
5422 ldr: Ldr,
5423 ldrsw: Ldrsw,
5424 prfm: Prfm,
5425 };
5426 pub fn decode(inst: @This()) @This().Decoded {
5427 return switch (inst.group.size) {
5428 .byte => switch (inst.group.V) {
5429 false => switch (inst.group.opc) {
5430 0b00 => .{ .strb = inst.strb },
5431 0b01 => .{ .ldrb = inst.ldrb },
5432 0b10, 0b11 => .{ .ldrsb = inst.ldrsb },
5433 },
5434 true => .unallocated,
5435 },
5436 .halfword => switch (inst.group.V) {
5437 false => switch (inst.group.opc) {
5438 0b00 => .{ .strh = inst.strh },
5439 0b01 => .{ .ldrh = inst.ldrh },
5440 0b10, 0b11 => .{ .ldrsh = inst.ldrsh },
5441 },
5442 true => .unallocated,
5443 },
5444 .word => switch (inst.group.V) {
5445 false => switch (inst.group.opc) {
5446 0b00 => .{ .str = inst.str },
5447 0b01 => .{ .ldr = inst.ldr },
5448 0b10 => .{ .ldrsw = inst.ldrsw },
5449 0b11 => .unallocated,
5450 },
5451 true => .unallocated,
5452 },
5453 .doubleword => switch (inst.group.V) {
5454 false => switch (inst.group.opc) {
5455 0b00 => .{ .str = inst.str },
5456 0b01 => .{ .ldr = inst.ldr },
5457 0b10 => .{ .prfm = inst.prfm },
5458 0b11 => .unallocated,
5459 },
5460 true => .unallocated,
5461 },
5462 };
5463 }
5464 };
5465
5466 pub const Vector = packed union {
5467 group: @This().Group,
5468 str: Str,
5469 ldr: Ldr,
5470
5471 pub const Group = packed struct {
5472 Rt: Register.Encoded,
5473 Rn: Register.Encoded,
5474 imm12: u12,
5475 opc0: L,
5476 opc1: Opc1,
5477 decoded24: u2 = 0b01,
5478 V: bool = true,
5479 decoded27: u3 = 0b111,
5480 size: Size,
5481 };
5482
5483 /// C7.2.331 STR (immediate, SIMD&FP)
5484 pub const Str = packed struct {
5485 Rt: Register.Encoded,
5486 Rn: Register.Encoded,
5487 imm12: u12,
5488 opc0: L = .store,
5489 opc1: Opc1,
5490 decoded24: u2 = 0b01,
5491 V: bool = true,
5492 decoded27: u3 = 0b111,
5493 size: Size,
5494 };
5495
5496 /// C7.2.191 LDR (immediate, SIMD&FP)
5497 pub const Ldr = packed struct {
5498 Rt: Register.Encoded,
5499 Rn: Register.Encoded,
5500 imm12: u12,
5501 opc0: L = .load,
5502 opc1: Opc1,
5503 decoded24: u2 = 0b01,
5504 V: bool = true,
5505 decoded27: u3 = 0b111,
5506 size: Size,
5507 };
5508
5509 pub const Opc1 = packed struct {
5510 encoded: u1,
5511
5512 pub fn encode(vs: Register.VectorSize) Opc1 {
5513 return .{ .encoded = switch (vs) {
5514 .byte, .half, .single, .double => 0b0,
5515 .quad => 0b1,
5516 else => unreachable,
5517 } };
5518 }
5519
5520 pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize {
5521 return switch (enc_size.encoded) {
5522 0b00 => switch (enc_opc1.encoded) {
5523 0b0 => .byte,
5524 0b1 => .quad,
5525 },
5526 0b01 => switch (enc_opc1.encoded) {
5527 0b0 => .half,
5528 0b1 => unreachable,
5529 },
5530 0b10 => switch (enc_opc1.encoded) {
5531 0b0 => .single,
5532 0b1 => unreachable,
5533 },
5534 0b11 => switch (enc_opc1.encoded) {
5535 0b0 => .double,
5536 0b1 => unreachable,
5537 },
5538 };
5539 }
5540 };
5541
5542 pub const Size = packed struct {
5543 encoded: u2,
5544
5545 pub fn encode(vs: Register.VectorSize) Size {
5546 return .{ .encoded = switch (vs) {
5547 .byte, .quad => 0b00,
5548 .half => 0b01,
5549 .single => 0b10,
5550 .double => 0b11,
5551 else => unreachable,
5552 } };
5553 }
5554 };
5555
5556 pub const Decoded = union(enum) {
5557 unallocated,
5558 str: Str,
5559 ldr: Ldr,
5560 };
5561 pub fn decode(inst: @This()) @This().Decoded {
5562 return switch (inst.group.size.encoded) {
5563 0b00 => switch (inst.group.opc0) {
5564 .store => .{ .str = inst.str },
5565 .load => .{ .ldr = inst.ldr },
5566 },
5567 0b01, 0b10, 0b11 => switch (inst.group.opc1.encoded) {
5568 0b0 => switch (inst.group.opc0) {
5569 .store => .{ .str = inst.str },
5570 .load => .{ .ldr = inst.ldr },
5571 },
5572 0b1 => .unallocated,
5573 },
5574 };
5575 }
5576 };
5577
5578 pub const Decoded = union(enum) {
5579 integer: Integer,
5580 vector: Vector,
5581 };
5582 pub fn decode(inst: @This()) @This().Decoded {
5583 return switch (inst.group.V) {
5584 false => .{ .integer = inst.integer },
5585 true => .{ .vector = inst.vector },
5586 };
5587 }
5588 };
5589
5590 pub const L = enum(u1) {
5591 store = 0b0,
5592 load = 0b1,
5593 };
5594
5595 pub const IntegerSize = enum(u2) {
5596 byte = 0b00,
5597 halfword = 0b01,
5598 word = 0b10,
5599 doubleword = 0b11,
5600 };
5601
5602 pub const VectorSize = enum(u2) {
5603 single = 0b00,
5604 double = 0b01,
5605 quad = 0b10,
5606 _,
5607
5608 pub fn decode(vs: VectorSize) Register.VectorSize {
5609 return switch (vs) {
5610 .single => .single,
5611 .double => .double,
5612 .quad => .quad,
5613 _ => unreachable,
5614 };
5615 }
5616
5617 pub fn encode(vs: Register.VectorSize) VectorSize {
5618 return switch (vs) {
5619 else => unreachable,
5620 .single => .single,
5621 .double => .double,
5622 .quad => .quad,
5623 };
5624 }
5625 };
5626
5627 pub const PrfOp = packed struct {
5628 policy: Policy,
5629 target: Target,
5630 type: Type,
5631
5632 pub const Policy = enum(u1) {
5633 keep = 0b0,
5634 strm = 0b1,
5635 };
5636
5637 pub const Target = enum(u2) {
5638 l1 = 0b00,
5639 l2 = 0b01,
5640 l3 = 0b10,
5641 _,
5642 };
5643
5644 pub const Type = enum(u2) {
5645 pld = 0b00,
5646 pli = 0b01,
5647 pst = 0b10,
5648 _,
5649 };
5650
5651 pub const pldl1keep: PrfOp = .{ .type = .pld, .target = .l1, .policy = .keep };
5652 pub const pldl1strm: PrfOp = .{ .type = .pld, .target = .l1, .policy = .strm };
5653 pub const pldl2keep: PrfOp = .{ .type = .pld, .target = .l2, .policy = .keep };
5654 pub const pldl2strm: PrfOp = .{ .type = .pld, .target = .l2, .policy = .strm };
5655 pub const pldl3keep: PrfOp = .{ .type = .pld, .target = .l3, .policy = .keep };
5656 pub const pldl3strm: PrfOp = .{ .type = .pld, .target = .l3, .policy = .strm };
5657 pub const plil1keep: PrfOp = .{ .type = .pli, .target = .l1, .policy = .keep };
5658 pub const plil1strm: PrfOp = .{ .type = .pli, .target = .l1, .policy = .strm };
5659 pub const plil2keep: PrfOp = .{ .type = .pli, .target = .l2, .policy = .keep };
5660 pub const plil2strm: PrfOp = .{ .type = .pli, .target = .l2, .policy = .strm };
5661 pub const plil3keep: PrfOp = .{ .type = .pli, .target = .l3, .policy = .keep };
5662 pub const plil3strm: PrfOp = .{ .type = .pli, .target = .l3, .policy = .strm };
5663 pub const pstl1keep: PrfOp = .{ .type = .pst, .target = .l1, .policy = .keep };
5664 pub const pstl1strm: PrfOp = .{ .type = .pst, .target = .l1, .policy = .strm };
5665 pub const pstl2keep: PrfOp = .{ .type = .pst, .target = .l2, .policy = .keep };
5666 pub const pstl2strm: PrfOp = .{ .type = .pst, .target = .l2, .policy = .strm };
5667 pub const pstl3keep: PrfOp = .{ .type = .pst, .target = .l3, .policy = .keep };
5668 pub const pstl3strm: PrfOp = .{ .type = .pst, .target = .l3, .policy = .strm_ };
5669 };
5670
5671 pub const Decoded = union(enum) {
5672 unallocated,
5673 register_literal: RegisterLiteral,
5674 memory: Memory,
5675 no_allocate_pair_offset: NoAllocatePairOffset,
5676 register_pair_post_indexed: RegisterPairPostIndexed,
5677 register_pair_offset: RegisterPairOffset,
5678 register_pair_pre_indexed: RegisterPairPreIndexed,
5679 register_unscaled_immediate: RegisterUnscaledImmediate,
5680 register_immediate_post_indexed: RegisterImmediatePostIndexed,
5681 register_unprivileged: RegisterUnprivileged,
5682 register_immediate_pre_indexed: RegisterImmediatePreIndexed,
5683 register_register_offset: RegisterRegisterOffset,
5684 register_unsigned_immediate: RegisterUnsignedImmediate,
5685 };
5686 pub fn decode(inst: @This()) @This().Decoded {
5687 return switch (inst.group.op0) {
5688 else => .unallocated,
5689 0b0010, 0b0110, 0b1010, 0b1110 => switch (inst.group.op2) {
5690 0b00 => .{ .no_allocate_pair_offset = inst.no_allocate_pair_offset },
5691 0b01 => .{ .register_pair_post_indexed = inst.register_pair_post_indexed },
5692 0b10 => .{ .register_pair_offset = inst.register_pair_offset },
5693 0b11 => .{ .register_pair_pre_indexed = inst.register_pair_pre_indexed },
5694 },
5695 0b0011, 0b0111, 0b1011, 0b1111 => switch (inst.group.op2) {
5696 0b00...0b01 => switch (inst.group.op3) {
5697 0b000000...0b011111 => switch (inst.group.op4) {
5698 0b00 => .{ .register_unscaled_immediate = inst.register_unscaled_immediate },
5699 0b01 => .{ .register_immediate_post_indexed = inst.register_immediate_post_indexed },
5700 0b10 => .{ .register_unprivileged = inst.register_unprivileged },
5701 0b11 => .{ .register_immediate_pre_indexed = inst.register_immediate_pre_indexed },
5702 },
5703 0b100000...0b111111 => switch (inst.group.op4) {
5704 0b00 => .unallocated,
5705 0b10 => .{ .register_register_offset = inst.register_register_offset },
5706 0b01, 0b11 => .unallocated,
5707 },
5708 },
5709 0b10...0b11 => .{ .register_unsigned_immediate = inst.register_unsigned_immediate },
5710 },
5711 };
5712 }
5713 };
5714
5715 /// C4.1.89 Data Processing -- Register
5716 pub const DataProcessingRegister = packed union {
5717 group: @This().Group,
5718 data_processing_two_source: DataProcessingTwoSource,
5719 data_processing_one_source: DataProcessingOneSource,
5720 logical_shifted_register: LogicalShiftedRegister,
5721 add_subtract_shifted_register: AddSubtractShiftedRegister,
5722 add_subtract_extended_register: AddSubtractExtendedRegister,
5723 add_subtract_with_carry: AddSubtractWithCarry,
5724 rotate_right_into_flags: RotateRightIntoFlags,
5725 evaluate_into_flags: EvaluateIntoFlags,
5726 conditional_compare_register: ConditionalCompareRegister,
5727 conditional_compare_immediate: ConditionalCompareImmediate,
5728 conditional_select: ConditionalSelect,
5729 data_processing_three_source: DataProcessingThreeSource,
5730
5731 /// Table C4-90 Encoding table for the Data Processing -- Register group
5732 pub const Group = packed struct {
5733 encoded0: u10,
5734 op3: u6,
5735 encoded16: u5,
5736 op2: u4,
5737 decoded25: u3 = 0b101,
5738 op1: u1,
5739 encoded29: u1,
5740 op0: u1,
5741 encoded31: u1,
5742 };
5743
5744 /// Data-processing (2 source)
5745 pub const DataProcessingTwoSource = packed union {
5746 group: @This().Group,
5747 udiv: Udiv,
5748 sdiv: Sdiv,
5749 lslv: Lslv,
5750 lsrv: Lsrv,
5751 asrv: Asrv,
5752 rorv: Rorv,
5753
5754 pub const Group = packed struct {
5755 Rd: Register.Encoded,
5756 Rn: Register.Encoded,
5757 opcode: u6,
5758 Rm: Register.Encoded,
5759 decoded21: u8 = 0b11010110,
5760 S: bool,
5761 decoded30: u1 = 0b0,
5762 sf: Register.IntegerSize,
5763 };
5764
5765 /// C6.2.388 UDIV
5766 pub const Udiv = packed struct {
5767 Rd: Register.Encoded,
5768 Rn: Register.Encoded,
5769 o1: DivOp = .udiv,
5770 decoded11: u5 = 0b00001,
5771 Rm: Register.Encoded,
5772 decoded21: u8 = 0b11010110,
5773 S: bool = false,
5774 decoded30: u1 = 0b0,
5775 sf: Register.IntegerSize,
5776 };
5777
5778 /// C6.2.270 SDIV
5779 pub const Sdiv = packed struct {
5780 Rd: Register.Encoded,
5781 Rn: Register.Encoded,
5782 o1: DivOp = .sdiv,
5783 decoded11: u5 = 0b00001,
5784 Rm: Register.Encoded,
5785 decoded21: u8 = 0b11010110,
5786 S: bool = false,
5787 decoded30: u1 = 0b0,
5788 sf: Register.IntegerSize,
5789 };
5790
5791 /// C6.2.214 LSLV
5792 pub const Lslv = packed struct {
5793 Rd: Register.Encoded,
5794 Rn: Register.Encoded,
5795 op2: ShiftOp = .lslv,
5796 decoded12: u4 = 0b0010,
5797 Rm: Register.Encoded,
5798 decoded21: u8 = 0b11010110,
5799 S: bool = false,
5800 decoded30: u1 = 0b0,
5801 sf: Register.IntegerSize,
5802 };
5803
5804 /// C6.2.217 LSRV
5805 pub const Lsrv = packed struct {
5806 Rd: Register.Encoded,
5807 Rn: Register.Encoded,
5808 op2: ShiftOp = .lsrv,
5809 decoded12: u4 = 0b0010,
5810 Rm: Register.Encoded,
5811 decoded21: u8 = 0b11010110,
5812 S: bool = false,
5813 decoded30: u1 = 0b0,
5814 sf: Register.IntegerSize,
5815 };
5816
5817 /// C6.2.18 ASRV
5818 pub const Asrv = packed struct {
5819 Rd: Register.Encoded,
5820 Rn: Register.Encoded,
5821 op2: ShiftOp = .asrv,
5822 decoded12: u4 = 0b0010,
5823 Rm: Register.Encoded,
5824 decoded21: u8 = 0b11010110,
5825 S: bool = false,
5826 decoded30: u1 = 0b0,
5827 sf: Register.IntegerSize,
5828 };
5829
5830 /// C6.2.263 RORV
5831 pub const Rorv = packed struct {
5832 Rd: Register.Encoded,
5833 Rn: Register.Encoded,
5834 op2: ShiftOp = .rorv,
5835 decoded12: u4 = 0b0010,
5836 Rm: Register.Encoded,
5837 decoded21: u8 = 0b11010110,
5838 S: bool = false,
5839 decoded30: u1 = 0b0,
5840 sf: Register.IntegerSize,
5841 };
5842
5843 pub const DivOp = enum(u1) {
5844 udiv = 0b0,
5845 sdiv = 0b1,
5846 };
5847
5848 pub const ShiftOp = enum(u2) {
5849 lslv = 0b00,
5850 lsrv = 0b01,
5851 asrv = 0b10,
5852 rorv = 0b11,
5853 };
5854
5855 pub const Decoded = union(enum) {
5856 unallocated,
5857 udiv: Udiv,
5858 sdiv: Sdiv,
5859 lslv: Lslv,
5860 lsrv: Lsrv,
5861 asrv: Asrv,
5862 rorv: Rorv,
5863 };
5864 pub fn decode(inst: @This()) @This().Decoded {
5865 return switch (inst.group.S) {
5866 false => switch (inst.group.opcode) {
5867 else => .unallocated,
5868 0b000010 => .{ .udiv = inst.udiv },
5869 0b000011 => .{ .sdiv = inst.sdiv },
5870 0b001000 => .{ .lslv = inst.lslv },
5871 0b001001 => .{ .lsrv = inst.lsrv },
5872 0b001010 => .{ .asrv = inst.asrv },
5873 0b001011 => .{ .rorv = inst.rorv },
5874 },
5875 true => .unallocated,
5876 };
5877 }
5878 };
5879
5880 /// Data-processing (1 source)
5881 pub const DataProcessingOneSource = packed union {
5882 group: @This().Group,
5883 rbit: Rbit,
5884 rev16: Rev16,
5885 rev32: Rev32,
5886 rev: Rev,
5887 clz: Clz,
5888 cls: Cls,
5889
5890 pub const Group = packed struct {
5891 Rd: Register.Encoded,
5892 Rn: Register.Encoded,
5893 opcode: u6,
5894 opcode2: u5,
5895 decoded21: u8 = 0b11010110,
5896 S: bool,
5897 decoded30: u1 = 0b1,
5898 sf: Register.IntegerSize,
5899 };
5900
5901 /// C6.2.253 RBIT
5902 pub const Rbit = packed struct {
5903 Rd: Register.Encoded,
5904 Rn: Register.Encoded,
5905 decoded10: u2 = 0b00,
5906 decoded12: u4 = 0b0000,
5907 decoded16: u5 = 0b00000,
5908 decoded21: u8 = 0b11010110,
5909 S: bool = false,
5910 decoded30: u1 = 0b1,
5911 sf: Register.IntegerSize,
5912 };
5913
5914 /// C6.2.257 REV16
5915 pub const Rev16 = packed struct {
5916 Rd: Register.Encoded,
5917 Rn: Register.Encoded,
5918 opc: u2 = 0b01,
5919 decoded12: u4 = 0b0000,
5920 decoded16: u5 = 0b00000,
5921 decoded21: u8 = 0b11010110,
5922 S: bool = false,
5923 decoded30: u1 = 0b1,
5924 sf: Register.IntegerSize,
5925 };
5926
5927 /// C6.2.258 REV32
5928 pub const Rev32 = packed struct {
5929 Rd: Register.Encoded,
5930 Rn: Register.Encoded,
5931 opc: u2 = 0b10,
5932 decoded12: u4 = 0b0000,
5933 decoded16: u5 = 0b00000,
5934 decoded21: u8 = 0b11010110,
5935 S: bool = false,
5936 decoded30: u1 = 0b1,
5937 sf: Register.IntegerSize = .doubleword,
5938 };
5939
5940 /// C6.2.256 REV
5941 pub const Rev = packed struct {
5942 Rd: Register.Encoded,
5943 Rn: Register.Encoded,
5944 opc0: Register.IntegerSize,
5945 opc1: u1 = 0b1,
5946 decoded12: u4 = 0b0000,
5947 decoded16: u5 = 0b00000,
5948 decoded21: u8 = 0b11010110,
5949 S: bool = false,
5950 decoded30: u1 = 0b1,
5951 sf: Register.IntegerSize,
5952 };
5953
5954 /// C6.2.58 CLZ
5955 pub const Clz = packed struct {
5956 Rd: Register.Encoded,
5957 Rn: Register.Encoded,
5958 op: u1 = 0b0,
5959 decoded11: u5 = 0b00010,
5960 decoded16: u5 = 0b00000,
5961 decoded21: u8 = 0b11010110,
5962 S: bool = false,
5963 decoded30: u1 = 0b1,
5964 sf: Register.IntegerSize,
5965 };
5966
5967 /// C6.2.57 CLS
5968 pub const Cls = packed struct {
5969 Rd: Register.Encoded,
5970 Rn: Register.Encoded,
5971 op: u1 = 0b1,
5972 decoded11: u5 = 0b00010,
5973 decoded16: u5 = 0b00000,
5974 decoded21: u8 = 0b11010110,
5975 S: bool = false,
5976 decoded30: u1 = 0b1,
5977 sf: Register.IntegerSize,
5978 };
5979
5980 pub const Decoded = union(enum) {
5981 unallocated,
5982 rbit: Rbit,
5983 rev16: Rev16,
5984 rev32: Rev32,
5985 rev: Rev,
5986 clz: Clz,
5987 cls: Cls,
5988 };
5989 pub fn decode(inst: @This()) @This().Decoded {
5990 return switch (inst.group.S) {
5991 true => .unallocated,
5992 false => switch (inst.group.opcode2) {
5993 else => .unallocated,
5994 0b00000 => switch (inst.group.opcode) {
5995 else => .unallocated,
5996 0b000000 => .{ .rbit = inst.rbit },
5997 0b000001 => .{ .rev16 = inst.rev16 },
5998 0b000010 => switch (inst.group.sf) {
5999 .word => .{ .rev = inst.rev },
6000 .doubleword => .{ .rev32 = inst.rev32 },
6001 },
6002 0b000011 => switch (inst.group.sf) {
6003 .word => .unallocated,
6004 .doubleword => .{ .rev = inst.rev },
6005 },
6006 0b000100 => .{ .clz = inst.clz },
6007 0b000101 => .{ .cls = inst.cls },
6008 },
6009 },
6010 };
6011 }
6012 };
6013
6014 /// Logical (shifted register)
6015 pub const LogicalShiftedRegister = packed union {
6016 group: @This().Group,
6017 @"and": And,
6018 bic: Bic,
6019 orr: Orr,
6020 orn: Orn,
6021 eor: Eor,
6022 eon: Eon,
6023 ands: Ands,
6024 bics: Bics,
6025
6026 pub const Group = packed struct {
6027 Rd: Register.Encoded,
6028 Rn: Register.Encoded,
6029 imm6: Shift.Amount,
6030 Rm: Register.Encoded,
6031 N: bool,
6032 shift: Shift.Op,
6033 decoded24: u5 = 0b01010,
6034 opc: LogicalOpc,
6035 sf: Register.IntegerSize,
6036 };
6037
6038 /// C6.2.13 AND (shifted register)
6039 pub const And = packed struct {
6040 Rd: Register.Encoded,
6041 Rn: Register.Encoded,
6042 imm6: Shift.Amount,
6043 Rm: Register.Encoded,
6044 N: bool = false,
6045 shift: Shift.Op,
6046 decoded24: u5 = 0b01010,
6047 opc: LogicalOpc = .@"and",
6048 sf: Register.IntegerSize,
6049 };
6050
6051 /// C6.2.32 BIC (shifted register)
6052 pub const Bic = packed struct {
6053 Rd: Register.Encoded,
6054 Rn: Register.Encoded,
6055 imm6: Shift.Amount,
6056 Rm: Register.Encoded,
6057 N: bool = true,
6058 shift: Shift.Op,
6059 decoded24: u5 = 0b01010,
6060 opc: LogicalOpc = .@"and",
6061 sf: Register.IntegerSize,
6062 };
6063
6064 /// C6.2.241 ORR (shifted register)
6065 pub const Orr = packed struct {
6066 Rd: Register.Encoded,
6067 Rn: Register.Encoded,
6068 imm6: Shift.Amount,
6069 Rm: Register.Encoded,
6070 N: bool = false,
6071 shift: Shift.Op,
6072 decoded24: u5 = 0b01010,
6073 opc: LogicalOpc = .orr,
6074 sf: Register.IntegerSize,
6075 };
6076
6077 /// C6.2.239 ORN (shifted register)
6078 pub const Orn = packed struct {
6079 Rd: Register.Encoded,
6080 Rn: Register.Encoded,
6081 imm6: Shift.Amount,
6082 Rm: Register.Encoded,
6083 N: bool = true,
6084 shift: Shift.Op,
6085 decoded24: u5 = 0b01010,
6086 opc: LogicalOpc = .orr,
6087 sf: Register.IntegerSize,
6088 };
6089
6090 /// C6.2.120 EOR (shifted register)
6091 pub const Eor = packed struct {
6092 Rd: Register.Encoded,
6093 Rn: Register.Encoded,
6094 imm6: Shift.Amount,
6095 Rm: Register.Encoded,
6096 N: bool = false,
6097 shift: Shift.Op,
6098 decoded24: u5 = 0b01010,
6099 opc: LogicalOpc = .eor,
6100 sf: Register.IntegerSize,
6101 };
6102
6103 /// C6.2.118 EON (shifted register)
6104 pub const Eon = packed struct {
6105 Rd: Register.Encoded,
6106 Rn: Register.Encoded,
6107 imm6: Shift.Amount,
6108 Rm: Register.Encoded,
6109 N: bool = true,
6110 shift: Shift.Op,
6111 decoded24: u5 = 0b01010,
6112 opc: LogicalOpc = .eor,
6113 sf: Register.IntegerSize,
6114 };
6115
6116 /// C6.2.15 ANDS (shifted register)
6117 pub const Ands = packed struct {
6118 Rd: Register.Encoded,
6119 Rn: Register.Encoded,
6120 imm6: Shift.Amount,
6121 Rm: Register.Encoded,
6122 N: bool = false,
6123 shift: Shift.Op,
6124 decoded24: u5 = 0b01010,
6125 opc: LogicalOpc = .ands,
6126 sf: Register.IntegerSize,
6127 };
6128
6129 /// C6.2.33 BICS (shifted register)
6130 pub const Bics = packed struct {
6131 Rd: Register.Encoded,
6132 Rn: Register.Encoded,
6133 imm6: Shift.Amount,
6134 Rm: Register.Encoded,
6135 N: bool = true,
6136 shift: Shift.Op,
6137 decoded24: u5 = 0b01010,
6138 opc: LogicalOpc = .ands,
6139 sf: Register.IntegerSize,
6140 };
6141
6142 pub const Decoded = union(enum) {
6143 unallocated,
6144 @"and": And,
6145 bic: Bic,
6146 orr: Orr,
6147 orn: Orn,
6148 eor: Eor,
6149 eon: Eon,
6150 ands: Ands,
6151 bics: Bics,
6152 };
6153 pub fn decode(inst: @This()) @This().Decoded {
6154 return if (inst.group.sf == .word and @as(u1, @truncate(inst.group.imm6 >> 5)) == 0b1)
6155 .unallocated
6156 else switch (inst.group.opc) {
6157 .@"and" => switch (inst.group.N) {
6158 false => .{ .@"and" = inst.@"and" },
6159 true => .{ .bic = inst.bic },
6160 },
6161 .orr => switch (inst.group.N) {
6162 false => .{ .orr = inst.orr },
6163 true => .{ .orn = inst.orn },
6164 },
6165 .eor => switch (inst.group.N) {
6166 false => .{ .eor = inst.eor },
6167 true => .{ .eon = inst.eon },
6168 },
6169 .ands => switch (inst.group.N) {
6170 false => .{ .ands = inst.ands },
6171 true => .{ .bics = inst.bics },
6172 },
6173 };
6174 }
6175 };
6176
6177 /// Add/subtract (shifted register)
6178 pub const AddSubtractShiftedRegister = packed union {
6179 group: @This().Group,
6180 add: Add,
6181 adds: Adds,
6182 sub: Sub,
6183 subs: Subs,
6184
6185 pub const Group = packed struct {
6186 Rd: Register.Encoded,
6187 Rn: Register.Encoded,
6188 imm6: Shift.Amount,
6189 Rm: Register.Encoded,
6190 decoded21: u1 = 0b0,
6191 shift: Shift.Op,
6192 decoded24: u5 = 0b01011,
6193 S: bool,
6194 op: AddSubtractOp,
6195 sf: Register.IntegerSize,
6196 };
6197
6198 /// C6.2.5 ADD (shifted register)
6199 pub const Add = packed struct {
6200 Rd: Register.Encoded,
6201 Rn: Register.Encoded,
6202 imm6: Shift.Amount,
6203 Rm: Register.Encoded,
6204 decoded21: u1 = 0b0,
6205 shift: Shift.Op,
6206 decoded24: u5 = 0b01011,
6207 S: bool = false,
6208 op: AddSubtractOp = .add,
6209 sf: Register.IntegerSize,
6210 };
6211
6212 /// C6.2.9 ADDS (shifted register)
6213 pub const Adds = packed struct {
6214 Rd: Register.Encoded,
6215 Rn: Register.Encoded,
6216 imm6: Shift.Amount,
6217 Rm: Register.Encoded,
6218 decoded21: u1 = 0b0,
6219 shift: Shift.Op,
6220 decoded24: u5 = 0b01011,
6221 S: bool = true,
6222 op: AddSubtractOp = .add,
6223 sf: Register.IntegerSize,
6224 };
6225
6226 /// C6.2.5 SUB (shifted register)
6227 pub const Sub = packed struct {
6228 Rd: Register.Encoded,
6229 Rn: Register.Encoded,
6230 imm6: Shift.Amount,
6231 Rm: Register.Encoded,
6232 decoded21: u1 = 0b0,
6233 shift: Shift.Op,
6234 decoded24: u5 = 0b01011,
6235 S: bool = false,
6236 op: AddSubtractOp = .sub,
6237 sf: Register.IntegerSize,
6238 };
6239
6240 /// C6.2.9 SUBS (shifted register)
6241 pub const Subs = packed struct {
6242 Rd: Register.Encoded,
6243 Rn: Register.Encoded,
6244 imm6: Shift.Amount,
6245 Rm: Register.Encoded,
6246 decoded21: u1 = 0b0,
6247 shift: Shift.Op,
6248 decoded24: u5 = 0b01011,
6249 S: bool = true,
6250 op: AddSubtractOp = .sub,
6251 sf: Register.IntegerSize,
6252 };
6253
6254 pub const Decoded = union(enum) {
6255 unallocated,
6256 add: Add,
6257 adds: Adds,
6258 sub: Sub,
6259 subs: Subs,
6260 };
6261 pub fn decode(inst: @This()) @This().Decoded {
6262 return switch (inst.group.shift) {
6263 .ror => .unallocated,
6264 .lsl, .lsr, .asr => if (inst.group.sf == .word and @as(u1, @truncate(inst.group.imm6 >> 5)) == 0b1)
6265 .unallocated
6266 else switch (inst.group.op) {
6267 .add => switch (inst.group.S) {
6268 false => .{ .add = inst.add },
6269 true => .{ .adds = inst.adds },
6270 },
6271 .sub => switch (inst.group.S) {
6272 false => .{ .sub = inst.sub },
6273 true => .{ .subs = inst.subs },
6274 },
6275 },
6276 };
6277 }
6278 };
6279
6280 /// Add/subtract (extended register)
6281 pub const AddSubtractExtendedRegister = packed union {
6282 group: @This().Group,
6283 add: Add,
6284 adds: Adds,
6285 sub: Sub,
6286 subs: Subs,
6287
6288 pub const Group = packed struct {
6289 Rd: Register.Encoded,
6290 Rn: Register.Encoded,
6291 imm3: Extend.Amount,
6292 option: Option,
6293 Rm: Register.Encoded,
6294 decoded21: u1 = 0b1,
6295 opt: u2,
6296 decoded24: u5 = 0b01011,
6297 S: bool,
6298 op: AddSubtractOp,
6299 sf: Register.IntegerSize,
6300 };
6301
6302 /// C6.2.3 ADD (extended register)
6303 pub const Add = packed struct {
6304 Rd: Register.Encoded,
6305 Rn: Register.Encoded,
6306 imm3: Extend.Amount,
6307 option: Option,
6308 Rm: Register.Encoded,
6309 decoded21: u1 = 0b1,
6310 opt: u2 = 0b00,
6311 decoded24: u5 = 0b01011,
6312 S: bool = false,
6313 op: AddSubtractOp = .add,
6314 sf: Register.IntegerSize,
6315 };
6316
6317 /// C6.2.7 ADDS (extended register)
6318 pub const Adds = packed struct {
6319 Rd: Register.Encoded,
6320 Rn: Register.Encoded,
6321 imm3: Extend.Amount,
6322 option: Option,
6323 Rm: Register.Encoded,
6324 decoded21: u1 = 0b1,
6325 opt: u2 = 0b00,
6326 decoded24: u5 = 0b01011,
6327 S: bool = true,
6328 op: AddSubtractOp = .add,
6329 sf: Register.IntegerSize,
6330 };
6331
6332 /// C6.2.356 SUB (extended register)
6333 pub const Sub = packed struct {
6334 Rd: Register.Encoded,
6335 Rn: Register.Encoded,
6336 imm3: Extend.Amount,
6337 option: Option,
6338 Rm: Register.Encoded,
6339 decoded21: u1 = 0b1,
6340 opt: u2 = 0b00,
6341 decoded24: u5 = 0b01011,
6342 S: bool = false,
6343 op: AddSubtractOp = .sub,
6344 sf: Register.IntegerSize,
6345 };
6346
6347 /// C6.2.362 SUBS (extended register)
6348 pub const Subs = packed struct {
6349 Rd: Register.Encoded,
6350 Rn: Register.Encoded,
6351 imm3: Extend.Amount,
6352 option: Option,
6353 Rm: Register.Encoded,
6354 decoded21: u1 = 0b1,
6355 opt: u2 = 0b00,
6356 decoded24: u5 = 0b01011,
6357 S: bool = true,
6358 op: AddSubtractOp = .sub,
6359 sf: Register.IntegerSize,
6360 };
6361
6362 pub const Option = enum(u3) {
6363 uxtb = 0b000,
6364 uxth = 0b001,
6365 uxtw = 0b010,
6366 uxtx = 0b011,
6367 sxtb = 0b100,
6368 sxth = 0b101,
6369 sxtw = 0b110,
6370 sxtx = 0b111,
6371
6372 pub fn sf(option: Option) Register.IntegerSize {
6373 return switch (option) {
6374 .uxtb, .uxth, .uxtw, .sxtb, .sxth, .sxtw => .word,
6375 .uxtx, .sxtx => .doubleword,
6376 };
6377 }
6378 };
6379
6380 pub const Extend = union(Option) {
6381 uxtb: Amount,
6382 uxth: Amount,
6383 uxtw: Amount,
6384 uxtx: Amount,
6385 sxtb: Amount,
6386 sxth: Amount,
6387 sxtw: Amount,
6388 sxtx: Amount,
6389
6390 pub const Amount = u3;
6391 };
6392
6393 pub const Decoded = union(enum) {
6394 unallocated,
6395 add: Add,
6396 adds: Adds,
6397 sub: Sub,
6398 subs: Subs,
6399 };
6400 pub fn decode(inst: @This()) @This().Decoded {
6401 return switch (inst.group.imm3) {
6402 0b101 => .unallocated,
6403 0b110...0b111 => .unallocated,
6404 0b000...0b100 => switch (inst.group.opt) {
6405 0b01 => .unallocated,
6406 0b10...0b11 => .unallocated,
6407 0b00 => switch (inst.group.op) {
6408 .add => switch (inst.group.S) {
6409 false => .{ .add = inst.add },
6410 true => .{ .adds = inst.adds },
6411 },
6412 .sub => switch (inst.group.S) {
6413 false => .{ .sub = inst.sub },
6414 true => .{ .subs = inst.subs },
6415 },
6416 },
6417 },
6418 };
6419 }
6420 };
6421
6422 /// Add/subtract (with carry)
6423 pub const AddSubtractWithCarry = packed union {
6424 group: @This().Group,
6425 adc: Adc,
6426 adcs: Adcs,
6427 sbc: Sbc,
6428 sbcs: Sbcs,
6429
6430 pub const Group = packed struct {
6431 Rd: Register.Encoded,
6432 Rn: Register.Encoded,
6433 decoded10: u6 = 0b000000,
6434 Rm: Register.Encoded,
6435 decoded21: u8 = 0b11010000,
6436 S: bool,
6437 op: Op,
6438 sf: Register.IntegerSize,
6439 };
6440
6441 /// C6.2.1 ADC
6442 pub const Adc = packed struct {
6443 Rd: Register.Encoded,
6444 Rn: Register.Encoded,
6445 decoded10: u6 = 0b000000,
6446 Rm: Register.Encoded,
6447 decoded21: u8 = 0b11010000,
6448 S: bool = false,
6449 op: Op = .adc,
6450 sf: Register.IntegerSize,
6451 };
6452
6453 /// C6.2.2 ADCS
6454 pub const Adcs = packed struct {
6455 Rd: Register.Encoded,
6456 Rn: Register.Encoded,
6457 decoded10: u6 = 0b000000,
6458 Rm: Register.Encoded,
6459 decoded21: u8 = 0b11010000,
6460 S: bool = true,
6461 op: Op = .adc,
6462 sf: Register.IntegerSize,
6463 };
6464
6465 /// C6.2.265 SBC
6466 pub const Sbc = packed struct {
6467 Rd: Register.Encoded,
6468 Rn: Register.Encoded,
6469 decoded10: u6 = 0b000000,
6470 Rm: Register.Encoded,
6471 decoded21: u8 = 0b11010000,
6472 S: bool = false,
6473 op: Op = .sbc,
6474 sf: Register.IntegerSize,
6475 };
6476
6477 /// C6.2.266 SBCS
6478 pub const Sbcs = packed struct {
6479 Rd: Register.Encoded,
6480 Rn: Register.Encoded,
6481 decoded10: u6 = 0b000000,
6482 Rm: Register.Encoded,
6483 decoded21: u8 = 0b11010000,
6484 S: bool = true,
6485 op: Op = .sbc,
6486 sf: Register.IntegerSize,
6487 };
6488
6489 pub const Op = enum(u1) {
6490 adc = 0b0,
6491 sbc = 0b1,
6492 };
6493
6494 pub const Decoded = union(enum) {
6495 adc: Adc,
6496 adcs: Adcs,
6497 sbc: Sbc,
6498 sbcs: Sbcs,
6499 };
6500 pub fn decode(inst: @This()) @This().Decoded {
6501 return switch (inst.group.op) {
6502 .adc => switch (inst.group.S) {
6503 false => .{ .adc = inst.adc },
6504 true => .{ .adcs = inst.adcs },
6505 },
6506 .sbc => switch (inst.group.S) {
6507 false => .{ .sbc = inst.sbc },
6508 true => .{ .sbcs = inst.sbcs },
6509 },
6510 };
6511 }
6512 };
6513
6514 /// Rotate right into flags
6515 pub const RotateRightIntoFlags = packed union {
6516 group: @This().Group,
6517
6518 pub const Group = packed struct {
6519 mask: Nzcv,
6520 o2: u1,
6521 Rn: Register.Encoded,
6522 decoded10: u5 = 0b0001,
6523 imm6: u6,
6524 decoded21: u8 = 0b11010000,
6525 S: bool,
6526 op: u1,
6527 sf: Register.IntegerSize,
6528 };
6529 };
6530
6531 /// Evaluate into flags
6532 pub const EvaluateIntoFlags = packed union {
6533 group: @This().Group,
6534
6535 pub const Group = packed struct {
6536 mask: Nzcv,
6537 o3: u1,
6538 Rn: Register.Encoded,
6539 decoded10: u4 = 0b0010,
6540 sz: enum(u1) {
6541 byte = 0b0,
6542 word = 0b1,
6543 },
6544 opcode2: u6,
6545 decoded21: u8 = 0b11010000,
6546 S: bool,
6547 op: u1,
6548 sf: Register.IntegerSize,
6549 };
6550 };
6551
6552 /// Conditional compare (register)
6553 pub const ConditionalCompareRegister = packed union {
6554 group: @This().Group,
6555 ccmn: Ccmn,
6556 ccmp: Ccmp,
6557
6558 pub const Group = packed struct {
6559 nzcv: Nzcv,
6560 o3: u1,
6561 Rn: Register.Encoded,
6562 o2: u1,
6563 decoded11: u1 = 0b0,
6564 cond: ConditionCode,
6565 Rm: Register.Encoded,
6566 decoded21: u8 = 0b11010010,
6567 S: bool,
6568 op: Op,
6569 sf: Register.IntegerSize,
6570 };
6571
6572 /// C6.2.49 CCMN (register)
6573 pub const Ccmn = packed struct {
6574 nzcv: Nzcv,
6575 o3: u1 = 0b0,
6576 Rn: Register.Encoded,
6577 o2: u1 = 0b0,
6578 decoded11: u1 = 0b0,
6579 cond: ConditionCode,
6580 Rm: Register.Encoded,
6581 decoded21: u8 = 0b11010010,
6582 S: bool = true,
6583 op: Op = .ccmn,
6584 sf: Register.IntegerSize,
6585 };
6586
6587 /// C6.2.51 CCMP (register)
6588 pub const Ccmp = packed struct {
6589 nzcv: Nzcv,
6590 o3: u1 = 0b0,
6591 Rn: Register.Encoded,
6592 o2: u1 = 0b0,
6593 decoded11: u1 = 0b0,
6594 cond: ConditionCode,
6595 Rm: Register.Encoded,
6596 decoded21: u8 = 0b11010010,
6597 S: bool = true,
6598 op: Op = .ccmp,
6599 sf: Register.IntegerSize,
6600 };
6601
6602 pub const Op = enum(u1) {
6603 ccmn = 0b0,
6604 ccmp = 0b1,
6605 };
6606 };
6607
6608 /// Conditional compare (immediate)
6609 pub const ConditionalCompareImmediate = packed union {
6610 group: @This().Group,
6611 ccmn: Ccmn,
6612 ccmp: Ccmp,
6613
6614 pub const Group = packed struct {
6615 nzcv: Nzcv,
6616 o3: u1,
6617 Rn: Register.Encoded,
6618 o2: u1,
6619 decoded11: u1 = 0b1,
6620 cond: ConditionCode,
6621 imm5: u5,
6622 decoded21: u8 = 0b11010010,
6623 S: bool,
6624 op: Op,
6625 sf: Register.IntegerSize,
6626 };
6627
6628 /// C6.2.48 CCMN (immediate)
6629 pub const Ccmn = packed struct {
6630 nzcv: Nzcv,
6631 o3: u1 = 0b0,
6632 Rn: Register.Encoded,
6633 o2: u1 = 0b0,
6634 decoded11: u1 = 0b1,
6635 cond: ConditionCode,
6636 imm5: u5,
6637 decoded21: u8 = 0b11010010,
6638 S: bool = true,
6639 op: Op = .ccmn,
6640 sf: Register.IntegerSize,
6641 };
6642
6643 /// C6.2.50 CCMP (immediate)
6644 pub const Ccmp = packed struct {
6645 nzcv: Nzcv,
6646 o3: u1 = 0b0,
6647 Rn: Register.Encoded,
6648 o2: u1 = 0b0,
6649 decoded11: u1 = 0b1,
6650 cond: ConditionCode,
6651 imm5: u5,
6652 decoded21: u8 = 0b11010010,
6653 S: bool = true,
6654 op: Op = .ccmp,
6655 sf: Register.IntegerSize,
6656 };
6657
6658 pub const Op = enum(u1) {
6659 ccmn = 0b0,
6660 ccmp = 0b1,
6661 };
6662 };
6663
6664 /// Conditional select
6665 pub const ConditionalSelect = packed union {
6666 group: @This().Group,
6667 csel: Csel,
6668 csinc: Csinc,
6669 csinv: Csinv,
6670 csneg: Csneg,
6671
6672 pub const Group = packed struct {
6673 Rd: Register.Encoded,
6674 Rn: Register.Encoded,
6675 op2: u2,
6676 cond: ConditionCode,
6677 Rm: Register.Encoded,
6678 decoded21: u8 = 0b11010100,
6679 S: bool,
6680 op: u1,
6681 sf: Register.IntegerSize,
6682 };
6683
6684 /// C6.2.103 CSEL
6685 pub const Csel = packed struct {
6686 Rd: Register.Encoded,
6687 Rn: Register.Encoded,
6688 op2: u2 = 0b00,
6689 cond: ConditionCode,
6690 Rm: Register.Encoded,
6691 decoded21: u8 = 0b11010100,
6692 S: bool = false,
6693 op: u1 = 0b0,
6694 sf: Register.IntegerSize,
6695 };
6696
6697 /// C6.2.106 CSINC
6698 pub const Csinc = packed struct {
6699 Rd: Register.Encoded,
6700 Rn: Register.Encoded,
6701 op2: u2 = 0b01,
6702 cond: ConditionCode,
6703 Rm: Register.Encoded,
6704 decoded21: u8 = 0b11010100,
6705 S: bool = false,
6706 op: u1 = 0b0,
6707 sf: Register.IntegerSize,
6708 };
6709
6710 /// C6.2.107 CSINV
6711 pub const Csinv = packed struct {
6712 Rd: Register.Encoded,
6713 Rn: Register.Encoded,
6714 op2: u2 = 0b00,
6715 cond: ConditionCode,
6716 Rm: Register.Encoded,
6717 decoded21: u8 = 0b11010100,
6718 S: bool = false,
6719 op: u1 = 0b1,
6720 sf: Register.IntegerSize,
6721 };
6722
6723 /// C6.2.108 CSNEG
6724 pub const Csneg = packed struct {
6725 Rd: Register.Encoded,
6726 Rn: Register.Encoded,
6727 op2: u2 = 0b01,
6728 cond: ConditionCode,
6729 Rm: Register.Encoded,
6730 decoded21: u8 = 0b11010100,
6731 S: bool = false,
6732 op: u1 = 0b1,
6733 sf: Register.IntegerSize,
6734 };
6735
6736 pub const Decoded = union(enum) {
6737 unallocated,
6738 csel: Csel,
6739 csinc: Csinc,
6740 csinv: Csinv,
6741 csneg: Csneg,
6742 };
6743 pub fn decode(inst: @This()) @This().Decoded {
6744 return switch (inst.group.S) {
6745 true => .unallocated,
6746 false => switch (inst.group.op) {
6747 0b0 => switch (inst.group.op2) {
6748 0b10...0b11 => .unallocated,
6749 0b00 => .{ .csel = inst.csel },
6750 0b01 => .{ .csinc = inst.csinc },
6751 },
6752 0b1 => switch (inst.group.op2) {
6753 0b10...0b11 => .unallocated,
6754 0b00 => .{ .csinv = inst.csinv },
6755 0b01 => .{ .csneg = inst.csneg },
6756 },
6757 },
6758 };
6759 }
6760 };
6761
6762 /// Data-processing (3 source)
6763 pub const DataProcessingThreeSource = packed union {
6764 group: @This().Group,
6765 madd: Madd,
6766 msub: Msub,
6767 smaddl: Smaddl,
6768 smsubl: Smsubl,
6769 smulh: Smulh,
6770 umaddl: Umaddl,
6771 umsubl: Umsubl,
6772 umulh: Umulh,
6773
6774 pub const Group = packed struct {
6775 Rd: Register.Encoded,
6776 Rn: Register.Encoded,
6777 Ra: Register.Encoded,
6778 o0: AddSubtractOp,
6779 Rm: Register.Encoded,
6780 op31: u3,
6781 decoded24: u5 = 0b11011,
6782 op54: u2,
6783 sf: Register.IntegerSize,
6784 };
6785
6786 /// C6.2.218 MADD
6787 pub const Madd = packed struct {
6788 Rd: Register.Encoded,
6789 Rn: Register.Encoded,
6790 Ra: Register.Encoded,
6791 o0: AddSubtractOp = .add,
6792 Rm: Register.Encoded,
6793 op31: u3 = 0b000,
6794 decoded24: u5 = 0b11011,
6795 op54: u2 = 0b00,
6796 sf: Register.IntegerSize,
6797 };
6798
6799 /// C6.2.231 MSUB
6800 pub const Msub = packed struct {
6801 Rd: Register.Encoded,
6802 Rn: Register.Encoded,
6803 Ra: Register.Encoded,
6804 o0: AddSubtractOp = .sub,
6805 Rm: Register.Encoded,
6806 op31: u3 = 0b000,
6807 decoded24: u5 = 0b11011,
6808 op54: u2 = 0b00,
6809 sf: Register.IntegerSize,
6810 };
6811
6812 /// C6.2.282 SMADDL
6813 pub const Smaddl = packed struct {
6814 Rd: Register.Encoded,
6815 Rn: Register.Encoded,
6816 Ra: Register.Encoded,
6817 o0: AddSubtractOp = .add,
6818 Rm: Register.Encoded,
6819 op21: u2 = 0b01,
6820 U: bool = false,
6821 decoded24: u5 = 0b11011,
6822 op54: u2 = 0b00,
6823 sf: Register.IntegerSize = .doubleword,
6824 };
6825
6826 /// C6.2.287 SMSUBL
6827 pub const Smsubl = packed struct {
6828 Rd: Register.Encoded,
6829 Rn: Register.Encoded,
6830 Ra: Register.Encoded,
6831 o0: AddSubtractOp = .sub,
6832 Rm: Register.Encoded,
6833 op21: u2 = 0b01,
6834 U: bool = false,
6835 decoded24: u5 = 0b11011,
6836 op54: u2 = 0b00,
6837 sf: Register.IntegerSize = .doubleword,
6838 };
6839
6840 /// C6.2.288 SMULH
6841 pub const Smulh = packed struct {
6842 Rd: Register.Encoded,
6843 Rn: Register.Encoded,
6844 Ra: Register.Encoded = @enumFromInt(0b11111),
6845 o0: AddSubtractOp = .add,
6846 Rm: Register.Encoded,
6847 op21: u2 = 0b10,
6848 U: bool = false,
6849 decoded24: u5 = 0b11011,
6850 op54: u2 = 0b00,
6851 sf: Register.IntegerSize = .doubleword,
6852 };
6853
6854 /// C6.2.389 UMADDL
6855 pub const Umaddl = packed struct {
6856 Rd: Register.Encoded,
6857 Rn: Register.Encoded,
6858 Ra: Register.Encoded,
6859 o0: AddSubtractOp = .add,
6860 Rm: Register.Encoded,
6861 op21: u2 = 0b01,
6862 U: bool = true,
6863 decoded24: u5 = 0b11011,
6864 op54: u2 = 0b00,
6865 sf: Register.IntegerSize = .doubleword,
6866 };
6867
6868 /// C6.2.391 UMSUBL
6869 pub const Umsubl = packed struct {
6870 Rd: Register.Encoded,
6871 Rn: Register.Encoded,
6872 Ra: Register.Encoded,
6873 o0: AddSubtractOp = .sub,
6874 Rm: Register.Encoded,
6875 op21: u2 = 0b01,
6876 U: bool = true,
6877 decoded24: u5 = 0b11011,
6878 op54: u2 = 0b00,
6879 sf: Register.IntegerSize = .doubleword,
6880 };
6881
6882 /// C6.2.392 UMULH
6883 pub const Umulh = packed struct {
6884 Rd: Register.Encoded,
6885 Rn: Register.Encoded,
6886 Ra: Register.Encoded = @enumFromInt(0b11111),
6887 o0: AddSubtractOp = .add,
6888 Rm: Register.Encoded,
6889 op21: u2 = 0b10,
6890 U: bool = true,
6891 decoded24: u5 = 0b11011,
6892 op54: u2 = 0b00,
6893 sf: Register.IntegerSize = .doubleword,
6894 };
6895
6896 pub const Decoded = union(enum) {
6897 unallocated,
6898 madd: Madd,
6899 msub: Msub,
6900 smaddl: Smaddl,
6901 smsubl: Smsubl,
6902 smulh: Smulh,
6903 umaddl: Umaddl,
6904 umsubl: Umsubl,
6905 umulh: Umulh,
6906 };
6907 pub fn decode(inst: @This()) @This().Decoded {
6908 return switch (inst.group.op54) {
6909 0b01, 0b10...0b11 => .unallocated,
6910 0b00 => switch (inst.group.op31) {
6911 0b011, 0b100, 0b111 => .unallocated,
6912 0b000 => switch (inst.group.o0) {
6913 .add => .{ .madd = inst.madd },
6914 .sub => .{ .msub = inst.msub },
6915 },
6916 0b001 => switch (inst.group.sf) {
6917 .word => .unallocated,
6918 .doubleword => switch (inst.group.o0) {
6919 .add => .{ .smaddl = inst.smaddl },
6920 .sub => .{ .smsubl = inst.smsubl },
6921 },
6922 },
6923 0b010 => switch (inst.group.sf) {
6924 .word => .unallocated,
6925 .doubleword => switch (inst.group.o0) {
6926 .add => .{ .smulh = inst.smulh },
6927 .sub => .unallocated,
6928 },
6929 },
6930 0b101 => switch (inst.group.sf) {
6931 .word => .unallocated,
6932 .doubleword => switch (inst.group.o0) {
6933 .add => .{ .umaddl = inst.umaddl },
6934 .sub => .{ .umsubl = inst.umsubl },
6935 },
6936 },
6937 0b110 => switch (inst.group.sf) {
6938 .word => .unallocated,
6939 .doubleword => switch (inst.group.o0) {
6940 .add => .{ .umulh = inst.umulh },
6941 .sub => .unallocated,
6942 },
6943 },
6944 },
6945 };
6946 }
6947 };
6948
6949 pub const Shift = union(enum(u2)) {
6950 lsl: Amount = 0b00,
6951 lsr: Amount = 0b01,
6952 asr: Amount = 0b10,
6953 ror: Amount = 0b11,
6954
6955 pub const Op = @typeInfo(Shift).@"union".tag_type.?;
6956 pub const Amount = u6;
6957 pub const none: Shift = .{ .lsl = 0 };
6958 };
6959
6960 pub const Nzcv = packed struct { v: bool, c: bool, z: bool, n: bool };
6961
6962 pub const Decoded = union(enum) {
6963 unallocated,
6964 data_processing_two_source: DataProcessingTwoSource,
6965 data_processing_one_source: DataProcessingOneSource,
6966 logical_shifted_register: LogicalShiftedRegister,
6967 add_subtract_shifted_register: AddSubtractShiftedRegister,
6968 add_subtract_extended_register: AddSubtractExtendedRegister,
6969 add_subtract_with_carry: AddSubtractWithCarry,
6970 rotate_right_into_flags: RotateRightIntoFlags,
6971 evaluate_into_flags: EvaluateIntoFlags,
6972 conditional_compare_register: ConditionalCompareRegister,
6973 conditional_compare_immediate: ConditionalCompareImmediate,
6974 conditional_select: ConditionalSelect,
6975 data_processing_three_source: DataProcessingThreeSource,
6976 };
6977 pub fn decode(inst: @This()) @This().Decoded {
6978 return switch (inst.group.op1) {
6979 0b0 => switch (@as(u1, @truncate(inst.group.op2 >> 3))) {
6980 0b0 => .{ .logical_shifted_register = inst.logical_shifted_register },
6981 0b1 => switch (@as(u1, @truncate(inst.group.op2 >> 0))) {
6982 0b0 => .{ .add_subtract_shifted_register = inst.add_subtract_shifted_register },
6983 0b1 => .{ .add_subtract_extended_register = inst.add_subtract_extended_register },
6984 },
6985 },
6986 0b1 => switch (inst.group.op2) {
6987 0b0000 => switch (inst.group.op3) {
6988 0b000000 => .{ .add_subtract_with_carry = inst.add_subtract_with_carry },
6989 0b000001, 0b100001 => .{ .rotate_right_into_flags = inst.rotate_right_into_flags },
6990 0b000010, 0b010010, 0b100010, 0b110010 => .{ .evaluate_into_flags = inst.evaluate_into_flags },
6991 else => .unallocated,
6992 },
6993 0b0010 => switch (@as(u1, @truncate(inst.group.op3 >> 1))) {
6994 0b0 => .{ .conditional_compare_register = inst.conditional_compare_register },
6995 0b1 => .{ .conditional_compare_immediate = inst.conditional_compare_immediate },
6996 },
6997 0b0100 => .{ .conditional_select = inst.conditional_select },
6998 0b0110 => switch (inst.group.op0) {
6999 0b0 => .{ .data_processing_two_source = inst.data_processing_two_source },
7000 0b1 => .{ .data_processing_one_source = inst.data_processing_one_source },
7001 },
7002 0b1000...0b1111 => .{ .data_processing_three_source = inst.data_processing_three_source },
7003 else => .unallocated,
7004 },
7005 };
7006 }
7007 };
7008
7009 /// C4.1.90 Data Processing -- Scalar Floating-Point and Advanced SIMD
7010 pub const DataProcessingVector = packed union {
7011 group: @This().Group,
7012 simd_scalar_pairwise: SimdScalarPairwise,
7013 simd_copy: SimdCopy,
7014 simd_two_register_miscellaneous: SimdTwoRegisterMiscellaneous,
7015 simd_across_lanes: SimdAcrossLanes,
7016 simd_three_same: SimdThreeSame,
7017 simd_modified_immediate: SimdModifiedImmediate,
7018 convert_float_integer: ConvertFloatInteger,
7019 float_data_processing_one_source: FloatDataProcessingOneSource,
7020 float_compare: FloatCompare,
7021 float_immediate: FloatImmediate,
7022 float_data_processing_two_source: FloatDataProcessingTwoSource,
7023 float_data_processing_three_source: FloatDataProcessingThreeSource,
7024
7025 /// Table C4-91 Encoding table for the Data Processing -- Scalar Floating-Point and Advanced SIMD group
7026 pub const Group = packed struct {
7027 encoded0: u10,
7028 op3: u9,
7029 op2: u4,
7030 op1: u2,
7031 decoded25: u3 = 0b111,
7032 op0: u4,
7033 };
7034
7035 /// Advanced SIMD scalar pairwise
7036 pub const SimdScalarPairwise = packed union {
7037 group: @This().Group,
7038 addp: Addp,
7039
7040 pub const Group = packed struct {
7041 Rd: Register.Encoded,
7042 Rn: Register.Encoded,
7043 decoded10: u2 = 0b10,
7044 opcode: u5,
7045 decoded17: u5 = 0b11000,
7046 size: Size,
7047 decoded24: u5 = 0b11110,
7048 U: u1,
7049 decoded30: u2 = 0b01,
7050 };
7051
7052 /// C7.2.4 ADDP (scalar)
7053 pub const Addp = packed struct {
7054 Rd: Register.Encoded,
7055 Rn: Register.Encoded,
7056 decoded10: u2 = 0b10,
7057 opcode: u5 = 0b11011,
7058 decoded17: u5 = 0b11000,
7059 size: Size,
7060 decoded24: u5 = 0b11110,
7061 U: u1 = 0b0,
7062 decoded30: u2 = 0b01,
7063 };
7064 };
7065
7066 /// Advanced SIMD copy
7067 pub const SimdCopy = packed union {
7068 group: @This().Group,
7069 smov: Smov,
7070 umov: Umov,
7071
7072 pub const Group = packed struct {
7073 Rd: Register.Encoded,
7074 Rn: Register.Encoded,
7075 decoded10: u1 = 0b1,
7076 imm4: u4,
7077 decoded15: u1 = 0b0,
7078 imm5: u5,
7079 decoded21: u8 = 0b01110000,
7080 op: u1,
7081 Q: Register.IntegerSize,
7082 decoded31: u1 = 0b0,
7083 };
7084
7085 /// C7.2.279 SMOV
7086 pub const Smov = packed struct {
7087 Rd: Register.Encoded,
7088 Rn: Register.Encoded,
7089 decoded10: u1 = 0b1,
7090 decoded11: u1 = 0b1,
7091 decoded12: u1 = 0b0,
7092 decoded13: u2 = 0b01,
7093 decoded15: u1 = 0b0,
7094 imm5: u5,
7095 decoded21: u8 = 0b01110000,
7096 decoded29: u1 = 0b0,
7097 Q: Register.IntegerSize,
7098 decoded31: u1 = 0b0,
7099 };
7100
7101 /// C7.2.371 UMOV
7102 pub const Umov = packed struct {
7103 Rd: Register.Encoded,
7104 Rn: Register.Encoded,
7105 decoded10: u1 = 0b1,
7106 decoded11: u1 = 0b1,
7107 decoded12: u1 = 0b1,
7108 decoded13: u2 = 0b01,
7109 decoded15: u1 = 0b0,
7110 imm5: u5,
7111 decoded21: u8 = 0b01110000,
7112 decoded29: u1 = 0b0,
7113 Q: Register.IntegerSize,
7114 decoded31: u1 = 0b0,
7115 };
7116 };
7117
7118 /// Advanced SIMD two-register miscellaneous
7119 pub const SimdTwoRegisterMiscellaneous = packed union {
7120 group: @This().Group,
7121 cnt: Cnt,
7122
7123 pub const Group = packed struct {
7124 Rd: Register.Encoded,
7125 Rn: Register.Encoded,
7126 decoded10: u2 = 0b10,
7127 opcode: u5,
7128 decoded17: u5 = 0b10000,
7129 size: Size,
7130 decoded24: u5 = 0b01110,
7131 U: u1,
7132 Q: Q,
7133 decoded31: u1 = 0b0,
7134 };
7135
7136 /// C7.2.38 CNT
7137 pub const Cnt = packed struct {
7138 Rd: Register.Encoded,
7139 Rn: Register.Encoded,
7140 decoded10: u2 = 0b10,
7141 opcode: u5 = 0b00101,
7142 decoded17: u5 = 0b10000,
7143 size: Size,
7144 decoded24: u5 = 0b01110,
7145 U: u1 = 0b0,
7146 Q: Q,
7147 decoded31: u1 = 0b0,
7148 };
7149 };
7150
7151 /// Advanced SIMD across lanes
7152 pub const SimdAcrossLanes = packed union {
7153 group: @This().Group,
7154 addv: Addv,
7155
7156 pub const Group = packed struct {
7157 Rd: Register.Encoded,
7158 Rn: Register.Encoded,
7159 decoded10: u2 = 0b10,
7160 opcode: u5,
7161 decoded17: u5 = 0b11000,
7162 size: Size,
7163 decoded24: u5 = 0b01110,
7164 U: u1,
7165 Q: Q,
7166 decoded31: u1 = 0b0,
7167 };
7168
7169 /// C7.2.6 ADDV
7170 pub const Addv = packed struct {
7171 Rd: Register.Encoded,
7172 Rn: Register.Encoded,
7173 decoded10: u2 = 0b10,
7174 opcode: u5 = 0b11011,
7175 decoded17: u5 = 0b11000,
7176 size: Size,
7177 decoded24: u5 = 0b01110,
7178 U: u1 = 0b0,
7179 Q: Q,
7180 decoded31: u1 = 0b0,
7181 };
7182 };
7183
7184 /// Advanced SIMD three same
7185 pub const SimdThreeSame = packed union {
7186 group: @This().Group,
7187 addp: Addp,
7188 @"and": And,
7189 bic: Bic,
7190 orr: Orr,
7191 orn: Orn,
7192 eor: Eor,
7193
7194 pub const Group = packed struct {
7195 Rd: Register.Encoded,
7196 Rn: Register.Encoded,
7197 decoded10: u1 = 0b1,
7198 opcode: u5,
7199 Rm: Register.Encoded,
7200 decoded21: u1 = 0b1,
7201 size: Size,
7202 decoded24: u5 = 0b01110,
7203 U: u1,
7204 Q: Q,
7205 decoded31: u1 = 0b0,
7206 };
7207
7208 /// C7.2.5 ADDP (vector)
7209 pub const Addp = packed struct {
7210 Rd: Register.Encoded,
7211 Rn: Register.Encoded,
7212 decoded10: u1 = 0b1,
7213 opcode: u5 = 0b10111,
7214 Rm: Register.Encoded,
7215 decoded21: u1 = 0b1,
7216 size: Size,
7217 decoded24: u5 = 0b01110,
7218 U: u1 = 0b0,
7219 Q: Q,
7220 decoded31: u1 = 0b0,
7221 };
7222
7223 /// C7.2.11 AND (vector)
7224 pub const And = packed struct {
7225 Rd: Register.Encoded,
7226 Rn: Register.Encoded,
7227 decoded10: u1 = 0b1,
7228 opcode: u5 = 0b00011,
7229 Rm: Register.Encoded,
7230 decoded21: u1 = 0b1,
7231 size: Size = .byte,
7232 decoded24: u5 = 0b01110,
7233 U: u1 = 0b0,
7234 Q: Q,
7235 decoded31: u1 = 0b0,
7236 };
7237
7238 /// C7.2.21 BIC (vector, register)
7239 pub const Bic = packed struct {
7240 Rd: Register.Encoded,
7241 Rn: Register.Encoded,
7242 decoded10: u1 = 0b1,
7243 opcode: u5 = 0b00011,
7244 Rm: Register.Encoded,
7245 decoded21: u1 = 0b1,
7246 size: Size = .half,
7247 decoded24: u5 = 0b01110,
7248 U: u1 = 0b0,
7249 Q: Q,
7250 decoded31: u1 = 0b0,
7251 };
7252
7253 /// C7.2.213 ORR (vector, register)
7254 pub const Orr = packed struct {
7255 Rd: Register.Encoded,
7256 Rn: Register.Encoded,
7257 decoded10: u1 = 0b1,
7258 opcode: u5 = 0b00011,
7259 Rm: Register.Encoded,
7260 decoded21: u1 = 0b1,
7261 size: Size = .single,
7262 decoded24: u5 = 0b01110,
7263 U: u1 = 0b0,
7264 Q: Q,
7265 decoded31: u1 = 0b0,
7266 };
7267
7268 /// C7.2.211 ORN (vector)
7269 pub const Orn = packed struct {
7270 Rd: Register.Encoded,
7271 Rn: Register.Encoded,
7272 decoded10: u1 = 0b1,
7273 opcode: u5 = 0b00011,
7274 Rm: Register.Encoded,
7275 decoded21: u1 = 0b1,
7276 size: Size = .double,
7277 decoded24: u5 = 0b01110,
7278 U: u1 = 0b0,
7279 Q: Q,
7280 decoded31: u1 = 0b0,
7281 };
7282
7283 /// C7.2.41 EOR (vector)
7284 pub const Eor = packed struct {
7285 Rd: Register.Encoded,
7286 Rn: Register.Encoded,
7287 decoded10: u1 = 0b1,
7288 opcode: u5 = 0b00011,
7289 Rm: Register.Encoded,
7290 decoded21: u1 = 0b1,
7291 size: Size = .byte,
7292 decoded24: u5 = 0b01110,
7293 U: u1 = 0b1,
7294 Q: Q,
7295 decoded31: u1 = 0b0,
7296 };
7297 };
7298
7299 /// Advanced SIMD modified immediate
7300 pub const SimdModifiedImmediate = packed union {
7301 group: @This().Group,
7302 movi: Movi,
7303 orr: Orr,
7304 fmov: Fmov,
7305 mvni: Mvni,
7306 bic: Bic,
7307
7308 pub const Group = packed struct {
7309 Rd: Register.Encoded,
7310 imm5: u5,
7311 decoded10: u1 = 0b1,
7312 o2: u1,
7313 cmode: u4,
7314 imm3: u3,
7315 decoded19: u10 = 0b0111100000,
7316 op: u1,
7317 Q: Q,
7318 decoded31: u1 = 0b0,
7319 };
7320
7321 /// C7.2.204 MOVI
7322 pub const Movi = packed struct {
7323 Rd: Register.Encoded,
7324 imm5: u5,
7325 decoded10: u1 = 0b1,
7326 o2: u1 = 0b0,
7327 cmode: u4,
7328 imm3: u3,
7329 decoded19: u10 = 0b0111100000,
7330 op: u1,
7331 Q: Q,
7332 decoded31: u1 = 0b0,
7333 };
7334
7335 /// C7.2.212 ORR (vector, immediate)
7336 pub const Orr = packed struct {
7337 Rd: Register.Encoded,
7338 imm5: u5,
7339 decoded10: u1 = 0b1,
7340 o2: u1 = 0b0,
7341 cmode0: u1 = 0b1,
7342 cmode: u3,
7343 imm3: u3,
7344 decoded19: u10 = 0b0111100000,
7345 op: u1 = 0b0,
7346 Q: Q,
7347 decoded31: u1 = 0b0,
7348 };
7349
7350 /// C7.2.129 FMOV (vector, immediate)
7351 pub const Fmov = packed struct {
7352 Rd: Register.Encoded,
7353 imm5: u5,
7354 decoded10: u1 = 0b1,
7355 o2: u1 = 0b1,
7356 cmode: u4 = 0b1111,
7357 imm3: u3,
7358 decoded19: u10 = 0b0111100000,
7359 op: u1 = 0b0,
7360 Q: Q,
7361 decoded31: u1 = 0b0,
7362 };
7363
7364 /// C7.2.208 MVNI
7365 pub const Mvni = packed struct {
7366 Rd: Register.Encoded,
7367 imm5: u5,
7368 decoded10: u1 = 0b1,
7369 o2: u1 = 0b0,
7370 cmode: u4,
7371 imm3: u3,
7372 decoded19: u10 = 0b0111100000,
7373 op: u1 = 0b1,
7374 Q: Q,
7375 decoded31: u1 = 0b0,
7376 };
7377
7378 /// C7.2.20 BIC (vector, immediate)
7379 pub const Bic = packed struct {
7380 Rd: Register.Encoded,
7381 imm5: u5,
7382 decoded10: u1 = 0b1,
7383 o2: u1 = 0b0,
7384 cmode0: u1 = 0b1,
7385 cmode: u3,
7386 imm3: u3,
7387 decoded19: u10 = 0b0111100000,
7388 op: u1 = 0b1,
7389 Q: Q,
7390 decoded31: u1 = 0b0,
7391 };
7392 };
7393
7394 /// Conversion between floating-point and integer
7395 pub const ConvertFloatInteger = packed union {
7396 group: @This().Group,
7397 fcvtns: Fcvtns,
7398 fcvtnu: Fcvtnu,
7399 scvtf: Scvtf,
7400 ucvtf: Ucvtf,
7401 fcvtas: Fcvtas,
7402 fcvtau: Fcvtau,
7403 fmov: Fmov,
7404 fcvtps: Fcvtps,
7405 fcvtpu: Fcvtpu,
7406 fcvtms: Fcvtms,
7407 fcvtmu: Fcvtmu,
7408 fcvtzs: Fcvtzs,
7409 fcvtzu: Fcvtzu,
7410 fjcvtzs: Fjcvtzs,
7411
7412 pub const Group = packed struct {
7413 Rd: Register.Encoded,
7414 Rn: Register.Encoded,
7415 decoded10: u6 = 0b000000,
7416 opcode: u3,
7417 rmode: u2,
7418 decoded21: u1 = 0b1,
7419 ptype: Ftype,
7420 decoded24: u5 = 0b11110,
7421 S: bool,
7422 decoded30: u1 = 0b0,
7423 sf: Register.IntegerSize,
7424 };
7425
7426 /// C7.2.81 FCVTNS (scalar)
7427 pub const Fcvtns = packed struct {
7428 Rd: Register.Encoded,
7429 Rn: Register.Encoded,
7430 decoded10: u6 = 0b000000,
7431 opcode: u3 = 0b000,
7432 rmode: Rmode = .n,
7433 decoded21: u1 = 0b1,
7434 ftype: Ftype,
7435 decoded24: u5 = 0b11110,
7436 S: bool = false,
7437 decoded30: u1 = 0b0,
7438 sf: Register.IntegerSize,
7439 };
7440
7441 /// C7.2.83 FCVTNU (scalar)
7442 pub const Fcvtnu = packed struct {
7443 Rd: Register.Encoded,
7444 Rn: Register.Encoded,
7445 decoded10: u6 = 0b000000,
7446 opcode: u3 = 0b001,
7447 rmode: Rmode = .n,
7448 decoded21: u1 = 0b1,
7449 ftype: Ftype,
7450 decoded24: u5 = 0b11110,
7451 S: bool = false,
7452 decoded30: u1 = 0b0,
7453 sf: Register.IntegerSize,
7454 };
7455
7456 /// C7.2.236 SCVTF (scalar, integer)
7457 pub const Scvtf = packed struct {
7458 Rd: Register.Encoded,
7459 Rn: Register.Encoded,
7460 decoded10: u6 = 0b000000,
7461 opcode: u3 = 0b010,
7462 rmode: Rmode = .n,
7463 decoded21: u1 = 0b1,
7464 ftype: Ftype,
7465 decoded24: u5 = 0b11110,
7466 S: bool = false,
7467 decoded30: u1 = 0b0,
7468 sf: Register.IntegerSize,
7469 };
7470
7471 /// C7.2.355 UCVTF (scalar, integer)
7472 pub const Ucvtf = packed struct {
7473 Rd: Register.Encoded,
7474 Rn: Register.Encoded,
7475 decoded10: u6 = 0b000000,
7476 opcode: u3 = 0b011,
7477 rmode: Rmode = .n,
7478 decoded21: u1 = 0b1,
7479 ftype: Ftype,
7480 decoded24: u5 = 0b11110,
7481 S: bool = false,
7482 decoded30: u1 = 0b0,
7483 sf: Register.IntegerSize,
7484 };
7485
7486 /// C7.2.71 FCVTAS (scalar)
7487 pub const Fcvtas = packed struct {
7488 Rd: Register.Encoded,
7489 Rn: Register.Encoded,
7490 decoded10: u6 = 0b000000,
7491 opcode: u3 = 0b100,
7492 rmode: Rmode = .n,
7493 decoded21: u1 = 0b1,
7494 ftype: Ftype,
7495 decoded24: u5 = 0b11110,
7496 S: bool = false,
7497 decoded30: u1 = 0b0,
7498 sf: Register.IntegerSize,
7499 };
7500
7501 /// C7.2.73 FCVTAU (scalar)
7502 pub const Fcvtau = packed struct {
7503 Rd: Register.Encoded,
7504 Rn: Register.Encoded,
7505 decoded10: u6 = 0b000000,
7506 opcode: u3 = 0b101,
7507 rmode: Rmode = .n,
7508 decoded21: u1 = 0b1,
7509 ftype: Ftype,
7510 decoded24: u5 = 0b11110,
7511 S: bool = false,
7512 decoded30: u1 = 0b0,
7513 sf: Register.IntegerSize,
7514 };
7515
7516 /// C7.2.131 FMOV (general)
7517 pub const Fmov = packed struct {
7518 Rd: Register.Encoded,
7519 Rn: Register.Encoded,
7520 decoded10: u6 = 0b000000,
7521 opcode: Opcode,
7522 rmode: Fmov.Rmode,
7523 decoded21: u1 = 0b1,
7524 ftype: Ftype,
7525 decoded24: u5 = 0b11110,
7526 S: bool = false,
7527 decoded30: u1 = 0b0,
7528 sf: Register.IntegerSize,
7529
7530 pub const Opcode = enum(u3) {
7531 float_to_integer = 0b110,
7532 integer_to_float = 0b111,
7533 _,
7534 };
7535
7536 pub const Rmode = enum(u2) {
7537 @"0" = 0b00,
7538 @"1" = 0b01,
7539 _,
7540 };
7541 };
7542
7543 /// C7.2.85 FCVTPS (scalar)
7544 pub const Fcvtps = packed struct {
7545 Rd: Register.Encoded,
7546 Rn: Register.Encoded,
7547 decoded10: u6 = 0b000000,
7548 opcode: u3 = 0b000,
7549 rmode: Rmode = .p,
7550 decoded21: u1 = 0b1,
7551 ftype: Ftype,
7552 decoded24: u5 = 0b11110,
7553 S: bool = false,
7554 decoded30: u1 = 0b0,
7555 sf: Register.IntegerSize,
7556 };
7557
7558 /// C7.2.87 FCVTPU (scalar)
7559 pub const Fcvtpu = packed struct {
7560 Rd: Register.Encoded,
7561 Rn: Register.Encoded,
7562 decoded10: u6 = 0b000000,
7563 opcode: u3 = 0b001,
7564 rmode: Rmode = .p,
7565 decoded21: u1 = 0b1,
7566 ftype: Ftype,
7567 decoded24: u5 = 0b11110,
7568 S: bool = false,
7569 decoded30: u1 = 0b0,
7570 sf: Register.IntegerSize,
7571 };
7572
7573 /// C7.2.76 FCVTMS (scalar)
7574 pub const Fcvtms = packed struct {
7575 Rd: Register.Encoded,
7576 Rn: Register.Encoded,
7577 decoded10: u6 = 0b000000,
7578 opcode: u3 = 0b000,
7579 rmode: Rmode = .m,
7580 decoded21: u1 = 0b1,
7581 ftype: Ftype,
7582 decoded24: u5 = 0b11110,
7583 S: bool = false,
7584 decoded30: u1 = 0b0,
7585 sf: Register.IntegerSize,
7586 };
7587
7588 /// C7.2.78 FCVTMU (scalar)
7589 pub const Fcvtmu = packed struct {
7590 Rd: Register.Encoded,
7591 Rn: Register.Encoded,
7592 decoded10: u6 = 0b000000,
7593 opcode: u3 = 0b001,
7594 rmode: Rmode = .m,
7595 decoded21: u1 = 0b1,
7596 ftype: Ftype,
7597 decoded24: u5 = 0b11110,
7598 S: bool = false,
7599 decoded30: u1 = 0b0,
7600 sf: Register.IntegerSize,
7601 };
7602
7603 /// C7.2.92 FCVTZS (scalar, integer)
7604 pub const Fcvtzs = packed struct {
7605 Rd: Register.Encoded,
7606 Rn: Register.Encoded,
7607 decoded10: u6 = 0b000000,
7608 opcode: u3 = 0b000,
7609 rmode: Rmode = .z,
7610 decoded21: u1 = 0b1,
7611 ftype: Ftype,
7612 decoded24: u5 = 0b11110,
7613 S: bool = false,
7614 decoded30: u1 = 0b0,
7615 sf: Register.IntegerSize,
7616 };
7617
7618 /// C7.2.96 FCVTZU (scalar, integer)
7619 pub const Fcvtzu = packed struct {
7620 Rd: Register.Encoded,
7621 Rn: Register.Encoded,
7622 decoded10: u6 = 0b000000,
7623 opcode: u3 = 0b001,
7624 rmode: Rmode = .z,
7625 decoded21: u1 = 0b1,
7626 ftype: Ftype,
7627 decoded24: u5 = 0b11110,
7628 S: bool = false,
7629 decoded30: u1 = 0b0,
7630 sf: Register.IntegerSize,
7631 };
7632
7633 /// C7.2.99 FJCVTZS
7634 pub const Fjcvtzs = packed struct {
7635 Rd: Register.Encoded,
7636 Rn: Register.Encoded,
7637 decoded10: u6 = 0b000000,
7638 opcode: u3 = 0b110,
7639 rmode: Rmode = .z,
7640 decoded21: u1 = 0b1,
7641 ftype: Ftype = .double,
7642 decoded24: u5 = 0b11110,
7643 S: bool = false,
7644 decoded30: u1 = 0b0,
7645 sf: Register.IntegerSize = .word,
7646 };
7647
7648 pub const Rmode = enum(u2) {
7649 /// to nearest
7650 n = 0b00,
7651 /// toward plus infinity
7652 p = 0b01,
7653 /// toward minus infinity
7654 m = 0b10,
7655 /// toward zero
7656 z = 0b11,
7657 };
7658 };
7659
7660 /// Floating-point data-processing (1 source)
7661 pub const FloatDataProcessingOneSource = packed union {
7662 group: @This().Group,
7663 fmov: Fmov,
7664 fabs: Fabs,
7665 fneg: Fneg,
7666 fsqrt: Fsqrt,
7667 fcvt: Fcvt,
7668 frintn: Frintn,
7669 frintp: Frintp,
7670 frintm: Frintm,
7671 frintz: Frintz,
7672 frinta: Frinta,
7673 frintx: Frintx,
7674 frinti: Frinti,
7675
7676 pub const Group = packed struct {
7677 Rd: Register.Encoded,
7678 Rn: Register.Encoded,
7679 decoded10: u5 = 0b10000,
7680 opcode: u6,
7681 decoded21: u1 = 0b1,
7682 ptype: Ftype,
7683 decoded24: u5 = 0b11110,
7684 S: bool,
7685 decoded30: u1 = 0b0,
7686 M: u1,
7687 };
7688
7689 /// C7.2.130 FMOV (register)
7690 pub const Fmov = packed struct {
7691 Rd: Register.Encoded,
7692 Rn: Register.Encoded,
7693 decoded10: u5 = 0b10000,
7694 opc: u2 = 0b00,
7695 decoded17: u4 = 0b0000,
7696 decoded21: u1 = 0b1,
7697 ftype: Ftype,
7698 decoded24: u5 = 0b11110,
7699 S: bool = false,
7700 decoded30: u1 = 0b0,
7701 M: u1 = 0b0,
7702 };
7703
7704 /// C7.2.46 FABS (scalar)
7705 pub const Fabs = packed struct {
7706 Rd: Register.Encoded,
7707 Rn: Register.Encoded,
7708 decoded10: u5 = 0b10000,
7709 opc: u2 = 0b01,
7710 decoded17: u4 = 0b0000,
7711 decoded21: u1 = 0b1,
7712 ftype: Ftype,
7713 decoded24: u5 = 0b11110,
7714 S: bool = false,
7715 decoded30: u1 = 0b0,
7716 M: u1 = 0b0,
7717 };
7718
7719 /// C7.2.140 FNEG (scalar)
7720 pub const Fneg = packed struct {
7721 Rd: Register.Encoded,
7722 Rn: Register.Encoded,
7723 decoded10: u5 = 0b10000,
7724 opc: u2 = 0b10,
7725 decoded17: u4 = 0b0000,
7726 decoded21: u1 = 0b1,
7727 ftype: Ftype,
7728 decoded24: u5 = 0b11110,
7729 S: bool = false,
7730 decoded30: u1 = 0b0,
7731 M: u1 = 0b0,
7732 };
7733
7734 /// C7.2.172 FSQRT (scalar)
7735 pub const Fsqrt = packed struct {
7736 Rd: Register.Encoded,
7737 Rn: Register.Encoded,
7738 decoded10: u5 = 0b10000,
7739 opc: u2 = 0b11,
7740 decoded17: u4 = 0b0000,
7741 decoded21: u1 = 0b1,
7742 ftype: Ftype,
7743 decoded24: u5 = 0b11110,
7744 S: bool = false,
7745 decoded30: u1 = 0b0,
7746 M: u1 = 0b0,
7747 };
7748
7749 /// C7.2.69 FCVT
7750 pub const Fcvt = packed struct {
7751 Rd: Register.Encoded,
7752 Rn: Register.Encoded,
7753 decoded10: u5 = 0b10000,
7754 opc: Ftype,
7755 decoded17: u4 = 0b0001,
7756 decoded21: u1 = 0b1,
7757 ftype: Ftype,
7758 decoded24: u5 = 0b11110,
7759 S: bool = false,
7760 decoded30: u1 = 0b0,
7761 M: u1 = 0b0,
7762 };
7763
7764 /// C7.2.162 FRINTN (scalar)
7765 pub const Frintn = packed struct {
7766 Rd: Register.Encoded,
7767 Rn: Register.Encoded,
7768 decoded10: u5 = 0b10000,
7769 rmode: Rmode = .n,
7770 decoded18: u3 = 0b001,
7771 decoded21: u1 = 0b1,
7772 ftype: Ftype,
7773 decoded24: u5 = 0b11110,
7774 S: bool = false,
7775 decoded30: u1 = 0b0,
7776 M: u1 = 0b0,
7777 };
7778
7779 /// C7.2.164 FRINTP (scalar)
7780 pub const Frintp = packed struct {
7781 Rd: Register.Encoded,
7782 Rn: Register.Encoded,
7783 decoded10: u5 = 0b10000,
7784 rmode: Rmode = .p,
7785 decoded18: u3 = 0b001,
7786 decoded21: u1 = 0b1,
7787 ftype: Ftype,
7788 decoded24: u5 = 0b11110,
7789 S: bool = false,
7790 decoded30: u1 = 0b0,
7791 M: u1 = 0b0,
7792 };
7793
7794 /// C7.2.160 FRINTM (scalar)
7795 pub const Frintm = packed struct {
7796 Rd: Register.Encoded,
7797 Rn: Register.Encoded,
7798 decoded10: u5 = 0b10000,
7799 rmode: Rmode = .m,
7800 decoded18: u3 = 0b001,
7801 decoded21: u1 = 0b1,
7802 ftype: Ftype,
7803 decoded24: u5 = 0b11110,
7804 S: bool = false,
7805 decoded30: u1 = 0b0,
7806 M: u1 = 0b0,
7807 };
7808
7809 /// C7.2.168 FRINTZ (scalar)
7810 pub const Frintz = packed struct {
7811 Rd: Register.Encoded,
7812 Rn: Register.Encoded,
7813 decoded10: u5 = 0b10000,
7814 rmode: Rmode = .z,
7815 decoded18: u3 = 0b001,
7816 decoded21: u1 = 0b1,
7817 ftype: Ftype,
7818 decoded24: u5 = 0b11110,
7819 S: bool = false,
7820 decoded30: u1 = 0b0,
7821 M: u1 = 0b0,
7822 };
7823
7824 /// C7.2.156 FRINTA (scalar)
7825 pub const Frinta = packed struct {
7826 Rd: Register.Encoded,
7827 Rn: Register.Encoded,
7828 decoded10: u5 = 0b10000,
7829 rmode: Rmode = .a,
7830 decoded18: u3 = 0b001,
7831 decoded21: u1 = 0b1,
7832 ftype: Ftype,
7833 decoded24: u5 = 0b11110,
7834 S: bool = false,
7835 decoded30: u1 = 0b0,
7836 M: u1 = 0b0,
7837 };
7838
7839 /// C7.2.166 FRINTX (scalar)
7840 pub const Frintx = packed struct {
7841 Rd: Register.Encoded,
7842 Rn: Register.Encoded,
7843 decoded10: u5 = 0b10000,
7844 rmode: Rmode = .x,
7845 decoded18: u3 = 0b001,
7846 decoded21: u1 = 0b1,
7847 ftype: Ftype,
7848 decoded24: u5 = 0b11110,
7849 S: bool = false,
7850 decoded30: u1 = 0b0,
7851 M: u1 = 0b0,
7852 };
7853
7854 /// C7.2.158 FRINTI (scalar)
7855 pub const Frinti = packed struct {
7856 Rd: Register.Encoded,
7857 Rn: Register.Encoded,
7858 decoded10: u5 = 0b10000,
7859 rmode: Rmode = .i,
7860 decoded18: u3 = 0b001,
7861 decoded21: u1 = 0b1,
7862 ftype: Ftype,
7863 decoded24: u5 = 0b11110,
7864 S: bool = false,
7865 decoded30: u1 = 0b0,
7866 M: u1 = 0b0,
7867 };
7868
7869 pub const Rmode = enum(u3) {
7870 /// to nearest with ties to even
7871 n = 0b000,
7872 /// toward plus infinity
7873 p = 0b001,
7874 /// toward minus infinity
7875 m = 0b010,
7876 /// toward zero
7877 z = 0b011,
7878 /// to nearest with ties to away
7879 a = 0b100,
7880 /// exact, using current rounding mode
7881 x = 0b110,
7882 /// using current rounding mode
7883 i = 0b111,
7884 _,
7885 };
7886 };
7887
7888 /// Floating-point compare
7889 pub const FloatCompare = packed union {
7890 group: @This().Group,
7891 fcmp: Fcmp,
7892 fcmpe: Fcmpe,
7893
7894 pub const Group = packed struct {
7895 opcode2: u5,
7896 Rn: Register.Encoded,
7897 decoded10: u4 = 0b1000,
7898 op: u2,
7899 Rm: Register.Encoded,
7900 decoded21: u1 = 0b1,
7901 ptype: Ftype,
7902 decoded24: u5 = 0b11110,
7903 S: bool,
7904 decoded30: u1 = 0b0,
7905 M: u1,
7906 };
7907
7908 /// C7.2.66 FCMP
7909 pub const Fcmp = packed struct {
7910 decoded0: u3 = 0b000,
7911 opc0: Opc0,
7912 opc1: u1 = 0b0,
7913 Rn: Register.Encoded,
7914 decoded10: u4 = 0b1000,
7915 op: u2 = 0b00,
7916 Rm: Register.Encoded,
7917 decoded21: u1 = 0b1,
7918 ftype: Ftype,
7919 decoded24: u5 = 0b11110,
7920 S: bool = false,
7921 decoded30: u1 = 0b0,
7922 M: u1 = 0b0,
7923 };
7924
7925 /// C7.2.67 FCMPE
7926 pub const Fcmpe = packed struct {
7927 decoded0: u3 = 0b000,
7928 opc0: Opc0,
7929 opc1: u1 = 0b1,
7930 Rn: Register.Encoded,
7931 decoded10: u4 = 0b1000,
7932 op: u2 = 0b00,
7933 Rm: Register.Encoded,
7934 decoded21: u1 = 0b1,
7935 ftype: Ftype,
7936 decoded24: u5 = 0b11110,
7937 S: bool = false,
7938 decoded30: u1 = 0b0,
7939 M: u1 = 0b0,
7940 };
7941
7942 pub const Opc0 = enum(u1) {
7943 register = 0b00,
7944 zero = 0b01,
7945 };
7946 };
7947
7948 /// Floating-point immediate
7949 pub const FloatImmediate = packed union {
7950 group: @This().Group,
7951 fmov: Fmov,
7952
7953 pub const Group = packed struct {
7954 Rd: Register.Encoded,
7955 imm5: u5,
7956 decoded10: u3 = 0b100,
7957 imm8: u8,
7958 decoded21: u1 = 0b1,
7959 ptype: Ftype,
7960 decoded24: u5 = 0b11110,
7961 S: bool,
7962 decoded30: u1 = 0b0,
7963 M: u1,
7964 };
7965
7966 /// C7.2.132 FMOV (scalar, immediate)
7967 pub const Fmov = packed struct {
7968 Rd: Register.Encoded,
7969 imm5: u5 = 0b00000,
7970 decoded10: u3 = 0b100,
7971 imm8: u8,
7972 decoded21: u1 = 0b1,
7973 ftype: Ftype,
7974 decoded24: u5 = 0b11110,
7975 S: bool = false,
7976 decoded30: u1 = 0b0,
7977 M: u1 = 0b0,
7978 };
7979 };
7980
7981 /// Floating-point data-processing (2 source)
7982 pub const FloatDataProcessingTwoSource = packed union {
7983 group: @This().Group,
7984 fmul: Fmul,
7985 fdiv: Fdiv,
7986 fadd: Fadd,
7987 fsub: Fsub,
7988 fmax: Fmax,
7989 fmin: Fmin,
7990 fmaxnm: Fmaxnm,
7991 fminnm: Fminnm,
7992 fnmul: Fnmul,
7993
7994 pub const Group = packed struct {
7995 Rd: Register.Encoded,
7996 Rn: Register.Encoded,
7997 decoded10: u2 = 0b10,
7998 opcode: Opcode,
7999 Rm: Register.Encoded,
8000 decoded21: u1 = 0b1,
8001 ptype: Ftype,
8002 decoded24: u5 = 0b11110,
8003 S: bool,
8004 decoded30: u1 = 0b0,
8005 M: u1,
8006 };
8007
8008 /// C7.2.136 FMUL (scalar)
8009 pub const Fmul = packed struct {
8010 Rd: Register.Encoded,
8011 Rn: Register.Encoded,
8012 decoded10: u2 = 0b10,
8013 opcode: Opcode = .fmul,
8014 Rm: Register.Encoded,
8015 decoded21: u1 = 0b1,
8016 ftype: Ftype,
8017 decoded24: u5 = 0b11110,
8018 S: bool = false,
8019 decoded30: u1 = 0b0,
8020 M: u1 = 0b0,
8021 };
8022
8023 /// C7.2.98 FDIV (scalar)
8024 pub const Fdiv = packed struct {
8025 Rd: Register.Encoded,
8026 Rn: Register.Encoded,
8027 decoded10: u2 = 0b10,
8028 opcode: Opcode = .fdiv,
8029 Rm: Register.Encoded,
8030 decoded21: u1 = 0b1,
8031 ftype: Ftype,
8032 decoded24: u5 = 0b11110,
8033 S: bool = false,
8034 decoded30: u1 = 0b0,
8035 M: u1 = 0b0,
8036 };
8037
8038 /// C7.2.50 FADD (scalar)
8039 pub const Fadd = packed struct {
8040 Rd: Register.Encoded,
8041 Rn: Register.Encoded,
8042 decoded10: u2 = 0b10,
8043 opcode: Opcode = .fadd,
8044 Rm: Register.Encoded,
8045 decoded21: u1 = 0b1,
8046 ftype: Ftype,
8047 decoded24: u5 = 0b11110,
8048 S: bool = false,
8049 decoded30: u1 = 0b0,
8050 M: u1 = 0b0,
8051 };
8052
8053 /// C7.2.174 FSUB (scalar)
8054 pub const Fsub = packed struct {
8055 Rd: Register.Encoded,
8056 Rn: Register.Encoded,
8057 decoded10: u2 = 0b10,
8058 opcode: Opcode = .fsub,
8059 Rm: Register.Encoded,
8060 decoded21: u1 = 0b1,
8061 ftype: Ftype,
8062 decoded24: u5 = 0b11110,
8063 S: bool = false,
8064 decoded30: u1 = 0b0,
8065 M: u1 = 0b0,
8066 };
8067
8068 /// C7.2.102 FMAX (scalar)
8069 pub const Fmax = packed struct {
8070 Rd: Register.Encoded,
8071 Rn: Register.Encoded,
8072 decoded10: u2 = 0b10,
8073 opcode: Opcode = .fmax,
8074 Rm: Register.Encoded,
8075 decoded21: u1 = 0b1,
8076 ftype: Ftype,
8077 decoded24: u5 = 0b11110,
8078 S: bool = false,
8079 decoded30: u1 = 0b0,
8080 M: u1 = 0b0,
8081 };
8082
8083 /// C7.2.112 FMIN (scalar)
8084 pub const Fmin = packed struct {
8085 Rd: Register.Encoded,
8086 Rn: Register.Encoded,
8087 decoded10: u2 = 0b10,
8088 opcode: Opcode = .fmin,
8089 Rm: Register.Encoded,
8090 decoded21: u1 = 0b1,
8091 ftype: Ftype,
8092 decoded24: u5 = 0b11110,
8093 S: bool = false,
8094 decoded30: u1 = 0b0,
8095 M: u1 = 0b0,
8096 };
8097
8098 /// C7.2.104 FMAXNM (scalar)
8099 pub const Fmaxnm = packed struct {
8100 Rd: Register.Encoded,
8101 Rn: Register.Encoded,
8102 decoded10: u2 = 0b10,
8103 opcode: Opcode = .fmaxnm,
8104 Rm: Register.Encoded,
8105 decoded21: u1 = 0b1,
8106 ftype: Ftype,
8107 decoded24: u5 = 0b11110,
8108 S: bool = false,
8109 decoded30: u1 = 0b0,
8110 M: u1 = 0b0,
8111 };
8112
8113 /// C7.2.114 FMINNM (scalar)
8114 pub const Fminnm = packed struct {
8115 Rd: Register.Encoded,
8116 Rn: Register.Encoded,
8117 decoded10: u2 = 0b10,
8118 opcode: Opcode = .fminnm,
8119 Rm: Register.Encoded,
8120 decoded21: u1 = 0b1,
8121 ftype: Ftype,
8122 decoded24: u5 = 0b11110,
8123 S: bool = false,
8124 decoded30: u1 = 0b0,
8125 M: u1 = 0b0,
8126 };
8127
8128 /// C7.2.143 FNMUL (scalar)
8129 pub const Fnmul = packed struct {
8130 Rd: Register.Encoded,
8131 Rn: Register.Encoded,
8132 decoded10: u2 = 0b10,
8133 opcode: Opcode = .fnmul,
8134 Rm: Register.Encoded,
8135 decoded21: u1 = 0b1,
8136 ftype: Ftype,
8137 decoded24: u5 = 0b11110,
8138 S: bool = false,
8139 decoded30: u1 = 0b0,
8140 M: u1 = 0b0,
8141 };
8142
8143 pub const Opcode = enum(u4) {
8144 fmul = 0b0000,
8145 fdiv = 0b0001,
8146 fadd = 0b0010,
8147 fsub = 0b0011,
8148 fmax = 0b0100,
8149 fmin = 0b0101,
8150 fmaxnm = 0b0110,
8151 fminnm = 0b0111,
8152 fnmul = 0b1000,
8153 _,
8154 };
8155 };
8156
8157 /// Floating-point data-processing (3 source)
8158 pub const FloatDataProcessingThreeSource = packed union {
8159 group: @This().Group,
8160 fmadd: Fmadd,
8161 fmsub: Fmsub,
8162 fnmadd: Fnmadd,
8163 fnmsub: Fnmsub,
8164
8165 pub const Group = packed struct {
8166 Rd: Register.Encoded,
8167 Rn: Register.Encoded,
8168 Ra: Register.Encoded,
8169 o0: AddSubtractOp,
8170 Rm: Register.Encoded,
8171 o1: u1,
8172 ptype: Ftype,
8173 decoded24: u5 = 0b11111,
8174 S: bool,
8175 decoded30: u1 = 0b0,
8176 M: u1,
8177 };
8178
8179 /// C7.2.100 FMADD
8180 pub const Fmadd = packed struct {
8181 Rd: Register.Encoded,
8182 Rn: Register.Encoded,
8183 Ra: Register.Encoded,
8184 o0: AddSubtractOp = .add,
8185 Rm: Register.Encoded,
8186 o1: O1 = .fm,
8187 ftype: Ftype,
8188 decoded24: u5 = 0b11111,
8189 S: bool = false,
8190 decoded30: u1 = 0b0,
8191 M: u1 = 0b0,
8192 };
8193
8194 /// C7.2.133 FMSUB
8195 pub const Fmsub = packed struct {
8196 Rd: Register.Encoded,
8197 Rn: Register.Encoded,
8198 Ra: Register.Encoded,
8199 o0: AddSubtractOp = .sub,
8200 Rm: Register.Encoded,
8201 o1: O1 = .fm,
8202 ftype: Ftype,
8203 decoded24: u5 = 0b11111,
8204 S: bool = false,
8205 decoded30: u1 = 0b0,
8206 M: u1 = 0b0,
8207 };
8208
8209 /// C7.2.141 FNMADD
8210 pub const Fnmadd = packed struct {
8211 Rd: Register.Encoded,
8212 Rn: Register.Encoded,
8213 Ra: Register.Encoded,
8214 o0: AddSubtractOp = .add,
8215 Rm: Register.Encoded,
8216 o1: O1 = .fnm,
8217 ftype: Ftype,
8218 decoded24: u5 = 0b11111,
8219 S: bool = false,
8220 decoded30: u1 = 0b0,
8221 M: u1 = 0b0,
8222 };
8223
8224 /// C7.2.142 FNMSUB
8225 pub const Fnmsub = packed struct {
8226 Rd: Register.Encoded,
8227 Rn: Register.Encoded,
8228 Ra: Register.Encoded,
8229 o0: AddSubtractOp = .sub,
8230 Rm: Register.Encoded,
8231 o1: O1 = .fnm,
8232 ftype: Ftype,
8233 decoded24: u5 = 0b11111,
8234 S: bool = false,
8235 decoded30: u1 = 0b0,
8236 M: u1 = 0b0,
8237 };
8238
8239 pub const O1 = enum(u1) {
8240 fm = 0b0,
8241 fnm = 0b1,
8242 };
8243 };
8244
8245 pub const Q = enum(u1) {
8246 double = 0b0,
8247 quad = 0b1,
8248 };
8249
8250 pub const Size = enum(u2) {
8251 byte = 0b00,
8252 half = 0b01,
8253 single = 0b10,
8254 double = 0b11,
8255
8256 pub fn toVectorSize(s: Size) Register.VectorSize {
8257 return switch (s) {
8258 .byte => .byte,
8259 .half => .half,
8260 .single => .single,
8261 .double => .double,
8262 };
8263 }
8264
8265 pub fn fromVectorSize(vs: Register.VectorSize) Size {
8266 return switch (vs) {
8267 .byte => .byte,
8268 .half => .half,
8269 .single => .single,
8270 .double => .double,
8271 };
8272 }
8273 };
8274
8275 pub const Ftype = enum(u2) {
8276 single = 0b00,
8277 double = 0b01,
8278 quad = 0b10,
8279 half = 0b11,
8280 };
8281 };
8282
8283 pub const AddSubtractOp = enum(u1) {
8284 add = 0b0,
8285 sub = 0b1,
8286 };
8287
8288 pub const LogicalOpc = enum(u2) {
8289 @"and" = 0b00,
8290 orr = 0b01,
8291 eor = 0b10,
8292 ands = 0b11,
8293 };
8294
8295 pub const Decoded = union(enum) {
8296 unallocated,
8297 reserved: Reserved,
8298 sme: Sme,
8299 sve: Sve,
8300 data_processing_immediate: DataProcessingImmediate,
8301 branch_exception_generating_system: BranchExceptionGeneratingSystem,
8302 load_store: LoadStore,
8303 data_processing_register: DataProcessingRegister,
8304 data_processing_vector: DataProcessingVector,
8305 };
8306 pub fn decode(inst: @This()) @This().Decoded {
8307 return switch (inst.group.op1) {
8308 0b0000 => switch (inst.group.op0) {
8309 0b0 => .{ .reserved = inst.reserved },
8310 0b1 => .{ .sme = inst.sme },
8311 },
8312 0b0001 => .unallocated,
8313 0b0010 => .{ .sve = inst.sve },
8314 0b0011 => .unallocated,
8315 0b1000, 0b1001 => .{ .data_processing_immediate = inst.data_processing_immediate },
8316 0b1010, 0b1011 => .{ .branch_exception_generating_system = inst.branch_exception_generating_system },
8317 0b0100, 0b0110, 0b1100, 0b1110 => .{ .load_store = inst.load_store },
8318 0b0101, 0b1101 => .{ .data_processing_register = inst.data_processing_register },
8319 0b0111, 0b1111 => .{ .data_processing_vector = inst.data_processing_vector },
8320 };
8321 }
8322
8323 /// C6.2.1 ADC
8324 pub fn adc(d: Register, n: Register, m: Register) Instruction {
8325 const sf = d.format.integer;
8326 assert(n.format.integer == sf and m.format.integer == sf);
8327 return .{ .data_processing_register = .{ .add_subtract_with_carry = .{
8328 .adc = .{
8329 .Rd = d.alias.encode(.{}),
8330 .Rn = n.alias.encode(.{}),
8331 .Rm = m.alias.encode(.{}),
8332 .sf = sf,
8333 },
8334 } } };
8335 }
8336 /// C6.2.2 ADCS
8337 pub fn adcs(d: Register, n: Register, m: Register) Instruction {
8338 const sf = d.format.integer;
8339 assert(n.format.integer == sf and m.format.integer == sf);
8340 return .{ .data_processing_register = .{ .add_subtract_with_carry = .{
8341 .adcs = .{
8342 .Rd = d.alias.encode(.{}),
8343 .Rn = n.alias.encode(.{}),
8344 .Rm = m.alias.encode(.{}),
8345 .sf = sf,
8346 },
8347 } } };
8348 }
8349 /// C6.2.3 ADD (extended register)
8350 /// C6.2.4 ADD (immediate)
8351 /// C6.2.5 ADD (shifted register)
8352 pub fn add(d: Register, n: Register, form: union(enum) {
8353 extended_register_explicit: struct {
8354 register: Register,
8355 option: DataProcessingRegister.AddSubtractExtendedRegister.Option,
8356 amount: DataProcessingRegister.AddSubtractExtendedRegister.Extend.Amount,
8357 },
8358 extended_register: struct { register: Register, extend: DataProcessingRegister.AddSubtractExtendedRegister.Extend },
8359 immediate: u12,
8360 shifted_immediate: struct { immediate: u12, lsl: DataProcessingImmediate.AddSubtractImmediate.Shift = .@"0" },
8361 register: Register,
8362 shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
8363 shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
8364 }) Instruction {
8365 const sf = d.format.integer;
8366 assert(n.format.integer == sf);
8367 form: switch (form) {
8368 .extended_register_explicit => |extended_register_explicit| {
8369 assert(extended_register_explicit.register.format.integer == extended_register_explicit.option.sf());
8370 return .{ .data_processing_register = .{ .add_subtract_extended_register = .{
8371 .add = .{
8372 .Rd = d.alias.encode(.{ .sp = true }),
8373 .Rn = n.alias.encode(.{ .sp = true }),
8374 .imm3 = switch (extended_register_explicit.amount) {
8375 0...4 => |amount| amount,
8376 else => unreachable,
8377 },
8378 .option = extended_register_explicit.option,
8379 .Rm = extended_register_explicit.register.alias.encode(.{}),
8380 .sf = sf,
8381 },
8382 } } };
8383 },
8384 .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
8385 .register = extended_register.register,
8386 .option = extended_register.extend,
8387 .amount = switch (extended_register.extend) {
8388 .uxtb, .uxth, .uxtw, .uxtx, .sxtb, .sxth, .sxtw, .sxtx => |amount| amount,
8389 },
8390 } },
8391 .immediate => |immediate| continue :form .{ .shifted_immediate = .{ .immediate = immediate } },
8392 .shifted_immediate => |shifted_immediate| {
8393 return .{ .data_processing_immediate = .{ .add_subtract_immediate = .{
8394 .add = .{
8395 .Rd = d.alias.encode(.{ .sp = true }),
8396 .Rn = n.alias.encode(.{ .sp = true }),
8397 .imm12 = shifted_immediate.immediate,
8398 .sh = shifted_immediate.lsl,
8399 .sf = sf,
8400 },
8401 } } };
8402 },
8403 .register => |register| continue :form if (d.alias == .sp or n.alias == .sp or register.alias == .sp)
8404 .{ .extended_register = .{ .register = register, .extend = switch (sf) {
8405 .word => .{ .uxtw = 0 },
8406 .doubleword => .{ .uxtx = 0 },
8407 } } }
8408 else
8409 .{ .shifted_register = .{ .register = register } },
8410 .shifted_register_explicit => |shifted_register_explicit| {
8411 assert(shifted_register_explicit.register.format.integer == sf);
8412 return .{ .data_processing_register = .{ .add_subtract_shifted_register = .{
8413 .add = .{
8414 .Rd = d.alias.encode(.{}),
8415 .Rn = n.alias.encode(.{}),
8416 .imm6 = switch (sf) {
8417 .word => @as(u5, @intCast(shifted_register_explicit.amount)),
8418 .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
8419 },
8420 .Rm = shifted_register_explicit.register.alias.encode(.{}),
8421 .shift = switch (shifted_register_explicit.shift) {
8422 .lsl, .lsr, .asr => |shift| shift,
8423 .ror => unreachable,
8424 },
8425 .sf = sf,
8426 },
8427 } } };
8428 },
8429 .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
8430 .register = shifted_register.register,
8431 .shift = shifted_register.shift,
8432 .amount = switch (shifted_register.shift) {
8433 .lsl, .lsr, .asr => |amount| amount,
8434 .ror => unreachable,
8435 },
8436 } },
8437 }
8438 }
8439 /// C7.2.4 ADDP (scalar)
8440 /// C7.2.5 ADDP (vector)
8441 pub fn addp(d: Register, n: Register, form: union(enum) {
8442 scalar,
8443 vector: Register,
8444 }) Instruction {
8445 switch (form) {
8446 .scalar => {
8447 assert(d.format.scalar == .double and n.format.vector == .@"2d");
8448 return .{ .data_processing_vector = .{ .simd_scalar_pairwise = .{
8449 .addp = .{
8450 .Rd = d.alias.encode(.{ .V = true }),
8451 .Rn = n.alias.encode(.{ .V = true }),
8452 .size = .double,
8453 },
8454 } } };
8455 },
8456 .vector => |m| {
8457 const arrangement = d.format.vector;
8458 assert(arrangement != .@"1d" and n.format.vector == arrangement and m.format.vector == arrangement);
8459 return .{ .data_processing_vector = .{ .simd_three_same = .{
8460 .addp = .{
8461 .Rd = d.alias.encode(.{ .V = true }),
8462 .Rn = n.alias.encode(.{ .V = true }),
8463 .Rm = m.alias.encode(.{ .V = true }),
8464 .size = arrangement.elemSize(),
8465 .Q = arrangement.size(),
8466 },
8467 } } };
8468 },
8469 }
8470 }
8471 /// C6.2.7 ADDS (extended register)
8472 /// C6.2.8 ADDS (immediate)
8473 /// C6.2.9 ADDS (shifted register)
8474 pub fn adds(d: Register, n: Register, form: union(enum) {
8475 extended_register_explicit: struct {
8476 register: Register,
8477 option: DataProcessingRegister.AddSubtractExtendedRegister.Option,
8478 amount: DataProcessingRegister.AddSubtractExtendedRegister.Extend.Amount,
8479 },
8480 extended_register: struct { register: Register, extend: DataProcessingRegister.AddSubtractExtendedRegister.Extend },
8481 immediate: u12,
8482 shifted_immediate: struct { immediate: u12, lsl: DataProcessingImmediate.AddSubtractImmediate.Shift = .@"0" },
8483 register: Register,
8484 shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
8485 shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
8486 }) Instruction {
8487 const sf = d.format.integer;
8488 assert(n.format.integer == sf);
8489 form: switch (form) {
8490 .extended_register_explicit => |extended_register_explicit| {
8491 assert(extended_register_explicit.register.format.integer == extended_register_explicit.option.sf());
8492 return .{ .data_processing_register = .{ .add_subtract_extended_register = .{
8493 .adds = .{
8494 .Rd = d.alias.encode(.{}),
8495 .Rn = n.alias.encode(.{ .sp = true }),
8496 .imm3 = switch (extended_register_explicit.amount) {
8497 0...4 => |amount| amount,
8498 else => unreachable,
8499 },
8500 .option = extended_register_explicit.option,
8501 .Rm = extended_register_explicit.register.alias.encode(.{}),
8502 .sf = sf,
8503 },
8504 } } };
8505 },
8506 .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
8507 .register = extended_register.register,
8508 .option = extended_register.extend,
8509 .amount = switch (extended_register.extend) {
8510 .uxtb, .uxth, .uxtw, .uxtx, .sxtb, .sxth, .sxtw, .sxtx => |amount| amount,
8511 },
8512 } },
8513 .immediate => |immediate| continue :form .{ .shifted_immediate = .{ .immediate = immediate } },
8514 .shifted_immediate => |shifted_immediate| {
8515 return .{ .data_processing_immediate = .{ .add_subtract_immediate = .{
8516 .adds = .{
8517 .Rd = d.alias.encode(.{}),
8518 .Rn = n.alias.encode(.{ .sp = true }),
8519 .imm12 = shifted_immediate.immediate,
8520 .sh = shifted_immediate.lsl,
8521 .sf = sf,
8522 },
8523 } } };
8524 },
8525 .register => |register| continue :form if (d.alias == .sp or n.alias == .sp or register.alias == .sp)
8526 .{ .extended_register = .{ .register = register, .extend = switch (sf) {
8527 .word => .{ .uxtw = 0 },
8528 .doubleword => .{ .uxtx = 0 },
8529 } } }
8530 else
8531 .{ .shifted_register = .{ .register = register } },
8532 .shifted_register_explicit => |shifted_register_explicit| {
8533 assert(shifted_register_explicit.register.format.integer == sf);
8534 return .{ .data_processing_register = .{ .add_subtract_shifted_register = .{
8535 .adds = .{
8536 .Rd = d.alias.encode(.{}),
8537 .Rn = n.alias.encode(.{}),
8538 .imm6 = switch (sf) {
8539 .word => @as(u5, @intCast(shifted_register_explicit.amount)),
8540 .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
8541 },
8542 .Rm = shifted_register_explicit.register.alias.encode(.{}),
8543 .shift = switch (shifted_register_explicit.shift) {
8544 .lsl, .lsr, .asr => |shift| shift,
8545 .ror => unreachable,
8546 },
8547 .sf = sf,
8548 },
8549 } } };
8550 },
8551 .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
8552 .register = shifted_register.register,
8553 .shift = shifted_register.shift,
8554 .amount = switch (shifted_register.shift) {
8555 .lsl, .lsr, .asr => |amount| amount,
8556 .ror => unreachable,
8557 },
8558 } },
8559 }
8560 }
8561 /// C7.2.6 ADDV
8562 pub fn addv(d: Register, n: Register) Instruction {
8563 const arrangement = n.format.vector;
8564 assert(arrangement.len() > 2 and d.format.scalar == arrangement.elemSize().toVectorSize());
8565 return .{ .data_processing_vector = .{ .simd_across_lanes = .{
8566 .addv = .{
8567 .Rd = d.alias.encode(.{ .V = true }),
8568 .Rn = n.alias.encode(.{ .V = true }),
8569 .size = arrangement.elemSize(),
8570 .Q = arrangement.size(),
8571 },
8572 } } };
8573 }
8574 /// C6.2.10 ADR
8575 pub fn adr(d: Register, label: i21) Instruction {
8576 assert(d.format.integer == .doubleword);
8577 return .{ .data_processing_immediate = .{ .pc_relative_addressing = .{
8578 .adr = .{
8579 .Rd = d.alias.encode(.{}),
8580 .immhi = @intCast(label >> 2),
8581 .immlo = @truncate(@as(u21, @bitCast(label))),
8582 },
8583 } } };
8584 }
8585 /// C6.2.11 ADRP
8586 pub fn adrp(d: Register, label: i33) Instruction {
8587 assert(d.format.integer == .doubleword);
8588 const imm: i21 = @intCast(@shrExact(label, 12));
8589 return .{ .data_processing_immediate = .{ .pc_relative_addressing = .{
8590 .adrp = .{
8591 .Rd = d.alias.encode(.{}),
8592 .immhi = @intCast(imm >> 2),
8593 .immlo = @truncate(@as(u21, @bitCast(imm))),
8594 },
8595 } } };
8596 }
8597 /// C6.2.12 AND (immediate)
8598 /// C6.2.13 AND (shifted register)
8599 /// C7.2.11 AND (vector)
8600 pub fn @"and"(d: Register, n: Register, form: union(enum) {
8601 immediate: DataProcessingImmediate.Bitmask,
8602 register: Register,
8603 shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
8604 shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
8605 }) Instruction {
8606 switch (d.format) {
8607 else => unreachable,
8608 .integer => |sf| {
8609 assert(n.format.integer == sf);
8610 form: switch (form) {
8611 .immediate => |bitmask| {
8612 assert(bitmask.validImmediate(sf));
8613 return .{ .data_processing_immediate = .{ .logical_immediate = .{
8614 .@"and" = .{
8615 .Rd = d.alias.encode(.{ .sp = true }),
8616 .Rn = n.alias.encode(.{}),
8617 .imm = bitmask,
8618 .sf = sf,
8619 },
8620 } } };
8621 },
8622 .register => |register| continue :form .{ .shifted_register = .{ .register = register } },
8623 .shifted_register_explicit => |shifted_register_explicit| {
8624 assert(shifted_register_explicit.register.format.integer == sf);
8625 return .{ .data_processing_register = .{ .logical_shifted_register = .{
8626 .@"and" = .{
8627 .Rd = d.alias.encode(.{}),
8628 .Rn = n.alias.encode(.{}),
8629 .imm6 = switch (sf) {
8630 .word => @as(u5, @intCast(shifted_register_explicit.amount)),
8631 .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
8632 },
8633 .Rm = shifted_register_explicit.register.alias.encode(.{}),
8634 .shift = shifted_register_explicit.shift,
8635 .sf = sf,
8636 },
8637 } } };
8638 },
8639 .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
8640 .register = shifted_register.register,
8641 .shift = shifted_register.shift,
8642 .amount = switch (shifted_register.shift) {
8643 .lsl, .lsr, .asr, .ror => |amount| amount,
8644 },
8645 } },
8646 }
8647 },
8648 .vector => |arrangement| {
8649 const m = form.register;
8650 assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement);
8651 return .{ .data_processing_vector = .{ .simd_three_same = .{
8652 .@"and" = .{
8653 .Rd = d.alias.encode(.{ .V = true }),
8654 .Rn = n.alias.encode(.{ .V = true }),
8655 .Rm = m.alias.encode(.{ .V = true }),
8656 .Q = arrangement.size(),
8657 },
8658 } } };
8659 },
8660 }
8661 }
8662 /// C6.2.14 ANDS (immediate)
8663 /// C6.2.15 ANDS (shifted register)
8664 pub fn ands(d: Register, n: Register, form: union(enum) {
8665 immediate: DataProcessingImmediate.Bitmask,
8666 register: Register,
8667 shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
8668 shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
8669 }) Instruction {
8670 const sf = d.format.integer;
8671 assert(n.format.integer == sf);
8672 form: switch (form) {
8673 .immediate => |bitmask| {
8674 assert(bitmask.validImmediate(sf));
8675 return .{ .data_processing_immediate = .{ .logical_immediate = .{
8676 .ands = .{
8677 .Rd = d.alias.encode(.{}),
8678 .Rn = n.alias.encode(.{}),
8679 .imm = bitmask,
8680 .sf = sf,
8681 },
8682 } } };
8683 },
8684 .register => |register| continue :form .{ .shifted_register = .{ .register = register } },
8685 .shifted_register_explicit => |shifted_register_explicit| {
8686 assert(shifted_register_explicit.register.format.integer == sf);
8687 return .{ .data_processing_register = .{ .logical_shifted_register = .{
8688 .ands = .{
8689 .Rd = d.alias.encode(.{}),
8690 .Rn = n.alias.encode(.{}),
8691 .imm6 = switch (sf) {
8692 .word => @as(u5, @intCast(shifted_register_explicit.amount)),
8693 .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
8694 },
8695 .Rm = shifted_register_explicit.register.alias.encode(.{}),
8696 .shift = shifted_register_explicit.shift,
8697 .sf = sf,
8698 },
8699 } } };
8700 },
8701 .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
8702 .register = shifted_register.register,
8703 .shift = shifted_register.shift,
8704 .amount = switch (shifted_register.shift) {
8705 .lsl, .lsr, .asr, .ror => |amount| amount,
8706 },
8707 } },
8708 }
8709 }
8710 /// C6.2.18 ASRV
8711 pub fn asrv(d: Register, n: Register, m: Register) Instruction {
8712 const sf = d.format.integer;
8713 assert(n.format.integer == sf and m.format.integer == sf);
8714 return .{ .data_processing_register = .{ .data_processing_two_source = .{
8715 .asrv = .{
8716 .Rd = d.alias.encode(.{}),
8717 .Rn = n.alias.encode(.{}),
8718 .Rm = m.alias.encode(.{}),
8719 .sf = sf,
8720 },
8721 } } };
8722 }
8723 /// C6.2.25 B
8724 pub fn b(label: i28) Instruction {
8725 return .{ .branch_exception_generating_system = .{ .unconditional_branch_immediate = .{
8726 .b = .{ .imm26 = @intCast(@shrExact(label, 2)) },
8727 } } };
8728 }
8729 /// C6.2.26 B.cond
8730 pub fn @"b."(cond: ConditionCode, label: i21) Instruction {
8731 return .{ .branch_exception_generating_system = .{ .conditional_branch_immediate = .{
8732 .b = .{
8733 .cond = cond,
8734 .imm19 = @intCast(@shrExact(label, 2)),
8735 },
8736 } } };
8737 }
8738 /// C6.2.27 BC.cond
8739 pub fn @"bc."(cond: ConditionCode, label: i21) Instruction {
8740 return .{ .branch_exception_generating_system = .{ .conditional_branch_immediate = .{
8741 .bc = .{
8742 .cond = cond,
8743 .imm19 = @intCast(@shrExact(label, 2)),
8744 },
8745 } } };
8746 }
8747 /// C6.2.30 BFM
8748 pub fn bfm(d: Register, n: Register, bitmask: DataProcessingImmediate.Bitmask) Instruction {
8749 const sf = d.format.integer;
8750 assert(n.format.integer == sf and bitmask.validBitfield(sf));
8751 return .{ .data_processing_immediate = .{ .bitfield = .{
8752 .bfm = .{
8753 .Rd = d.alias.encode(.{}),
8754 .Rn = n.alias.encode(.{}),
8755 .imm = bitmask,
8756 .sf = sf,
8757 },
8758 } } };
8759 }
8760 /// C6.2.32 BIC (shifted register)
8761 /// C7.2.20 BIC (vector, immediate)
8762 /// C7.2.21 BIC (vector, register)
8763 pub fn bic(d: Register, n: Register, form: union(enum) {
8764 shifted_immediate: struct { immediate: u8, lsl: u5 = 0 },
8765 register: Register,
8766 shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
8767 shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
8768 }) Instruction {
8769 switch (d.format) {
8770 else => unreachable,
8771 .integer => |sf| {
8772 assert(n.format.integer == sf);
8773 form: switch (form) {
8774 else => unreachable,
8775 .register => |register| continue :form .{ .shifted_register = .{ .register = register } },
8776 .shifted_register_explicit => |shifted_register_explicit| {
8777 assert(shifted_register_explicit.register.format.integer == sf);
8778 return .{ .data_processing_register = .{ .logical_shifted_register = .{
8779 .bic = .{
8780 .Rd = d.alias.encode(.{}),
8781 .Rn = n.alias.encode(.{}),
8782 .imm6 = switch (sf) {
8783 .word => @as(u5, @intCast(shifted_register_explicit.amount)),
8784 .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
8785 },
8786 .Rm = shifted_register_explicit.register.alias.encode(.{}),
8787 .shift = shifted_register_explicit.shift,
8788 .sf = sf,
8789 },
8790 } } };
8791 },
8792 .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
8793 .register = shifted_register.register,
8794 .shift = shifted_register.shift,
8795 .amount = switch (shifted_register.shift) {
8796 .lsl, .lsr, .asr, .ror => |amount| amount,
8797 },
8798 } },
8799 }
8800 },
8801 .vector => |arrangement| switch (form) {
8802 else => unreachable,
8803 .shifted_immediate => |shifted_immediate| {
8804 assert(n.alias == d.alias and n.format.vector == arrangement);
8805 return .{ .data_processing_vector = .{ .simd_modified_immediate = .{
8806 .bic = .{
8807 .Rd = d.alias.encode(.{ .V = true }),
8808 .imm5 = @truncate(shifted_immediate.immediate >> 0),
8809 .cmode = switch (arrangement) {
8810 else => unreachable,
8811 .@"4h", .@"8h" => @as(u3, 0b100) |
8812 @as(u3, @as(u1, @intCast(@shrExact(shifted_immediate.lsl, 3)))) << 0,
8813 .@"2s", .@"4s" => @as(u3, 0b000) |
8814 @as(u3, @as(u2, @intCast(@shrExact(shifted_immediate.lsl, 3)))) << 0,
8815 },
8816 .imm3 = @intCast(shifted_immediate.immediate >> 5),
8817 .Q = arrangement.size(),
8818 },
8819 } } };
8820 },
8821 .register => |m| {
8822 assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement);
8823 return .{ .data_processing_vector = .{ .simd_three_same = .{
8824 .bic = .{
8825 .Rd = d.alias.encode(.{ .V = true }),
8826 .Rn = n.alias.encode(.{ .V = true }),
8827 .Rm = m.alias.encode(.{ .V = true }),
8828 .Q = arrangement.size(),
8829 },
8830 } } };
8831 },
8832 },
8833 }
8834 }
8835 /// C6.2.33 BICS (shifted register)
8836 pub fn bics(d: Register, n: Register, form: union(enum) {
8837 register: Register,
8838 shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
8839 shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
8840 }) Instruction {
8841 const sf = d.format.integer;
8842 assert(n.format.integer == sf);
8843 form: switch (form) {
8844 .register => |register| continue :form .{ .shifted_register = .{ .register = register } },
8845 .shifted_register_explicit => |shifted_register_explicit| {
8846 assert(shifted_register_explicit.register.format.integer == sf);
8847 return .{ .data_processing_register = .{ .logical_shifted_register = .{
8848 .bics = .{
8849 .Rd = d.alias.encode(.{}),
8850 .Rn = n.alias.encode(.{}),
8851 .imm6 = switch (sf) {
8852 .word => @as(u5, @intCast(shifted_register_explicit.amount)),
8853 .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
8854 },
8855 .Rm = shifted_register_explicit.register.alias.encode(.{}),
8856 .shift = shifted_register_explicit.shift,
8857 .sf = sf,
8858 },
8859 } } };
8860 },
8861 .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
8862 .register = shifted_register.register,
8863 .shift = shifted_register.shift,
8864 .amount = switch (shifted_register.shift) {
8865 .lsl, .lsr, .asr, .ror => |amount| amount,
8866 },
8867 } },
8868 }
8869 }
8870 /// C6.2.34 BL
8871 pub fn bl(label: i28) Instruction {
8872 return .{ .branch_exception_generating_system = .{ .unconditional_branch_immediate = .{
8873 .bl = .{ .imm26 = @intCast(@shrExact(label, 2)) },
8874 } } };
8875 }
8876 /// C6.2.35 BLR
8877 pub fn blr(n: Register) Instruction {
8878 assert(n.format.integer == .doubleword);
8879 return .{ .branch_exception_generating_system = .{ .unconditional_branch_register = .{
8880 .blr = .{ .Rn = n.alias.encode(.{}) },
8881 } } };
8882 }
8883 /// C6.2.37 BR
8884 pub fn br(n: Register) Instruction {
8885 assert(n.format.integer == .doubleword);
8886 return .{ .branch_exception_generating_system = .{ .unconditional_branch_register = .{
8887 .br = .{ .Rn = n.alias.encode(.{}) },
8888 } } };
8889 }
8890 /// C6.2.40 BRK
8891 pub fn brk(imm: u16) Instruction {
8892 return .{ .branch_exception_generating_system = .{ .exception_generating = .{
8893 .brk = .{ .imm16 = imm },
8894 } } };
8895 }
8896 /// C6.2.46 CBNZ
8897 pub fn cbnz(t: Register, label: i21) Instruction {
8898 return .{ .branch_exception_generating_system = .{ .compare_branch_immediate = .{
8899 .cbnz = .{
8900 .Rt = t.alias.encode(.{}),
8901 .imm19 = @intCast(@shrExact(label, 2)),
8902 .sf = t.format.integer,
8903 },
8904 } } };
8905 }
8906 /// C6.2.47 CBZ
8907 pub fn cbz(t: Register, label: i21) Instruction {
8908 return .{ .branch_exception_generating_system = .{ .compare_branch_immediate = .{
8909 .cbz = .{
8910 .Rt = t.alias.encode(.{}),
8911 .imm19 = @intCast(@shrExact(label, 2)),
8912 .sf = t.format.integer,
8913 },
8914 } } };
8915 }
8916 /// C6.2.48 CCMN (immediate)
8917 /// C6.2.49 CCMN (register)
8918 pub fn ccmn(
8919 n: Register,
8920 form: union(enum) { register: Register, immediate: u5 },
8921 nzcv: DataProcessingRegister.Nzcv,
8922 cond: ConditionCode,
8923 ) Instruction {
8924 const sf = n.format.integer;
8925 switch (form) {
8926 .register => |m| {
8927 assert(m.format.integer == sf);
8928 return .{ .data_processing_register = .{ .conditional_compare_register = .{
8929 .ccmn = .{
8930 .nzcv = nzcv,
8931 .Rn = n.alias.encode(.{}),
8932 .cond = cond,
8933 .Rm = m.alias.encode(.{}),
8934 .sf = sf,
8935 },
8936 } } };
8937 },
8938 .immediate => |imm| return .{ .data_processing_register = .{ .conditional_compare_immediate = .{
8939 .ccmn = .{
8940 .nzcv = nzcv,
8941 .Rn = n.alias.encode(.{}),
8942 .cond = cond,
8943 .imm5 = imm,
8944 .sf = sf,
8945 },
8946 } } },
8947 }
8948 }
8949 /// C6.2.50 CCMP (immediate)
8950 /// C6.2.51 CCMP (register)
8951 pub fn ccmp(
8952 n: Register,
8953 form: union(enum) { register: Register, immediate: u5 },
8954 nzcv: DataProcessingRegister.Nzcv,
8955 cond: ConditionCode,
8956 ) Instruction {
8957 const sf = n.format.integer;
8958 switch (form) {
8959 .register => |m| {
8960 assert(m.format.integer == sf);
8961 return .{ .data_processing_register = .{ .conditional_compare_register = .{
8962 .ccmp = .{
8963 .nzcv = nzcv,
8964 .Rn = n.alias.encode(.{}),
8965 .cond = cond,
8966 .Rm = m.alias.encode(.{}),
8967 .sf = sf,
8968 },
8969 } } };
8970 },
8971 .immediate => |imm| return .{ .data_processing_register = .{ .conditional_compare_immediate = .{
8972 .ccmp = .{
8973 .nzcv = nzcv,
8974 .Rn = n.alias.encode(.{}),
8975 .cond = cond,
8976 .imm5 = imm,
8977 .sf = sf,
8978 },
8979 } } },
8980 }
8981 }
8982 /// C6.2.56 CLREX
8983 pub fn clrex(imm: u4) Instruction {
8984 return .{ .branch_exception_generating_system = .{ .barriers = .{
8985 .clrex = .{
8986 .CRm = imm,
8987 },
8988 } } };
8989 }
8990 /// C6.2.58 CLZ
8991 pub fn clz(d: Register, n: Register) Instruction {
8992 const sf = d.format.integer;
8993 assert(n.format.integer == sf);
8994 return .{ .data_processing_register = .{ .data_processing_one_source = .{
8995 .clz = .{
8996 .Rd = d.alias.encode(.{}),
8997 .Rn = n.alias.encode(.{}),
8998 .sf = sf,
8999 },
9000 } } };
9001 }
9002 /// C7.2.38 CNT
9003 pub fn cnt(d: Register, n: Register) Instruction {
9004 const arrangement = d.format.vector;
9005 assert(arrangement.elemSize() == .byte and n.format.vector == arrangement);
9006 return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{
9007 .cnt = .{
9008 .Rd = d.alias.encode(.{ .V = true }),
9009 .Rn = n.alias.encode(.{ .V = true }),
9010 .size = arrangement.elemSize(),
9011 .Q = arrangement.size(),
9012 },
9013 } } };
9014 }
9015 /// C6.2.103 CSEL
9016 pub fn csel(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction {
9017 const sf = d.format.integer;
9018 assert(n.format.integer == sf and m.format.integer == sf);
9019 return .{ .data_processing_register = .{ .conditional_select = .{
9020 .csel = .{
9021 .Rd = d.alias.encode(.{}),
9022 .Rn = n.alias.encode(.{}),
9023 .cond = cond,
9024 .Rm = m.alias.encode(.{}),
9025 .sf = sf,
9026 },
9027 } } };
9028 }
9029 /// C6.2.106 CSINC
9030 pub fn csinc(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction {
9031 const sf = d.format.integer;
9032 assert(n.format.integer == sf and m.format.integer == sf);
9033 return .{ .data_processing_register = .{ .conditional_select = .{
9034 .csinc = .{
9035 .Rd = d.alias.encode(.{}),
9036 .Rn = n.alias.encode(.{}),
9037 .cond = cond,
9038 .Rm = m.alias.encode(.{}),
9039 .sf = sf,
9040 },
9041 } } };
9042 }
9043 /// C6.2.107 CSINV
9044 pub fn csinv(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction {
9045 const sf = d.format.integer;
9046 assert(n.format.integer == sf and m.format.integer == sf);
9047 return .{ .data_processing_register = .{ .conditional_select = .{
9048 .csinv = .{
9049 .Rd = d.alias.encode(.{}),
9050 .Rn = n.alias.encode(.{}),
9051 .cond = cond,
9052 .Rm = m.alias.encode(.{}),
9053 .sf = sf,
9054 },
9055 } } };
9056 }
9057 /// C6.2.108 CSNEG
9058 pub fn csneg(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction {
9059 const sf = d.format.integer;
9060 assert(n.format.integer == sf and m.format.integer == sf);
9061 return .{ .data_processing_register = .{ .conditional_select = .{
9062 .csneg = .{
9063 .Rd = d.alias.encode(.{}),
9064 .Rn = n.alias.encode(.{}),
9065 .cond = cond,
9066 .Rm = m.alias.encode(.{}),
9067 .sf = sf,
9068 },
9069 } } };
9070 }
9071 /// C6.2.110 DCPS1
9072 pub fn dcps1(imm: u16) Instruction {
9073 return .{ .branch_exception_generating_system = .{ .exception_generating = .{
9074 .dcps1 = .{ .imm16 = imm },
9075 } } };
9076 }
9077 /// C6.2.111 DCPS2
9078 pub fn dcps2(imm: u16) Instruction {
9079 return .{ .branch_exception_generating_system = .{ .exception_generating = .{
9080 .dcps2 = .{ .imm16 = imm },
9081 } } };
9082 }
9083 /// C6.2.112 DCPS3
9084 pub fn dcps3(imm: u16) Instruction {
9085 return .{ .branch_exception_generating_system = .{ .exception_generating = .{
9086 .dcps3 = .{ .imm16 = imm },
9087 } } };
9088 }
9089 /// C6.2.116 DSB
9090 pub fn dsb(option: BranchExceptionGeneratingSystem.Barriers.Option) Instruction {
9091 return .{ .branch_exception_generating_system = .{ .barriers = .{
9092 .dsb = .{
9093 .CRm = option,
9094 },
9095 } } };
9096 }
9097 /// C6.2.118 EON (shifted register)
9098 pub fn eon(d: Register, n: Register, form: union(enum) {
9099 register: Register,
9100 shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
9101 shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
9102 }) Instruction {
9103 const sf = d.format.integer;
9104 assert(n.format.integer == sf);
9105 form: switch (form) {
9106 .register => |register| continue :form .{ .shifted_register = .{ .register = register } },
9107 .shifted_register_explicit => |shifted_register_explicit| {
9108 assert(shifted_register_explicit.register.format.integer == sf);
9109 return .{ .data_processing_register = .{ .logical_shifted_register = .{
9110 .eon = .{
9111 .Rd = d.alias.encode(.{}),
9112 .Rn = n.alias.encode(.{}),
9113 .imm6 = switch (sf) {
9114 .word => @as(u5, @intCast(shifted_register_explicit.amount)),
9115 .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
9116 },
9117 .Rm = shifted_register_explicit.register.alias.encode(.{}),
9118 .shift = shifted_register_explicit.shift,
9119 .sf = sf,
9120 },
9121 } } };
9122 },
9123 .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
9124 .register = shifted_register.register,
9125 .shift = shifted_register.shift,
9126 .amount = switch (shifted_register.shift) {
9127 .lsl, .lsr, .asr, .ror => |amount| amount,
9128 },
9129 } },
9130 }
9131 }
9132 /// C6.2.119 EOR (immediate)
9133 /// C6.2.120 EOR (shifted register)
9134 /// C7.2.41 EOR (vector)
9135 pub fn eor(d: Register, n: Register, form: union(enum) {
9136 immediate: DataProcessingImmediate.Bitmask,
9137 register: Register,
9138 shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
9139 shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
9140 }) Instruction {
9141 switch (d.format) {
9142 else => unreachable,
9143 .integer => |sf| {
9144 assert(n.format.integer == sf);
9145 form: switch (form) {
9146 .immediate => |bitmask| {
9147 assert(bitmask.validImmediate(sf));
9148 return .{ .data_processing_immediate = .{ .logical_immediate = .{
9149 .eor = .{
9150 .Rd = d.alias.encode(.{ .sp = true }),
9151 .Rn = n.alias.encode(.{}),
9152 .imm = bitmask,
9153 .sf = sf,
9154 },
9155 } } };
9156 },
9157 .register => |register| continue :form .{ .shifted_register = .{ .register = register } },
9158 .shifted_register_explicit => |shifted_register_explicit| {
9159 assert(shifted_register_explicit.register.format.integer == sf);
9160 return .{ .data_processing_register = .{ .logical_shifted_register = .{
9161 .eor = .{
9162 .Rd = d.alias.encode(.{}),
9163 .Rn = n.alias.encode(.{}),
9164 .imm6 = switch (sf) {
9165 .word => @as(u5, @intCast(shifted_register_explicit.amount)),
9166 .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
9167 },
9168 .Rm = shifted_register_explicit.register.alias.encode(.{}),
9169 .shift = shifted_register_explicit.shift,
9170 .sf = sf,
9171 },
9172 } } };
9173 },
9174 .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
9175 .register = shifted_register.register,
9176 .shift = shifted_register.shift,
9177 .amount = switch (shifted_register.shift) {
9178 .lsl, .lsr, .asr, .ror => |amount| amount,
9179 },
9180 } },
9181 }
9182 },
9183 .vector => |arrangement| {
9184 const m = form.register;
9185 assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement);
9186 return .{ .data_processing_vector = .{ .simd_three_same = .{
9187 .eor = .{
9188 .Rd = d.alias.encode(.{ .V = true }),
9189 .Rn = n.alias.encode(.{ .V = true }),
9190 .Rm = m.alias.encode(.{ .V = true }),
9191 .Q = arrangement.size(),
9192 },
9193 } } };
9194 },
9195 }
9196 }
9197 /// C6.2.124 EXTR
9198 pub fn extr(d: Register, n: Register, m: Register, lsb: u6) Instruction {
9199 const sf = d.format.integer;
9200 assert(n.format.integer == sf and m.format.integer == sf);
9201 return .{ .data_processing_immediate = .{ .extract = .{
9202 .extr = .{
9203 .Rd = d.alias.encode(.{}),
9204 .Rn = n.alias.encode(.{}),
9205 .imms = switch (sf) {
9206 .word => @as(u5, @intCast(lsb)),
9207 .doubleword => @as(u6, @intCast(lsb)),
9208 },
9209 .Rm = m.alias.encode(.{}),
9210 .N = sf,
9211 .sf = sf,
9212 },
9213 } } };
9214 }
9215 /// C7.2.46 FABS (scalar)
9216 pub fn fabs(d: Register, n: Register) Instruction {
9217 const ftype = d.format.scalar;
9218 assert(n.format.scalar == ftype);
9219 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9220 .fabs = .{
9221 .Rd = d.alias.encode(.{ .V = true }),
9222 .Rn = n.alias.encode(.{ .V = true }),
9223 .ftype = switch (ftype) {
9224 else => unreachable,
9225 .single => .single,
9226 .double => .double,
9227 .half => .half,
9228 },
9229 },
9230 } } };
9231 }
9232 /// C7.2.50 FADD (scalar)
9233 pub fn fadd(d: Register, n: Register, m: Register) Instruction {
9234 const ftype = d.format.scalar;
9235 assert(n.format.scalar == ftype and m.format.scalar == ftype);
9236 return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
9237 .fadd = .{
9238 .Rd = d.alias.encode(.{ .V = true }),
9239 .Rn = n.alias.encode(.{ .V = true }),
9240 .Rm = m.alias.encode(.{ .V = true }),
9241 .ftype = switch (ftype) {
9242 else => unreachable,
9243 .single => .single,
9244 .double => .double,
9245 .half => .half,
9246 },
9247 },
9248 } } };
9249 }
9250 /// C7.2.66 FCMP
9251 pub fn fcmp(n: Register, form: union(enum) { register: Register, zero }) Instruction {
9252 const ftype = n.format.scalar;
9253 switch (form) {
9254 .register => |m| {
9255 assert(m.format.scalar == ftype);
9256 return .{ .data_processing_vector = .{ .float_compare = .{
9257 .fcmp = .{
9258 .opc0 = .register,
9259 .Rn = n.alias.encode(.{ .V = true }),
9260 .Rm = m.alias.encode(.{ .V = true }),
9261 .ftype = switch (ftype) {
9262 else => unreachable,
9263 .single => .single,
9264 .double => .double,
9265 .half => .half,
9266 },
9267 },
9268 } } };
9269 },
9270 .zero => return .{ .data_processing_vector = .{ .float_compare = .{
9271 .fcmp = .{
9272 .opc0 = .register,
9273 .Rn = n.alias.encode(.{ .V = true }),
9274 .Rm = @enumFromInt(0b00000),
9275 .ftype = switch (ftype) {
9276 else => unreachable,
9277 .single => .single,
9278 .double => .double,
9279 .half => .half,
9280 },
9281 },
9282 } } },
9283 }
9284 }
9285 /// C7.2.67 FCMPE
9286 pub fn fcmpe(n: Register, form: union(enum) { register: Register, zero }) Instruction {
9287 const ftype = n.format.scalar;
9288 switch (form) {
9289 .register => |m| {
9290 assert(m.format.scalar == ftype);
9291 return .{ .data_processing_vector = .{ .float_compare = .{
9292 .fcmpe = .{
9293 .opc0 = .zero,
9294 .Rn = n.alias.encode(.{ .V = true }),
9295 .Rm = m.alias.encode(.{ .V = true }),
9296 .ftype = switch (ftype) {
9297 else => unreachable,
9298 .single => .single,
9299 .double => .double,
9300 .half => .half,
9301 },
9302 },
9303 } } };
9304 },
9305 .zero => return .{ .data_processing_vector = .{ .float_compare = .{
9306 .fcmpe = .{
9307 .opc0 = .zero,
9308 .Rn = n.alias.encode(.{ .V = true }),
9309 .Rm = @enumFromInt(0b00000),
9310 .ftype = switch (ftype) {
9311 else => unreachable,
9312 .single => .single,
9313 .double => .double,
9314 .half => .half,
9315 },
9316 },
9317 } } },
9318 }
9319 }
9320 /// C7.2.69 FCVT
9321 pub fn fcvt(d: Register, n: Register) Instruction {
9322 assert(d.format.scalar != n.format.scalar);
9323 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9324 .fcvt = .{
9325 .Rd = d.alias.encode(.{ .V = true }),
9326 .Rn = n.alias.encode(.{ .V = true }),
9327 .opc = switch (d.format.scalar) {
9328 else => unreachable,
9329 .single => .single,
9330 .double => .double,
9331 .half => .half,
9332 },
9333 .ftype = switch (n.format.scalar) {
9334 else => unreachable,
9335 .single => .single,
9336 .double => .double,
9337 .half => .half,
9338 },
9339 },
9340 } } };
9341 }
9342 /// C7.2.71 FCVTAS (scalar)
9343 pub fn fcvtas(d: Register, n: Register) Instruction {
9344 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9345 .fcvtas = .{
9346 .Rd = d.alias.encode(.{}),
9347 .Rn = n.alias.encode(.{ .V = true }),
9348 .ftype = switch (n.format.scalar) {
9349 else => unreachable,
9350 .single => .single,
9351 .double => .double,
9352 .half => .half,
9353 },
9354 .sf = d.format.integer,
9355 },
9356 } } };
9357 }
9358 /// C7.2.73 FCVTAU (scalar)
9359 pub fn fcvtau(d: Register, n: Register) Instruction {
9360 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9361 .fcvtau = .{
9362 .Rd = d.alias.encode(.{}),
9363 .Rn = n.alias.encode(.{ .V = true }),
9364 .ftype = switch (n.format.scalar) {
9365 else => unreachable,
9366 .single => .single,
9367 .double => .double,
9368 .half => .half,
9369 },
9370 .sf = d.format.integer,
9371 },
9372 } } };
9373 }
9374 /// C7.2.76 FCVTMS (scalar)
9375 pub fn fcvtms(d: Register, n: Register) Instruction {
9376 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9377 .fcvtms = .{
9378 .Rd = d.alias.encode(.{}),
9379 .Rn = n.alias.encode(.{ .V = true }),
9380 .ftype = switch (n.format.scalar) {
9381 else => unreachable,
9382 .single => .single,
9383 .double => .double,
9384 .half => .half,
9385 },
9386 .sf = d.format.integer,
9387 },
9388 } } };
9389 }
9390 /// C7.2.78 FCVTMU (scalar)
9391 pub fn fcvtmu(d: Register, n: Register) Instruction {
9392 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9393 .fcvtmu = .{
9394 .Rd = d.alias.encode(.{}),
9395 .Rn = n.alias.encode(.{ .V = true }),
9396 .ftype = switch (n.format.scalar) {
9397 else => unreachable,
9398 .single => .single,
9399 .double => .double,
9400 .half => .half,
9401 },
9402 .sf = d.format.integer,
9403 },
9404 } } };
9405 }
9406 /// C7.2.81 FCVTNS (scalar)
9407 pub fn fcvtns(d: Register, n: Register) Instruction {
9408 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9409 .fcvtns = .{
9410 .Rd = d.alias.encode(.{}),
9411 .Rn = n.alias.encode(.{ .V = true }),
9412 .ftype = switch (n.format.scalar) {
9413 else => unreachable,
9414 .single => .single,
9415 .double => .double,
9416 .half => .half,
9417 },
9418 .sf = d.format.integer,
9419 },
9420 } } };
9421 }
9422 /// C7.2.83 FCVTNU (scalar)
9423 pub fn fcvtnu(d: Register, n: Register) Instruction {
9424 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9425 .fcvtnu = .{
9426 .Rd = d.alias.encode(.{}),
9427 .Rn = n.alias.encode(.{ .V = true }),
9428 .ftype = switch (n.format.scalar) {
9429 else => unreachable,
9430 .single => .single,
9431 .double => .double,
9432 .half => .half,
9433 },
9434 .sf = d.format.integer,
9435 },
9436 } } };
9437 }
9438 /// C7.2.85 FCVTPS (scalar)
9439 pub fn fcvtps(d: Register, n: Register) Instruction {
9440 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9441 .fcvtps = .{
9442 .Rd = d.alias.encode(.{}),
9443 .Rn = n.alias.encode(.{ .V = true }),
9444 .ftype = switch (n.format.scalar) {
9445 else => unreachable,
9446 .single => .single,
9447 .double => .double,
9448 .half => .half,
9449 },
9450 .sf = d.format.integer,
9451 },
9452 } } };
9453 }
9454 /// C7.2.87 FCVTPU (scalar)
9455 pub fn fcvtpu(d: Register, n: Register) Instruction {
9456 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9457 .fcvtpu = .{
9458 .Rd = d.alias.encode(.{}),
9459 .Rn = n.alias.encode(.{ .V = true }),
9460 .ftype = switch (n.format.scalar) {
9461 else => unreachable,
9462 .single => .single,
9463 .double => .double,
9464 .half => .half,
9465 },
9466 .sf = d.format.integer,
9467 },
9468 } } };
9469 }
9470 /// C7.2.92 FCVTZS (scalar, integer)
9471 pub fn fcvtzs(d: Register, n: Register) Instruction {
9472 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9473 .fcvtzs = .{
9474 .Rd = d.alias.encode(.{}),
9475 .Rn = n.alias.encode(.{ .V = true }),
9476 .ftype = switch (n.format.scalar) {
9477 else => unreachable,
9478 .single => .single,
9479 .double => .double,
9480 .half => .half,
9481 },
9482 .sf = d.format.integer,
9483 },
9484 } } };
9485 }
9486 /// C7.2.96 FCVTZU (scalar, integer)
9487 pub fn fcvtzu(d: Register, n: Register) Instruction {
9488 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9489 .fcvtzu = .{
9490 .Rd = d.alias.encode(.{}),
9491 .Rn = n.alias.encode(.{ .V = true }),
9492 .ftype = switch (n.format.scalar) {
9493 else => unreachable,
9494 .single => .single,
9495 .double => .double,
9496 .half => .half,
9497 },
9498 .sf = d.format.integer,
9499 },
9500 } } };
9501 }
9502 /// C7.2.98 FDIV (scalar)
9503 pub fn fdiv(d: Register, n: Register, m: Register) Instruction {
9504 const ftype = d.format.scalar;
9505 assert(n.format.scalar == ftype and m.format.scalar == ftype);
9506 return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
9507 .fdiv = .{
9508 .Rd = d.alias.encode(.{ .V = true }),
9509 .Rn = n.alias.encode(.{ .V = true }),
9510 .Rm = m.alias.encode(.{ .V = true }),
9511 .ftype = switch (ftype) {
9512 else => unreachable,
9513 .single => .single,
9514 .double => .double,
9515 .half => .half,
9516 },
9517 },
9518 } } };
9519 }
9520 /// C7.2.99 FJCVTZS
9521 pub fn fjcvtzs(d: Register, n: Register) Instruction {
9522 assert(d.format.integer == .word);
9523 assert(n.format.scalar == .double);
9524 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9525 .fjcvtzs = .{
9526 .Rd = d.alias.encode(.{}),
9527 .Rn = n.alias.encode(.{ .V = true }),
9528 },
9529 } } };
9530 }
9531 /// C7.2.100 FMADD
9532 pub fn fmadd(d: Register, n: Register, m: Register, a: Register) Instruction {
9533 const ftype = d.format.scalar;
9534 assert(n.format.scalar == ftype and m.format.scalar == ftype and a.format.scalar == ftype);
9535 return .{ .data_processing_vector = .{ .float_data_processing_three_source = .{
9536 .fmadd = .{
9537 .Rd = d.alias.encode(.{ .V = true }),
9538 .Rn = n.alias.encode(.{ .V = true }),
9539 .Rm = m.alias.encode(.{ .V = true }),
9540 .Ra = a.alias.encode(.{ .V = true }),
9541 .ftype = switch (ftype) {
9542 else => unreachable,
9543 .single => .single,
9544 .double => .double,
9545 .half => .half,
9546 },
9547 },
9548 } } };
9549 }
9550 /// C7.2.102 FMAX (scalar)
9551 pub fn fmax(d: Register, n: Register, m: Register) Instruction {
9552 const ftype = d.format.scalar;
9553 assert(n.format.scalar == ftype and m.format.scalar == ftype);
9554 return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
9555 .fmax = .{
9556 .Rd = d.alias.encode(.{ .V = true }),
9557 .Rn = n.alias.encode(.{ .V = true }),
9558 .Rm = m.alias.encode(.{ .V = true }),
9559 .ftype = switch (ftype) {
9560 else => unreachable,
9561 .single => .single,
9562 .double => .double,
9563 .half => .half,
9564 },
9565 },
9566 } } };
9567 }
9568 /// C7.2.104 FMAXNM (scalar)
9569 pub fn fmaxnm(d: Register, n: Register, m: Register) Instruction {
9570 const ftype = d.format.scalar;
9571 assert(n.format.scalar == ftype and m.format.scalar == ftype);
9572 return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
9573 .fmaxnm = .{
9574 .Rd = d.alias.encode(.{ .V = true }),
9575 .Rn = n.alias.encode(.{ .V = true }),
9576 .Rm = m.alias.encode(.{ .V = true }),
9577 .ftype = switch (ftype) {
9578 else => unreachable,
9579 .single => .single,
9580 .double => .double,
9581 .half => .half,
9582 },
9583 },
9584 } } };
9585 }
9586 /// C7.2.112 FMIN (scalar)
9587 pub fn fmin(d: Register, n: Register, m: Register) Instruction {
9588 const ftype = d.format.scalar;
9589 assert(n.format.scalar == ftype and m.format.scalar == ftype);
9590 return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
9591 .fmin = .{
9592 .Rd = d.alias.encode(.{ .V = true }),
9593 .Rn = n.alias.encode(.{ .V = true }),
9594 .Rm = m.alias.encode(.{ .V = true }),
9595 .ftype = switch (ftype) {
9596 else => unreachable,
9597 .single => .single,
9598 .double => .double,
9599 .half => .half,
9600 },
9601 },
9602 } } };
9603 }
9604 /// C7.2.114 FMINNM (scalar)
9605 pub fn fminnm(d: Register, n: Register, m: Register) Instruction {
9606 const ftype = d.format.scalar;
9607 assert(n.format.scalar == ftype and m.format.scalar == ftype);
9608 return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
9609 .fminnm = .{
9610 .Rd = d.alias.encode(.{ .V = true }),
9611 .Rn = n.alias.encode(.{ .V = true }),
9612 .Rm = m.alias.encode(.{ .V = true }),
9613 .ftype = switch (ftype) {
9614 else => unreachable,
9615 .single => .single,
9616 .double => .double,
9617 .half => .half,
9618 },
9619 },
9620 } } };
9621 }
9622 /// C7.2.129 FMOV (vector, immediate)
9623 /// C7.2.130 FMOV (register)
9624 /// C7.2.131 FMOV (general)
9625 /// C7.2.132 FMOV (scalar, immediate)
9626 pub fn fmov(d: Register, form: union(enum) { immediate: f16, register: Register }) Instruction {
9627 switch (form) {
9628 .immediate => |immediate| {
9629 const repr: std.math.FloatRepr(f16) = @bitCast(immediate);
9630 const imm: u8 = @bitCast(@as(packed struct(u8) {
9631 mantissa: u4,
9632 exponent: i3,
9633 sign: std.math.Sign,
9634 }, .{
9635 .mantissa = @intCast(@shrExact(repr.mantissa, 6)),
9636 .exponent = @intCast(repr.exponent.unbias() - 1),
9637 .sign = repr.sign,
9638 }));
9639 switch (d.format) {
9640 else => unreachable,
9641 .scalar => |ftype| return .{ .data_processing_vector = .{ .float_immediate = .{
9642 .fmov = .{
9643 .Rd = d.alias.encode(.{ .V = true }),
9644 .imm8 = imm,
9645 .ftype = switch (ftype) {
9646 else => unreachable,
9647 .single => .single,
9648 .double => .double,
9649 .half => .half,
9650 },
9651 },
9652 } } },
9653 .vector => |arrangement| {
9654 assert(arrangement.len() > 1 and arrangement.elemSize() != .byte);
9655 return .{ .data_processing_vector = .{ .simd_modified_immediate = .{
9656 .fmov = .{
9657 .Rd = d.alias.encode(.{ .V = true }),
9658 .imm5 = @truncate(imm >> 0),
9659 .imm3 = @intCast(imm >> 5),
9660 .Q = arrangement.size(),
9661 },
9662 } } };
9663 },
9664 }
9665 },
9666 .register => |n| switch (d.format) {
9667 else => unreachable,
9668 .integer => |sf| switch (n.format) {
9669 else => unreachable,
9670 .scalar => |ftype| {
9671 switch (ftype) {
9672 else => unreachable,
9673 .half => {},
9674 .single => assert(sf == .word),
9675 .double => assert(sf == .doubleword),
9676 }
9677 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9678 .fmov = .{
9679 .Rd = d.alias.encode(.{}),
9680 .Rn = n.alias.encode(.{ .V = true }),
9681 .opcode = .float_to_integer,
9682 .rmode = .@"0",
9683 .ftype = switch (ftype) {
9684 else => unreachable,
9685 .single => .single,
9686 .double => .double,
9687 .half => .half,
9688 },
9689 .sf = sf,
9690 },
9691 } } };
9692 },
9693 .element => |element| return .{ .data_processing_vector = .{ .convert_float_integer = .{
9694 .fmov = .{
9695 .Rd = d.alias.encode(.{}),
9696 .Rn = n.alias.encode(.{ .V = true }),
9697 .opcode = .float_to_integer,
9698 .rmode = switch (element.index) {
9699 else => unreachable,
9700 1 => .@"1",
9701 },
9702 .ftype = switch (element.size) {
9703 else => unreachable,
9704 .double => .quad,
9705 },
9706 .sf = sf,
9707 },
9708 } } },
9709 },
9710 .scalar => |ftype| switch (n.format) {
9711 else => unreachable,
9712 .integer => {
9713 const sf = n.format.integer;
9714 switch (ftype) {
9715 else => unreachable,
9716 .half => {},
9717 .single => assert(sf == .word),
9718 .double => assert(sf == .doubleword),
9719 }
9720 return .{ .data_processing_vector = .{ .convert_float_integer = .{
9721 .fmov = .{
9722 .Rd = d.alias.encode(.{ .V = true }),
9723 .Rn = n.alias.encode(.{}),
9724 .opcode = .integer_to_float,
9725 .rmode = .@"0",
9726 .ftype = switch (ftype) {
9727 else => unreachable,
9728 .single => .single,
9729 .double => .double,
9730 .half => .half,
9731 },
9732 .sf = sf,
9733 },
9734 } } };
9735 },
9736 .scalar => {
9737 assert(n.format.scalar == ftype);
9738 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9739 .fmov = .{
9740 .Rd = d.alias.encode(.{ .V = true }),
9741 .Rn = n.alias.encode(.{ .V = true }),
9742 .ftype = switch (ftype) {
9743 else => unreachable,
9744 .single => .single,
9745 .double => .double,
9746 .half => .half,
9747 },
9748 },
9749 } } };
9750 },
9751 },
9752 .element => |element| switch (n.format) {
9753 else => unreachable,
9754 .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{
9755 .fmov = .{
9756 .Rd = d.alias.encode(.{ .V = true }),
9757 .Rn = n.alias.encode(.{}),
9758 .opcode = .integer_to_float,
9759 .rmode = switch (element.index) {
9760 else => unreachable,
9761 1 => .@"1",
9762 },
9763 .ftype = switch (element.size) {
9764 else => unreachable,
9765 .double => .quad,
9766 },
9767 .sf = sf,
9768 },
9769 } } },
9770 },
9771 },
9772 }
9773 }
9774 /// C7.2.133 FMSUB
9775 pub fn fmsub(d: Register, n: Register, m: Register, a: Register) Instruction {
9776 const ftype = d.format.scalar;
9777 assert(n.format.scalar == ftype and m.format.scalar == ftype and a.format.scalar == ftype);
9778 return .{ .data_processing_vector = .{ .float_data_processing_three_source = .{
9779 .fmsub = .{
9780 .Rd = d.alias.encode(.{ .V = true }),
9781 .Rn = n.alias.encode(.{ .V = true }),
9782 .Rm = m.alias.encode(.{ .V = true }),
9783 .Ra = a.alias.encode(.{ .V = true }),
9784 .ftype = switch (ftype) {
9785 else => unreachable,
9786 .single => .single,
9787 .double => .double,
9788 .half => .half,
9789 },
9790 },
9791 } } };
9792 }
9793 /// C7.2.136 FMUL (scalar)
9794 pub fn fmul(d: Register, n: Register, m: Register) Instruction {
9795 const ftype = d.format.scalar;
9796 assert(n.format.scalar == ftype and m.format.scalar == ftype);
9797 return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
9798 .fmul = .{
9799 .Rd = d.alias.encode(.{ .V = true }),
9800 .Rn = n.alias.encode(.{ .V = true }),
9801 .Rm = m.alias.encode(.{ .V = true }),
9802 .ftype = switch (ftype) {
9803 else => unreachable,
9804 .single => .single,
9805 .double => .double,
9806 .half => .half,
9807 },
9808 },
9809 } } };
9810 }
9811 /// C7.2.140 FNEG (scalar)
9812 pub fn fneg(d: Register, n: Register) Instruction {
9813 const ftype = d.format.scalar;
9814 assert(n.format.scalar == ftype);
9815 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9816 .fneg = .{
9817 .Rd = d.alias.encode(.{ .V = true }),
9818 .Rn = n.alias.encode(.{ .V = true }),
9819 .ftype = switch (ftype) {
9820 else => unreachable,
9821 .single => .single,
9822 .double => .double,
9823 .half => .half,
9824 },
9825 },
9826 } } };
9827 }
9828 /// C7.2.141 FNMADD
9829 pub fn fnmadd(d: Register, n: Register, m: Register, a: Register) Instruction {
9830 const ftype = d.format.scalar;
9831 assert(n.format.scalar == ftype and m.format.scalar == ftype and a.format.scalar == ftype);
9832 return .{ .data_processing_vector = .{ .float_data_processing_three_source = .{
9833 .fnmadd = .{
9834 .Rd = d.alias.encode(.{ .V = true }),
9835 .Rn = n.alias.encode(.{ .V = true }),
9836 .Rm = m.alias.encode(.{ .V = true }),
9837 .Ra = a.alias.encode(.{ .V = true }),
9838 .ftype = switch (ftype) {
9839 else => unreachable,
9840 .single => .single,
9841 .double => .double,
9842 .half => .half,
9843 },
9844 },
9845 } } };
9846 }
9847 /// C7.2.142 FNMSUB
9848 pub fn fnmsub(d: Register, n: Register, m: Register, a: Register) Instruction {
9849 const ftype = d.format.scalar;
9850 assert(n.format.scalar == ftype and m.format.scalar == ftype and a.format.scalar == ftype);
9851 return .{ .data_processing_vector = .{ .float_data_processing_three_source = .{
9852 .fnmsub = .{
9853 .Rd = d.alias.encode(.{ .V = true }),
9854 .Rn = n.alias.encode(.{ .V = true }),
9855 .Rm = m.alias.encode(.{ .V = true }),
9856 .Ra = a.alias.encode(.{ .V = true }),
9857 .ftype = switch (ftype) {
9858 else => unreachable,
9859 .single => .single,
9860 .double => .double,
9861 .half => .half,
9862 },
9863 },
9864 } } };
9865 }
9866 /// C7.2.143 FNMUL (scalar)
9867 pub fn fnmul(d: Register, n: Register, m: Register) Instruction {
9868 const ftype = d.format.scalar;
9869 assert(n.format.scalar == ftype and m.format.scalar == ftype);
9870 return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
9871 .fnmul = .{
9872 .Rd = d.alias.encode(.{ .V = true }),
9873 .Rn = n.alias.encode(.{ .V = true }),
9874 .Rm = m.alias.encode(.{ .V = true }),
9875 .ftype = switch (ftype) {
9876 else => unreachable,
9877 .single => .single,
9878 .double => .double,
9879 .half => .half,
9880 },
9881 },
9882 } } };
9883 }
9884 /// C7.2.156 FRINTA (scalar)
9885 pub fn frinta(d: Register, n: Register) Instruction {
9886 const ftype = d.format.scalar;
9887 assert(n.format.scalar == ftype);
9888 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9889 .frinta = .{
9890 .Rd = d.alias.encode(.{ .V = true }),
9891 .Rn = n.alias.encode(.{ .V = true }),
9892 .ftype = switch (ftype) {
9893 else => unreachable,
9894 .single => .single,
9895 .double => .double,
9896 .half => .half,
9897 },
9898 },
9899 } } };
9900 }
9901 /// C7.2.158 FRINTI (scalar)
9902 pub fn frinti(d: Register, n: Register) Instruction {
9903 const ftype = d.format.scalar;
9904 assert(n.format.scalar == ftype);
9905 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9906 .frinti = .{
9907 .Rd = d.alias.encode(.{ .V = true }),
9908 .Rn = n.alias.encode(.{ .V = true }),
9909 .ftype = switch (ftype) {
9910 else => unreachable,
9911 .single => .single,
9912 .double => .double,
9913 .half => .half,
9914 },
9915 },
9916 } } };
9917 }
9918 /// C7.2.160 FRINTM (scalar)
9919 pub fn frintm(d: Register, n: Register) Instruction {
9920 const ftype = d.format.scalar;
9921 assert(n.format.scalar == ftype);
9922 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9923 .frintm = .{
9924 .Rd = d.alias.encode(.{ .V = true }),
9925 .Rn = n.alias.encode(.{ .V = true }),
9926 .ftype = switch (ftype) {
9927 else => unreachable,
9928 .single => .single,
9929 .double => .double,
9930 .half => .half,
9931 },
9932 },
9933 } } };
9934 }
9935 /// C7.2.162 FRINTN (scalar)
9936 pub fn frintn(d: Register, n: Register) Instruction {
9937 const ftype = d.format.scalar;
9938 assert(n.format.scalar == ftype);
9939 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9940 .frintn = .{
9941 .Rd = d.alias.encode(.{ .V = true }),
9942 .Rn = n.alias.encode(.{ .V = true }),
9943 .ftype = switch (ftype) {
9944 else => unreachable,
9945 .single => .single,
9946 .double => .double,
9947 .half => .half,
9948 },
9949 },
9950 } } };
9951 }
9952 /// C7.2.164 FRINTP (scalar)
9953 pub fn frintp(d: Register, n: Register) Instruction {
9954 const ftype = d.format.scalar;
9955 assert(n.format.scalar == ftype);
9956 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9957 .frintp = .{
9958 .Rd = d.alias.encode(.{ .V = true }),
9959 .Rn = n.alias.encode(.{ .V = true }),
9960 .ftype = switch (ftype) {
9961 else => unreachable,
9962 .single => .single,
9963 .double => .double,
9964 .half => .half,
9965 },
9966 },
9967 } } };
9968 }
9969 /// C7.2.166 FRINTX (scalar)
9970 pub fn frintx(d: Register, n: Register) Instruction {
9971 const ftype = d.format.scalar;
9972 assert(n.format.scalar == ftype);
9973 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9974 .frintx = .{
9975 .Rd = d.alias.encode(.{ .V = true }),
9976 .Rn = n.alias.encode(.{ .V = true }),
9977 .ftype = switch (ftype) {
9978 else => unreachable,
9979 .single => .single,
9980 .double => .double,
9981 .half => .half,
9982 },
9983 },
9984 } } };
9985 }
9986 /// C7.2.168 FRINTZ (scalar)
9987 pub fn frintz(d: Register, n: Register) Instruction {
9988 const ftype = d.format.scalar;
9989 assert(n.format.scalar == ftype);
9990 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
9991 .frintz = .{
9992 .Rd = d.alias.encode(.{ .V = true }),
9993 .Rn = n.alias.encode(.{ .V = true }),
9994 .ftype = switch (ftype) {
9995 else => unreachable,
9996 .single => .single,
9997 .double => .double,
9998 .half => .half,
9999 },
10000 },
10001 } } };
10002 }
10003 /// C7.2.172 FSQRT (scalar)
10004 pub fn fsqrt(d: Register, n: Register) Instruction {
10005 const ftype = d.format.scalar;
10006 assert(n.format.scalar == ftype);
10007 return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{
10008 .fsqrt = .{
10009 .Rd = d.alias.encode(.{ .V = true }),
10010 .Rn = n.alias.encode(.{ .V = true }),
10011 .ftype = switch (ftype) {
10012 else => unreachable,
10013 .single => .single,
10014 .double => .double,
10015 .half => .half,
10016 },
10017 },
10018 } } };
10019 }
10020 /// C7.2.174 FSUB (scalar)
10021 pub fn fsub(d: Register, n: Register, m: Register) Instruction {
10022 const ftype = d.format.scalar;
10023 assert(n.format.scalar == ftype and m.format.scalar == ftype);
10024 return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{
10025 .fsub = .{
10026 .Rd = d.alias.encode(.{ .V = true }),
10027 .Rn = n.alias.encode(.{ .V = true }),
10028 .Rm = m.alias.encode(.{ .V = true }),
10029 .ftype = switch (ftype) {
10030 else => unreachable,
10031 .single => .single,
10032 .double => .double,
10033 .half => .half,
10034 },
10035 },
10036 } } };
10037 }
10038 /// C6.2.126 HINT
10039 pub fn hint(imm: u7) Instruction {
10040 return .{ .branch_exception_generating_system = .{ .hints = .{
10041 .group = .{
10042 .op2 = @truncate(imm >> 0),
10043 .CRm = @intCast(imm >> 3),
10044 },
10045 } } };
10046 }
10047 /// C6.2.127 HLT
10048 pub fn hlt(imm: u16) Instruction {
10049 return .{ .branch_exception_generating_system = .{ .exception_generating = .{
10050 .hlt = .{ .imm16 = imm },
10051 } } };
10052 }
10053 /// C6.2.128 HVC
10054 pub fn hvc(imm: u16) Instruction {
10055 return .{ .branch_exception_generating_system = .{ .exception_generating = .{
10056 .hvc = .{ .imm16 = imm },
10057 } } };
10058 }
10059 /// C6.2.131 ISB
10060 pub fn isb(option: BranchExceptionGeneratingSystem.Barriers.Option) Instruction {
10061 return .{ .branch_exception_generating_system = .{ .barriers = .{
10062 .isb = .{
10063 .CRm = option,
10064 },
10065 } } };
10066 }
10067 /// C6.2.164 LDP
10068 /// C7.2.190 LDP (SIMD&FP)
10069 pub fn ldp(t1: Register, t2: Register, form: union(enum) {
10070 post_index: struct { base: Register, index: i10 },
10071 pre_index: struct { base: Register, index: i10 },
10072 signed_offset: struct { base: Register, offset: i10 = 0 },
10073 base: Register,
10074 }) Instruction {
10075 switch (t1.format) {
10076 else => unreachable,
10077 .integer => |sf| {
10078 assert(t2.format.integer == sf);
10079 form: switch (form) {
10080 .post_index => |post_index| {
10081 assert(post_index.base.format.integer == .doubleword);
10082 return .{ .load_store = .{ .register_pair_post_indexed = .{ .integer = .{
10083 .ldp = .{
10084 .Rt = t1.alias.encode(.{}),
10085 .Rn = post_index.base.alias.encode(.{ .sp = true }),
10086 .Rt2 = t2.alias.encode(.{}),
10087 .imm7 = @intCast(@shrExact(post_index.index, @as(u2, 2) + @intFromEnum(sf))),
10088 .sf = sf,
10089 },
10090 } } } };
10091 },
10092 .pre_index => |pre_index| {
10093 assert(pre_index.base.format.integer == .doubleword);
10094 return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{
10095 .ldp = .{
10096 .Rt = t1.alias.encode(.{}),
10097 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
10098 .Rt2 = t2.alias.encode(.{}),
10099 .imm7 = @intCast(@shrExact(pre_index.index, @as(u2, 2) + @intFromEnum(sf))),
10100 .sf = sf,
10101 },
10102 } } } };
10103 },
10104 .signed_offset => |signed_offset| {
10105 assert(signed_offset.base.format.integer == .doubleword);
10106 return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{
10107 .ldp = .{
10108 .Rt = t1.alias.encode(.{}),
10109 .Rn = signed_offset.base.alias.encode(.{ .sp = true }),
10110 .Rt2 = t2.alias.encode(.{}),
10111 .imm7 = @intCast(@shrExact(signed_offset.offset, @as(u2, 2) + @intFromEnum(sf))),
10112 .sf = sf,
10113 },
10114 } } } };
10115 },
10116 .base => |base| continue :form .{ .signed_offset = .{ .base = base } },
10117 }
10118 },
10119 .scalar => |vs| {
10120 assert(t2.format.scalar == vs);
10121 form: switch (form) {
10122 .post_index => |post_index| {
10123 assert(post_index.base.format.integer == .doubleword);
10124 return .{ .load_store = .{ .register_pair_post_indexed = .{ .vector = .{
10125 .ldp = .{
10126 .Rt = t1.alias.encode(.{ .V = true }),
10127 .Rn = post_index.base.alias.encode(.{ .sp = true }),
10128 .Rt2 = t2.alias.encode(.{ .V = true }),
10129 .imm7 = @intCast(@shrExact(post_index.index, @intFromEnum(vs))),
10130 .opc = .encode(vs),
10131 },
10132 } } } };
10133 },
10134 .signed_offset => |signed_offset| {
10135 assert(signed_offset.base.format.integer == .doubleword);
10136 return .{ .load_store = .{ .register_pair_offset = .{ .vector = .{
10137 .ldp = .{
10138 .Rt = t1.alias.encode(.{ .V = true }),
10139 .Rn = signed_offset.base.alias.encode(.{ .sp = true }),
10140 .Rt2 = t2.alias.encode(.{ .V = true }),
10141 .imm7 = @intCast(@shrExact(signed_offset.offset, @intFromEnum(vs))),
10142 .opc = .encode(vs),
10143 },
10144 } } } };
10145 },
10146 .pre_index => |pre_index| {
10147 assert(pre_index.base.format.integer == .doubleword);
10148 return .{ .load_store = .{ .register_pair_pre_indexed = .{ .vector = .{
10149 .ldp = .{
10150 .Rt = t1.alias.encode(.{ .V = true }),
10151 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
10152 .Rt2 = t2.alias.encode(.{ .V = true }),
10153 .imm7 = @intCast(@shrExact(pre_index.index, @intFromEnum(vs))),
10154 .opc = .encode(vs),
10155 },
10156 } } } };
10157 },
10158 .base => |base| continue :form .{ .signed_offset = .{ .base = base } },
10159 }
10160 },
10161 }
10162 }
10163 /// C6.2.166 LDR (immediate)
10164 /// C6.2.167 LDR (literal)
10165 /// C6.2.168 LDR (register)
10166 /// C7.2.191 LDR (immediate, SIMD&FP)
10167 /// C7.2.192 LDR (literal, SIMD&FP)
10168 /// C7.2.193 LDR (register, SIMD&FP)
10169 pub fn ldr(t: Register, form: union(enum) {
10170 post_index: struct { base: Register, index: i9 },
10171 pre_index: struct { base: Register, index: i9 },
10172 unsigned_offset: struct { base: Register, offset: u16 = 0 },
10173 base: Register,
10174 literal: i21,
10175 extended_register_explicit: struct {
10176 base: Register,
10177 index: Register,
10178 option: LoadStore.RegisterRegisterOffset.Option,
10179 amount: LoadStore.RegisterRegisterOffset.Extend.Amount,
10180 },
10181 extended_register: struct {
10182 base: Register,
10183 index: Register,
10184 extend: LoadStore.RegisterRegisterOffset.Extend,
10185 },
10186 }) Instruction {
10187 switch (t.format) {
10188 else => unreachable,
10189 .integer => |sf| form: switch (form) {
10190 .post_index => |post_index| {
10191 assert(post_index.base.format.integer == .doubleword);
10192 return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{
10193 .ldr = .{
10194 .Rt = t.alias.encode(.{}),
10195 .Rn = post_index.base.alias.encode(.{ .sp = true }),
10196 .imm9 = post_index.index,
10197 .sf = sf,
10198 },
10199 } } } };
10200 },
10201 .pre_index => |pre_index| {
10202 assert(pre_index.base.format.integer == .doubleword);
10203 return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
10204 .ldr = .{
10205 .Rt = t.alias.encode(.{}),
10206 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
10207 .imm9 = pre_index.index,
10208 .sf = sf,
10209 },
10210 } } } };
10211 },
10212 .unsigned_offset => |unsigned_offset| {
10213 assert(unsigned_offset.base.format.integer == .doubleword);
10214 return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
10215 .ldr = .{
10216 .Rt = t.alias.encode(.{}),
10217 .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
10218 .imm12 = @intCast(@shrExact(unsigned_offset.offset, @as(u2, 2) + @intFromEnum(sf))),
10219 .sf = sf,
10220 },
10221 } } } };
10222 },
10223 .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
10224 .literal => |offset| return .{ .load_store = .{ .register_literal = .{ .integer = .{
10225 .ldr = .{
10226 .Rt = t.alias.encode(.{}),
10227 .imm19 = @intCast(@shrExact(offset, 2)),
10228 .sf = sf,
10229 },
10230 } } } },
10231 .extended_register_explicit => |extended_register_explicit| {
10232 assert(extended_register_explicit.base.format.integer == .doubleword and
10233 extended_register_explicit.index.format.integer == extended_register_explicit.option.sf());
10234 return .{ .load_store = .{ .register_register_offset = .{ .integer = .{
10235 .ldr = .{
10236 .Rt = t.alias.encode(.{}),
10237 .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }),
10238 .S = switch (sf) {
10239 .word => switch (extended_register_explicit.amount) {
10240 0 => false,
10241 2 => true,
10242 else => unreachable,
10243 },
10244 .doubleword => switch (extended_register_explicit.amount) {
10245 0 => false,
10246 3 => true,
10247 else => unreachable,
10248 },
10249 },
10250 .option = extended_register_explicit.option,
10251 .Rm = extended_register_explicit.index.alias.encode(.{}),
10252 .sf = sf,
10253 },
10254 } } } };
10255 },
10256 .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
10257 .base = extended_register.base,
10258 .index = extended_register.index,
10259 .option = extended_register.extend,
10260 .amount = switch (extended_register.extend) {
10261 .uxtw, .lsl, .sxtw, .sxtx => |amount| amount,
10262 },
10263 } },
10264 },
10265 .scalar => |vs| form: switch (form) {
10266 .post_index => |post_index| {
10267 assert(post_index.base.format.integer == .doubleword);
10268 return .{ .load_store = .{ .register_immediate_post_indexed = .{ .vector = .{
10269 .ldr = .{
10270 .Rt = t.alias.encode(.{ .V = true }),
10271 .Rn = post_index.base.alias.encode(.{ .sp = true }),
10272 .imm9 = post_index.index,
10273 .opc1 = .encode(vs),
10274 .size = .encode(vs),
10275 },
10276 } } } };
10277 },
10278 .pre_index => |pre_index| {
10279 assert(pre_index.base.format.integer == .doubleword);
10280 return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .vector = .{
10281 .ldr = .{
10282 .Rt = t.alias.encode(.{ .V = true }),
10283 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
10284 .imm9 = pre_index.index,
10285 .opc1 = .encode(vs),
10286 .size = .encode(vs),
10287 },
10288 } } } };
10289 },
10290 .unsigned_offset => |unsigned_offset| {
10291 assert(unsigned_offset.base.format.integer == .doubleword);
10292 return .{ .load_store = .{ .register_unsigned_immediate = .{ .vector = .{
10293 .ldr = .{
10294 .Rt = t.alias.encode(.{ .V = true }),
10295 .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
10296 .imm12 = @intCast(@shrExact(unsigned_offset.offset, @intFromEnum(vs))),
10297 .opc1 = .encode(vs),
10298 .size = .encode(vs),
10299 },
10300 } } } };
10301 },
10302 .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
10303 .literal => |offset| return .{ .load_store = .{ .register_literal = .{ .vector = .{
10304 .ldr = .{
10305 .Rt = t.alias.encode(.{ .V = true }),
10306 .imm19 = @intCast(@shrExact(offset, 2)),
10307 .opc = .encode(vs),
10308 },
10309 } } } },
10310 .extended_register_explicit => |extended_register_explicit| {
10311 assert(extended_register_explicit.base.format.integer == .doubleword and
10312 extended_register_explicit.index.format.integer == extended_register_explicit.option.sf());
10313 return .{ .load_store = .{ .register_register_offset = .{ .vector = .{
10314 .ldr = .{
10315 .Rt = t.alias.encode(.{ .V = true }),
10316 .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }),
10317 .S = switch (vs) {
10318 else => unreachable,
10319 .byte => switch (extended_register_explicit.amount) {
10320 0 => false,
10321 else => unreachable,
10322 },
10323 .half => switch (extended_register_explicit.amount) {
10324 0 => false,
10325 1 => true,
10326 else => unreachable,
10327 },
10328 .single => switch (extended_register_explicit.amount) {
10329 0 => false,
10330 2 => true,
10331 else => unreachable,
10332 },
10333 .double => switch (extended_register_explicit.amount) {
10334 0 => false,
10335 3 => true,
10336 else => unreachable,
10337 },
10338 .quad => switch (extended_register_explicit.amount) {
10339 0 => false,
10340 4 => true,
10341 else => unreachable,
10342 },
10343 },
10344 .option = extended_register_explicit.option,
10345 .Rm = extended_register_explicit.index.alias.encode(.{}),
10346 .opc1 = .encode(vs),
10347 .size = .encode(vs),
10348 },
10349 } } } };
10350 },
10351 .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
10352 .base = extended_register.base,
10353 .index = extended_register.index,
10354 .option = extended_register.extend,
10355 .amount = switch (extended_register.extend) {
10356 .uxtw, .lsl, .sxtw, .sxtx => |amount| amount,
10357 },
10358 } },
10359 },
10360 }
10361 }
10362 /// C6.2.170 LDRB (immediate)
10363 /// C6.2.171 LDRB (register)
10364 pub fn ldrb(t: Register, form: union(enum) {
10365 post_index: struct { base: Register, index: i9 },
10366 pre_index: struct { base: Register, index: i9 },
10367 unsigned_offset: struct { base: Register, offset: u12 = 0 },
10368 base: Register,
10369 extended_register_explicit: struct {
10370 base: Register,
10371 index: Register,
10372 option: LoadStore.RegisterRegisterOffset.Option,
10373 amount: LoadStore.RegisterRegisterOffset.Extend.Amount,
10374 },
10375 extended_register: struct {
10376 base: Register,
10377 index: Register,
10378 extend: LoadStore.RegisterRegisterOffset.Extend,
10379 },
10380 }) Instruction {
10381 assert(t.format.integer == .word);
10382 form: switch (form) {
10383 .post_index => |post_index| {
10384 assert(post_index.base.format.integer == .doubleword);
10385 return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{
10386 .ldrb = .{
10387 .Rt = t.alias.encode(.{}),
10388 .Rn = post_index.base.alias.encode(.{ .sp = true }),
10389 .imm9 = post_index.index,
10390 },
10391 } } } };
10392 },
10393 .pre_index => |pre_index| {
10394 assert(pre_index.base.format.integer == .doubleword);
10395 return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
10396 .ldrb = .{
10397 .Rt = t.alias.encode(.{}),
10398 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
10399 .imm9 = pre_index.index,
10400 },
10401 } } } };
10402 },
10403 .unsigned_offset => |unsigned_offset| {
10404 assert(unsigned_offset.base.format.integer == .doubleword);
10405 return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
10406 .ldrb = .{
10407 .Rt = t.alias.encode(.{}),
10408 .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
10409 .imm12 = unsigned_offset.offset,
10410 },
10411 } } } };
10412 },
10413 .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
10414 .extended_register_explicit => |extended_register_explicit| {
10415 assert(extended_register_explicit.base.format.integer == .doubleword and
10416 extended_register_explicit.index.format.integer == extended_register_explicit.option.sf());
10417 return .{ .load_store = .{ .register_register_offset = .{ .integer = .{
10418 .ldrb = .{
10419 .Rt = t.alias.encode(.{}),
10420 .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }),
10421 .S = switch (extended_register_explicit.amount) {
10422 0 => false,
10423 else => unreachable,
10424 },
10425 .option = extended_register_explicit.option,
10426 .Rm = extended_register_explicit.index.alias.encode(.{}),
10427 },
10428 } } } };
10429 },
10430 .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
10431 .base = extended_register.base,
10432 .index = extended_register.index,
10433 .option = extended_register.extend,
10434 .amount = switch (extended_register.extend) {
10435 .uxtw, .lsl, .sxtw, .sxtx => |amount| amount,
10436 },
10437 } },
10438 }
10439 }
10440 /// C6.2.172 LDRH (immediate)
10441 /// C6.2.173 LDRH (register)
10442 pub fn ldrh(t: Register, form: union(enum) {
10443 post_index: struct { base: Register, index: i9 },
10444 pre_index: struct { base: Register, index: i9 },
10445 unsigned_offset: struct { base: Register, offset: u13 = 0 },
10446 base: Register,
10447 extended_register_explicit: struct {
10448 base: Register,
10449 index: Register,
10450 option: LoadStore.RegisterRegisterOffset.Option,
10451 amount: LoadStore.RegisterRegisterOffset.Extend.Amount,
10452 },
10453 extended_register: struct {
10454 base: Register,
10455 index: Register,
10456 extend: LoadStore.RegisterRegisterOffset.Extend,
10457 },
10458 }) Instruction {
10459 assert(t.format.integer == .word);
10460 form: switch (form) {
10461 .post_index => |post_index| {
10462 assert(post_index.base.format.integer == .doubleword);
10463 return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{
10464 .ldrh = .{
10465 .Rt = t.alias.encode(.{}),
10466 .Rn = post_index.base.alias.encode(.{ .sp = true }),
10467 .imm9 = post_index.index,
10468 },
10469 } } } };
10470 },
10471 .pre_index => |pre_index| {
10472 assert(pre_index.base.format.integer == .doubleword);
10473 return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
10474 .ldrh = .{
10475 .Rt = t.alias.encode(.{}),
10476 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
10477 .imm9 = pre_index.index,
10478 },
10479 } } } };
10480 },
10481 .unsigned_offset => |unsigned_offset| {
10482 assert(unsigned_offset.base.format.integer == .doubleword);
10483 return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
10484 .ldrh = .{
10485 .Rt = t.alias.encode(.{}),
10486 .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
10487 .imm12 = @intCast(@shrExact(unsigned_offset.offset, 1)),
10488 },
10489 } } } };
10490 },
10491 .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
10492 .extended_register_explicit => |extended_register_explicit| {
10493 assert(extended_register_explicit.base.format.integer == .doubleword and
10494 extended_register_explicit.index.format.integer == extended_register_explicit.option.sf());
10495 return .{ .load_store = .{ .register_register_offset = .{ .integer = .{
10496 .ldrh = .{
10497 .Rt = t.alias.encode(.{}),
10498 .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }),
10499 .S = switch (extended_register_explicit.amount) {
10500 0 => false,
10501 1 => true,
10502 else => unreachable,
10503 },
10504 .option = extended_register_explicit.option,
10505 .Rm = extended_register_explicit.index.alias.encode(.{}),
10506 },
10507 } } } };
10508 },
10509 .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
10510 .base = extended_register.base,
10511 .index = extended_register.index,
10512 .option = extended_register.extend,
10513 .amount = switch (extended_register.extend) {
10514 .uxtw, .lsl, .sxtw, .sxtx => |amount| amount,
10515 },
10516 } },
10517 }
10518 }
10519 /// C6.2.174 LDRSB (immediate)
10520 /// C6.2.175 LDRSB (register)
10521 pub fn ldrsb(t: Register, form: union(enum) {
10522 post_index: struct { base: Register, index: i9 },
10523 pre_index: struct { base: Register, index: i9 },
10524 unsigned_offset: struct { base: Register, offset: u12 = 0 },
10525 base: Register,
10526 extended_register_explicit: struct {
10527 base: Register,
10528 index: Register,
10529 option: LoadStore.RegisterRegisterOffset.Option,
10530 amount: LoadStore.RegisterRegisterOffset.Extend.Amount,
10531 },
10532 extended_register: struct {
10533 base: Register,
10534 index: Register,
10535 extend: LoadStore.RegisterRegisterOffset.Extend,
10536 },
10537 }) Instruction {
10538 const sf = t.format.integer;
10539 form: switch (form) {
10540 .post_index => |post_index| {
10541 assert(post_index.base.format.integer == .doubleword);
10542 return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{
10543 .ldrsb = .{
10544 .Rt = t.alias.encode(.{}),
10545 .Rn = post_index.base.alias.encode(.{ .sp = true }),
10546 .imm9 = post_index.index,
10547 .opc0 = ~@intFromEnum(sf),
10548 },
10549 } } } };
10550 },
10551 .pre_index => |pre_index| {
10552 assert(pre_index.base.format.integer == .doubleword);
10553 return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
10554 .ldrsb = .{
10555 .Rt = t.alias.encode(.{}),
10556 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
10557 .imm9 = pre_index.index,
10558 .opc0 = ~@intFromEnum(sf),
10559 },
10560 } } } };
10561 },
10562 .unsigned_offset => |unsigned_offset| {
10563 assert(unsigned_offset.base.format.integer == .doubleword);
10564 return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
10565 .ldrsb = .{
10566 .Rt = t.alias.encode(.{}),
10567 .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
10568 .imm12 = unsigned_offset.offset,
10569 .opc0 = ~@intFromEnum(sf),
10570 },
10571 } } } };
10572 },
10573 .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
10574 .extended_register_explicit => |extended_register_explicit| {
10575 assert(extended_register_explicit.base.format.integer == .doubleword and
10576 extended_register_explicit.index.format.integer == extended_register_explicit.option.sf());
10577 return .{ .load_store = .{ .register_register_offset = .{ .integer = .{
10578 .ldrsb = .{
10579 .Rt = t.alias.encode(.{}),
10580 .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }),
10581 .S = switch (extended_register_explicit.amount) {
10582 0 => false,
10583 else => unreachable,
10584 },
10585 .option = extended_register_explicit.option,
10586 .Rm = extended_register_explicit.index.alias.encode(.{}),
10587 .opc0 = ~@intFromEnum(sf),
10588 },
10589 } } } };
10590 },
10591 .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
10592 .base = extended_register.base,
10593 .index = extended_register.index,
10594 .option = extended_register.extend,
10595 .amount = switch (extended_register.extend) {
10596 .uxtw, .lsl, .sxtw, .sxtx => |amount| amount,
10597 },
10598 } },
10599 }
10600 }
10601 /// C6.2.176 LDRSH (immediate)
10602 /// C6.2.177 LDRSH (register)
10603 pub fn ldrsh(t: Register, form: union(enum) {
10604 post_index: struct { base: Register, index: i9 },
10605 pre_index: struct { base: Register, index: i9 },
10606 unsigned_offset: struct { base: Register, offset: u13 = 0 },
10607 base: Register,
10608 extended_register_explicit: struct {
10609 base: Register,
10610 index: Register,
10611 option: LoadStore.RegisterRegisterOffset.Option,
10612 amount: LoadStore.RegisterRegisterOffset.Extend.Amount,
10613 },
10614 extended_register: struct {
10615 base: Register,
10616 index: Register,
10617 extend: LoadStore.RegisterRegisterOffset.Extend,
10618 },
10619 }) Instruction {
10620 const sf = t.format.integer;
10621 form: switch (form) {
10622 .post_index => |post_index| {
10623 assert(post_index.base.format.integer == .doubleword);
10624 return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{
10625 .ldrsh = .{
10626 .Rt = t.alias.encode(.{}),
10627 .Rn = post_index.base.alias.encode(.{ .sp = true }),
10628 .imm9 = post_index.index,
10629 .opc0 = ~@intFromEnum(sf),
10630 },
10631 } } } };
10632 },
10633 .pre_index => |pre_index| {
10634 assert(pre_index.base.format.integer == .doubleword);
10635 return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
10636 .ldrsh = .{
10637 .Rt = t.alias.encode(.{}),
10638 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
10639 .imm9 = pre_index.index,
10640 .opc0 = ~@intFromEnum(sf),
10641 },
10642 } } } };
10643 },
10644 .unsigned_offset => |unsigned_offset| {
10645 assert(unsigned_offset.base.format.integer == .doubleword);
10646 return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
10647 .ldrsh = .{
10648 .Rt = t.alias.encode(.{}),
10649 .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
10650 .imm12 = @intCast(@shrExact(unsigned_offset.offset, 1)),
10651 .opc0 = ~@intFromEnum(sf),
10652 },
10653 } } } };
10654 },
10655 .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
10656 .extended_register_explicit => |extended_register_explicit| {
10657 assert(extended_register_explicit.base.format.integer == .doubleword and
10658 extended_register_explicit.index.format.integer == extended_register_explicit.option.sf());
10659 return .{ .load_store = .{ .register_register_offset = .{ .integer = .{
10660 .ldrsh = .{
10661 .Rt = t.alias.encode(.{}),
10662 .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }),
10663 .S = switch (extended_register_explicit.amount) {
10664 0 => false,
10665 1 => true,
10666 else => unreachable,
10667 },
10668 .option = extended_register_explicit.option,
10669 .Rm = extended_register_explicit.index.alias.encode(.{}),
10670 .opc0 = ~@intFromEnum(sf),
10671 },
10672 } } } };
10673 },
10674 .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
10675 .base = extended_register.base,
10676 .index = extended_register.index,
10677 .option = extended_register.extend,
10678 .amount = switch (extended_register.extend) {
10679 .uxtw, .lsl, .sxtw, .sxtx => |amount| amount,
10680 },
10681 } },
10682 }
10683 }
10684 /// C6.2.178 LDRSW (immediate)
10685 /// C6.2.179 LDRSW (literal)
10686 /// C6.2.180 LDRSW (register)
10687 pub fn ldrsw(t: Register, form: union(enum) {
10688 post_index: struct { base: Register, index: i9 },
10689 pre_index: struct { base: Register, index: i9 },
10690 unsigned_offset: struct { base: Register, offset: u14 = 0 },
10691 base: Register,
10692 literal: i21,
10693 extended_register_explicit: struct {
10694 base: Register,
10695 index: Register,
10696 option: LoadStore.RegisterRegisterOffset.Integer.Option,
10697 amount: LoadStore.RegisterRegisterOffset.Integer.Extend.Amount,
10698 },
10699 extended_register: struct {
10700 base: Register,
10701 index: Register,
10702 extend: LoadStore.RegisterRegisterOffset.Integer.Extend,
10703 },
10704 }) Instruction {
10705 assert(t.format.integer == .doubleword);
10706 form: switch (form) {
10707 .post_index => |post_index| {
10708 assert(post_index.base.format.integer == .doubleword);
10709 return .{ .load_store = .{ .register_immediate_post_indexed = .{
10710 .ldrsw = .{
10711 .Rt = t.alias.encode(.{}),
10712 .Rn = post_index.base.alias.encode(.{ .sp = true }),
10713 .imm9 = post_index.index,
10714 },
10715 } } };
10716 },
10717 .pre_index => |pre_index| {
10718 assert(pre_index.base.format.integer == .doubleword);
10719 return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
10720 .ldrsw = .{
10721 .Rt = t.alias.encode(.{}),
10722 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
10723 .imm9 = pre_index.index,
10724 },
10725 } } } };
10726 },
10727 .unsigned_offset => |unsigned_offset| {
10728 assert(unsigned_offset.base.format.integer == .doubleword);
10729 return .{ .load_store = .{ .register_unsigned_immediate = .{
10730 .ldrsw = .{
10731 .Rt = t.alias.encode(.{}),
10732 .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
10733 .imm12 = @intCast(@shrExact(unsigned_offset.offset, 2)),
10734 },
10735 } } };
10736 },
10737 .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
10738 .literal => |offset| return .{ .load_store = .{ .register_literal = .{
10739 .ldrsw = .{
10740 .Rt = t.alias.encode(.{}),
10741 .imm19 = @intCast(@shrExact(offset, 2)),
10742 },
10743 } } },
10744 .extended_register_explicit => |extended_register_explicit| {
10745 assert(extended_register_explicit.base.format.integer == .doubleword and
10746 extended_register_explicit.index.format.integer == extended_register_explicit.option.sf());
10747 return .{ .load_store = .{ .register_register_offset = .{ .integer = .{
10748 .ldrsw = .{
10749 .Rt = t.alias.encode(.{}),
10750 .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }),
10751 .S = switch (extended_register_explicit.amount) {
10752 0 => 0b0,
10753 2 => 0b1,
10754 else => unreachable,
10755 },
10756 .option = extended_register_explicit.option,
10757 .Rm = extended_register_explicit.index.alias.encode(.{}),
10758 },
10759 } } } };
10760 },
10761 .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
10762 .base = extended_register.base,
10763 .index = extended_register.index,
10764 .option = extended_register.extend,
10765 .amount = switch (extended_register.extend) {
10766 .uxtw, .lsl, .sxtw, .sxtx => |amount| amount,
10767 },
10768 } },
10769 }
10770 }
10771 /// C6.2.202 LDUR
10772 /// C7.2.194 LDUR (SIMD&FP)
10773 pub fn ldur(t: Register, n: Register, simm: i9) Instruction {
10774 assert(n.format.integer == .doubleword);
10775 switch (t.format) {
10776 else => unreachable,
10777 .integer => |sf| return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
10778 .ldur = .{
10779 .Rt = t.alias.encode(.{}),
10780 .Rn = n.alias.encode(.{ .sp = true }),
10781 .imm9 = simm,
10782 .sf = sf,
10783 },
10784 } } } },
10785 .scalar => |vs| return .{ .load_store = .{ .register_unscaled_immediate = .{ .vector = .{
10786 .ldur = .{
10787 .Rt = t.alias.encode(.{ .V = true }),
10788 .Rn = n.alias.encode(.{ .sp = true }),
10789 .imm9 = simm,
10790 .opc1 = .encode(vs),
10791 .size = .encode(vs),
10792 },
10793 } } } },
10794 }
10795 }
10796 /// C6.2.203 LDURB
10797 pub fn ldurb(t: Register, n: Register, simm: i9) Instruction {
10798 assert(t.format.integer == .word and n.format.integer == .doubleword);
10799 return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
10800 .ldurb = .{
10801 .Rt = t.alias.encode(.{}),
10802 .Rn = n.alias.encode(.{ .sp = true }),
10803 .imm9 = simm,
10804 },
10805 } } } };
10806 }
10807 /// C6.2.204 LDURH
10808 pub fn ldurh(t: Register, n: Register, simm: i9) Instruction {
10809 assert(t.format.integer == .word and n.format.integer == .doubleword);
10810 return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
10811 .ldurh = .{
10812 .Rt = t.alias.encode(.{}),
10813 .Rn = n.alias.encode(.{ .sp = true }),
10814 .imm9 = simm,
10815 },
10816 } } } };
10817 }
10818 /// C6.2.205 LDURSB
10819 pub fn ldursb(t: Register, n: Register, simm: i9) Instruction {
10820 assert(n.format.integer == .doubleword);
10821 return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
10822 .ldursb = .{
10823 .Rt = t.alias.encode(.{}),
10824 .Rn = n.alias.encode(.{ .sp = true }),
10825 .imm9 = simm,
10826 .opc0 = ~@intFromEnum(t.format.integer),
10827 },
10828 } } } };
10829 }
10830 /// C6.2.206 LDURSH
10831 pub fn ldursh(t: Register, n: Register, simm: i9) Instruction {
10832 assert(n.format.integer == .doubleword);
10833 return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
10834 .ldursh = .{
10835 .Rt = t.alias.encode(.{}),
10836 .Rn = n.alias.encode(.{ .sp = true }),
10837 .imm9 = simm,
10838 .opc0 = ~@intFromEnum(t.format.integer),
10839 },
10840 } } } };
10841 }
10842 /// C6.2.207 LDURSW
10843 pub fn ldursw(t: Register, n: Register, simm: i9) Instruction {
10844 assert(t.format.integer == .doubleword and n.format.integer == .doubleword);
10845 return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
10846 .ldursw = .{
10847 .Rt = t.alias.encode(.{}),
10848 .Rn = n.alias.encode(.{ .sp = true }),
10849 .imm9 = simm,
10850 },
10851 } } } };
10852 }
10853 /// C6.2.214 LSLV
10854 pub fn lslv(d: Register, n: Register, m: Register) Instruction {
10855 const sf = d.format.integer;
10856 assert(n.format.integer == sf and m.format.integer == sf);
10857 return .{ .data_processing_register = .{ .data_processing_two_source = .{
10858 .lslv = .{
10859 .Rd = d.alias.encode(.{}),
10860 .Rn = n.alias.encode(.{}),
10861 .Rm = m.alias.encode(.{}),
10862 .sf = sf,
10863 },
10864 } } };
10865 }
10866 /// C6.2.217 LSRV
10867 pub fn lsrv(d: Register, n: Register, m: Register) Instruction {
10868 const sf = d.format.integer;
10869 assert(n.format.integer == sf and m.format.integer == sf);
10870 return .{ .data_processing_register = .{ .data_processing_two_source = .{
10871 .lsrv = .{
10872 .Rd = d.alias.encode(.{}),
10873 .Rn = n.alias.encode(.{}),
10874 .Rm = m.alias.encode(.{}),
10875 .sf = sf,
10876 },
10877 } } };
10878 }
10879 /// C6.2.218 MADD
10880 pub fn madd(d: Register, n: Register, m: Register, a: Register) Instruction {
10881 const sf = d.format.integer;
10882 assert(n.format.integer == sf and m.format.integer == sf and a.format.integer == sf);
10883 return .{ .data_processing_register = .{ .data_processing_three_source = .{
10884 .madd = .{
10885 .Rd = d.alias.encode(.{}),
10886 .Rn = n.alias.encode(.{}),
10887 .Ra = a.alias.encode(.{}),
10888 .Rm = m.alias.encode(.{}),
10889 .sf = sf,
10890 },
10891 } } };
10892 }
10893 /// C7.2.204 MOVI
10894 pub fn movi(d: Register, imm8: u8, shift: union(enum) { lsl: u5, msl: u5, replicate }) Instruction {
10895 const arrangement = switch (d.format) {
10896 else => unreachable,
10897 .scalar => |vs| switch (vs) {
10898 else => unreachable,
10899 .double => .@"1d",
10900 },
10901 .vector => |arrangement| switch (arrangement) {
10902 .@"1d" => unreachable,
10903 else => arrangement,
10904 },
10905 };
10906 return .{ .data_processing_vector = .{ .simd_modified_immediate = .{
10907 .movi = .{
10908 .Rd = d.alias.encode(.{ .V = true }),
10909 .imm5 = @truncate(imm8 >> 0),
10910 .cmode = switch (shift) {
10911 .lsl => |amount| switch (arrangement) {
10912 else => unreachable,
10913 .@"8b", .@"16b" => @as(u4, 0b1110) |
10914 @as(u4, @as(u0, @intCast(@shrExact(amount, 3)))) << 1,
10915 .@"4h", .@"8h" => @as(u4, 0b1000) |
10916 @as(u4, @as(u1, @intCast(@shrExact(amount, 3)))) << 1,
10917 .@"2s", .@"4s" => @as(u4, 0b0000) |
10918 @as(u4, @as(u2, @intCast(@shrExact(amount, 3)))) << 1,
10919 },
10920 .msl => |amount| switch (arrangement) {
10921 else => unreachable,
10922 .@"2s", .@"4s" => @as(u4, 0b1100) |
10923 @as(u4, @as(u1, @intCast(@shrExact(amount, 3) - 1))) << 0,
10924 },
10925 .replicate => switch (arrangement) {
10926 else => unreachable,
10927 .@"1d", .@"2d" => 0b1110,
10928 },
10929 },
10930 .imm3 = @intCast(imm8 >> 5),
10931 .op = switch (shift) {
10932 .lsl, .msl => 0b0,
10933 .replicate => 0b1,
10934 },
10935 .Q = arrangement.size(),
10936 },
10937 } } };
10938 }
10939 /// C6.2.225 MOVK
10940 pub fn movk(
10941 d: Register,
10942 imm: u16,
10943 shift: struct { lsl: DataProcessingImmediate.MoveWideImmediate.Hw = .@"0" },
10944 ) Instruction {
10945 const sf = d.format.integer;
10946 assert(sf == .doubleword or shift.lsl.sf() == .word);
10947 return .{ .data_processing_immediate = .{ .move_wide_immediate = .{
10948 .movk = .{
10949 .Rd = d.alias.encode(.{}),
10950 .imm16 = imm,
10951 .hw = shift.lsl,
10952 .sf = sf,
10953 },
10954 } } };
10955 }
10956 /// C6.2.226 MOVN
10957 pub fn movn(
10958 d: Register,
10959 imm: u16,
10960 shift: struct { lsl: DataProcessingImmediate.MoveWideImmediate.Hw = .@"0" },
10961 ) Instruction {
10962 const sf = d.format.integer;
10963 assert(sf == .doubleword or shift.lsl.sf() == .word);
10964 return .{ .data_processing_immediate = .{ .move_wide_immediate = .{
10965 .movn = .{
10966 .Rd = d.alias.encode(.{}),
10967 .imm16 = imm,
10968 .hw = shift.lsl,
10969 .sf = sf,
10970 },
10971 } } };
10972 }
10973 /// C6.2.227 MOVZ
10974 pub fn movz(
10975 d: Register,
10976 imm: u16,
10977 shift: struct { lsl: DataProcessingImmediate.MoveWideImmediate.Hw = .@"0" },
10978 ) Instruction {
10979 const sf = d.format.integer;
10980 assert(sf == .doubleword or shift.lsl.sf() == .word);
10981 return .{ .data_processing_immediate = .{ .move_wide_immediate = .{
10982 .movz = .{
10983 .Rd = d.alias.encode(.{}),
10984 .imm16 = imm,
10985 .hw = shift.lsl,
10986 .sf = sf,
10987 },
10988 } } };
10989 }
10990 /// C6.2.228 MRS
10991 pub fn mrs(t: Register, systemreg: Register.System) Instruction {
10992 assert(t.format.integer == .doubleword and systemreg.op0 >= 0b10);
10993 return .{ .branch_exception_generating_system = .{ .system_register_move = .{
10994 .mrs = .{
10995 .Rt = t.alias.encode(.{}),
10996 .systemreg = systemreg,
10997 },
10998 } } };
10999 }
11000 /// C6.2.230 MSR (register)
11001 pub fn msr(systemreg: Register.System, t: Register) Instruction {
11002 assert(systemreg.op0 >= 0b10 and t.format.integer == .doubleword);
11003 return .{ .branch_exception_generating_system = .{ .system_register_move = .{
11004 .msr = .{
11005 .Rt = t.alias.encode(.{}),
11006 .systemreg = systemreg,
11007 },
11008 } } };
11009 }
11010 /// C6.2.231 MSUB
11011 pub fn msub(d: Register, n: Register, m: Register, a: Register) Instruction {
11012 const sf = d.format.integer;
11013 assert(n.format.integer == sf and m.format.integer == sf and a.format.integer == sf);
11014 return .{ .data_processing_register = .{ .data_processing_three_source = .{
11015 .msub = .{
11016 .Rd = d.alias.encode(.{}),
11017 .Rn = n.alias.encode(.{}),
11018 .Ra = a.alias.encode(.{}),
11019 .Rm = m.alias.encode(.{}),
11020 .sf = sf,
11021 },
11022 } } };
11023 }
11024 /// C6.2.238 NOP
11025 pub fn nop() Instruction {
11026 return .{ .branch_exception_generating_system = .{ .hints = .{
11027 .nop = .{},
11028 } } };
11029 }
11030 /// C6.2.239 ORN (shifted register)
11031 /// C7.2.211 ORN (vector)
11032 pub fn orn(d: Register, n: Register, form: union(enum) {
11033 register: Register,
11034 shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
11035 shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
11036 }) Instruction {
11037 switch (d.format) {
11038 else => unreachable,
11039 .integer => |sf| {
11040 assert(n.format.integer == sf);
11041 form: switch (form) {
11042 .register => |register| continue :form .{ .shifted_register = .{ .register = register } },
11043 .shifted_register_explicit => |shifted_register_explicit| {
11044 assert(shifted_register_explicit.register.format.integer == sf);
11045 return .{ .data_processing_register = .{ .logical_shifted_register = .{
11046 .orn = .{
11047 .Rd = d.alias.encode(.{}),
11048 .Rn = n.alias.encode(.{}),
11049 .imm6 = switch (sf) {
11050 .word => @as(u5, @intCast(shifted_register_explicit.amount)),
11051 .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
11052 },
11053 .Rm = shifted_register_explicit.register.alias.encode(.{}),
11054 .shift = shifted_register_explicit.shift,
11055 .sf = sf,
11056 },
11057 } } };
11058 },
11059 .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
11060 .register = shifted_register.register,
11061 .shift = shifted_register.shift,
11062 .amount = switch (shifted_register.shift) {
11063 .lsl, .lsr, .asr, .ror => |amount| amount,
11064 },
11065 } },
11066 }
11067 },
11068 .vector => |arrangement| {
11069 const m = form.register;
11070 assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement);
11071 return .{ .data_processing_vector = .{ .simd_three_same = .{
11072 .orn = .{
11073 .Rd = d.alias.encode(.{ .V = true }),
11074 .Rn = n.alias.encode(.{ .V = true }),
11075 .Rm = m.alias.encode(.{ .V = true }),
11076 .Q = arrangement.size(),
11077 },
11078 } } };
11079 },
11080 }
11081 }
11082 /// C6.2.240 ORR (immediate)
11083 /// C6.2.241 ORR (shifted register)
11084 /// C7.2.212 ORR (vector, immediate)
11085 /// C7.2.213 ORR (vector, register)
11086 pub fn orr(d: Register, n: Register, form: union(enum) {
11087 immediate: DataProcessingImmediate.Bitmask,
11088 shifted_immediate: struct { immediate: u8, lsl: u5 = 0 },
11089 register: Register,
11090 shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
11091 shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
11092 }) Instruction {
11093 switch (d.format) {
11094 else => unreachable,
11095 .integer => |sf| {
11096 assert(n.format.integer == sf);
11097 form: switch (form) {
11098 .immediate => |bitmask| {
11099 assert(bitmask.validImmediate(sf));
11100 return .{ .data_processing_immediate = .{ .logical_immediate = .{
11101 .orr = .{
11102 .Rd = d.alias.encode(.{ .sp = true }),
11103 .Rn = n.alias.encode(.{}),
11104 .imm = bitmask,
11105 .sf = sf,
11106 },
11107 } } };
11108 },
11109 .shifted_immediate => unreachable,
11110 .register => |register| continue :form .{ .shifted_register = .{ .register = register } },
11111 .shifted_register_explicit => |shifted_register_explicit| {
11112 assert(shifted_register_explicit.register.format.integer == sf);
11113 return .{ .data_processing_register = .{ .logical_shifted_register = .{
11114 .orr = .{
11115 .Rd = d.alias.encode(.{}),
11116 .Rn = n.alias.encode(.{}),
11117 .imm6 = switch (sf) {
11118 .word => @as(u5, @intCast(shifted_register_explicit.amount)),
11119 .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
11120 },
11121 .Rm = shifted_register_explicit.register.alias.encode(.{}),
11122 .shift = shifted_register_explicit.shift,
11123 .sf = sf,
11124 },
11125 } } };
11126 },
11127 .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
11128 .register = shifted_register.register,
11129 .shift = shifted_register.shift,
11130 .amount = switch (shifted_register.shift) {
11131 .lsl, .lsr, .asr, .ror => |amount| amount,
11132 },
11133 } },
11134 }
11135 },
11136 .vector => |arrangement| switch (form) {
11137 else => unreachable,
11138 .shifted_immediate => |shifted_immediate| {
11139 assert(n.alias == d.alias and n.format.vector == arrangement);
11140 return .{ .data_processing_vector = .{ .simd_modified_immediate = .{
11141 .orr = .{
11142 .Rd = d.alias.encode(.{ .V = true }),
11143 .imm5 = @truncate(shifted_immediate.immediate >> 0),
11144 .cmode = switch (arrangement) {
11145 else => unreachable,
11146 .@"4h", .@"8h" => @as(u3, 0b100) |
11147 @as(u3, @as(u1, @intCast(@shrExact(shifted_immediate.lsl, 3)))) << 0,
11148 .@"2s", .@"4s" => @as(u3, 0b000) |
11149 @as(u3, @as(u2, @intCast(@shrExact(shifted_immediate.lsl, 3)))) << 0,
11150 },
11151 .imm3 = @intCast(shifted_immediate.immediate >> 5),
11152 .Q = arrangement.size(),
11153 },
11154 } } };
11155 },
11156 .register => |m| {
11157 assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement);
11158 return .{ .data_processing_vector = .{ .simd_three_same = .{
11159 .orr = .{
11160 .Rd = d.alias.encode(.{ .V = true }),
11161 .Rn = n.alias.encode(.{ .V = true }),
11162 .Rm = m.alias.encode(.{ .V = true }),
11163 .Q = arrangement.size(),
11164 },
11165 } } };
11166 },
11167 },
11168 }
11169 }
11170 /// C6.2.247 PRFM (immediate)
11171 /// C6.2.248 PRFM (literal)
11172 /// C6.2.249 PRFM (register)
11173 pub fn prfm(prfop: LoadStore.PrfOp, form: union(enum) {
11174 unsigned_offset: struct { base: Register, offset: u15 = 0 },
11175 base: Register,
11176 literal: i21,
11177 extended_register_explicit: struct {
11178 base: Register,
11179 index: Register,
11180 option: LoadStore.RegisterRegisterOffset.Option,
11181 amount: LoadStore.RegisterRegisterOffset.Extend.Amount,
11182 },
11183 extended_register: struct {
11184 base: Register,
11185 index: Register,
11186 extend: LoadStore.RegisterRegisterOffset.Extend,
11187 },
11188 }) Instruction {
11189 form: switch (form) {
11190 .unsigned_offset => |unsigned_offset| {
11191 assert(unsigned_offset.base.format.integer == .doubleword);
11192 return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
11193 .prfm = .{
11194 .prfop = prfop,
11195 .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
11196 .imm12 = @intCast(@shrExact(unsigned_offset.offset, 3)),
11197 },
11198 } } } };
11199 },
11200 .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
11201 .literal => |offset| return .{ .load_store = .{ .register_literal = .{ .integer = .{
11202 .prfm = .{
11203 .prfop = prfop,
11204 .imm19 = @intCast(@shrExact(offset, 2)),
11205 },
11206 } } } },
11207 .extended_register_explicit => |extended_register_explicit| {
11208 assert(extended_register_explicit.base.format.integer == .doubleword and
11209 extended_register_explicit.index.format.integer == extended_register_explicit.option.sf());
11210 return .{ .load_store = .{ .register_register_offset = .{ .integer = .{
11211 .prfm = .{
11212 .prfop = prfop,
11213 .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }),
11214 .S = switch (extended_register_explicit.amount) {
11215 0 => false,
11216 3 => true,
11217 else => unreachable,
11218 },
11219 .option = extended_register_explicit.option,
11220 .Rm = extended_register_explicit.index.alias.encode(.{}),
11221 },
11222 } } } };
11223 },
11224 .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
11225 .base = extended_register.base,
11226 .index = extended_register.index,
11227 .option = extended_register.extend,
11228 .amount = switch (extended_register.extend) {
11229 .uxtw, .lsl, .sxtw, .sxtx => |amount| amount,
11230 },
11231 } },
11232 }
11233 }
11234 /// C6.2.253 RBIT
11235 pub fn rbit(d: Register, n: Register) Instruction {
11236 const sf = d.format.integer;
11237 assert(n.format.integer == sf);
11238 return .{ .data_processing_register = .{ .data_processing_one_source = .{
11239 .rbit = .{
11240 .Rd = d.alias.encode(.{}),
11241 .Rn = n.alias.encode(.{}),
11242 .sf = sf,
11243 },
11244 } } };
11245 }
11246 /// C6.2.254 RET
11247 pub fn ret(n: Register) Instruction {
11248 assert(n.format.integer == .doubleword);
11249 return .{ .branch_exception_generating_system = .{ .unconditional_branch_register = .{
11250 .ret = .{ .Rn = n.alias.encode(.{}) },
11251 } } };
11252 }
11253 /// C6.2.256 REV
11254 pub fn rev(d: Register, n: Register) Instruction {
11255 const sf = d.format.integer;
11256 assert(n.format.integer == sf);
11257 return .{ .data_processing_register = .{ .data_processing_one_source = .{
11258 .rev = .{
11259 .Rd = d.alias.encode(.{}),
11260 .Rn = n.alias.encode(.{}),
11261 .opc0 = sf,
11262 .sf = sf,
11263 },
11264 } } };
11265 }
11266 /// C6.2.257 REV16
11267 pub fn rev16(d: Register, n: Register) Instruction {
11268 const sf = d.format.integer;
11269 assert(n.format.integer == sf);
11270 return .{ .data_processing_register = .{ .data_processing_one_source = .{
11271 .rev16 = .{
11272 .Rd = d.alias.encode(.{}),
11273 .Rn = n.alias.encode(.{}),
11274 .sf = sf,
11275 },
11276 } } };
11277 }
11278 /// C6.2.258 REV32
11279 pub fn rev32(d: Register, n: Register) Instruction {
11280 assert(d.format.integer == .doubleword and n.format.integer == .doubleword);
11281 return .{ .data_processing_register = .{ .data_processing_one_source = .{
11282 .rev32 = .{
11283 .Rd = d.alias.encode(.{}),
11284 .Rn = n.alias.encode(.{}),
11285 },
11286 } } };
11287 }
11288 /// C6.2.263 RORV
11289 pub fn rorv(d: Register, n: Register, m: Register) Instruction {
11290 const sf = d.format.integer;
11291 assert(n.format.integer == sf and m.format.integer == sf);
11292 return .{ .data_processing_register = .{ .data_processing_two_source = .{
11293 .rorv = .{
11294 .Rd = d.alias.encode(.{}),
11295 .Rn = n.alias.encode(.{}),
11296 .Rm = m.alias.encode(.{}),
11297 .sf = sf,
11298 },
11299 } } };
11300 }
11301 /// C6.2.264 SB
11302 pub fn sb() Instruction {
11303 return .{ .branch_exception_generating_system = .{ .barriers = .{
11304 .sb = .{},
11305 } } };
11306 }
11307 /// C6.2.265 SBC
11308 pub fn sbc(d: Register, n: Register, m: Register) Instruction {
11309 const sf = d.format.integer;
11310 assert(n.format.integer == sf and m.format.integer == sf);
11311 return .{ .data_processing_register = .{ .add_subtract_with_carry = .{
11312 .sbc = .{
11313 .Rd = d.alias.encode(.{}),
11314 .Rn = n.alias.encode(.{}),
11315 .Rm = m.alias.encode(.{}),
11316 .sf = sf,
11317 },
11318 } } };
11319 }
11320 /// C6.2.266 SBCS
11321 pub fn sbcs(d: Register, n: Register, m: Register) Instruction {
11322 const sf = d.format.integer;
11323 assert(n.format.integer == sf and m.format.integer == sf);
11324 return .{ .data_processing_register = .{ .add_subtract_with_carry = .{
11325 .sbcs = .{
11326 .Rd = d.alias.encode(.{}),
11327 .Rn = n.alias.encode(.{}),
11328 .Rm = m.alias.encode(.{}),
11329 .sf = sf,
11330 },
11331 } } };
11332 }
11333 /// C6.2.268 SBFM
11334 pub fn sbfm(d: Register, n: Register, bitmask: DataProcessingImmediate.Bitmask) Instruction {
11335 const sf = d.format.integer;
11336 assert(n.format.integer == sf and bitmask.validBitfield(sf));
11337 return .{ .data_processing_immediate = .{ .bitfield = .{
11338 .sbfm = .{
11339 .Rd = d.alias.encode(.{}),
11340 .Rn = n.alias.encode(.{}),
11341 .imm = bitmask,
11342 .sf = sf,
11343 },
11344 } } };
11345 }
11346 /// C7.2.236 SCVTF (scalar, integer)
11347 pub fn scvtf(d: Register, n: Register) Instruction {
11348 return .{ .data_processing_vector = .{ .convert_float_integer = .{
11349 .scvtf = .{
11350 .Rd = d.alias.encode(.{ .V = true }),
11351 .Rn = n.alias.encode(.{}),
11352 .ftype = switch (d.format.scalar) {
11353 else => unreachable,
11354 .single => .single,
11355 .double => .double,
11356 .half => .half,
11357 },
11358 .sf = n.format.integer,
11359 },
11360 } } };
11361 }
11362 /// C6.2.270 SDIV
11363 pub fn sdiv(d: Register, n: Register, m: Register) Instruction {
11364 const sf = d.format.integer;
11365 assert(n.format.integer == sf and m.format.integer == sf);
11366 return .{ .data_processing_register = .{ .data_processing_two_source = .{
11367 .sdiv = .{
11368 .Rd = d.alias.encode(.{}),
11369 .Rn = n.alias.encode(.{}),
11370 .Rm = m.alias.encode(.{}),
11371 .sf = sf,
11372 },
11373 } } };
11374 }
11375 /// C6.2.280 SEV
11376 pub fn sev() Instruction {
11377 return .{ .branch_exception_generating_system = .{ .hints = .{
11378 .sev = .{},
11379 } } };
11380 }
11381 /// C6.2.281 SEVL
11382 pub fn sevl() Instruction {
11383 return .{ .branch_exception_generating_system = .{ .hints = .{
11384 .sevl = .{},
11385 } } };
11386 }
11387 /// C6.2.282 SMADDL
11388 pub fn smaddl(d: Register, n: Register, m: Register, a: Register) Instruction {
11389 assert(d.format.integer == .doubleword and n.format.integer == .word and m.format.integer == .word and a.format.integer == .doubleword);
11390 return .{ .data_processing_register = .{ .data_processing_three_source = .{
11391 .smaddl = .{
11392 .Rd = d.alias.encode(.{}),
11393 .Rn = n.alias.encode(.{}),
11394 .Ra = a.alias.encode(.{}),
11395 .Rm = m.alias.encode(.{}),
11396 },
11397 } } };
11398 }
11399 /// C6.2.283 SMC
11400 pub fn smc(imm: u16) Instruction {
11401 return .{ .branch_exception_generating_system = .{ .exception_generating = .{
11402 .smc = .{ .imm16 = imm },
11403 } } };
11404 }
11405 /// C7.2.279 SMOV
11406 pub fn smov(d: Register, n: Register) Instruction {
11407 const sf = d.format.integer;
11408 const vs = n.format.element.size;
11409 switch (vs) {
11410 else => unreachable,
11411 .byte, .half => {},
11412 .single => assert(sf == .doubleword),
11413 }
11414 return .{ .data_processing_vector = .{ .simd_copy = .{
11415 .smov = .{
11416 .Rd = d.alias.encode(.{}),
11417 .Rn = n.alias.encode(.{ .V = true }),
11418 .imm5 = switch (vs) {
11419 else => unreachable,
11420 .byte => @as(u5, @as(u4, @intCast(n.format.element.index))) << 1 | @as(u5, 0b1) << 0,
11421 .half => @as(u5, @as(u3, @intCast(n.format.element.index))) << 2 | @as(u5, 0b10) << 0,
11422 .single => @as(u5, @as(u2, @intCast(n.format.element.index))) << 3 | @as(u5, 0b100) << 0,
11423 },
11424 .Q = sf,
11425 },
11426 } } };
11427 }
11428 /// C6.2.287 SMSUBL
11429 pub fn smsubl(d: Register, n: Register, m: Register, a: Register) Instruction {
11430 assert(d.format.integer == .doubleword and n.format.integer == .word and m.format.integer == .word and a.format.integer == .doubleword);
11431 return .{ .data_processing_register = .{ .data_processing_three_source = .{
11432 .smsubl = .{
11433 .Rd = d.alias.encode(.{}),
11434 .Rn = n.alias.encode(.{}),
11435 .Ra = a.alias.encode(.{}),
11436 .Rm = m.alias.encode(.{}),
11437 },
11438 } } };
11439 }
11440 /// C6.2.288 SMULH
11441 pub fn smulh(d: Register, n: Register, m: Register) Instruction {
11442 assert(d.format.integer == .doubleword and n.format.integer == .doubleword and m.format.integer == .doubleword);
11443 return .{ .data_processing_register = .{ .data_processing_three_source = .{
11444 .smulh = .{
11445 .Rd = d.alias.encode(.{}),
11446 .Rn = n.alias.encode(.{}),
11447 .Rm = m.alias.encode(.{}),
11448 },
11449 } } };
11450 }
11451 /// C6.2.321 STP
11452 /// C7.2.330 STP (SIMD&FP)
11453 pub fn stp(t1: Register, t2: Register, form: union(enum) {
11454 post_index: struct { base: Register, index: i10 },
11455 pre_index: struct { base: Register, index: i10 },
11456 signed_offset: struct { base: Register, offset: i10 = 0 },
11457 base: Register,
11458 }) Instruction {
11459 switch (t1.format) {
11460 else => unreachable,
11461 .integer => |sf| {
11462 assert(t2.format.integer == sf);
11463 form: switch (form) {
11464 .post_index => |post_index| {
11465 assert(post_index.base.format.integer == .doubleword);
11466 return .{ .load_store = .{ .register_pair_post_indexed = .{ .integer = .{
11467 .stp = .{
11468 .Rt = t1.alias.encode(.{}),
11469 .Rn = post_index.base.alias.encode(.{ .sp = true }),
11470 .Rt2 = t2.alias.encode(.{}),
11471 .imm7 = @intCast(@shrExact(post_index.index, @as(u2, 2) + @intFromEnum(sf))),
11472 .sf = sf,
11473 },
11474 } } } };
11475 },
11476 .pre_index => |pre_index| {
11477 assert(pre_index.base.format.integer == .doubleword);
11478 return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{
11479 .stp = .{
11480 .Rt = t1.alias.encode(.{}),
11481 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
11482 .Rt2 = t2.alias.encode(.{}),
11483 .imm7 = @intCast(@shrExact(pre_index.index, @as(u2, 2) + @intFromEnum(sf))),
11484 .sf = sf,
11485 },
11486 } } } };
11487 },
11488 .signed_offset => |signed_offset| {
11489 assert(signed_offset.base.format.integer == .doubleword);
11490 return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{
11491 .stp = .{
11492 .Rt = t1.alias.encode(.{}),
11493 .Rn = signed_offset.base.alias.encode(.{ .sp = true }),
11494 .Rt2 = t2.alias.encode(.{}),
11495 .imm7 = @intCast(@shrExact(signed_offset.offset, @as(u2, 2) + @intFromEnum(sf))),
11496 .sf = sf,
11497 },
11498 } } } };
11499 },
11500 .base => |base| continue :form .{ .signed_offset = .{ .base = base } },
11501 }
11502 },
11503 .scalar => |vs| {
11504 assert(t2.format.scalar == vs);
11505 form: switch (form) {
11506 .post_index => |post_index| {
11507 assert(post_index.base.format.integer == .doubleword);
11508 return .{ .load_store = .{ .register_pair_post_indexed = .{ .vector = .{
11509 .stp = .{
11510 .Rt = t1.alias.encode(.{ .V = true }),
11511 .Rn = post_index.base.alias.encode(.{ .sp = true }),
11512 .Rt2 = t2.alias.encode(.{ .V = true }),
11513 .imm7 = @intCast(@shrExact(post_index.index, @intFromEnum(vs))),
11514 .opc = .encode(vs),
11515 },
11516 } } } };
11517 },
11518 .signed_offset => |signed_offset| {
11519 assert(signed_offset.base.format.integer == .doubleword);
11520 return .{ .load_store = .{ .register_pair_offset = .{ .vector = .{
11521 .stp = .{
11522 .Rt = t1.alias.encode(.{ .V = true }),
11523 .Rn = signed_offset.base.alias.encode(.{ .sp = true }),
11524 .Rt2 = t2.alias.encode(.{ .V = true }),
11525 .imm7 = @intCast(@shrExact(signed_offset.offset, @intFromEnum(vs))),
11526 .opc = .encode(vs),
11527 },
11528 } } } };
11529 },
11530 .pre_index => |pre_index| {
11531 assert(pre_index.base.format.integer == .doubleword);
11532 return .{ .load_store = .{ .register_pair_pre_indexed = .{ .vector = .{
11533 .stp = .{
11534 .Rt = t1.alias.encode(.{ .V = true }),
11535 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
11536 .Rt2 = t2.alias.encode(.{ .V = true }),
11537 .imm7 = @intCast(@shrExact(pre_index.index, @intFromEnum(vs))),
11538 .opc = .encode(vs),
11539 },
11540 } } } };
11541 },
11542 .base => |base| continue :form .{ .signed_offset = .{ .base = base } },
11543 }
11544 },
11545 }
11546 }
11547 /// C6.2.322 STR (immediate)
11548 /// C7.2.331 STR (immediate, SIMD&FP)
11549 pub fn str(t: Register, form: union(enum) {
11550 post_index: struct { base: Register, index: i9 },
11551 pre_index: struct { base: Register, index: i9 },
11552 unsigned_offset: struct { base: Register, offset: u16 = 0 },
11553 base: Register,
11554 }) Instruction {
11555 switch (t.format) {
11556 else => unreachable,
11557 .integer => |sf| form: switch (form) {
11558 .post_index => |post_index| {
11559 assert(post_index.base.format.integer == .doubleword);
11560 return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{
11561 .str = .{
11562 .Rt = t.alias.encode(.{}),
11563 .Rn = post_index.base.alias.encode(.{ .sp = true }),
11564 .imm9 = post_index.index,
11565 .sf = sf,
11566 },
11567 } } } };
11568 },
11569 .pre_index => |pre_index| {
11570 assert(pre_index.base.format.integer == .doubleword);
11571 return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
11572 .str = .{
11573 .Rt = t.alias.encode(.{}),
11574 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
11575 .imm9 = pre_index.index,
11576 .sf = sf,
11577 },
11578 } } } };
11579 },
11580 .unsigned_offset => |unsigned_offset| {
11581 assert(unsigned_offset.base.format.integer == .doubleword);
11582 return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
11583 .str = .{
11584 .Rt = t.alias.encode(.{}),
11585 .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
11586 .imm12 = @intCast(@shrExact(unsigned_offset.offset, @as(u2, 2) + @intFromEnum(sf))),
11587 .sf = sf,
11588 },
11589 } } } };
11590 },
11591 .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
11592 },
11593 .scalar => |vs| form: switch (form) {
11594 .post_index => |post_index| {
11595 assert(post_index.base.format.integer == .doubleword);
11596 return .{ .load_store = .{ .register_immediate_post_indexed = .{ .vector = .{
11597 .str = .{
11598 .Rt = t.alias.encode(.{ .V = true }),
11599 .Rn = post_index.base.alias.encode(.{ .sp = true }),
11600 .imm9 = post_index.index,
11601 .opc1 = .encode(vs),
11602 .size = .encode(vs),
11603 },
11604 } } } };
11605 },
11606 .pre_index => |pre_index| {
11607 assert(pre_index.base.format.integer == .doubleword);
11608 return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .vector = .{
11609 .str = .{
11610 .Rt = t.alias.encode(.{ .V = true }),
11611 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
11612 .imm9 = pre_index.index,
11613 .opc1 = .encode(vs),
11614 .size = .encode(vs),
11615 },
11616 } } } };
11617 },
11618 .unsigned_offset => |unsigned_offset| {
11619 assert(unsigned_offset.base.format.integer == .doubleword);
11620 return .{ .load_store = .{ .register_unsigned_immediate = .{ .vector = .{
11621 .str = .{
11622 .Rt = t.alias.encode(.{ .V = true }),
11623 .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
11624 .imm12 = @intCast(@shrExact(unsigned_offset.offset, @intFromEnum(vs))),
11625 .opc1 = .encode(vs),
11626 .size = .encode(vs),
11627 },
11628 } } } };
11629 },
11630 .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
11631 },
11632 }
11633 }
11634 /// C6.2.324 STRB (immediate)
11635 pub fn strb(t: Register, form: union(enum) {
11636 post_index: struct { base: Register, index: i9 },
11637 pre_index: struct { base: Register, index: i9 },
11638 unsigned_offset: struct { base: Register, offset: u12 = 0 },
11639 base: Register,
11640 }) Instruction {
11641 assert(t.format.integer == .word);
11642 form: switch (form) {
11643 .post_index => |post_index| {
11644 assert(post_index.base.format.integer == .doubleword);
11645 return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{
11646 .strb = .{
11647 .Rt = t.alias.encode(.{}),
11648 .Rn = post_index.base.alias.encode(.{ .sp = true }),
11649 .imm9 = post_index.index,
11650 },
11651 } } } };
11652 },
11653 .pre_index => |pre_index| {
11654 assert(pre_index.base.format.integer == .doubleword);
11655 return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
11656 .strb = .{
11657 .Rt = t.alias.encode(.{}),
11658 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
11659 .imm9 = pre_index.index,
11660 },
11661 } } } };
11662 },
11663 .unsigned_offset => |unsigned_offset| {
11664 assert(unsigned_offset.base.format.integer == .doubleword);
11665 return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
11666 .strb = .{
11667 .Rt = t.alias.encode(.{}),
11668 .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
11669 .imm12 = unsigned_offset.offset,
11670 },
11671 } } } };
11672 },
11673 .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
11674 }
11675 }
11676 /// C6.2.326 STRH (immediate)
11677 pub fn strh(t: Register, form: union(enum) {
11678 post_index: struct { base: Register, index: i9 },
11679 pre_index: struct { base: Register, index: i9 },
11680 unsigned_offset: struct { base: Register, offset: u13 = 0 },
11681 base: Register,
11682 }) Instruction {
11683 assert(t.format.integer == .word);
11684 form: switch (form) {
11685 .post_index => |post_index| {
11686 assert(post_index.base.format.integer == .doubleword);
11687 return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{
11688 .strh = .{
11689 .Rt = t.alias.encode(.{}),
11690 .Rn = post_index.base.alias.encode(.{ .sp = true }),
11691 .imm9 = post_index.index,
11692 },
11693 } } } };
11694 },
11695 .pre_index => |pre_index| {
11696 assert(pre_index.base.format.integer == .doubleword);
11697 return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{
11698 .strh = .{
11699 .Rt = t.alias.encode(.{}),
11700 .Rn = pre_index.base.alias.encode(.{ .sp = true }),
11701 .imm9 = pre_index.index,
11702 },
11703 } } } };
11704 },
11705 .unsigned_offset => |unsigned_offset| {
11706 assert(unsigned_offset.base.format.integer == .doubleword);
11707 return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{
11708 .strh = .{
11709 .Rt = t.alias.encode(.{}),
11710 .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }),
11711 .imm12 = @intCast(@shrExact(unsigned_offset.offset, 1)),
11712 },
11713 } } } };
11714 },
11715 .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } },
11716 }
11717 }
11718 /// C6.2.346 STUR
11719 /// C7.2.333 STUR (SIMD&FP)
11720 pub fn stur(t: Register, n: Register, simm: i9) Instruction {
11721 assert(n.format.integer == .doubleword);
11722 switch (t.format) {
11723 else => unreachable,
11724 .integer => |sf| return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
11725 .stur = .{
11726 .Rt = t.alias.encode(.{}),
11727 .Rn = n.alias.encode(.{ .sp = true }),
11728 .imm9 = simm,
11729 .sf = sf,
11730 },
11731 } } } },
11732 .scalar => |vs| return .{ .load_store = .{ .register_unscaled_immediate = .{ .vector = .{
11733 .stur = .{
11734 .Rt = t.alias.encode(.{ .V = true }),
11735 .Rn = n.alias.encode(.{ .sp = true }),
11736 .imm9 = simm,
11737 .opc1 = .encode(vs),
11738 .size = .encode(vs),
11739 },
11740 } } } },
11741 }
11742 }
11743 /// C6.2.347 STURB
11744 pub fn sturb(t: Register, n: Register, simm: i9) Instruction {
11745 assert(t.format.integer == .word and n.format.integer == .doubleword);
11746 return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
11747 .sturb = .{
11748 .Rt = t.alias.encode(.{}),
11749 .Rn = n.alias.encode(.{ .sp = true }),
11750 .imm9 = simm,
11751 },
11752 } } } };
11753 }
11754 /// C6.2.348 STURH
11755 pub fn sturh(t: Register, n: Register, simm: i9) Instruction {
11756 assert(t.format.integer == .word and n.format.integer == .doubleword);
11757 return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{
11758 .sturh = .{
11759 .Rt = t.alias.encode(.{}),
11760 .Rn = n.alias.encode(.{ .sp = true }),
11761 .imm9 = simm,
11762 },
11763 } } } };
11764 }
11765 /// C6.2.356 SUB (extended register)
11766 /// C6.2.357 SUB (immediate)
11767 /// C6.2.358 SUB (shifted register)
11768 pub fn sub(d: Register, n: Register, form: union(enum) {
11769 extended_register_explicit: struct {
11770 register: Register,
11771 option: DataProcessingRegister.AddSubtractExtendedRegister.Option,
11772 amount: DataProcessingRegister.AddSubtractExtendedRegister.Extend.Amount,
11773 },
11774 extended_register: struct { register: Register, extend: DataProcessingRegister.AddSubtractExtendedRegister.Extend },
11775 immediate: u12,
11776 shifted_immediate: struct { immediate: u12, lsl: DataProcessingImmediate.AddSubtractImmediate.Shift = .@"0" },
11777 register: Register,
11778 shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
11779 shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
11780 }) Instruction {
11781 const sf = d.format.integer;
11782 assert(n.format.integer == sf);
11783 form: switch (form) {
11784 .extended_register_explicit => |extended_register_explicit| {
11785 assert(extended_register_explicit.register.format.integer == extended_register_explicit.option.sf());
11786 return .{ .data_processing_register = .{ .add_subtract_extended_register = .{
11787 .sub = .{
11788 .Rd = d.alias.encode(.{ .sp = true }),
11789 .Rn = n.alias.encode(.{ .sp = true }),
11790 .imm3 = switch (extended_register_explicit.amount) {
11791 0...4 => |amount| amount,
11792 else => unreachable,
11793 },
11794 .option = extended_register_explicit.option,
11795 .Rm = extended_register_explicit.register.alias.encode(.{}),
11796 .sf = sf,
11797 },
11798 } } };
11799 },
11800 .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
11801 .register = extended_register.register,
11802 .option = extended_register.extend,
11803 .amount = switch (extended_register.extend) {
11804 .uxtb, .uxth, .uxtw, .uxtx, .sxtb, .sxth, .sxtw, .sxtx => |amount| amount,
11805 },
11806 } },
11807 .immediate => |immediate| continue :form .{ .shifted_immediate = .{ .immediate = immediate } },
11808 .shifted_immediate => |shifted_immediate| {
11809 return .{ .data_processing_immediate = .{ .add_subtract_immediate = .{
11810 .sub = .{
11811 .Rd = d.alias.encode(.{ .sp = true }),
11812 .Rn = n.alias.encode(.{ .sp = true }),
11813 .imm12 = shifted_immediate.immediate,
11814 .sh = shifted_immediate.lsl,
11815 .sf = sf,
11816 },
11817 } } };
11818 },
11819 .register => |register| continue :form if (d.alias == .sp or n.alias == .sp or register.alias == .sp)
11820 .{ .extended_register = .{ .register = register, .extend = switch (sf) {
11821 .word => .{ .uxtw = 0 },
11822 .doubleword => .{ .uxtx = 0 },
11823 } } }
11824 else
11825 .{ .shifted_register = .{ .register = register } },
11826 .shifted_register_explicit => |shifted_register_explicit| {
11827 assert(shifted_register_explicit.register.format.integer == sf);
11828 return .{ .data_processing_register = .{ .add_subtract_shifted_register = .{
11829 .sub = .{
11830 .Rd = d.alias.encode(.{}),
11831 .Rn = n.alias.encode(.{}),
11832 .imm6 = switch (sf) {
11833 .word => @as(u5, @intCast(shifted_register_explicit.amount)),
11834 .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
11835 },
11836 .Rm = shifted_register_explicit.register.alias.encode(.{}),
11837 .shift = switch (shifted_register_explicit.shift) {
11838 .lsl, .lsr, .asr => |shift| shift,
11839 .ror => unreachable,
11840 },
11841 .sf = sf,
11842 },
11843 } } };
11844 },
11845 .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
11846 .register = shifted_register.register,
11847 .shift = shifted_register.shift,
11848 .amount = switch (shifted_register.shift) {
11849 .lsl, .lsr, .asr => |amount| amount,
11850 .ror => unreachable,
11851 },
11852 } },
11853 }
11854 }
11855 /// C6.2.362 SUBS (extended register)
11856 /// C6.2.363 SUBS (immediate)
11857 /// C6.2.364 SUBS (shifted register)
11858 pub fn subs(d: Register, n: Register, form: union(enum) {
11859 extended_register_explicit: struct {
11860 register: Register,
11861 option: DataProcessingRegister.AddSubtractExtendedRegister.Option,
11862 amount: DataProcessingRegister.AddSubtractExtendedRegister.Extend.Amount,
11863 },
11864 extended_register: struct { register: Register, extend: DataProcessingRegister.AddSubtractExtendedRegister.Extend },
11865 immediate: u12,
11866 shifted_immediate: struct { immediate: u12, lsl: DataProcessingImmediate.AddSubtractImmediate.Shift = .@"0" },
11867 register: Register,
11868 shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 },
11869 shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none },
11870 }) Instruction {
11871 const sf = d.format.integer;
11872 assert(n.format.integer == sf);
11873 form: switch (form) {
11874 .extended_register_explicit => |extended_register_explicit| {
11875 assert(extended_register_explicit.register.format.integer == extended_register_explicit.option.sf());
11876 return .{ .data_processing_register = .{ .add_subtract_extended_register = .{
11877 .subs = .{
11878 .Rd = d.alias.encode(.{}),
11879 .Rn = n.alias.encode(.{ .sp = true }),
11880 .imm3 = switch (extended_register_explicit.amount) {
11881 0...4 => |amount| amount,
11882 else => unreachable,
11883 },
11884 .option = extended_register_explicit.option,
11885 .Rm = extended_register_explicit.register.alias.encode(.{}),
11886 .sf = sf,
11887 },
11888 } } };
11889 },
11890 .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{
11891 .register = extended_register.register,
11892 .option = extended_register.extend,
11893 .amount = switch (extended_register.extend) {
11894 .uxtb, .uxth, .uxtw, .uxtx, .sxtb, .sxth, .sxtw, .sxtx => |amount| amount,
11895 },
11896 } },
11897 .immediate => |immediate| continue :form .{ .shifted_immediate = .{ .immediate = immediate } },
11898 .shifted_immediate => |shifted_immediate| {
11899 return .{ .data_processing_immediate = .{ .add_subtract_immediate = .{
11900 .subs = .{
11901 .Rd = d.alias.encode(.{}),
11902 .Rn = n.alias.encode(.{ .sp = true }),
11903 .imm12 = shifted_immediate.immediate,
11904 .sh = shifted_immediate.lsl,
11905 .sf = sf,
11906 },
11907 } } };
11908 },
11909 .register => |register| continue :form if (d.alias == .sp or n.alias == .sp or register.alias == .sp)
11910 .{ .extended_register = .{ .register = register, .extend = switch (sf) {
11911 .word => .{ .uxtw = 0 },
11912 .doubleword => .{ .uxtx = 0 },
11913 } } }
11914 else
11915 .{ .shifted_register = .{ .register = register } },
11916 .shifted_register_explicit => |shifted_register_explicit| {
11917 assert(shifted_register_explicit.register.format.integer == sf);
11918 return .{ .data_processing_register = .{ .add_subtract_shifted_register = .{
11919 .subs = .{
11920 .Rd = d.alias.encode(.{}),
11921 .Rn = n.alias.encode(.{}),
11922 .imm6 = switch (sf) {
11923 .word => @as(u5, @intCast(shifted_register_explicit.amount)),
11924 .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)),
11925 },
11926 .Rm = shifted_register_explicit.register.alias.encode(.{}),
11927 .shift = switch (shifted_register_explicit.shift) {
11928 .lsl, .lsr, .asr => |shift| shift,
11929 .ror => unreachable,
11930 },
11931 .sf = sf,
11932 },
11933 } } };
11934 },
11935 .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{
11936 .register = shifted_register.register,
11937 .shift = shifted_register.shift,
11938 .amount = switch (shifted_register.shift) {
11939 .lsl, .lsr, .asr => |amount| amount,
11940 .ror => unreachable,
11941 },
11942 } },
11943 }
11944 }
11945 /// C6.2.365 SVC
11946 pub fn svc(imm: u16) Instruction {
11947 return .{ .branch_exception_generating_system = .{ .exception_generating = .{
11948 .svc = .{ .imm16 = imm },
11949 } } };
11950 }
11951 /// C6.2.372 SYS
11952 pub fn sys(op1: u3, n: u4, m: u4, op2: u3, t: Register) Instruction {
11953 assert(t.format.integer == .doubleword);
11954 return .{ .branch_exception_generating_system = .{ .system = .{
11955 .sys = .{
11956 .Rt = t.alias.encode(.{}),
11957 .op2 = op2,
11958 .CRm = m,
11959 .CRn = n,
11960 .op1 = op1,
11961 },
11962 } } };
11963 }
11964 /// C6.2.373 SYSL
11965 pub fn sysl(t: Register, op1: u3, n: u4, m: u4, op2: u3) Instruction {
11966 assert(t.format.integer == .doubleword);
11967 return .{ .branch_exception_generating_system = .{ .system = .{
11968 .sysl = .{
11969 .Rt = t.alias.encode(.{}),
11970 .op2 = op2,
11971 .CRm = m,
11972 .CRn = n,
11973 .op1 = op1,
11974 },
11975 } } };
11976 }
11977 /// C6.2.374 TBNZ
11978 pub fn tbnz(t: Register, imm: u6, label: i16) Instruction {
11979 return .{ .branch_exception_generating_system = .{ .test_branch_immediate = .{
11980 .tbnz = .{
11981 .Rt = t.alias.encode(.{}),
11982 .imm14 = @intCast(@shrExact(label, 2)),
11983 .b40 = @truncate(switch (t.format.integer) {
11984 .word => @as(u5, @intCast(imm)),
11985 .doubleword => imm,
11986 }),
11987 .b5 = @intCast(imm >> 5),
11988 },
11989 } } };
11990 }
11991 /// C6.2.375 TBZ
11992 pub fn tbz(t: Register, imm: u6, label: i16) Instruction {
11993 return .{ .branch_exception_generating_system = .{ .test_branch_immediate = .{
11994 .tbz = .{
11995 .Rt = t.alias.encode(.{}),
11996 .imm14 = @intCast(@shrExact(label, 2)),
11997 .b40 = @truncate(switch (t.format.integer) {
11998 .word => @as(u5, @intCast(imm)),
11999 .doubleword => imm,
12000 }),
12001 .b5 = @intCast(imm >> 5),
12002 },
12003 } } };
12004 }
12005 /// C6.2.376 TCANCEL
12006 pub fn tcancel(imm: u16) Instruction {
12007 return .{ .branch_exception_generating_system = .{ .exception_generating = .{
12008 .tcancel = .{ .imm16 = imm },
12009 } } };
12010 }
12011 /// C6.2.385 UBFM
12012 pub fn ubfm(d: Register, n: Register, bitmask: DataProcessingImmediate.Bitmask) Instruction {
12013 const sf = d.format.integer;
12014 assert(n.format.integer == sf and bitmask.validBitfield(sf));
12015 return .{ .data_processing_immediate = .{ .bitfield = .{
12016 .ubfm = .{
12017 .Rd = d.alias.encode(.{}),
12018 .Rn = n.alias.encode(.{}),
12019 .imm = bitmask,
12020 .sf = sf,
12021 },
12022 } } };
12023 }
12024 /// C7.2.355 UCVTF (scalar, integer)
12025 pub fn ucvtf(d: Register, n: Register) Instruction {
12026 return .{ .data_processing_vector = .{ .convert_float_integer = .{
12027 .ucvtf = .{
12028 .Rd = d.alias.encode(.{ .V = true }),
12029 .Rn = n.alias.encode(.{}),
12030 .ftype = switch (d.format.scalar) {
12031 else => unreachable,
12032 .single => .single,
12033 .double => .double,
12034 .half => .half,
12035 },
12036 .sf = n.format.integer,
12037 },
12038 } } };
12039 }
12040 /// C6.2.387 UDF
12041 pub fn udf(imm: u16) Instruction {
12042 return .{ .reserved = .{
12043 .udf = .{ .imm16 = imm },
12044 } };
12045 }
12046 /// C6.2.388 UDIV
12047 pub fn udiv(d: Register, n: Register, m: Register) Instruction {
12048 const sf = d.format.integer;
12049 assert(n.format.integer == sf and m.format.integer == sf);
12050 return .{ .data_processing_register = .{ .data_processing_two_source = .{
12051 .udiv = .{
12052 .Rd = d.alias.encode(.{}),
12053 .Rn = n.alias.encode(.{}),
12054 .Rm = m.alias.encode(.{}),
12055 .sf = sf,
12056 },
12057 } } };
12058 }
12059 /// C6.2.389 UMADDL
12060 pub fn umaddl(d: Register, n: Register, m: Register, a: Register) Instruction {
12061 assert(d.format.integer == .doubleword and n.format.integer == .word and m.format.integer == .word and a.format.integer == .doubleword);
12062 return .{ .data_processing_register = .{ .data_processing_three_source = .{
12063 .umaddl = .{
12064 .Rd = d.alias.encode(.{}),
12065 .Rn = n.alias.encode(.{}),
12066 .Ra = a.alias.encode(.{}),
12067 .Rm = m.alias.encode(.{}),
12068 },
12069 } } };
12070 }
12071 /// C6.2.391 UMSUBL
12072 pub fn umsubl(d: Register, n: Register, m: Register, a: Register) Instruction {
12073 assert(d.format.integer == .doubleword and n.format.integer == .word and m.format.integer == .word and a.format.integer == .doubleword);
12074 return .{ .data_processing_register = .{ .data_processing_three_source = .{
12075 .umsubl = .{
12076 .Rd = d.alias.encode(.{}),
12077 .Rn = n.alias.encode(.{}),
12078 .Ra = a.alias.encode(.{}),
12079 .Rm = m.alias.encode(.{}),
12080 },
12081 } } };
12082 }
12083 /// C7.2.371 UMOV
12084 pub fn umov(d: Register, n: Register) Instruction {
12085 const sf = d.format.integer;
12086 const vs = n.format.element.size;
12087 switch (vs) {
12088 else => unreachable,
12089 .byte, .half, .single => assert(sf == .word),
12090 .double => assert(sf == .doubleword),
12091 }
12092 return .{ .data_processing_vector = .{ .simd_copy = .{
12093 .umov = .{
12094 .Rd = d.alias.encode(.{}),
12095 .Rn = n.alias.encode(.{ .V = true }),
12096 .imm5 = switch (vs) {
12097 else => unreachable,
12098 .byte => @as(u5, @as(u4, @intCast(n.format.element.index))) << 1 | @as(u5, 0b1) << 0,
12099 .half => @as(u5, @as(u3, @intCast(n.format.element.index))) << 2 | @as(u5, 0b10) << 0,
12100 .single => @as(u5, @as(u2, @intCast(n.format.element.index))) << 3 | @as(u5, 0b100) << 0,
12101 .double => @as(u5, @as(u1, @intCast(n.format.element.index))) << 4 | @as(u5, 0b1000) << 0,
12102 },
12103 .Q = sf,
12104 },
12105 } } };
12106 }
12107 /// C6.2.392 UMULH
12108 pub fn umulh(d: Register, n: Register, m: Register) Instruction {
12109 assert(d.format.integer == .doubleword and n.format.integer == .doubleword and m.format.integer == .doubleword);
12110 return .{ .data_processing_register = .{ .data_processing_three_source = .{
12111 .umulh = .{
12112 .Rd = d.alias.encode(.{}),
12113 .Rn = n.alias.encode(.{}),
12114 .Rm = m.alias.encode(.{}),
12115 },
12116 } } };
12117 }
12118 /// C6.2.396 WFE
12119 pub fn wfe() Instruction {
12120 return .{ .branch_exception_generating_system = .{ .hints = .{
12121 .wfe = .{},
12122 } } };
12123 }
12124 /// C6.2.398 WFI
12125 pub fn wfi() Instruction {
12126 return .{ .branch_exception_generating_system = .{ .hints = .{
12127 .wfi = .{},
12128 } } };
12129 }
12130 /// C6.2.402 YIELD
12131 pub fn yield() Instruction {
12132 return .{ .branch_exception_generating_system = .{ .hints = .{
12133 .yield = .{},
12134 } } };
12135 }
12136
12137 pub const size = @divExact(@bitSizeOf(Backing), 8);
12138 pub const Backing = u32;
12139 pub fn read(mem: *const [size]u8) Instruction {
12140 return @bitCast(std.mem.readInt(Backing, mem, .little));
12141 }
12142 pub fn write(inst: Instruction, mem: *[size]u8) void {
12143 std.mem.writeInt(Backing, mem, @bitCast(inst), .little);
12144 }
12145
12146 pub fn format(inst: Instruction, writer: *std.Io.Writer) std.Io.Writer.Error!void {
12147 const dis: aarch64.Disassemble = .{};
12148 try dis.printInstruction(inst, writer);
12149 }
12150
12151 comptime {
12152 @setEvalBranchQuota(68_000);
12153 verify(@typeName(Instruction), Instruction);
12154 }
12155 fn verify(name: []const u8, Type: type) void {
12156 switch (@typeInfo(Type)) {
12157 .@"union" => |info| {
12158 if (info.layout != .@"packed" or @bitSizeOf(Type) != @bitSizeOf(Backing)) {
12159 @compileLog(name ++ " should have u32 abi");
12160 }
12161 for (info.fields) |field| verify(name ++ "." ++ field.name, field.type);
12162 },
12163 .@"struct" => |info| {
12164 if (info.layout != .@"packed" or info.backing_integer != Backing) {
12165 @compileLog(name ++ " should have u32 abi");
12166 }
12167 var bit_offset = 0;
12168 for (info.fields) |field| {
12169 if (std.mem.startsWith(u8, field.name, "encoded")) {
12170 if (if (std.fmt.parseInt(u5, field.name["encoded".len..], 10)) |encoded_bit_offset| encoded_bit_offset != bit_offset else |_| true) {
12171 @compileError(std.fmt.comptimePrint("{s}.{s} should be named encoded{d}", .{ name, field.name, bit_offset }));
12172 }
12173 if (field.default_value_ptr != null) {
12174 @compileError(std.fmt.comptimePrint("{s}.{s} should be named decoded{d}", .{ name, field.name, bit_offset }));
12175 }
12176 } else if (std.mem.startsWith(u8, field.name, "decoded")) {
12177 if (if (std.fmt.parseInt(u5, field.name["decoded".len..], 10)) |decoded_bit_offset| decoded_bit_offset != bit_offset else |_| true) {
12178 @compileError(std.fmt.comptimePrint("{s}.{s} should be named decoded{d}", .{ name, field.name, bit_offset }));
12179 }
12180 if (field.default_value_ptr == null) {
12181 @compileError(std.fmt.comptimePrint("{s}.{s} should be named encoded{d}", .{ name, field.name, bit_offset }));
12182 }
12183 }
12184 bit_offset += @bitSizeOf(field.type);
12185 }
12186 },
12187 else => @compileError(name ++ " has an unexpected field type"),
12188 }
12189 }
12190};
12191
12192const aarch64 = @import("../aarch64.zig");
12193const assert = std.debug.assert;
12194const std = @import("std");
src/codegen/aarch64/instructions.zon created+1543
...@@ -0,0 +1,1543 @@
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.16 ASR (register)
217 .{
218 .pattern = "ASR <Wd>, <Wn>, <Wm>",
219 .symbols = .{
220 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
221 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
222 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
223 },
224 .encode = .{ .asrv, .Wd, .Wn, .Wm },
225 },
226 .{
227 .pattern = "ASR <Xd>, <Xn>, <Xm>",
228 .symbols = .{
229 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
230 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
231 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
232 },
233 .encode = .{ .asrv, .Xd, .Xn, .Xm },
234 },
235 // C6.2.17 ASR (immediate)
236 .{
237 .pattern = "ASR <Wd>, <Wn>, #<shift>",
238 .symbols = .{
239 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
240 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
241 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
242 },
243 .encode = .{ .sbfm, .Wd, .Wn, .{ .N = .word, .immr = .shift, .imms = 31 } },
244 },
245 .{
246 .pattern = "ASR <Xd>, <Xn>, #<shift>",
247 .symbols = .{
248 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
249 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
250 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
251 },
252 .encode = .{ .sbfm, .Xd, .Xn, .{ .N = .doubleword, .immr = .shift, .imms = 63 } },
253 },
254 // C6.2.18 ASRV
255 .{
256 .pattern = "ASRV <Wd>, <Wn>, <Wm>",
257 .symbols = .{
258 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
259 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
260 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
261 },
262 .encode = .{ .asrv, .Wd, .Wn, .Wm },
263 },
264 .{
265 .pattern = "ASRV <Xd>, <Xn>, <Xm>",
266 .symbols = .{
267 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
268 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
269 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
270 },
271 .encode = .{ .asrv, .Xd, .Xn, .Xm },
272 },
273 // C6.2.35 BLR
274 .{
275 .pattern = "BLR <Xn>",
276 .symbols = .{
277 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
278 },
279 .encode = .{ .blr, .Xn },
280 },
281 // C6.2.30 BFM
282 .{
283 .pattern = "BFM <Wd>, <Wn>, #<immr>, #<imms>",
284 .symbols = .{
285 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
286 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
287 .immr = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
288 .imms = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
289 },
290 .encode = .{ .bfm, .Wd, .Wn, .{ .N = .word, .immr = .immr, .imms = .imms } },
291 },
292 .{
293 .pattern = "BFM <Xd>, <Xn>, #<immr>, #<imms>",
294 .symbols = .{
295 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
296 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
297 .immr = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
298 .imms = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
299 },
300 .encode = .{ .bfm, .Xd, .Xn, .{ .N = .doubleword, .immr = .immr, .imms = .imms } },
301 },
302 // C6.2.37 BR
303 .{
304 .pattern = "BR <Xn>",
305 .symbols = .{
306 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
307 },
308 .encode = .{ .br, .Xn },
309 },
310 // C6.2.40 BRK
311 .{
312 .pattern = "BRK #<imm>",
313 .symbols = .{
314 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
315 },
316 .encode = .{ .brk, .imm },
317 },
318 // C6.2.56 CLREX
319 .{
320 .pattern = "CLREX",
321 .symbols = .{},
322 .encode = .{ .clrex, 0b1111 },
323 },
324 .{
325 .pattern = "CLREX #<imm>",
326 .symbols = .{
327 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 } } },
328 },
329 .encode = .{ .clrex, .imm },
330 },
331 // C6.2.109 DC
332 .{
333 .pattern = "DC IVAC, <Xt>",
334 .symbols = .{
335 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
336 },
337 .encode = .{ .sys, 0b000, 0b0111, 0b0110, 0b001, .Xt },
338 },
339 .{
340 .pattern = "DC ISW, <Xt>",
341 .symbols = .{
342 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
343 },
344 .encode = .{ .sys, 0b000, 0b0111, 0b0110, 0b010, .Xt },
345 },
346 .{
347 .pattern = "DC CSW, <Xt>",
348 .symbols = .{
349 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
350 },
351 .encode = .{ .sys, 0b000, 0b0111, 0b1010, 0b010, .Xt },
352 },
353 .{
354 .pattern = "DC CISW, <Xt>",
355 .symbols = .{
356 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
357 },
358 .encode = .{ .sys, 0b000, 0b0111, 0b1110, 0b010, .Xt },
359 },
360 .{
361 .pattern = "DC ZVA, <Xt>",
362 .symbols = .{
363 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
364 },
365 .encode = .{ .sys, 0b011, 0b0111, 0b0100, 0b001, .Xt },
366 },
367 .{
368 .pattern = "DC CVAC, <Xt>",
369 .symbols = .{
370 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
371 },
372 .encode = .{ .sys, 0b011, 0b0111, 0b1010, 0b001, .Xt },
373 },
374 .{
375 .pattern = "DC CVAU, <Xt>",
376 .symbols = .{
377 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
378 },
379 .encode = .{ .sys, 0b011, 0b0111, 0b1011, 0b001, .Xt },
380 },
381 .{
382 .pattern = "DC CIVAC, <Xt>",
383 .symbols = .{
384 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
385 },
386 .encode = .{ .sys, 0b011, 0b0111, 0b1110, 0b001, .Xt },
387 },
388 // C6.2.110 DCPS1
389 .{
390 .pattern = "DCPS1",
391 .symbols = .{},
392 .encode = .{ .dcps1, 0 },
393 },
394 .{
395 .pattern = "DCPS1 #<imm>",
396 .symbols = .{
397 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
398 },
399 .encode = .{ .dcps1, .imm },
400 },
401 // C6.2.111 DCPS2
402 .{
403 .pattern = "DCPS2",
404 .symbols = .{},
405 .encode = .{ .dcps2, 0 },
406 },
407 .{
408 .pattern = "DCPS2 #<imm>",
409 .symbols = .{
410 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
411 },
412 .encode = .{ .dcps2, .imm },
413 },
414 // C6.2.112 DCPS3
415 .{
416 .pattern = "DCPS3",
417 .symbols = .{},
418 .encode = .{ .dcps3, 0 },
419 },
420 .{
421 .pattern = "DCPS3 #<imm>",
422 .symbols = .{
423 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
424 },
425 .encode = .{ .dcps3, .imm },
426 },
427 // C6.2.116 DSB
428 .{
429 .pattern = "DSB <option>",
430 .symbols = .{
431 .option = .{ .barrier = .{} },
432 },
433 .encode = .{ .dsb, .option },
434 },
435 .{
436 .pattern = "DSB #<imm>",
437 .symbols = .{
438 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 } } },
439 },
440 .encode = .{ .dsb, .imm },
441 },
442 // C6.2.120 EOR (shifted register)
443 .{
444 .pattern = "EOR <Wd>, <Wn>, <Wm>",
445 .symbols = .{
446 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
447 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
448 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
449 },
450 .encode = .{ .eor, .Wd, .Wn, .{ .register = .Wm } },
451 },
452 .{
453 .pattern = "EOR <Wd>, <Wn>, <Wm>, <shift> #<amount>",
454 .symbols = .{
455 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
456 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
457 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
458 .shift = .{ .shift = .{} },
459 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
460 },
461 .encode = .{ .eor, .Wd, .Wn, .{ .shifted_register_explicit = .{ .register = .Wm, .shift = .shift, .amount = .amount } } },
462 },
463 .{
464 .pattern = "EOR <Xd>, <Xn>, <Xm>",
465 .symbols = .{
466 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
467 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
468 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
469 },
470 .encode = .{ .eor, .Xd, .Xn, .{ .register = .Xm } },
471 },
472 .{
473 .pattern = "EOR <Xd>, <Xn>, <Xm>, <shift> #<amount>",
474 .symbols = .{
475 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
476 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
477 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
478 .shift = .{ .shift = .{} },
479 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
480 },
481 .encode = .{ .eor, .Xd, .Xn, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } },
482 },
483 // C6.2.124 EXTR
484 .{
485 .pattern = "EXTR <Wd>, <Wn>, <Wm>, #<lsb>",
486 .symbols = .{
487 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
488 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
489 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
490 .lsb = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
491 },
492 .encode = .{ .extr, .Wd, .Wn, .Wm, .lsb },
493 },
494 .{
495 .pattern = "EXTR <Xd>, <Xn>, <Xm>, #<lsb>",
496 .symbols = .{
497 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
498 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
499 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
500 .lsb = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
501 },
502 .encode = .{ .extr, .Xd, .Xn, .Xm, .lsb },
503 },
504 // C6.2.126 HINT
505 .{
506 .pattern = "HINT #<imm>",
507 .symbols = .{
508 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 7 } } },
509 },
510 .encode = .{ .hint, .imm },
511 },
512 // C6.2.127 HLT
513 .{
514 .pattern = "HLT #<imm>",
515 .symbols = .{
516 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
517 },
518 .encode = .{ .hlt, .imm },
519 },
520 // C6.2.128 HVC
521 .{
522 .pattern = "HVC #<imm>",
523 .symbols = .{
524 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
525 },
526 .encode = .{ .hvc, .imm },
527 },
528 // C6.2.129 IC
529 .{
530 .pattern = "IC IALLUIS",
531 .symbols = .{
532 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
533 },
534 .encode = .{ .sys, 0b000, 0b0111, 0b0001, 0b000, .xzr },
535 },
536 .{
537 .pattern = "IC IALLUIS, <Xt>",
538 .symbols = .{
539 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
540 },
541 .encode = .{ .sys, 0b000, 0b0111, 0b0001, 0b000, .Xt },
542 },
543 .{
544 .pattern = "IC IALLU",
545 .symbols = .{
546 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
547 },
548 .encode = .{ .sys, 0b000, 0b0111, 0b0101, 0b000, .xzr },
549 },
550 .{
551 .pattern = "IC IALLU, <Xt>",
552 .symbols = .{
553 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
554 },
555 .encode = .{ .sys, 0b000, 0b0111, 0b0101, 0b000, .Xt },
556 },
557 .{
558 .pattern = "IC IVAU",
559 .symbols = .{
560 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
561 },
562 .encode = .{ .sys, 0b011, 0b0111, 0b0101, 0b001, .xzr },
563 },
564 .{
565 .pattern = "IC IVAU, <Xt>",
566 .symbols = .{
567 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
568 },
569 .encode = .{ .sys, 0b011, 0b0111, 0b0101, 0b001, .Xt },
570 },
571 // C6.2.131 ISB
572 .{
573 .pattern = "ISB",
574 .symbols = .{},
575 .encode = .{ .isb, .sy },
576 },
577 .{
578 .pattern = "ISB <option>",
579 .symbols = .{
580 .option = .{ .barrier = .{ .only_sy = true } },
581 },
582 .encode = .{ .isb, .option },
583 },
584 .{
585 .pattern = "ISB #<imm>",
586 .symbols = .{
587 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 } } },
588 },
589 .encode = .{ .isb, .imm },
590 },
591 // C6.2.164 LDP
592 .{
593 .pattern = "LDP <Wt1>, <Wt2>, [<Xn|SP>], #<imm>",
594 .symbols = .{
595 .Wt1 = .{ .reg = .{ .format = .{ .integer = .word } } },
596 .Wt2 = .{ .reg = .{ .format = .{ .integer = .word } } },
597 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
598 .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 }, .multiple_of = 4 } },
599 },
600 .encode = .{ .ldp, .Wt1, .Wt2, .{ .post_index = .{ .base = .Xn, .index = .imm } } },
601 },
602 .{
603 .pattern = "LDP <Xt1>, <Xt2>, [<Xn|SP>], #<imm>",
604 .symbols = .{
605 .Xt1 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
606 .Xt2 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
607 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
608 .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 10 }, .multiple_of = 8 } },
609 },
610 .encode = .{ .ldp, .Xt1, .Xt2, .{ .post_index = .{ .base = .Xn, .index = .imm } } },
611 },
612 .{
613 .pattern = "LDP <Wt1>, <Wt2>, [<Xn|SP>, #<imm>]!",
614 .symbols = .{
615 .Wt1 = .{ .reg = .{ .format = .{ .integer = .word } } },
616 .Wt2 = .{ .reg = .{ .format = .{ .integer = .word } } },
617 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
618 .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 }, .multiple_of = 4 } },
619 },
620 .encode = .{ .ldp, .Wt1, .Wt2, .{ .pre_index = .{ .base = .Xn, .index = .imm } } },
621 },
622 .{
623 .pattern = "LDP <Xt1>, <Xt2>, [<Xn|SP>, #<imm>]!",
624 .symbols = .{
625 .Xt1 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
626 .Xt2 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
627 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
628 .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 10 }, .multiple_of = 8 } },
629 },
630 .encode = .{ .ldp, .Xt1, .Xt2, .{ .pre_index = .{ .base = .Xn, .index = .imm } } },
631 },
632 .{
633 .pattern = "LDP <Wt1>, <Wt2>, [<Xn|SP>]",
634 .symbols = .{
635 .Wt1 = .{ .reg = .{ .format = .{ .integer = .word } } },
636 .Wt2 = .{ .reg = .{ .format = .{ .integer = .word } } },
637 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
638 },
639 .encode = .{ .ldp, .Wt1, .Wt2, .{ .base = .Xn } },
640 },
641 .{
642 .pattern = "LDP <Wt1>, <Wt2>, [<Xn|SP>, #<imm>]",
643 .symbols = .{
644 .Wt1 = .{ .reg = .{ .format = .{ .integer = .word } } },
645 .Wt2 = .{ .reg = .{ .format = .{ .integer = .word } } },
646 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
647 .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 }, .multiple_of = 4 } },
648 },
649 .encode = .{ .ldp, .Wt1, .Wt2, .{ .signed_offset = .{ .base = .Xn, .offset = .imm } } },
650 },
651 .{
652 .pattern = "LDP <Xt1>, <Xt2>, [<Xn|SP>]",
653 .symbols = .{
654 .Xt1 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
655 .Xt2 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
656 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
657 },
658 .encode = .{ .ldp, .Xt1, .Xt2, .{ .base = .Xn } },
659 },
660 .{
661 .pattern = "LDP <Xt1>, <Xt2>, [<Xn|SP>, #<imm>]",
662 .symbols = .{
663 .Xt1 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
664 .Xt2 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
665 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
666 .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 10 }, .multiple_of = 8 } },
667 },
668 .encode = .{ .ldp, .Xt1, .Xt2, .{ .signed_offset = .{ .base = .Xn, .offset = .imm } } },
669 },
670 // C6.2.166 LDR (immediate)
671 .{
672 .pattern = "LDR <Wt>, [<Xn|SP>], #<simm>",
673 .symbols = .{
674 .Wt = .{ .reg = .{ .format = .{ .integer = .word } } },
675 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
676 .simm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 } } },
677 },
678 .encode = .{ .ldr, .Wt, .{ .post_index = .{ .base = .Xn, .index = .simm } } },
679 },
680 .{
681 .pattern = "LDR <Xt>, [<Xn|SP>], #<simm>",
682 .symbols = .{
683 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
684 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
685 .simm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 } } },
686 },
687 .encode = .{ .ldr, .Xt, .{ .post_index = .{ .base = .Xn, .index = .simm } } },
688 },
689 .{
690 .pattern = "LDR <Wt>, [<Xn|SP>, #<simm>]!",
691 .symbols = .{
692 .Wt = .{ .reg = .{ .format = .{ .integer = .word } } },
693 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
694 .simm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 } } },
695 },
696 .encode = .{ .ldr, .Wt, .{ .pre_index = .{ .base = .Xn, .index = .simm } } },
697 },
698 .{
699 .pattern = "LDR <Xt>, [<Xn|SP>, #<simm>]!",
700 .symbols = .{
701 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
702 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
703 .simm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 } } },
704 },
705 .encode = .{ .ldr, .Xt, .{ .pre_index = .{ .base = .Xn, .index = .simm } } },
706 },
707 .{
708 .pattern = "LDR <Wt>, [<Xn|SP>]",
709 .symbols = .{
710 .Wt = .{ .reg = .{ .format = .{ .integer = .word } } },
711 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
712 },
713 .encode = .{ .ldr, .Wt, .{ .base = .Xn } },
714 },
715 .{
716 .pattern = "LDR <Wt>, [<Xn|SP>, #<pimm>]",
717 .symbols = .{
718 .Wt = .{ .reg = .{ .format = .{ .integer = .word } } },
719 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
720 .pimm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 14 }, .multiple_of = 4 } },
721 },
722 .encode = .{ .ldr, .Wt, .{ .unsigned_offset = .{ .base = .Xn, .offset = .pimm } } },
723 },
724 .{
725 .pattern = "LDR <Xt>, [<Xn|SP>]",
726 .symbols = .{
727 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
728 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
729 },
730 .encode = .{ .ldr, .Xt, .{ .base = .Xn } },
731 },
732 .{
733 .pattern = "LDR <Xt>, [<Xn|SP>, #<pimm>]",
734 .symbols = .{
735 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
736 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
737 .pimm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 15 }, .multiple_of = 8 } },
738 },
739 .encode = .{ .ldr, .Xt, .{ .unsigned_offset = .{ .base = .Xn, .offset = .pimm } } },
740 },
741 // C6.2.212 LSL (register)
742 .{
743 .pattern = "LSL <Wd>, <Wn>, <Wm>",
744 .symbols = .{
745 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
746 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
747 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
748 },
749 .encode = .{ .lslv, .Wd, .Wn, .Wm },
750 },
751 .{
752 .pattern = "LSL <Xd>, <Xn>, <Xm>",
753 .symbols = .{
754 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
755 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
756 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
757 },
758 .encode = .{ .lslv, .Xd, .Xn, .Xm },
759 },
760 // C6.2.214 LSLV
761 .{
762 .pattern = "LSLV <Wd>, <Wn>, <Wm>",
763 .symbols = .{
764 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
765 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
766 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
767 },
768 .encode = .{ .lslv, .Wd, .Wn, .Wm },
769 },
770 .{
771 .pattern = "LSLV <Xd>, <Xn>, <Xm>",
772 .symbols = .{
773 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
774 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
775 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
776 },
777 .encode = .{ .lslv, .Xd, .Xn, .Xm },
778 },
779 // C6.2.215 LSR (register)
780 .{
781 .pattern = "LSR <Wd>, <Wn>, <Wm>",
782 .symbols = .{
783 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
784 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
785 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
786 },
787 .encode = .{ .lsrv, .Wd, .Wn, .Wm },
788 },
789 .{
790 .pattern = "LSR <Xd>, <Xn>, <Xm>",
791 .symbols = .{
792 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
793 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
794 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
795 },
796 .encode = .{ .lsrv, .Xd, .Xn, .Xm },
797 },
798 // C6.2.217 LSRV
799 .{
800 .pattern = "LSRV <Wd>, <Wn>, <Wm>",
801 .symbols = .{
802 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
803 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
804 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
805 },
806 .encode = .{ .lsrv, .Wd, .Wn, .Wm },
807 },
808 .{
809 .pattern = "LSRV <Xd>, <Xn>, <Xm>",
810 .symbols = .{
811 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
812 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
813 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
814 },
815 .encode = .{ .lsrv, .Xd, .Xn, .Xm },
816 },
817 // C6.2.220 MOV (to/from SP)
818 .{
819 .pattern = "MOV WSP, <Wn|WSP>",
820 .symbols = .{
821 .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
822 },
823 .encode = .{ .add, .wsp, .Wn, .{ .immediate = 0 } },
824 },
825 .{
826 .pattern = "MOV <Wd|WSP>, WSP",
827 .symbols = .{
828 .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
829 },
830 .encode = .{ .add, .Wd, .wsp, .{ .immediate = 0 } },
831 },
832 .{
833 .pattern = "MOV SP, <Xn|SP>",
834 .symbols = .{
835 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
836 },
837 .encode = .{ .add, .sp, .Xn, .{ .immediate = 0 } },
838 },
839 .{
840 .pattern = "MOV <Xd|SP>, SP",
841 .symbols = .{
842 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
843 },
844 .encode = .{ .add, .Xd, .sp, .{ .immediate = 0 } },
845 },
846 // C6.2.222 MOV (wide immediate)
847 .{
848 .pattern = "MOV <Wd>, #<imm>",
849 .symbols = .{
850 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
851 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
852 },
853 .encode = .{ .movz, .Wd, .imm, .{ .lsl = .@"0" } },
854 },
855 .{
856 .pattern = "MOV <Xd>, #<imm>",
857 .symbols = .{
858 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
859 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
860 },
861 .encode = .{ .movz, .Xd, .imm, .{ .lsl = .@"0" } },
862 },
863 // C6.2.224 MOV (register)
864 .{
865 .pattern = "MOV <Wd>, <Wm>",
866 .symbols = .{
867 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
868 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
869 },
870 .encode = .{ .orr, .Wd, .wzr, .{ .register = .Wm } },
871 },
872 .{
873 .pattern = "MOV <Xd>, <Xm>",
874 .symbols = .{
875 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
876 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
877 },
878 .encode = .{ .orr, .Xd, .xzr, .{ .register = .Xm } },
879 },
880 // C6.2.225 MOVK
881 .{
882 .pattern = "MOVK <Wd>, #<imm>",
883 .symbols = .{
884 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
885 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
886 },
887 .encode = .{ .movk, .Wd, .imm, .{} },
888 },
889 .{
890 .pattern = "MOVK <Wd>, #<imm>, LSL #<shift>",
891 .symbols = .{
892 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
893 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
894 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 }, .multiple_of = 16 } },
895 },
896 .encode = .{ .movk, .Wd, .imm, .{ .lsl = .shift } },
897 },
898 .{
899 .pattern = "MOVK <Xd>, #<imm>",
900 .symbols = .{
901 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
902 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
903 },
904 .encode = .{ .movk, .Xd, .imm, .{} },
905 },
906 .{
907 .pattern = "MOVK <Xd>, #<imm>, LSL #<shift>",
908 .symbols = .{
909 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
910 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
911 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 }, .multiple_of = 16 } },
912 },
913 .encode = .{ .movk, .Xd, .imm, .{ .lsl = .shift } },
914 },
915 // C6.2.226 MOVN
916 .{
917 .pattern = "MOVN <Wd>, #<imm>",
918 .symbols = .{
919 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
920 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
921 },
922 .encode = .{ .movn, .Wd, .imm, .{} },
923 },
924 .{
925 .pattern = "MOVN <Wd>, #<imm>, LSL #<shift>",
926 .symbols = .{
927 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
928 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
929 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 }, .multiple_of = 16 } },
930 },
931 .encode = .{ .movn, .Wd, .imm, .{ .lsl = .shift } },
932 },
933 .{
934 .pattern = "MOVN <Xd>, #<imm>",
935 .symbols = .{
936 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
937 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
938 },
939 .encode = .{ .movn, .Xd, .imm, .{} },
940 },
941 .{
942 .pattern = "MOVN <Xd>, #<imm>, LSL #<shift>",
943 .symbols = .{
944 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
945 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
946 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 }, .multiple_of = 16 } },
947 },
948 .encode = .{ .movn, .Xd, .imm, .{ .lsl = .shift } },
949 },
950 // C6.2.227 MOVZ
951 .{
952 .pattern = "MOVZ <Wd>, #<imm>",
953 .symbols = .{
954 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
955 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
956 },
957 .encode = .{ .movz, .Wd, .imm, .{} },
958 },
959 .{
960 .pattern = "MOVZ <Wd>, #<imm>, LSL #<shift>",
961 .symbols = .{
962 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
963 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
964 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 }, .multiple_of = 16 } },
965 },
966 .encode = .{ .movz, .Wd, .imm, .{ .lsl = .shift } },
967 },
968 .{
969 .pattern = "MOVZ <Xd>, #<imm>",
970 .symbols = .{
971 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
972 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
973 },
974 .encode = .{ .movz, .Xd, .imm, .{} },
975 },
976 .{
977 .pattern = "MOVZ <Xd>, #<imm>, LSL #<shift>",
978 .symbols = .{
979 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
980 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
981 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 }, .multiple_of = 16 } },
982 },
983 .encode = .{ .movz, .Xd, .imm, .{ .lsl = .shift } },
984 },
985 // C6.2.228 MRS
986 .{
987 .pattern = "MRS <Xt>, <systemreg>",
988 .symbols = .{
989 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
990 .systemreg = .systemreg,
991 },
992 .encode = .{ .mrs, .Xt, .systemreg },
993 },
994 // C6.2.230 MSR (register)
995 .{
996 .pattern = "MSR <systemreg>, <Xt>",
997 .symbols = .{
998 .systemreg = .systemreg,
999 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1000 },
1001 .encode = .{ .msr, .systemreg, .Xt },
1002 },
1003 // C6.2.234 NEG
1004 .{
1005 .pattern = "NEG <Wd>, <Wm>",
1006 .symbols = .{
1007 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
1008 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
1009 },
1010 .encode = .{ .sub, .Wd, .wzr, .{ .register = .Wm } },
1011 },
1012 .{
1013 .pattern = "NEG <Wd>, <Wm>, <shift> #<amount>",
1014 .symbols = .{
1015 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
1016 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
1017 .shift = .{ .shift = .{ .allow_ror = false } },
1018 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
1019 },
1020 .encode = .{ .sub, .Wd, .wzr, .{ .shifted_register_explicit = .{ .register = .Wm, .shift = .shift, .amount = .amount } } },
1021 },
1022 .{
1023 .pattern = "NEG <Xd>, <Xm>",
1024 .symbols = .{
1025 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1026 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1027 },
1028 .encode = .{ .sub, .Xd, .xzr, .{ .register = .Xm } },
1029 },
1030 .{
1031 .pattern = "NEG <Xd>, <Xm>, <shift> #<amount>",
1032 .symbols = .{
1033 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1034 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1035 .shift = .{ .shift = .{ .allow_ror = false } },
1036 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
1037 },
1038 .encode = .{ .sub, .Xd, .xzr, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } },
1039 },
1040 // C6.2.238 NOP
1041 .{
1042 .pattern = "NOP",
1043 .symbols = .{},
1044 .encode = .{.nop},
1045 },
1046 // C6.2.241 ORR (shifted register)
1047 .{
1048 .pattern = "ORR <Wd>, <Wn>, <Wm>",
1049 .symbols = .{
1050 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
1051 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
1052 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
1053 },
1054 .encode = .{ .orr, .Wd, .Wn, .{ .register = .Wm } },
1055 },
1056 .{
1057 .pattern = "ORR <Wd>, <Wn>, <Wm>, <shift> #<amount>",
1058 .symbols = .{
1059 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
1060 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
1061 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
1062 .shift = .{ .shift = .{} },
1063 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
1064 },
1065 .encode = .{ .orr, .Wd, .Wn, .{ .shifted_register_explicit = .{ .register = .Wm, .shift = .shift, .amount = .amount } } },
1066 },
1067 .{
1068 .pattern = "ORR <Xd>, <Xn>, <Xm>",
1069 .symbols = .{
1070 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1071 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1072 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1073 },
1074 .encode = .{ .orr, .Xd, .Xn, .{ .register = .Xm } },
1075 },
1076 .{
1077 .pattern = "ORR <Xd>, <Xn>, <Xm>, <shift> #<amount>",
1078 .symbols = .{
1079 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1080 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1081 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1082 .shift = .{ .shift = .{} },
1083 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
1084 },
1085 .encode = .{ .orr, .Xd, .Xn, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } },
1086 },
1087 // C6.2.254 RET
1088 .{
1089 .pattern = "RET",
1090 .symbols = .{},
1091 .encode = .{ .ret, .x30 },
1092 },
1093 .{
1094 .pattern = "RET <Xn>",
1095 .symbols = .{
1096 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1097 },
1098 .encode = .{ .ret, .Xn },
1099 },
1100 // C6.2.261 ROR (immediate)
1101 .{
1102 .pattern = "ROR <Wd>, <Ws>, #<shift>",
1103 .symbols = .{
1104 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
1105 .Ws = .{ .reg = .{ .format = .{ .integer = .word } } },
1106 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
1107 },
1108 .encode = .{ .extr, .Wd, .Ws, .Ws, .shift },
1109 },
1110 .{
1111 .pattern = "ROR <Xd>, <Xs>, #<shift>",
1112 .symbols = .{
1113 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1114 .Xs = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1115 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
1116 },
1117 .encode = .{ .extr, .Xd, .Xs, .Xs, .shift },
1118 },
1119 // C6.2.262 ROR (register)
1120 .{
1121 .pattern = "ROR <Wd>, <Wn>, <Wm>",
1122 .symbols = .{
1123 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
1124 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
1125 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
1126 },
1127 .encode = .{ .rorv, .Wd, .Wn, .Wm },
1128 },
1129 .{
1130 .pattern = "ROR <Xd>, <Xn>, <Xm>",
1131 .symbols = .{
1132 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1133 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1134 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1135 },
1136 .encode = .{ .rorv, .Xd, .Xn, .Xm },
1137 },
1138 // C6.2.263 RORV
1139 .{
1140 .pattern = "RORV <Wd>, <Wn>, <Wm>",
1141 .symbols = .{
1142 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
1143 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
1144 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
1145 },
1146 .encode = .{ .rorv, .Wd, .Wn, .Wm },
1147 },
1148 .{
1149 .pattern = "RORV <Xd>, <Xn>, <Xm>",
1150 .symbols = .{
1151 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1152 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1153 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1154 },
1155 .encode = .{ .rorv, .Xd, .Xn, .Xm },
1156 },
1157 // C6.2.268 SBFM
1158 .{
1159 .pattern = "SBFM <Wd>, <Wn>, #<immr>, #<imms>",
1160 .symbols = .{
1161 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
1162 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
1163 .immr = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
1164 .imms = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
1165 },
1166 .encode = .{ .sbfm, .Wd, .Wn, .{ .N = .word, .immr = .immr, .imms = .imms } },
1167 },
1168 .{
1169 .pattern = "SBFM <Xd>, <Xn>, #<immr>, #<imms>",
1170 .symbols = .{
1171 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1172 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1173 .immr = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
1174 .imms = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
1175 },
1176 .encode = .{ .sbfm, .Xd, .Xn, .{ .N = .doubleword, .immr = .immr, .imms = .imms } },
1177 },
1178 // C6.2.280 SEV
1179 .{
1180 .pattern = "SEV",
1181 .symbols = .{},
1182 .encode = .{.sev},
1183 },
1184 // C6.2.281 SEVL
1185 .{
1186 .pattern = "SEVL",
1187 .symbols = .{},
1188 .encode = .{.sevl},
1189 },
1190 // C6.2.283 SMC
1191 .{
1192 .pattern = "SMC #<imm>",
1193 .symbols = .{
1194 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
1195 },
1196 .encode = .{ .smc, .imm },
1197 },
1198 // C6.2.321 STP
1199 .{
1200 .pattern = "STP <Wt1>, <Wt2>, [<Xn|SP>], #<imm>",
1201 .symbols = .{
1202 .Wt1 = .{ .reg = .{ .format = .{ .integer = .word } } },
1203 .Wt2 = .{ .reg = .{ .format = .{ .integer = .word } } },
1204 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1205 .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 }, .multiple_of = 4 } },
1206 },
1207 .encode = .{ .stp, .Wt1, .Wt2, .{ .post_index = .{ .base = .Xn, .index = .imm } } },
1208 },
1209 .{
1210 .pattern = "STP <Xt1>, <Xt2>, [<Xn|SP>], #<imm>",
1211 .symbols = .{
1212 .Xt1 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1213 .Xt2 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1214 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1215 .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 10 }, .multiple_of = 8 } },
1216 },
1217 .encode = .{ .stp, .Xt1, .Xt2, .{ .post_index = .{ .base = .Xn, .index = .imm } } },
1218 },
1219 .{
1220 .pattern = "STP <Wt1>, <Wt2>, [<Xn|SP>, #<imm>]!",
1221 .symbols = .{
1222 .Wt1 = .{ .reg = .{ .format = .{ .integer = .word } } },
1223 .Wt2 = .{ .reg = .{ .format = .{ .integer = .word } } },
1224 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1225 .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 }, .multiple_of = 4 } },
1226 },
1227 .encode = .{ .stp, .Wt1, .Wt2, .{ .pre_index = .{ .base = .Xn, .index = .imm } } },
1228 },
1229 .{
1230 .pattern = "STP <Xt1>, <Xt2>, [<Xn|SP>, #<imm>]!",
1231 .symbols = .{
1232 .Xt1 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1233 .Xt2 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1234 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1235 .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 10 }, .multiple_of = 8 } },
1236 },
1237 .encode = .{ .stp, .Xt1, .Xt2, .{ .pre_index = .{ .base = .Xn, .index = .imm } } },
1238 },
1239 .{
1240 .pattern = "STP <Wt1>, <Wt2>, [<Xn|SP>]",
1241 .symbols = .{
1242 .Wt1 = .{ .reg = .{ .format = .{ .integer = .word } } },
1243 .Wt2 = .{ .reg = .{ .format = .{ .integer = .word } } },
1244 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1245 },
1246 .encode = .{ .stp, .Wt1, .Wt2, .{ .base = .Xn } },
1247 },
1248 .{
1249 .pattern = "STP <Wt1>, <Wt2>, [<Xn|SP>, #<imm>]",
1250 .symbols = .{
1251 .Wt1 = .{ .reg = .{ .format = .{ .integer = .word } } },
1252 .Wt2 = .{ .reg = .{ .format = .{ .integer = .word } } },
1253 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1254 .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 }, .multiple_of = 4 } },
1255 },
1256 .encode = .{ .stp, .Wt1, .Wt2, .{ .signed_offset = .{ .base = .Xn, .offset = .imm } } },
1257 },
1258 .{
1259 .pattern = "STP <Xt1>, <Xt2>, [<Xn|SP>]",
1260 .symbols = .{
1261 .Xt1 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1262 .Xt2 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1263 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1264 },
1265 .encode = .{ .stp, .Xt1, .Xt2, .{ .base = .Xn } },
1266 },
1267 .{
1268 .pattern = "STP <Xt1>, <Xt2>, [<Xn|SP>, #<imm>]",
1269 .symbols = .{
1270 .Xt1 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1271 .Xt2 = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1272 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1273 .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 10 }, .multiple_of = 8 } },
1274 },
1275 .encode = .{ .stp, .Xt1, .Xt2, .{ .signed_offset = .{ .base = .Xn, .offset = .imm } } },
1276 },
1277 // C6.2.322 STR (immediate)
1278 .{
1279 .pattern = "STR <Wt>, [<Xn|SP>], #<simm>",
1280 .symbols = .{
1281 .Wt = .{ .reg = .{ .format = .{ .integer = .word } } },
1282 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1283 .simm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 } } },
1284 },
1285 .encode = .{ .str, .Wt, .{ .post_index = .{ .base = .Xn, .index = .simm } } },
1286 },
1287 .{
1288 .pattern = "STR <Xt>, [<Xn|SP>], #<simm>",
1289 .symbols = .{
1290 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1291 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1292 .simm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 } } },
1293 },
1294 .encode = .{ .str, .Xt, .{ .post_index = .{ .base = .Xn, .index = .simm } } },
1295 },
1296 .{
1297 .pattern = "STR <Wt>, [<Xn|SP>, #<simm>]!",
1298 .symbols = .{
1299 .Wt = .{ .reg = .{ .format = .{ .integer = .word } } },
1300 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1301 .simm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 } } },
1302 },
1303 .encode = .{ .str, .Wt, .{ .pre_index = .{ .base = .Xn, .index = .simm } } },
1304 },
1305 .{
1306 .pattern = "STR <Xt>, [<Xn|SP>, #<simm>]!",
1307 .symbols = .{
1308 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1309 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1310 .simm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 } } },
1311 },
1312 .encode = .{ .str, .Xt, .{ .pre_index = .{ .base = .Xn, .index = .simm } } },
1313 },
1314 .{
1315 .pattern = "STR <Wt>, [<Xn|SP>]",
1316 .symbols = .{
1317 .Wt = .{ .reg = .{ .format = .{ .integer = .word } } },
1318 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1319 },
1320 .encode = .{ .str, .Wt, .{ .base = .Xn } },
1321 },
1322 .{
1323 .pattern = "STR <Wt>, [<Xn|SP>, #<pimm>]",
1324 .symbols = .{
1325 .Wt = .{ .reg = .{ .format = .{ .integer = .word } } },
1326 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1327 .pimm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 14 }, .multiple_of = 4 } },
1328 },
1329 .encode = .{ .str, .Wt, .{ .unsigned_offset = .{ .base = .Xn, .offset = .pimm } } },
1330 },
1331 .{
1332 .pattern = "STR <Xt>, [<Xn|SP>]",
1333 .symbols = .{
1334 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1335 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1336 },
1337 .encode = .{ .str, .Xt, .{ .base = .Xn } },
1338 },
1339 .{
1340 .pattern = "STR <Xt>, [<Xn|SP>, #<pimm>]",
1341 .symbols = .{
1342 .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1343 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1344 .pimm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 15 }, .multiple_of = 8 } },
1345 },
1346 .encode = .{ .str, .Xt, .{ .unsigned_offset = .{ .base = .Xn, .offset = .pimm } } },
1347 },
1348 // C6.2.356 SUB (extended register)
1349 .{
1350 .pattern = "SUB <Wd|WSP>, <Wn|WSP>, <Wm>",
1351 .symbols = .{
1352 .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
1353 .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
1354 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
1355 },
1356 .encode = .{ .sub, .Wd, .Wn, .{ .register = .Wm } },
1357 },
1358 .{
1359 .pattern = "SUB <Wd|WSP>, <Wn|WSP>, <Wm>, <extend> #<amount>",
1360 .symbols = .{
1361 .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
1362 .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
1363 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
1364 .extend = .{ .extend = .{ .size = .word } },
1365 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } },
1366 },
1367 .encode = .{ .sub, .Wd, .Wn, .{ .extended_register_explicit = .{ .register = .Wm, .option = .extend, .amount = .amount } } },
1368 },
1369 .{
1370 .pattern = "SUB <Xd|SP>, <Xn|SP>, <Xm>",
1371 .symbols = .{
1372 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1373 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1374 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1375 },
1376 .encode = .{ .sub, .Xd, .Xn, .{ .register = .Xm } },
1377 },
1378 .{
1379 .pattern = "SUB <Xd|SP>, <Xn|SP>, <Wm>, <extend> #<amount>",
1380 .symbols = .{
1381 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1382 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1383 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
1384 .extend = .{ .extend = .{ .size = .word } },
1385 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } },
1386 },
1387 .encode = .{ .sub, .Xd, .Xn, .{ .extended_register_explicit = .{ .register = .Wm, .option = .extend, .amount = .amount } } },
1388 },
1389 .{
1390 .pattern = "SUB <Xd|SP>, <Xn|SP>, <Xm>, <extend> #<amount>",
1391 .symbols = .{
1392 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1393 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1394 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1395 .extend = .{ .extend = .{ .size = .doubleword } },
1396 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } },
1397 },
1398 .encode = .{ .sub, .Xd, .Xn, .{ .extended_register_explicit = .{ .register = .Xm, .option = .extend, .amount = .amount } } },
1399 },
1400 // C6.2.357 SUB (immediate)
1401 .{
1402 .pattern = "SUB <Wd|WSP>, <Wn|WSP>, #<imm>",
1403 .symbols = .{
1404 .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
1405 .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
1406 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } },
1407 },
1408 .encode = .{ .sub, .Wd, .Wn, .{ .immediate = .imm } },
1409 },
1410 .{
1411 .pattern = "SUB <Wd|WSP>, <Wn|WSP>, #<imm>, LSL #<shift>",
1412 .symbols = .{
1413 .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
1414 .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } },
1415 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } },
1416 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 }, .multiple_of = 12 } },
1417 },
1418 .encode = .{ .sub, .Wd, .Wn, .{ .shifted_immediate = .{ .immediate = .imm, .lsl = .shift } } },
1419 },
1420 .{
1421 .pattern = "SUB <Xd|SP>, <Xn|SP>, #<imm>",
1422 .symbols = .{
1423 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1424 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1425 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } },
1426 },
1427 .encode = .{ .sub, .Xd, .Xn, .{ .immediate = .imm } },
1428 },
1429 .{
1430 .pattern = "SUB <Xd|SP>, <Xn|SP>, #<imm>, LSL #<shift>",
1431 .symbols = .{
1432 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1433 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } },
1434 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } },
1435 .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 }, .multiple_of = 12 } },
1436 },
1437 .encode = .{ .sub, .Xd, .Xn, .{ .shifted_immediate = .{ .immediate = .imm, .lsl = .shift } } },
1438 },
1439 // C6.2.358 SUB (shifted register)
1440 .{
1441 .pattern = "SUB <Wd>, <Wn>, <Wm>",
1442 .symbols = .{
1443 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
1444 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
1445 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
1446 },
1447 .encode = .{ .sub, .Wd, .Wn, .{ .register = .Wm } },
1448 },
1449 .{
1450 .pattern = "SUB <Wd>, <Wn>, <Wm>, <shift> #<amount>",
1451 .symbols = .{
1452 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
1453 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
1454 .Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
1455 .shift = .{ .shift = .{ .allow_ror = false } },
1456 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
1457 },
1458 .encode = .{ .sub, .Wd, .Wn, .{ .shifted_register_explicit = .{ .register = .Wm, .shift = .shift, .amount = .amount } } },
1459 },
1460 .{
1461 .pattern = "SUB <Xd>, <Xn>, <Xm>",
1462 .symbols = .{
1463 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1464 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1465 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1466 },
1467 .encode = .{ .sub, .Xd, .Xn, .{ .register = .Xm } },
1468 },
1469 .{
1470 .pattern = "SUB <Xd>, <Xn>, <Xm>, <shift> #<amount>",
1471 .symbols = .{
1472 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1473 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1474 .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1475 .shift = .{ .shift = .{ .allow_ror = false } },
1476 .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
1477 },
1478 .encode = .{ .sub, .Xd, .Xn, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } },
1479 },
1480 // C6.2.365 SVC
1481 .{
1482 .pattern = "SVC #<imm>",
1483 .symbols = .{
1484 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
1485 },
1486 .encode = .{ .svc, .imm },
1487 },
1488 // C6.2.376 TCANCEL
1489 .{
1490 .pattern = "TCANCEL #<imm>",
1491 .symbols = .{
1492 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
1493 },
1494 .encode = .{ .tcancel, .imm },
1495 },
1496 // C6.2.385 UBFM
1497 .{
1498 .pattern = "UBFM <Wd>, <Wn>, #<immr>, #<imms>",
1499 .symbols = .{
1500 .Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
1501 .Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
1502 .immr = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
1503 .imms = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
1504 },
1505 .encode = .{ .ubfm, .Wd, .Wn, .{ .N = .word, .immr = .immr, .imms = .imms } },
1506 },
1507 .{
1508 .pattern = "UBFM <Xd>, <Xn>, #<immr>, #<imms>",
1509 .symbols = .{
1510 .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1511 .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
1512 .immr = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
1513 .imms = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
1514 },
1515 .encode = .{ .ubfm, .Xd, .Xn, .{ .N = .doubleword, .immr = .immr, .imms = .imms } },
1516 },
1517 // C6.2.387 UDF
1518 .{
1519 .pattern = "UDF #<imm>",
1520 .symbols = .{
1521 .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } },
1522 },
1523 .encode = .{ .udf, .imm },
1524 },
1525 // C6.2.396 WFE
1526 .{
1527 .pattern = "WFE",
1528 .symbols = .{},
1529 .encode = .{.wfe},
1530 },
1531 // C6.2.398 WFI
1532 .{
1533 .pattern = "WFI",
1534 .symbols = .{},
1535 .encode = .{.wfi},
1536 },
1537 // C6.2.402 YIELD
1538 .{
1539 .pattern = "YIELD",
1540 .symbols = .{},
1541 .encode = .{.yield},
1542 },
1543}
src/codegen/c.zig+16-17
...@@ -449,14 +449,15 @@ pub const Function = struct {...@@ -449,14 +449,15 @@ pub const Function = struct {
449 if (gop.found_existing) return gop.value_ptr.*;449 if (gop.found_existing) return gop.value_ptr.*;
450450
451 const pt = f.object.dg.pt;451 const pt = f.object.dg.pt;
452 const zcu = pt.zcu;
452 const val = (try f.air.value(ref, pt)).?;453 const val = (try f.air.value(ref, pt)).?;
453 const ty = f.typeOf(ref);454 const ty = f.typeOf(ref);
454455
455 const result: CValue = if (lowersToArray(ty, pt)) result: {456 const result: CValue = if (lowersToArray(ty, zcu)) result: {
456 const ch = &f.object.code_header.writer;457 const ch = &f.object.code_header.writer;
457 const decl_c_value = try f.allocLocalValue(.{458 const decl_c_value = try f.allocLocalValue(.{
458 .ctype = try f.ctypeFromType(ty, .complete),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 const gpa = f.object.dg.gpa;462 const gpa = f.object.dg.gpa;
462 try f.allocs.put(gpa, decl_c_value.new_local, false);463 try f.allocs.put(gpa, decl_c_value.new_local, false);
...@@ -916,7 +917,7 @@ pub const DeclGen = struct {...@@ -916,7 +917,7 @@ pub const DeclGen = struct {
916 // Ensure complete type definition is available before accessing fields.917 // Ensure complete type definition is available before accessing fields.
917 _ = try dg.ctypeFromType(parent_ptr_ty.childType(zcu), .complete);918 _ = try dg.ctypeFromType(parent_ptr_ty.childType(zcu), .complete);
918919
919 switch (fieldLocation(parent_ptr_ty, field.result_ptr_ty, field.field_idx, pt)) {920 switch (fieldLocation(parent_ptr_ty, field.result_ptr_ty, field.field_idx, zcu)) {
920 .begin => {921 .begin => {
921 const ptr_ctype = try dg.ctypeFromType(field.result_ptr_ty, .complete);922 const ptr_ctype = try dg.ctypeFromType(field.result_ptr_ty, .complete);
922 try w.writeByte('(');923 try w.writeByte('(');
...@@ -3008,7 +3009,7 @@ pub fn generate(...@@ -3008,7 +3009,7 @@ pub fn generate(
3008 src_loc: Zcu.LazySrcLoc,3009 src_loc: Zcu.LazySrcLoc,
3009 func_index: InternPool.Index,3010 func_index: InternPool.Index,
3010 air: *const Air,3011 air: *const Air,
3011 liveness: *const Air.Liveness,3012 liveness: *const ?Air.Liveness,
3012) @import("../codegen.zig").CodeGenError!Mir {3013) @import("../codegen.zig").CodeGenError!Mir {
3013 const zcu = pt.zcu;3014 const zcu = pt.zcu;
3014 const gpa = zcu.gpa;3015 const gpa = zcu.gpa;
...@@ -3021,7 +3022,7 @@ pub fn generate(...@@ -3021,7 +3022,7 @@ pub fn generate(
3021 var function: Function = .{3022 var function: Function = .{
3022 .value_map = .init(gpa),3023 .value_map = .init(gpa),
3023 .air = air.*,3024 .air = air.*,
3024 .liveness = liveness.*,3025 .liveness = liveness.*.?,
3025 .func_index = func_index,3026 .func_index = func_index,
3026 .object = .{3027 .object = .{
3027 .dg = .{3028 .dg = .{
...@@ -3961,7 +3962,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3961,7 +3962,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
3961 ptr_info.flags.alignment.order(src_ty.abiAlignment(zcu)).compare(.gte)3962 ptr_info.flags.alignment.order(src_ty.abiAlignment(zcu)).compare(.gte)
3962 else3963 else
3963 true;3964 true;
3964 const is_array = lowersToArray(src_ty, pt);3965 const is_array = lowersToArray(src_ty, zcu);
3965 const need_memcpy = !is_aligned or is_array;3966 const need_memcpy = !is_aligned or is_array;
39663967
3967 const w = &f.object.code.writer;3968 const w = &f.object.code.writer;
...@@ -4044,7 +4045,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !void {...@@ -4044,7 +4045,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !void {
4044 const operand = try f.resolveInst(un_op);4045 const operand = try f.resolveInst(un_op);
4045 try reap(f, inst, &.{un_op});4046 try reap(f, inst, &.{un_op});
4046 var deref = is_ptr;4047 var deref = is_ptr;
4047 const is_array = lowersToArray(ret_ty, pt);4048 const is_array = lowersToArray(ret_ty, zcu);
4048 const ret_val = if (is_array) ret_val: {4049 const ret_val = if (is_array) ret_val: {
4049 const array_local = try f.allocAlignedLocal(inst, .{4050 const array_local = try f.allocAlignedLocal(inst, .{
4050 .ctype = ret_ctype,4051 .ctype = ret_ctype,
...@@ -4228,7 +4229,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {...@@ -4228,7 +4229,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
4228 ptr_info.flags.alignment.order(src_ty.abiAlignment(zcu)).compare(.gte)4229 ptr_info.flags.alignment.order(src_ty.abiAlignment(zcu)).compare(.gte)
4229 else4230 else
4230 true;4231 true;
4231 const is_array = lowersToArray(.fromInterned(ptr_info.child), pt);4232 const is_array = lowersToArray(.fromInterned(ptr_info.child), zcu);
4232 const need_memcpy = !is_aligned or is_array;4233 const need_memcpy = !is_aligned or is_array;
42334234
4234 const src_val = try f.resolveInst(bin_op.rhs);4235 const src_val = try f.resolveInst(bin_op.rhs);
...@@ -4873,7 +4874,7 @@ fn airCall(...@@ -4873,7 +4874,7 @@ fn airCall(
4873 }4874 }
48744875
4875 const result = result: {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 break :result result_local;4878 break :result result_local;
48784879
4879 const array_local = try f.allocLocal(inst, ret_ty);4880 const array_local = try f.allocLocal(inst, ret_ty);
...@@ -5971,13 +5972,12 @@ fn fieldLocation(...@@ -5971,13 +5972,12 @@ fn fieldLocation(
5971 container_ptr_ty: Type,5972 container_ptr_ty: Type,
5972 field_ptr_ty: Type,5973 field_ptr_ty: Type,
5973 field_index: u32,5974 field_index: u32,
5974 pt: Zcu.PerThread,5975 zcu: *Zcu,
5975) union(enum) {5976) union(enum) {
5976 begin: void,5977 begin: void,
5977 field: CValue,5978 field: CValue,
5978 byte_offset: u64,5979 byte_offset: u64,
5979} {5980} {
5980 const zcu = pt.zcu;
5981 const ip = &zcu.intern_pool;5981 const ip = &zcu.intern_pool;
5982 const container_ty: Type = .fromInterned(ip.indexToKey(container_ptr_ty.toIntern()).ptr_type.child);5982 const container_ty: Type = .fromInterned(ip.indexToKey(container_ptr_ty.toIntern()).ptr_type.child);
5983 switch (ip.indexToKey(container_ty.toIntern())) {5983 switch (ip.indexToKey(container_ty.toIntern())) {
...@@ -5994,7 +5994,7 @@ fn fieldLocation(...@@ -5994,7 +5994,7 @@ fn fieldLocation(
5994 else5994 else
5995 .{ .field = field_index } },5995 .{ .field = field_index } },
5996 .@"packed" => if (field_ptr_ty.ptrInfo(zcu).packed_offset.host_size == 0)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 container_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset, 8) }5998 container_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset, 8) }
5999 else5999 else
6000 .begin,6000 .begin,
...@@ -6076,7 +6076,7 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6076,7 +6076,7 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
6076 try f.renderType(w, container_ptr_ty);6076 try f.renderType(w, container_ptr_ty);
6077 try w.writeByte(')');6077 try w.writeByte(')');
60786078
6079 switch (fieldLocation(container_ptr_ty, field_ptr_ty, extra.field_index, pt)) {6079 switch (fieldLocation(container_ptr_ty, field_ptr_ty, extra.field_index, zcu)) {
6080 .begin => try f.writeCValue(w, field_ptr_val, .Other),6080 .begin => try f.writeCValue(w, field_ptr_val, .Other),
6081 .field => |field| {6081 .field => |field| {
6082 const u8_ptr_ty = try pt.adjustPtrTypeChild(field_ptr_ty, .u8);6082 const u8_ptr_ty = try pt.adjustPtrTypeChild(field_ptr_ty, .u8);
...@@ -6131,7 +6131,7 @@ fn fieldPtr(...@@ -6131,7 +6131,7 @@ fn fieldPtr(
6131 try f.renderType(w, field_ptr_ty);6131 try f.renderType(w, field_ptr_ty);
6132 try w.writeByte(')');6132 try w.writeByte(')');
61336133
6134 switch (fieldLocation(container_ptr_ty, field_ptr_ty, field_index, pt)) {6134 switch (fieldLocation(container_ptr_ty, field_ptr_ty, field_index, zcu)) {
6135 .begin => try f.writeCValue(w, container_ptr_val, .Other),6135 .begin => try f.writeCValue(w, container_ptr_val, .Other),
6136 .field => |field| {6136 .field => |field| {
6137 try w.writeByte('&');6137 try w.writeByte('&');
...@@ -6189,7 +6189,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6189,7 +6189,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
61896189
6190 const bit_offset_ty = try pt.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1));6190 const bit_offset_ty = try pt.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1));
61916191
6192 const bit_offset = pt.structPackedFieldBitOffset(loaded_struct, extra.field_index);6192 const bit_offset = zcu.structPackedFieldBitOffset(loaded_struct, extra.field_index);
61936193
6194 const field_int_signedness = if (inst_ty.isAbiInt(zcu))6194 const field_int_signedness = if (inst_ty.isAbiInt(zcu))
6195 inst_ty.intInfo(zcu).signedness6195 inst_ty.intInfo(zcu).signedness
...@@ -8573,8 +8573,7 @@ const Vectorize = struct {...@@ -8573,8 +8573,7 @@ const Vectorize = struct {
8573 }8573 }
8574};8574};
85758575
8576fn lowersToArray(ty: Type, pt: Zcu.PerThread) bool {8576fn lowersToArray(ty: Type, zcu: *Zcu) bool {
8577 const zcu = pt.zcu;
8578 return switch (ty.zigTypeTag(zcu)) {8577 return switch (ty.zigTypeTag(zcu)) {
8579 .array, .vector => return true,8578 .array, .vector => return true,
8580 else => return ty.isAbiInt(zcu) and toCIntBits(@as(u32, @intCast(ty.bitSize(zcu)))) == null,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,6 +20,7 @@ const Package = @import("../Package.zig");
20const Air = @import("../Air.zig");20const Air = @import("../Air.zig");
21const Value = @import("../Value.zig");21const Value = @import("../Value.zig");
22const Type = @import("../Type.zig");22const Type = @import("../Type.zig");
23const codegen = @import("../codegen.zig");
23const x86_64_abi = @import("../arch/x86_64/abi.zig");24const x86_64_abi = @import("../arch/x86_64/abi.zig");
24const wasm_c_abi = @import("wasm/abi.zig");25const wasm_c_abi = @import("wasm/abi.zig");
25const aarch64_c_abi = @import("aarch64/abi.zig");26const aarch64_c_abi = @import("aarch64/abi.zig");
...@@ -1131,7 +1132,7 @@ pub const Object = struct {...@@ -1131,7 +1132,7 @@ pub const Object = struct {
1131 pt: Zcu.PerThread,1132 pt: Zcu.PerThread,
1132 func_index: InternPool.Index,1133 func_index: InternPool.Index,
1133 air: *const Air,1134 air: *const Air,
1134 liveness: *const Air.Liveness,1135 liveness: *const ?Air.Liveness,
1135 ) !void {1136 ) !void {
1136 const zcu = pt.zcu;1137 const zcu = pt.zcu;
1137 const comp = zcu.comp;1138 const comp = zcu.comp;
...@@ -1489,7 +1490,7 @@ pub const Object = struct {...@@ -1489,7 +1490,7 @@ pub const Object = struct {
1489 var fg: FuncGen = .{1490 var fg: FuncGen = .{
1490 .gpa = gpa,1491 .gpa = gpa,
1491 .air = air.*,1492 .air = air.*,
1492 .liveness = liveness.*,1493 .liveness = liveness.*.?,
1493 .ng = &ng,1494 .ng = &ng,
1494 .wip = wip,1495 .wip = wip,
1495 .is_naked = fn_info.cc == .naked,1496 .is_naked = fn_info.cc == .naked,
...@@ -4210,7 +4211,7 @@ pub const Object = struct {...@@ -4210,7 +4211,7 @@ pub const Object = struct {
4210 .eu_payload => |eu_ptr| try o.lowerPtr(4211 .eu_payload => |eu_ptr| try o.lowerPtr(
4211 pt,4212 pt,
4212 eu_ptr,4213 eu_ptr,
4213 offset + @import("../codegen.zig").errUnionPayloadOffset(4214 offset + codegen.errUnionPayloadOffset(
4214 Value.fromInterned(eu_ptr).typeOf(zcu).childType(zcu),4215 Value.fromInterned(eu_ptr).typeOf(zcu).childType(zcu),
4215 zcu,4216 zcu,
4216 ),4217 ),
...@@ -6050,10 +6051,10 @@ pub const FuncGen = struct {...@@ -6050,10 +6051,10 @@ pub const FuncGen = struct {
6050 const target_blocks = dispatch_info.case_blocks[0..target_blocks_len];6051 const target_blocks = dispatch_info.case_blocks[0..target_blocks_len];
60516052
6052 // Make sure to cast the index to a usize so it's not treated as negative!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 const table_index = try self.wip.conv(
6054 .zext,6055 .unsigned,
6055 try self.wip.bin(.@"sub nuw", cond, jmp_table.min.toValue(), ""),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 const target_ptr_ptr = try self.wip.gep(6060 const target_ptr_ptr = try self.wip.gep(
...@@ -6969,7 +6970,7 @@ pub const FuncGen = struct {...@@ -6969,7 +6970,7 @@ pub const FuncGen = struct {
6969 .@"struct" => switch (struct_ty.containerLayout(zcu)) {6970 .@"struct" => switch (struct_ty.containerLayout(zcu)) {
6970 .@"packed" => {6971 .@"packed" => {
6971 const struct_type = zcu.typeToStruct(struct_ty).?;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 const containing_int = struct_llvm_val;6974 const containing_int = struct_llvm_val;
6974 const shift_amt =6975 const shift_amt =
6975 try o.builder.intValue(containing_int.typeOfWip(&self.wip), bit_offset);6976 try o.builder.intValue(containing_int.typeOfWip(&self.wip), bit_offset);
...@@ -11364,7 +11365,7 @@ pub const FuncGen = struct {...@@ -11364,7 +11365,7 @@ pub const FuncGen = struct {
1136411365
11365 // We have a pointer to a packed struct field that happens to be byte-aligned.11366 // We have a pointer to a packed struct field that happens to be byte-aligned.
11366 // Offset our operand pointer by the correct number of bytes.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 if (byte_offset == 0) return struct_ptr;11369 if (byte_offset == 0) return struct_ptr;
11369 const usize_ty = try o.lowerType(pt, Type.usize);11370 const usize_ty = try o.lowerType(pt, Type.usize);
11370 const llvm_index = try o.builder.intValue(usize_ty, byte_offset);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,11 +251,11 @@ pub const Object = struct {
251 pt: Zcu.PerThread,251 pt: Zcu.PerThread,
252 func_index: InternPool.Index,252 func_index: InternPool.Index,
253 air: *const Air,253 air: *const Air,
254 liveness: *const Air.Liveness,254 liveness: *const ?Air.Liveness,
255 ) !void {255 ) !void {
256 const nav = pt.zcu.funcInfo(func_index).owner_nav;256 const nav = pt.zcu.funcInfo(func_index).owner_nav;
257 // TODO: Separate types for generating decls and functions?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 }
260260
261 pub fn updateNav(261 pub fn updateNav(
...@@ -5134,7 +5134,7 @@ const NavGen = struct {...@@ -5134,7 +5134,7 @@ const NavGen = struct {
5134 .@"struct" => switch (object_ty.containerLayout(zcu)) {5134 .@"struct" => switch (object_ty.containerLayout(zcu)) {
5135 .@"packed" => {5135 .@"packed" => {
5136 const struct_ty = zcu.typeToPackedStruct(object_ty).?;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 const bit_offset_id = try self.constInt(.u16, bit_offset);5138 const bit_offset_id = try self.constInt(.u16, bit_offset);
5139 const signedness = if (field_ty.isInt(zcu)) field_ty.intInfo(zcu).signedness else .unsigned;5139 const signedness = if (field_ty.isInt(zcu)) field_ty.intInfo(zcu).signedness else .unsigned;
5140 const field_bit_size: u16 = @intCast(field_ty.bitSize(zcu));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,13 +25,13 @@ pub const Env = enum {
25 /// - `zig build-* -fno-emit-bin`25 /// - `zig build-* -fno-emit-bin`
26 sema,26 sema,
2727
28 /// - sema
29 /// - `zig build-* -fincremental -fno-llvm -fno-lld -target aarch64-linux --listen=-`
30 @"aarch64-linux",
31
28 /// - `zig build-* -ofmt=c`32 /// - `zig build-* -ofmt=c`
29 cbe,33 cbe,
3034
31 /// - sema
32 /// - `zig build-* -fincremental -fno-llvm -fno-lld -target x86_64-linux --listen=-`
33 @"x86_64-linux",
34
35 /// - sema35 /// - sema
36 /// - `zig build-* -fincremental -fno-llvm -fno-lld -target powerpc(64)(le)-linux --listen=-`36 /// - `zig build-* -fincremental -fno-llvm -fno-lld -target powerpc(64)(le)-linux --listen=-`
37 @"powerpc-linux",37 @"powerpc-linux",
...@@ -48,6 +48,10 @@ pub const Env = enum {...@@ -48,6 +48,10 @@ pub const Env = enum {
48 /// - `zig build-* -fno-llvm -fno-lld -target wasm32-* --listen=-`48 /// - `zig build-* -fno-llvm -fno-lld -target wasm32-* --listen=-`
49 wasm,49 wasm,
5050
51 /// - sema
52 /// - `zig build-* -fincremental -fno-llvm -fno-lld -target x86_64-linux --listen=-`
53 @"x86_64-linux",
54
51 pub inline fn supports(comptime dev_env: Env, comptime feature: Feature) bool {55 pub inline fn supports(comptime dev_env: Env, comptime feature: Feature) bool {
52 return switch (dev_env) {56 return switch (dev_env) {
53 .full => true,57 .full => true,
...@@ -153,23 +157,22 @@ pub const Env = enum {...@@ -153,23 +157,22 @@ pub const Env = enum {
153 => true,157 => true,
154 else => Env.ast_gen.supports(feature),158 else => Env.ast_gen.supports(feature),
155 },159 },
156 .cbe => switch (feature) {160 .@"aarch64-linux" => 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) {
164 .build_command,161 .build_command,
165 .stdio_listen,162 .stdio_listen,
166 .incremental,163 .incremental,
167 .legalize,164 .aarch64_backend,
168 .x86_64_backend,
169 .elf_linker,165 .elf_linker,
170 => true,166 => true,
171 else => Env.sema.supports(feature),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 .@"powerpc-linux" => switch (feature) {176 .@"powerpc-linux" => switch (feature) {
174 .build_command,177 .build_command,
175 .stdio_listen,178 .stdio_listen,
...@@ -199,6 +202,16 @@ pub const Env = enum {...@@ -199,6 +202,16 @@ pub const Env = enum {
199 => true,202 => true,
200 else => Env.sema.supports(feature),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 }
204217
src/fmt.zig+2-2
...@@ -348,10 +348,10 @@ fn fmtPathFile(...@@ -348,10 +348,10 @@ fn fmtPathFile(
348 try fmt.stdout_writer.interface.print("{s}\n", .{file_path});348 try fmt.stdout_writer.interface.print("{s}\n", .{file_path});
349 fmt.any_error = true;349 fmt.any_error = true;
350 } else {350 } else {
351 var af = try dir.atomicFile(sub_path, .{ .mode = stat.mode });351 var af = try dir.atomicFile(sub_path, .{ .mode = stat.mode, .write_buffer = &.{} });
352 defer af.deinit();352 defer af.deinit();
353353
354 try af.file.writeAll(fmt.out_buffer.getWritten());354 try af.file_writer.interface.writeAll(fmt.out_buffer.getWritten());
355 try af.finish();355 try af.finish();
356 try fmt.stdout_writer.interface.print("{s}\n", .{file_path});356 try fmt.stdout_writer.interface.print("{s}\n", .{file_path});
357 }357 }
src/link.zig+1
...@@ -23,6 +23,7 @@ const dev = @import("dev.zig");...@@ -23,6 +23,7 @@ const dev = @import("dev.zig");
23const target_util = @import("target.zig");23const target_util = @import("target.zig");
24const codegen = @import("codegen.zig");24const codegen = @import("codegen.zig");
2525
26pub const aarch64 = @import("link/aarch64.zig");
26pub const LdScript = @import("link/LdScript.zig");27pub const LdScript = @import("link/LdScript.zig");
27pub const Queue = @import("link/Queue.zig");28pub const Queue = @import("link/Queue.zig");
2829
src/link/Coff.zig+25-51
...@@ -1335,9 +1335,13 @@ fn updateNavCode(...@@ -1335,9 +1335,13 @@ fn updateNavCode(
13351335
1336 log.debug("updateNavCode {f} 0x{x}", .{ nav.fqn.fmt(ip), nav_index });1336 log.debug("updateNavCode {f} 0x{x}", .{ nav.fqn.fmt(ip), nav_index });
13371337
1338 const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;1338 const mod = zcu.navFileScope(nav_index).mod.?;
1339 const required_alignment = switch (pt.navAlignment(nav_index)) {1339 const target = &mod.resolved_target.result;
1340 .none => target_util.defaultFunctionAlignment(target),1340 const required_alignment = switch (nav.status.fully_resolved.alignment) {
1341 .none => switch (mod.optimize_mode) {
1342 .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target),
1343 .ReleaseSmall => target_util.minFunctionAlignment(target),
1344 },
1341 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),1345 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
1342 };1346 };
13431347
...@@ -2832,58 +2836,33 @@ pub const Relocation = struct {...@@ -2832,58 +2836,33 @@ pub const Relocation = struct {
2832 };2836 };
28332837
2834 fn resolveAarch64(reloc: Relocation, ctx: Context) void {2838 fn resolveAarch64(reloc: Relocation, ctx: Context) void {
2839 const Instruction = aarch64_util.encoding.Instruction;
2835 var buffer = ctx.code[reloc.offset..];2840 var buffer = ctx.code[reloc.offset..];
2836 switch (reloc.type) {2841 switch (reloc.type) {
2837 .got_page, .import_page, .page => {2842 .got_page, .import_page, .page => {
2838 const source_page = @as(i32, @intCast(ctx.source_vaddr >> 12));2843 const source_page = @as(i32, @intCast(ctx.source_vaddr >> 12));
2839 const target_page = @as(i32, @intCast(ctx.target_vaddr >> 12));2844 const target_page = @as(i32, @intCast(ctx.target_vaddr >> 12));
2840 const pages = @as(u21, @bitCast(@as(i21, @intCast(target_page - source_page))));2845 const pages: i21 = @intCast(target_page - source_page);
2841 var inst = aarch64_util.Instruction{2846 var inst: Instruction = .read(buffer[0..Instruction.size]);
2842 .pc_relative_address = mem.bytesToValue(@FieldType(2847 inst.data_processing_immediate.pc_relative_addressing.group.immhi = @intCast(pages >> 2);
2843 aarch64_util.Instruction,2848 inst.data_processing_immediate.pc_relative_addressing.group.immlo = @truncate(@as(u21, @bitCast(pages)));
2844 @tagName(aarch64_util.Instruction.pc_relative_address),2849 inst.write(buffer[0..Instruction.size]);
2845 ), buffer[0..4]),
2846 };
2847 inst.pc_relative_address.immhi = @as(u19, @truncate(pages >> 2));
2848 inst.pc_relative_address.immlo = @as(u2, @truncate(pages));
2849 mem.writeInt(u32, buffer[0..4], inst.toU32(), .little);
2850 },2850 },
2851 .got_pageoff, .import_pageoff, .pageoff => {2851 .got_pageoff, .import_pageoff, .pageoff => {
2852 assert(!reloc.pcrel);2852 assert(!reloc.pcrel);
28532853
2854 const narrowed = @as(u12, @truncate(@as(u64, @intCast(ctx.target_vaddr))));2854 const narrowed: u12 = @truncate(@as(u64, @intCast(ctx.target_vaddr)));
2855 if (isArithmeticOp(buffer[0..4])) {2855 var inst: Instruction = .read(buffer[0..Instruction.size]);
2856 var inst = aarch64_util.Instruction{2856 switch (inst.decode()) {
2857 .add_subtract_immediate = mem.bytesToValue(@FieldType(2857 else => unreachable,
2858 aarch64_util.Instruction,2858 .data_processing_immediate => inst.data_processing_immediate.add_subtract_immediate.group.imm12 = narrowed,
2859 @tagName(aarch64_util.Instruction.add_subtract_immediate),2859 .load_store => |load_store| inst.load_store.register_unsigned_immediate.group.imm12 =
2860 ), buffer[0..4]),2860 switch (load_store.register_unsigned_immediate.decode()) {
2861 };2861 .integer => |integer| @shrExact(narrowed, @intFromEnum(integer.group.size)),
2862 inst.add_subtract_immediate.imm12 = narrowed;2862 .vector => |vector| @shrExact(narrowed, @intFromEnum(vector.group.opc1.decode(vector.group.size))),
2863 mem.writeInt(u32, buffer[0..4], inst.toU32(), .little);2863 },
2864 } else {
2865 var inst = aarch64_util.Instruction{
2866 .load_store_register = mem.bytesToValue(@FieldType(
2867 aarch64_util.Instruction,
2868 @tagName(aarch64_util.Instruction.load_store_register),
2869 ), buffer[0..4]),
2870 };
2871 const offset: u12 = blk: {
2872 if (inst.load_store_register.size == 0) {
2873 if (inst.load_store_register.v == 1) {
2874 // 128-bit SIMD is scaled by 16.
2875 break :blk @divExact(narrowed, 16);
2876 }
2877 // Otherwise, 8-bit SIMD or ldrb.
2878 break :blk narrowed;
2879 } else {
2880 const denom: u4 = math.powi(u4, 2, inst.load_store_register.size) catch unreachable;
2881 break :blk @divExact(narrowed, denom);
2882 }
2883 };
2884 inst.load_store_register.offset = offset;
2885 mem.writeInt(u32, buffer[0..4], inst.toU32(), .little);
2886 }2864 }
2865 inst.write(buffer[0..Instruction.size]);
2887 },2866 },
2888 .direct => {2867 .direct => {
2889 assert(!reloc.pcrel);2868 assert(!reloc.pcrel);
...@@ -2934,11 +2913,6 @@ pub const Relocation = struct {...@@ -2934,11 +2913,6 @@ pub const Relocation = struct {
2934 },2913 },
2935 }2914 }
2936 }2915 }
2937
2938 fn isArithmeticOp(inst: *const [4]u8) bool {
2939 const group_decode = @as(u5, @truncate(inst[3]));
2940 return ((group_decode >> 2) == 4);
2941 }
2942};2916};
29432917
2944pub fn addRelocation(coff: *Coff, atom_index: Atom.Index, reloc: Relocation) !void {2918pub fn addRelocation(coff: *Coff, atom_index: Atom.Index, reloc: Relocation) !void {
...@@ -3112,7 +3086,7 @@ const Path = std.Build.Cache.Path;...@@ -3112,7 +3086,7 @@ const Path = std.Build.Cache.Path;
3112const Directory = std.Build.Cache.Directory;3086const Directory = std.Build.Cache.Directory;
3113const Cache = std.Build.Cache;3087const Cache = std.Build.Cache;
31143088
3115const aarch64_util = @import("../arch/aarch64/bits.zig");3089const aarch64_util = link.aarch64;
3116const allocPrint = std.fmt.allocPrint;3090const allocPrint = std.fmt.allocPrint;
3117const codegen = @import("../codegen.zig");3091const codegen = @import("../codegen.zig");
3118const link = @import("../link.zig");3092const link = @import("../link.zig");
src/link/Dwarf.zig+7-1
...@@ -2487,7 +2487,13 @@ fn initWipNavInner(...@@ -2487,7 +2487,13 @@ fn initWipNavInner(
2487 try wip_nav.strp(nav.fqn.toSlice(ip));2487 try wip_nav.strp(nav.fqn.toSlice(ip));
2488 const ty: Type = nav_val.typeOf(zcu);2488 const ty: Type = nav_val.typeOf(zcu);
2489 const addr: Loc = .{ .addr_reloc = sym_index };2489 const addr: Loc = .{ .addr_reloc = sym_index };
2490 const loc: Loc = if (decl.is_threadlocal) .{ .form_tls_address = &addr } else addr;2490 const loc: Loc = if (decl.is_threadlocal) loc: {
2491 const target = zcu.comp.root_mod.resolved_target.result;
2492 break :loc switch (target.cpu.arch) {
2493 .x86_64 => .{ .form_tls_address = &addr },
2494 else => .empty,
2495 };
2496 } else addr;
2491 switch (decl.kind) {2497 switch (decl.kind) {
2492 .unnamed_test, .@"test", .decltest, .@"comptime" => unreachable,2498 .unnamed_test, .@"test", .decltest, .@"comptime" => unreachable,
2493 .@"const" => {2499 .@"const" => {
src/link/Elf/Atom.zig+27-43
...@@ -1627,7 +1627,7 @@ const aarch64 = struct {...@@ -1627,7 +1627,7 @@ const aarch64 = struct {
1627 const S_ = th.targetAddress(target_index, elf_file);1627 const S_ = th.targetAddress(target_index, elf_file);
1628 break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow;1628 break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow;
1629 };1629 };
1630 aarch64_util.writeBranchImm(disp, code);1630 util.writeBranchImm(disp, code);
1631 },1631 },
16321632
1633 .PREL32 => {1633 .PREL32 => {
...@@ -1640,15 +1640,18 @@ const aarch64 = struct {...@@ -1640,15 +1640,18 @@ const aarch64 = struct {
1640 mem.writeInt(u64, code_buffer[r_offset..][0..8], @bitCast(value), .little);1640 mem.writeInt(u64, code_buffer[r_offset..][0..8], @bitCast(value), .little);
1641 },1641 },
16421642
1643 .ADR_PREL_LO21 => {
1644 const value = math.cast(i21, S + A - P) orelse return error.Overflow;
1645 util.writeAdrInst(value, code);
1646 },
1647
1643 .ADR_PREL_PG_HI21 => {1648 .ADR_PREL_PG_HI21 => {
1644 // TODO: check for relaxation of ADRP+ADD1649 // TODO: check for relaxation of ADRP+ADD
1645 const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(P, S + A)));1650 util.writeAdrInst(try util.calcNumberOfPages(P, S + A), code);
1646 aarch64_util.writeAdrpInst(pages, code);
1647 },1651 },
16481652
1649 .ADR_GOT_PAGE => if (target.flags.has_got) {1653 .ADR_GOT_PAGE => if (target.flags.has_got) {
1650 const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(P, G + GOT + A)));1654 util.writeAdrInst(try util.calcNumberOfPages(P, G + GOT + A), code);
1651 aarch64_util.writeAdrpInst(pages, code);
1652 } else {1655 } else {
1653 // TODO: relax1656 // TODO: relax
1654 var err = try diags.addErrorWithNotes(1);1657 var err = try diags.addErrorWithNotes(1);
...@@ -1663,12 +1666,12 @@ const aarch64 = struct {...@@ -1663,12 +1666,12 @@ const aarch64 = struct {
1663 .LD64_GOT_LO12_NC => {1666 .LD64_GOT_LO12_NC => {
1664 assert(target.flags.has_got);1667 assert(target.flags.has_got);
1665 const taddr = @as(u64, @intCast(G + GOT + A));1668 const taddr = @as(u64, @intCast(G + GOT + A));
1666 aarch64_util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code);1669 util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code);
1667 },1670 },
16681671
1669 .ADD_ABS_LO12_NC => {1672 .ADD_ABS_LO12_NC => {
1670 const taddr = @as(u64, @intCast(S + A));1673 const taddr = @as(u64, @intCast(S + A));
1671 aarch64_util.writeAddImmInst(@truncate(taddr), code);1674 util.writeAddImmInst(@truncate(taddr), code);
1672 },1675 },
16731676
1674 .LDST8_ABS_LO12_NC,1677 .LDST8_ABS_LO12_NC,
...@@ -1687,57 +1690,54 @@ const aarch64 = struct {...@@ -1687,57 +1690,54 @@ const aarch64 = struct {
1687 .LDST128_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 16),1690 .LDST128_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 16),
1688 else => unreachable,1691 else => unreachable,
1689 };1692 };
1690 aarch64_util.writeLoadStoreRegInst(off, code);1693 util.writeLoadStoreRegInst(off, code);
1691 },1694 },
16921695
1693 .TLSLE_ADD_TPREL_HI12 => {1696 .TLSLE_ADD_TPREL_HI12 => {
1694 const value = math.cast(i12, (S + A - TP) >> 12) orelse1697 const value = math.cast(i12, (S + A - TP) >> 12) orelse
1695 return error.Overflow;1698 return error.Overflow;
1696 aarch64_util.writeAddImmInst(@bitCast(value), code);1699 util.writeAddImmInst(@bitCast(value), code);
1697 },1700 },
16981701
1699 .TLSLE_ADD_TPREL_LO12_NC => {1702 .TLSLE_ADD_TPREL_LO12_NC => {
1700 const value: i12 = @truncate(S + A - TP);1703 const value: i12 = @truncate(S + A - TP);
1701 aarch64_util.writeAddImmInst(@bitCast(value), code);1704 util.writeAddImmInst(@bitCast(value), code);
1702 },1705 },
17031706
1704 .TLSIE_ADR_GOTTPREL_PAGE21 => {1707 .TLSIE_ADR_GOTTPREL_PAGE21 => {
1705 const S_ = target.gotTpAddress(elf_file);1708 const S_ = target.gotTpAddress(elf_file);
1706 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });1709 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1707 const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A));1710 util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code);
1708 aarch64_util.writeAdrpInst(pages, code);
1709 },1711 },
17101712
1711 .TLSIE_LD64_GOTTPREL_LO12_NC => {1713 .TLSIE_LD64_GOTTPREL_LO12_NC => {
1712 const S_ = target.gotTpAddress(elf_file);1714 const S_ = target.gotTpAddress(elf_file);
1713 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });1715 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1714 const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);1716 const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);
1715 aarch64_util.writeLoadStoreRegInst(off, code);1717 util.writeLoadStoreRegInst(off, code);
1716 },1718 },
17171719
1718 .TLSGD_ADR_PAGE21 => {1720 .TLSGD_ADR_PAGE21 => {
1719 const S_ = target.tlsGdAddress(elf_file);1721 const S_ = target.tlsGdAddress(elf_file);
1720 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });1722 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1721 const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A));1723 util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code);
1722 aarch64_util.writeAdrpInst(pages, code);
1723 },1724 },
17241725
1725 .TLSGD_ADD_LO12_NC => {1726 .TLSGD_ADD_LO12_NC => {
1726 const S_ = target.tlsGdAddress(elf_file);1727 const S_ = target.tlsGdAddress(elf_file);
1727 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });1728 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1728 const off: u12 = @truncate(@as(u64, @bitCast(S_ + A)));1729 const off: u12 = @truncate(@as(u64, @bitCast(S_ + A)));
1729 aarch64_util.writeAddImmInst(off, code);1730 util.writeAddImmInst(off, code);
1730 },1731 },
17311732
1732 .TLSDESC_ADR_PAGE21 => {1733 .TLSDESC_ADR_PAGE21 => {
1733 if (target.flags.has_tlsdesc) {1734 if (target.flags.has_tlsdesc) {
1734 const S_ = target.tlsDescAddress(elf_file);1735 const S_ = target.tlsDescAddress(elf_file);
1735 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });1736 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1736 const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A));1737 util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code);
1737 aarch64_util.writeAdrpInst(pages, code);
1738 } else {1738 } else {
1739 relocs_log.debug(" relaxing adrp => nop", .{});1739 relocs_log.debug(" relaxing adrp => nop", .{});
1740 mem.writeInt(u32, code, Instruction.nop().toU32(), .little);1740 util.encoding.Instruction.nop().write(code);
1741 }1741 }
1742 },1742 },
17431743
...@@ -1746,10 +1746,10 @@ const aarch64 = struct {...@@ -1746,10 +1746,10 @@ const aarch64 = struct {
1746 const S_ = target.tlsDescAddress(elf_file);1746 const S_ = target.tlsDescAddress(elf_file);
1747 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });1747 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1748 const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);1748 const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);
1749 aarch64_util.writeLoadStoreRegInst(off, code);1749 util.writeLoadStoreRegInst(off, code);
1750 } else {1750 } else {
1751 relocs_log.debug(" relaxing ldr => nop", .{});1751 relocs_log.debug(" relaxing ldr => nop", .{});
1752 mem.writeInt(u32, code, Instruction.nop().toU32(), .little);1752 util.encoding.Instruction.nop().write(code);
1753 }1753 }
1754 },1754 },
17551755
...@@ -1758,32 +1758,18 @@ const aarch64 = struct {...@@ -1758,32 +1758,18 @@ const aarch64 = struct {
1758 const S_ = target.tlsDescAddress(elf_file);1758 const S_ = target.tlsDescAddress(elf_file);
1759 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });1759 relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
1760 const off: u12 = @truncate(@as(u64, @bitCast(S_ + A)));1760 const off: u12 = @truncate(@as(u64, @bitCast(S_ + A)));
1761 aarch64_util.writeAddImmInst(off, code);1761 util.writeAddImmInst(off, code);
1762 } else {1762 } else {
1763 const old_inst: Instruction = .{1763 relocs_log.debug(" relaxing add => movz(x0, {x})", .{S + A - TP});
1764 .add_subtract_immediate = mem.bytesToValue(@FieldType(
1765 Instruction,
1766 @tagName(Instruction.add_subtract_immediate),
1767 ), code),
1768 };
1769 const rd: Register = @enumFromInt(old_inst.add_subtract_immediate.rd);
1770 relocs_log.debug(" relaxing add({s}) => movz(x0, {x})", .{ @tagName(rd), S + A - TP });
1771 const value: u16 = @bitCast(math.cast(i16, (S + A - TP) >> 16) orelse return error.Overflow);1764 const value: u16 = @bitCast(math.cast(i16, (S + A - TP) >> 16) orelse return error.Overflow);
1772 mem.writeInt(u32, code, Instruction.movz(.x0, value, 16).toU32(), .little);1765 util.encoding.Instruction.movz(.x0, value, .{ .lsl = .@"16" }).write(code);
1773 }1766 }
1774 },1767 },
17751768
1776 .TLSDESC_CALL => if (!target.flags.has_tlsdesc) {1769 .TLSDESC_CALL => if (!target.flags.has_tlsdesc) {
1777 const old_inst: Instruction = .{1770 relocs_log.debug(" relaxing br => movk(x0, {x})", .{S + A - TP});
1778 .unconditional_branch_register = mem.bytesToValue(@FieldType(
1779 Instruction,
1780 @tagName(Instruction.unconditional_branch_register),
1781 ), code),
1782 };
1783 const rn: Register = @enumFromInt(old_inst.unconditional_branch_register.rn);
1784 relocs_log.debug(" relaxing br({s}) => movk(x0, {x})", .{ @tagName(rn), S + A - TP });
1785 const value: u16 = @bitCast(@as(i16, @truncate(S + A - TP)));1771 const value: u16 = @bitCast(@as(i16, @truncate(S + A - TP)));
1786 mem.writeInt(u32, code, Instruction.movk(.x0, value, 0).toU32(), .little);1772 util.encoding.Instruction.movk(.x0, value, .{}).write(code);
1787 },1773 },
17881774
1789 else => try atom.reportUnhandledRelocError(rel, elf_file),1775 else => try atom.reportUnhandledRelocError(rel, elf_file),
...@@ -1819,9 +1805,7 @@ const aarch64 = struct {...@@ -1819,9 +1805,7 @@ const aarch64 = struct {
1819 }1805 }
1820 }1806 }
18211807
1822 const aarch64_util = @import("../aarch64.zig");1808 const util = @import("../aarch64.zig");
1823 const Instruction = aarch64_util.Instruction;
1824 const Register = aarch64_util.Register;
1825};1809};
18261810
1827const riscv = struct {1811const riscv = struct {
src/link/Elf/Thunk.zig+9-6
...@@ -95,18 +95,21 @@ const aarch64 = struct {...@@ -95,18 +95,21 @@ const aarch64 = struct {
95 const sym = elf_file.symbol(ref).?;95 const sym = elf_file.symbol(ref).?;
96 const saddr = thunk.address(elf_file) + @as(i64, @intCast(i * trampoline_size));96 const saddr = thunk.address(elf_file) + @as(i64, @intCast(i * trampoline_size));
97 const taddr = sym.address(.{}, elf_file);97 const taddr = sym.address(.{}, elf_file);
98 const pages = try util.calcNumberOfPages(saddr, taddr);98 try writer.writeInt(u32, @bitCast(
99 try writer.writeInt(u32, Instruction.adrp(.x16, pages).toU32(), .little);99 util.encoding.Instruction.adrp(.x16, try util.calcNumberOfPages(saddr, taddr) << 12),
100 const off: u12 = @truncate(@as(u64, @bitCast(taddr)));100 ), .little);
101 try writer.writeInt(u32, Instruction.add(.x16, .x16, off, false).toU32(), .little);101 try writer.writeInt(u32, @bitCast(util.encoding.Instruction.add(
102 try writer.writeInt(u32, Instruction.br(.x16).toU32(), .little);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 }
105109
106 const trampoline_size = 3 * @sizeOf(u32);110 const trampoline_size = 3 * @sizeOf(u32);
107111
108 const util = @import("../aarch64.zig");112 const util = @import("../aarch64.zig");
109 const Instruction = util.Instruction;
110};113};
111114
112const assert = std.debug.assert;115const assert = std.debug.assert;
src/link/Elf/ZigObject.zig+7-3
...@@ -1270,9 +1270,13 @@ fn updateNavCode(...@@ -1270,9 +1270,13 @@ fn updateNavCode(
12701270
1271 log.debug("updateNavCode {f}({d})", .{ nav.fqn.fmt(ip), nav_index });1271 log.debug("updateNavCode {f}({d})", .{ nav.fqn.fmt(ip), nav_index });
12721272
1273 const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;1273 const mod = zcu.navFileScope(nav_index).mod.?;
1274 const required_alignment = switch (pt.navAlignment(nav_index)) {1274 const target = &mod.resolved_target.result;
1275 .none => target_util.defaultFunctionAlignment(target),1275 const required_alignment = switch (nav.status.fully_resolved.alignment) {
1276 .none => switch (mod.optimize_mode) {
1277 .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target),
1278 .ReleaseSmall => target_util.minFunctionAlignment(target),
1279 },
1276 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),1280 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
1277 };1281 };
12781282
src/link/Elf/relocation.zig+18-6
...@@ -94,14 +94,18 @@ pub fn encode(comptime kind: Kind, cpu_arch: std.Target.Cpu.Arch) u32 {...@@ -94,14 +94,18 @@ pub fn encode(comptime kind: Kind, cpu_arch: std.Target.Cpu.Arch) u32 {
94pub const dwarf = struct {94pub const dwarf = struct {
95 pub fn crossSectionRelocType(format: DW.Format, cpu_arch: std.Target.Cpu.Arch) u32 {95 pub fn crossSectionRelocType(format: DW.Format, cpu_arch: std.Target.Cpu.Arch) u32 {
96 return switch (cpu_arch) {96 return switch (cpu_arch) {
97 .x86_64 => @intFromEnum(switch (format) {97 .x86_64 => @intFromEnum(@as(elf.R_X86_64, switch (format) {
98 .@"32" => elf.R_X86_64.@"32",98 .@"32" => .@"32",
99 .@"64" => .@"64",99 .@"64" => .@"64",
100 }),100 })),
101 .riscv64 => @intFromEnum(switch (format) {101 .aarch64 => @intFromEnum(@as(elf.R_AARCH64, switch (format) {
102 .@"32" => elf.R_RISCV.@"32",102 .@"32" => .ABS32,
103 .@"64" => .ABS64,
104 })),
105 .riscv64 => @intFromEnum(@as(elf.R_RISCV, switch (format) {
106 .@"32" => .@"32",
103 .@"64" => .@"64",107 .@"64" => .@"64",
104 }),108 })),
105 else => @panic("TODO unhandled cpu arch"),109 else => @panic("TODO unhandled cpu arch"),
106 };110 };
107 }111 }
...@@ -121,6 +125,14 @@ pub const dwarf = struct {...@@ -121,6 +125,14 @@ pub const dwarf = struct {
121 },125 },
122 .debug_frame => .PC32,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 .riscv64 => @intFromEnum(@as(elf.R_RISCV, switch (source_section) {136 .riscv64 => @intFromEnum(@as(elf.R_RISCV, switch (source_section) {
125 else => switch (address_size) {137 else => switch (address_size) {
126 .@"32" => .@"32",138 .@"32" => .@"32",
src/link/Elf/synthetic_sections.zig+30-45
...@@ -810,54 +810,43 @@ pub const PltSection = struct {...@@ -810,54 +810,43 @@ pub const PltSection = struct {
810 const got_plt_addr: i64 = @intCast(shdrs[elf_file.section_indexes.got_plt.?].sh_addr);810 const got_plt_addr: i64 = @intCast(shdrs[elf_file.section_indexes.got_plt.?].sh_addr);
811 // TODO: relax if possible811 // TODO: relax if possible
812 // .got.plt[2]812 // .got.plt[2]
813 const pages = try aarch64_util.calcNumberOfPages(plt_addr + 4, got_plt_addr + 16);813 const pages = try 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);814 const ldr_off: u12 = @truncate(@as(u64, @bitCast(got_plt_addr + 16)));
815 const add_off: u12 = @truncate(@as(u64, @bitCast(got_plt_addr + 16)));815 const add_off: u12 = @truncate(@as(u64, @bitCast(got_plt_addr + 16)));
816816
817 const preamble = &[_]Instruction{817 const preamble = [_]util.encoding.Instruction{
818 Instruction.stp(818 .stp(.x16, .x30, .{ .pre_index = .{ .base = .sp, .index = -16 } }),
819 .x16,819 .adrp(.x16, pages << 12),
820 .x30,820 .ldr(.x17, .{ .unsigned_offset = .{ .base = .x16, .offset = ldr_off } }),
821 Register.sp,821 .add(.x16, .x16, .{ .immediate = add_off }),
822 Instruction.LoadStorePairOffset.pre_index(-16),822 .br(.x17),
823 ),823 .nop(),
824 Instruction.adrp(.x16, pages),824 .nop(),
825 Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(ldr_off)),825 .nop(),
826 Instruction.add(.x16, .x16, add_off, false),
827 Instruction.br(.x17),
828 Instruction.nop(),
829 Instruction.nop(),
830 Instruction.nop(),
831 };826 };
832 comptime assert(preamble.len == 8);827 comptime assert(preamble.len == 8);
833 for (preamble) |inst| {828 for (preamble) |inst| try writer.writeInt(util.encoding.Instruction.Backing, @bitCast(inst), .little);
834 try writer.writeInt(u32, inst.toU32(), .little);
835 }
836 }829 }
837830
838 for (plt.symbols.items) |ref| {831 for (plt.symbols.items) |ref| {
839 const sym = elf_file.symbol(ref).?;832 const sym = elf_file.symbol(ref).?;
840 const target_addr = sym.gotPltAddress(elf_file);833 const target_addr = sym.gotPltAddress(elf_file);
841 const source_addr = sym.pltAddress(elf_file);834 const source_addr = sym.pltAddress(elf_file);
842 const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr);835 const pages = try util.calcNumberOfPages(source_addr, target_addr);
843 const ldr_off = try math.divExact(u12, @truncate(@as(u64, @bitCast(target_addr))), 8);836 const ldr_off: u12 = @truncate(@as(u64, @bitCast(target_addr)));
844 const add_off: u12 = @truncate(@as(u64, @bitCast(target_addr)));837 const add_off: u12 = @truncate(@as(u64, @bitCast(target_addr)));
845 const insts = &[_]Instruction{838 const insts = [_]util.encoding.Instruction{
846 Instruction.adrp(.x16, pages),839 .adrp(.x16, pages << 12),
847 Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(ldr_off)),840 .ldr(.x17, .{ .unsigned_offset = .{ .base = .x16, .offset = ldr_off } }),
848 Instruction.add(.x16, .x16, add_off, false),841 .add(.x16, .x16, .{ .immediate = add_off }),
849 Instruction.br(.x17),842 .br(.x17),
850 };843 };
851 comptime assert(insts.len == 4);844 comptime assert(insts.len == 4);
852 for (insts) |inst| {845 for (insts) |inst| try writer.writeInt(util.encoding.Instruction.Backing, @bitCast(inst), .little);
853 try writer.writeInt(u32, inst.toU32(), .little);
854 }
855 }846 }
856 }847 }
857848
858 const aarch64_util = @import("../aarch64.zig");849 const util = @import("../aarch64.zig");
859 const Instruction = aarch64_util.Instruction;
860 const Register = aarch64_util.Register;
861 };850 };
862};851};
863852
...@@ -979,24 +968,20 @@ pub const PltGotSection = struct {...@@ -979,24 +968,20 @@ pub const PltGotSection = struct {
979 const sym = elf_file.symbol(ref).?;968 const sym = elf_file.symbol(ref).?;
980 const target_addr = sym.gotAddress(elf_file);969 const target_addr = sym.gotAddress(elf_file);
981 const source_addr = sym.pltGotAddress(elf_file);970 const source_addr = sym.pltGotAddress(elf_file);
982 const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr);971 const pages = try util.calcNumberOfPages(source_addr, target_addr);
983 const off = try math.divExact(u12, @truncate(@as(u64, @bitCast(target_addr))), 8);972 const off: u12 = @truncate(@as(u64, @bitCast(target_addr)));
984 const insts = &[_]Instruction{973 const insts = [_]util.encoding.Instruction{
985 Instruction.adrp(.x16, pages),974 .adrp(.x16, pages << 12),
986 Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(off)),975 .ldr(.x17, .{ .unsigned_offset = .{ .base = .x16, .offset = off } }),
987 Instruction.br(.x17),976 .br(.x17),
988 Instruction.nop(),977 .nop(),
989 };978 };
990 comptime assert(insts.len == 4);979 comptime assert(insts.len == 4);
991 for (insts) |inst| {980 for (insts) |inst| try writer.writeInt(util.encoding.Instruction.Backing, @bitCast(inst), .little);
992 try writer.writeInt(u32, inst.toU32(), .little);
993 }
994 }981 }
995 }982 }
996983
997 const aarch64_util = @import("../aarch64.zig");984 const util = @import("../aarch64.zig");
998 const Instruction = aarch64_util.Instruction;
999 const Register = aarch64_util.Register;
1000 };985 };
1001};986};
1002987
src/link/MachO.zig+2-2
...@@ -328,6 +328,7 @@ pub fn deinit(self: *MachO) void {...@@ -328,6 +328,7 @@ pub fn deinit(self: *MachO) void {
328 self.unwind_info.deinit(gpa);328 self.unwind_info.deinit(gpa);
329 self.data_in_code.deinit(gpa);329 self.data_in_code.deinit(gpa);
330330
331 for (self.thunks.items) |*thunk| thunk.deinit(gpa);
331 self.thunks.deinit(gpa);332 self.thunks.deinit(gpa);
332}333}
333334
...@@ -612,7 +613,6 @@ pub fn flush(...@@ -612,7 +613,6 @@ pub fn flush(
612 };613 };
613 const emit = self.base.emit;614 const emit = self.base.emit;
614 invalidateKernelCache(emit.root_dir.handle, emit.sub_path) catch |err| switch (err) {615 invalidateKernelCache(emit.root_dir.handle, emit.sub_path) catch |err| switch (err) {
615 error.OutOfMemory => return error.OutOfMemory,
616 else => |e| return diags.fail("failed to invalidate kernel cache: {s}", .{@errorName(e)}),616 else => |e| return diags.fail("failed to invalidate kernel cache: {s}", .{@errorName(e)}),
617 };617 };
618 }618 }
...@@ -5374,7 +5374,7 @@ const mem = std.mem;...@@ -5374,7 +5374,7 @@ const mem = std.mem;
5374const meta = std.meta;5374const meta = std.meta;
5375const Writer = std.io.Writer;5375const Writer = std.io.Writer;
53765376
5377const aarch64 = @import("../arch/aarch64/bits.zig");5377const aarch64 = codegen.aarch64.encoding;
5378const bind = @import("MachO/dyld_info/bind.zig");5378const bind = @import("MachO/dyld_info/bind.zig");
5379const calcUuid = @import("MachO/uuid.zig").calcUuid;5379const calcUuid = @import("MachO/uuid.zig").calcUuid;
5380const codegen = @import("../codegen.zig");5380const codegen = @import("../codegen.zig");
src/link/MachO/Atom.zig+29-71
...@@ -780,8 +780,7 @@ fn resolveRelocInner(...@@ -780,8 +780,7 @@ fn resolveRelocInner(
780 };780 };
781 break :target math.cast(u64, target) orelse return error.Overflow;781 break :target math.cast(u64, target) orelse return error.Overflow;
782 };782 };
783 const pages = @as(u21, @bitCast(try aarch64.calcNumberOfPages(@intCast(source), @intCast(target))));783 aarch64.writeAdrInst(try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)), code[rel_offset..][0..aarch64.encoding.Instruction.size]);
784 aarch64.writeAdrpInst(pages, code[rel_offset..][0..4]);
785 },784 },
786785
787 .pageoff => {786 .pageoff => {
...@@ -789,26 +788,18 @@ fn resolveRelocInner(...@@ -789,26 +788,18 @@ fn resolveRelocInner(
789 assert(rel.meta.length == 2);788 assert(rel.meta.length == 2);
790 assert(!rel.meta.pcrel);789 assert(!rel.meta.pcrel);
791 const target = math.cast(u64, S + A) orelse return error.Overflow;790 const target = math.cast(u64, S + A) orelse return error.Overflow;
792 const inst_code = code[rel_offset..][0..4];791 const inst_code = code[rel_offset..][0..aarch64.encoding.Instruction.size];
793 if (aarch64.isArithmeticOp(inst_code)) {792 var inst: aarch64.encoding.Instruction = .read(inst_code);
794 aarch64.writeAddImmInst(@truncate(target), inst_code);793 switch (inst.decode()) {
795 } else {794 else => unreachable,
796 var inst = aarch64.Instruction{795 .data_processing_immediate => aarch64.writeAddImmInst(@truncate(target), inst_code),
797 .load_store_register = mem.bytesToValue(@FieldType(796 .load_store => |load_store| {
798 aarch64.Instruction,797 inst.load_store.register_unsigned_immediate.group.imm12 = switch (load_store.register_unsigned_immediate.decode()) {
799 @tagName(aarch64.Instruction.load_store_register),798 .integer => |integer| try divExact(self, rel, @truncate(target), @as(u4, 1) << @intFromEnum(integer.group.size), macho_file),
800 ), inst_code),799 .vector => |vector| try divExact(self, rel, @truncate(target), @as(u5, 1) << @intFromEnum(vector.group.opc1.decode(vector.group.size)), macho_file),
801 };800 };
802 inst.load_store_register.offset = switch (inst.load_store_register.size) {801 try writer.writeInt(u32, @bitCast(inst), .little);
803 0 => if (inst.load_store_register.v == 1)802 },
804 try divExact(self, rel, @truncate(target), 16, macho_file)
805 else
806 @truncate(target),
807 1 => try divExact(self, rel, @truncate(target), 2, macho_file),
808 2 => try divExact(self, rel, @truncate(target), 4, macho_file),
809 3 => try divExact(self, rel, @truncate(target), 8, macho_file),
810 };
811 try writer.writeInt(u32, inst.toU32(), .little);
812 }803 }
813 },804 },
814805
...@@ -834,59 +825,26 @@ fn resolveRelocInner(...@@ -834,59 +825,26 @@ fn resolveRelocInner(
834 break :target math.cast(u64, target) orelse return error.Overflow;825 break :target math.cast(u64, target) orelse return error.Overflow;
835 };826 };
836827
837 const RegInfo = struct {
838 rd: u5,
839 rn: u5,
840 size: u2,
841 };
842
843 const inst_code = code[rel_offset..][0..4];828 const inst_code = code[rel_offset..][0..4];
844 const reg_info: RegInfo = blk: {829 const rd, const rn = switch (aarch64.encoding.Instruction.read(inst_code).decode()) {
845 if (aarch64.isArithmeticOp(inst_code)) {830 else => unreachable,
846 const inst = mem.bytesToValue(@FieldType(831 .data_processing_immediate => |decoded| .{
847 aarch64.Instruction,832 decoded.add_subtract_immediate.group.Rd.decodeInteger(.doubleword, .{ .sp = true }),
848 @tagName(aarch64.Instruction.add_subtract_immediate),833 decoded.add_subtract_immediate.group.Rn.decodeInteger(.doubleword, .{ .sp = true }),
849 ), inst_code);
850 break :blk .{
851 .rd = inst.rd,
852 .rn = inst.rn,
853 .size = inst.sf,
854 };
855 } else {
856 const inst = mem.bytesToValue(@FieldType(
857 aarch64.Instruction,
858 @tagName(aarch64.Instruction.load_store_register),
859 ), inst_code);
860 break :blk .{
861 .rd = inst.rt,
862 .rn = inst.rn,
863 .size = inst.size,
864 };
865 }
866 };
867
868 var inst = if (sym.getSectionFlags().tlv_ptr) aarch64.Instruction{
869 .load_store_register = .{
870 .rt = reg_info.rd,
871 .rn = reg_info.rn,
872 .offset = try divExact(self, rel, @truncate(target), 8, macho_file),
873 .opc = 0b01,
874 .op1 = 0b01,
875 .v = 0,
876 .size = reg_info.size,
877 },834 },
878 } else aarch64.Instruction{835 .load_store => |decoded| .{
879 .add_subtract_immediate = .{836 decoded.register_unsigned_immediate.integer.group.Rt.decodeInteger(.doubleword, .{}),
880 .rd = reg_info.rd,837 decoded.register_unsigned_immediate.group.Rn.decodeInteger(.doubleword, .{ .sp = true }),
881 .rn = reg_info.rn,
882 .imm12 = @truncate(target),
883 .sh = 0,
884 .s = 0,
885 .op = 0,
886 .sf = @as(u1, @truncate(reg_info.size)),
887 },838 },
888 };839 };
889 try writer.writeInt(u32, inst.toU32(), .little);840
841 try writer.writeInt(u32, @bitCast(@as(
842 aarch64.encoding.Instruction,
843 if (sym.getSectionFlags().tlv_ptr) .ldr(rd, .{ .unsigned_offset = .{
844 .base = rn,
845 .offset = try divExact(self, rel, @truncate(target), 8, macho_file) * 8,
846 } }) else .add(rd, rn, .{ .immediate = @truncate(target) }),
847 )), .little);
890 },848 },
891 }849 }
892}850}
src/link/MachO/Thunk.zig+6-4
...@@ -21,15 +21,17 @@ pub fn getTargetAddress(thunk: Thunk, ref: MachO.Ref, macho_file: *MachO) u64 {...@@ -21,15 +21,17 @@ pub fn getTargetAddress(thunk: Thunk, ref: MachO.Ref, macho_file: *MachO) u64 {
21}21}
2222
23pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void {23pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void {
24 const Instruction = aarch64.encoding.Instruction;
24 for (thunk.symbols.keys(), 0..) |ref, i| {25 for (thunk.symbols.keys(), 0..) |ref, i| {
25 const sym = ref.getSymbol(macho_file).?;26 const sym = ref.getSymbol(macho_file).?;
26 const saddr = thunk.getAddress(macho_file) + i * trampoline_size;27 const saddr = thunk.getAddress(macho_file) + i * trampoline_size;
27 const taddr = sym.getAddress(.{}, macho_file);28 const taddr = sym.getAddress(.{}, macho_file);
28 const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr));29 const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr));
29 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);30 try writer.writeInt(u32, @bitCast(Instruction.adrp(.x16, pages << 12)), .little);
30 const off: u12 = @truncate(taddr);31 try writer.writeInt(u32, @bitCast(
31 try writer.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little);32 Instruction.add(.x16, .x16, .{ .immediate = @truncate(taddr) }),
32 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);33 ), .little);
34 try writer.writeInt(u32, @bitCast(Instruction.br(.x16)), .little);
33 }35 }
34}36}
3537
src/link/MachO/ZigObject.zig+7-3
...@@ -945,9 +945,13 @@ fn updateNavCode(...@@ -945,9 +945,13 @@ fn updateNavCode(
945945
946 log.debug("updateNavCode {f} 0x{x}", .{ nav.fqn.fmt(ip), nav_index });946 log.debug("updateNavCode {f} 0x{x}", .{ nav.fqn.fmt(ip), nav_index });
947947
948 const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;948 const mod = zcu.navFileScope(nav_index).mod.?;
949 const required_alignment = switch (pt.navAlignment(nav_index)) {949 const target = &mod.resolved_target.result;
950 .none => target_util.defaultFunctionAlignment(target),950 const required_alignment = switch (nav.status.fully_resolved.alignment) {
951 .none => switch (mod.optimize_mode) {
952 .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target),
953 .ReleaseSmall => target_util.minFunctionAlignment(target),
954 },
951 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),955 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
952 };956 };
953957
src/link/MachO/synthetic.zig+43-52
...@@ -105,16 +105,15 @@ pub const StubsSection = struct {...@@ -105,16 +105,15 @@ pub const StubsSection = struct {
105 try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little);105 try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little);
106 },106 },
107 .aarch64 => {107 .aarch64 => {
108 const Instruction = aarch64.encoding.Instruction;
108 // TODO relax if possible109 // TODO relax if possible
109 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));110 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
110 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);111 try writer.writeInt(u32, @bitCast(Instruction.adrp(.x16, pages << 12)), .little);
111 const off = try math.divExact(u12, @truncate(target), 8);112 try writer.writeInt(u32, @bitCast(Instruction.ldr(
112 try writer.writeInt(113 .x16,
113 u32,114 .{ .unsigned_offset = .{ .base = .x16, .offset = @as(u12, @truncate(target)) } },
114 aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),115 )), .little);
115 .little,116 try writer.writeInt(u32, @bitCast(Instruction.br(.x16)), .little);
116 );
117 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
118 },117 },
119 else => unreachable,118 else => unreachable,
120 }119 }
...@@ -201,18 +200,16 @@ pub const StubsHelperSection = struct {...@@ -201,18 +200,16 @@ pub const StubsHelperSection = struct {
201 try writer.writeInt(i32, @intCast(target - source - 6 - 4), .little);200 try writer.writeInt(i32, @intCast(target - source - 6 - 4), .little);
202 },201 },
203 .aarch64 => {202 .aarch64 => {
204 const literal = blk: {203 const Instruction = aarch64.encoding.Instruction;
205 const div_res = try std.math.divExact(u64, entry_size - @sizeOf(u32), 4);204 if (entry_size % Instruction.size != 0) return error.UnexpectedRemainder;
206 break :blk std.math.cast(u18, div_res) orelse return error.Overflow;205 try writer.writeInt(u32, @bitCast(
207 };206 Instruction.ldr(.w16, .{ .literal = std.math.cast(i21, entry_size - Instruction.size) orelse
208 try writer.writeInt(u32, aarch64.Instruction.ldrLiteral(207 return error.Overflow }),
209 .w16,208 ), .little);
210 literal,
211 ).toU32(), .little);
212 const disp = math.cast(i28, @as(i64, @intCast(target)) - @as(i64, @intCast(source + 4))) orelse209 const disp = math.cast(i28, @as(i64, @intCast(target)) - @as(i64, @intCast(source + 4))) orelse
213 return error.Overflow;210 return error.Overflow;
214 try writer.writeInt(u32, aarch64.Instruction.b(disp).toU32(), .little);211 try writer.writeInt(u32, @bitCast(Instruction.b(disp)), .little);
215 try writer.writeAll(&.{ 0x0, 0x0, 0x0, 0x0 });212 try writer.writeInt(u32, @bitCast(Instruction.udf(0x0)), .little);
216 },213 },
217 else => unreachable,214 else => unreachable,
218 }215 }
...@@ -242,31 +239,28 @@ pub const StubsHelperSection = struct {...@@ -242,31 +239,28 @@ pub const StubsHelperSection = struct {
242 try writer.writeByte(0x90);239 try writer.writeByte(0x90);
243 },240 },
244 .aarch64 => {241 .aarch64 => {
242 const Instruction = aarch64.encoding.Instruction;
245 {243 {
246 // TODO relax if possible244 // TODO relax if possible
247 const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr), @intCast(dyld_private_addr));245 const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr), @intCast(dyld_private_addr));
248 try writer.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little);246 try writer.writeInt(Instruction.Backing, @bitCast(Instruction.adrp(.x17, pages << 12)), .little);
249 const off: u12 = @truncate(dyld_private_addr);247 try writer.writeInt(Instruction.Backing, @bitCast(
250 try writer.writeInt(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32(), .little);248 Instruction.add(.x17, .x17, .{ .immediate = @as(u12, @truncate(dyld_private_addr)) }),
249 ), .little);
251 }250 }
252 try writer.writeInt(u32, aarch64.Instruction.stp(251 try writer.writeInt(Instruction.Backing, @bitCast(
253 .x16,252 Instruction.stp(.x16, .x17, .{ .pre_index = .{ .base = .sp, .index = -16 } }),
254 .x17,253 ), .little);
255 aarch64.Register.sp,
256 aarch64.Instruction.LoadStorePairOffset.pre_index(-16),
257 ).toU32(), .little);
258 {254 {
259 // TODO relax if possible255 // TODO relax if possible
260 const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr + 12), @intCast(dyld_stub_binder_addr));256 const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr + 12), @intCast(dyld_stub_binder_addr));
261 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);257 try writer.writeInt(Instruction.Backing, @bitCast(Instruction.adrp(.x16, pages << 12)), .little);
262 const off = try math.divExact(u12, @truncate(dyld_stub_binder_addr), 8);258 try writer.writeInt(Instruction.Backing, @bitCast(Instruction.ldr(
263 try writer.writeInt(u32, aarch64.Instruction.ldr(
264 .x16,
265 .x16,259 .x16,
266 aarch64.Instruction.LoadStoreOffset.imm(off),260 .{ .unsigned_offset = .{ .base = .x16, .offset = @as(u12, @truncate(dyld_stub_binder_addr)) } },
267 ).toU32(), .little);261 )), .little);
268 }262 }
269 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);263 try writer.writeInt(Instruction.Backing, @bitCast(Instruction.br(.x16)), .little);
270 },264 },
271 else => unreachable,265 else => unreachable,
272 }266 }
...@@ -426,35 +420,32 @@ pub const ObjcStubsSection = struct {...@@ -426,35 +420,32 @@ pub const ObjcStubsSection = struct {
426 }420 }
427 },421 },
428 .aarch64 => {422 .aarch64 => {
423 const Instruction = aarch64.encoding.Instruction;
429 {424 {
430 const target = sym.getObjcSelrefsAddress(macho_file);425 const target = sym.getObjcSelrefsAddress(macho_file);
431 const source = addr;426 const source = addr;
432 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));427 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
433 try writer.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little);428 try writer.writeInt(u32, @bitCast(Instruction.adrp(.x1, pages << 12)), .little);
434 const off = try math.divExact(u12, @truncate(target), 8);429 try writer.writeInt(u32, @bitCast(Instruction.ldr(
435 try writer.writeInt(430 .x1,
436 u32,431 .{ .unsigned_offset = .{ .base = .x1, .offset = @as(u12, @truncate(target)) } },
437 aarch64.Instruction.ldr(.x1, .x1, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),432 )), .little);
438 .little,
439 );
440 }433 }
441 {434 {
442 const target_sym = obj.getObjcMsgSendRef(macho_file).?.getSymbol(macho_file).?;435 const target_sym = obj.getObjcMsgSendRef(macho_file).?.getSymbol(macho_file).?;
443 const target = target_sym.getGotAddress(macho_file);436 const target = target_sym.getGotAddress(macho_file);
444 const source = addr + 2 * @sizeOf(u32);437 const source = addr + 2 * @sizeOf(u32);
445 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));438 const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target));
446 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);439 try writer.writeInt(u32, @bitCast(Instruction.adrp(.x16, pages << 12)), .little);
447 const off = try math.divExact(u12, @truncate(target), 8);440 try writer.writeInt(u32, @bitCast(Instruction.ldr(
448 try writer.writeInt(441 .x16,
449 u32,442 .{ .unsigned_offset = .{ .base = .x16, .offset = @as(u12, @truncate(target)) } },
450 aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),443 )), .little);
451 .little,
452 );
453 }444 }
454 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);445 try writer.writeInt(u32, @bitCast(Instruction.br(.x16)), .little);
455 try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);446 try writer.writeInt(u32, @bitCast(Instruction.brk(0x1)), .little);
456 try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);447 try writer.writeInt(u32, @bitCast(Instruction.brk(0x1)), .little);
457 try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little);448 try writer.writeInt(u32, @bitCast(Instruction.brk(0x1)), .little);
458 },449 },
459 else => unreachable,450 else => unreachable,
460 }451 }
src/link/aarch64.zig+17-47
...@@ -1,66 +1,36 @@...@@ -1,66 +1,36 @@
1pub inline fn isArithmeticOp(inst: *const [4]u8) bool {1pub const encoding = @import("../codegen.zig").aarch64.encoding;
2 const group_decode = @as(u5, @truncate(inst[3]));
3 return ((group_decode >> 2) == 4);
4}
52
6pub fn writeAddImmInst(value: u12, code: *[4]u8) void {3pub fn writeAddImmInst(value: u12, code: *[4]u8) void {
7 var inst = Instruction{4 var inst: encoding.Instruction = .read(code);
8 .add_subtract_immediate = mem.bytesToValue(@FieldType(5 inst.data_processing_immediate.add_subtract_immediate.group.imm12 = value;
9 Instruction,6 inst.write(code);
10 @tagName(Instruction.add_subtract_immediate),
11 ), code),
12 };
13 inst.add_subtract_immediate.imm12 = value;
14 mem.writeInt(u32, code, inst.toU32(), .little);
15}7}
168
17pub fn writeLoadStoreRegInst(value: u12, code: *[4]u8) void {9pub fn writeLoadStoreRegInst(value: u12, code: *[4]u8) void {
18 var inst: Instruction = .{10 var inst: encoding.Instruction = .read(code);
19 .load_store_register = mem.bytesToValue(@FieldType(11 inst.load_store.register_unsigned_immediate.group.imm12 = value;
20 Instruction,12 inst.write(code);
21 @tagName(Instruction.load_store_register),
22 ), code),
23 };
24 inst.load_store_register.offset = value;
25 mem.writeInt(u32, code, inst.toU32(), .little);
26}13}
2714
28pub fn calcNumberOfPages(saddr: i64, taddr: i64) error{Overflow}!i21 {15pub fn calcNumberOfPages(saddr: i64, taddr: i64) error{Overflow}!i33 {
29 const spage = math.cast(i32, saddr >> 12) orelse return error.Overflow;16 return math.cast(i21, (taddr >> 12) - (saddr >> 12)) orelse 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;
33}17}
3418
35pub fn writeAdrpInst(pages: u21, code: *[4]u8) void {19pub fn writeAdrInst(imm: i33, code: *[4]u8) void {
36 var inst = Instruction{20 var inst: encoding.Instruction = .read(code);
37 .pc_relative_address = mem.bytesToValue(@FieldType(21 inst.data_processing_immediate.pc_relative_addressing.group.immhi = @intCast(imm >> 2);
38 Instruction,22 inst.data_processing_immediate.pc_relative_addressing.group.immlo = @bitCast(@as(i2, @truncate(imm)));
39 @tagName(Instruction.pc_relative_address),23 inst.write(code);
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);
45}24}
4625
47pub fn writeBranchImm(disp: i28, code: *[4]u8) void {26pub fn writeBranchImm(disp: i28, code: *[4]u8) void {
48 var inst = Instruction{27 var inst: encoding.Instruction = .read(code);
49 .unconditional_branch_immediate = mem.bytesToValue(@FieldType(28 inst.branch_exception_generating_system.unconditional_branch_immediate.group.imm26 = @intCast(@shrExact(disp, 2));
50 Instruction,29 inst.write(code);
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);
56}30}
5731
58const assert = std.debug.assert;32const assert = std.debug.assert;
59const bits = @import("../arch/aarch64/bits.zig");
60const builtin = @import("builtin");33const builtin = @import("builtin");
61const math = std.math;34const math = std.math;
62const mem = std.mem;35const mem = std.mem;
63const std = @import("std");36const std = @import("std");
64
65pub const Instruction = bits.Instruction;
66pub const Register = bits.Register;
src/main.zig+96-55
...@@ -37,6 +37,7 @@ const dev = @import("dev.zig");...@@ -37,6 +37,7 @@ const dev = @import("dev.zig");
3737
38test {38test {
39 _ = Package;39 _ = Package;
40 _ = @import("codegen.zig");
40}41}
4142
42const thread_stack_size = 60 << 20;43const thread_stack_size = 60 << 20;
...@@ -4624,7 +4625,9 @@ fn cmdTranslateC(...@@ -4624,7 +4625,9 @@ fn cmdTranslateC(
4624 fatal("unable to open cached translated zig file '{s}{s}{s}': {s}", .{ path, fs.path.sep_str, out_zig_path, @errorName(err) });4625 fatal("unable to open cached translated zig file '{s}{s}{s}': {s}", .{ path, fs.path.sep_str, out_zig_path, @errorName(err) });
4625 };4626 };
4626 defer zig_file.close();4627 defer zig_file.close();
4627 try fs.File.stdout().writeFileAll(zig_file, .{});4628 var stdout_writer = fs.File.stdout().writer(&stdout_buffer);
4629 var file_reader = zig_file.reader(&.{});
4630 _ = try stdout_writer.interface.sendFileAll(&file_reader, .unlimited);
4628 return cleanExit();4631 return cleanExit();
4629 }4632 }
4630}4633}
...@@ -4645,14 +4648,14 @@ const usage_init =...@@ -4645,14 +4648,14 @@ const usage_init =
4645fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {4648fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
4646 dev.check(.init_command);4649 dev.check(.init_command);
46474650
4648 var strip = false;4651 var template: enum { example, minimal } = .example;
4649 {4652 {
4650 var i: usize = 0;4653 var i: usize = 0;
4651 while (i < args.len) : (i += 1) {4654 while (i < args.len) : (i += 1) {
4652 const arg = args[i];4655 const arg = args[i];
4653 if (mem.startsWith(u8, arg, "-")) {4656 if (mem.startsWith(u8, arg, "-")) {
4654 if (mem.eql(u8, arg, "-s") or mem.eql(u8, arg, "--strip")) {4657 if (mem.eql(u8, arg, "-m") or mem.eql(u8, arg, "--minimal")) {
4655 strip = true;4658 template = .minimal;
4656 } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {4659 } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
4657 try fs.File.stdout().writeAll(usage_init);4660 try fs.File.stdout().writeAll(usage_init);
4658 return cleanExit();4661 return cleanExit();
...@@ -4665,40 +4668,79 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {...@@ -4665,40 +4668,79 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
4665 }4668 }
4666 }4669 }
46674670
4668 var templates = findTemplates(gpa, arena, strip);
4669 defer templates.deinit();
4670
4671 const cwd_path = try introspect.getResolvedCwd(arena);4671 const cwd_path = try introspect.getResolvedCwd(arena);
4672 const cwd_basename = fs.path.basename(cwd_path);4672 const cwd_basename = fs.path.basename(cwd_path);
4673 const sanitized_root_name = try sanitizeExampleName(arena, cwd_basename);4673 const sanitized_root_name = try sanitizeExampleName(arena, cwd_basename);
46744674
4675 const s = fs.path.sep_str;
4676 const template_paths = [_][]const u8{
4677 Package.build_zig_basename,
4678 Package.Manifest.basename,
4679 "src" ++ s ++ "main.zig",
4680 "src" ++ s ++ "root.zig",
4681 };
4682 var ok_count: usize = 0;
4683
4684 const fingerprint: Package.Fingerprint = .generate(sanitized_root_name);4675 const fingerprint: Package.Fingerprint = .generate(sanitized_root_name);
46854676
4686 for (template_paths) |template_path| {4677 switch (template) {
4687 if (templates.write(arena, fs.cwd(), sanitized_root_name, template_path, fingerprint)) |_| {4678 .example => {
4688 std.log.info("created {s}", .{template_path});4679 var templates = findTemplates(gpa, arena);
4689 ok_count += 1;4680 defer templates.deinit();
4690 } else |err| switch (err) {4681
4691 error.PathAlreadyExists => std.log.info("preserving already existing file: {s}", .{4682 const s = fs.path.sep_str;
4692 template_path,4683 const template_paths = [_][]const u8{
4693 }),4684 Package.build_zig_basename,
4694 else => std.log.err("unable to write {s}: {s}\n", .{ template_path, @errorName(err) }),4685 Package.Manifest.basename,
4695 }4686 "src" ++ s ++ "main.zig",
4696 }4687 "src" ++ s ++ "root.zig",
4688 };
4689 var ok_count: usize = 0;
4690
4691 for (template_paths) |template_path| {
4692 if (templates.write(arena, fs.cwd(), sanitized_root_name, template_path, fingerprint)) |_| {
4693 std.log.info("created {s}", .{template_path});
4694 ok_count += 1;
4695 } else |err| switch (err) {
4696 error.PathAlreadyExists => std.log.info("preserving already existing file: {s}", .{
4697 template_path,
4698 }),
4699 else => std.log.err("unable to write {s}: {s}\n", .{ template_path, @errorName(err) }),
4700 }
4701 }
46974702
4698 if (ok_count == template_paths.len) {4703 if (ok_count == template_paths.len) {
4699 std.log.info("see `zig build --help` for a menu of options", .{});4704 std.log.info("see `zig build --help` for a menu of options", .{});
4705 }
4706 return cleanExit();
4707 },
4708 .minimal => {
4709 writeSimpleTemplateFile(Package.Manifest.basename,
4710 \\.{{
4711 \\ .name = .{s},
4712 \\ .version = "{s}",
4713 \\ .paths = .{{""}},
4714 \\ .fingerprint = 0x{x},
4715 \\}}
4716 \\
4717 , .{
4718 sanitized_root_name,
4719 build_options.version,
4720 fingerprint.int(),
4721 }) catch |err| switch (err) {
4722 else => fatal("failed to create '{s}': {s}", .{ Package.Manifest.basename, @errorName(err) }),
4723 error.PathAlreadyExists => fatal("refusing to overwrite '{s}'", .{Package.Manifest.basename}),
4724 };
4725 writeSimpleTemplateFile(Package.build_zig_basename,
4726 \\const std = @import("std");
4727 \\pub fn build(b: *std.Build) void {{
4728 \\ _ = b; // stub
4729 \\}}
4730 \\
4731 , .{}) catch |err| switch (err) {
4732 else => fatal("failed to create '{s}': {s}", .{ Package.build_zig_basename, @errorName(err) }),
4733 // `build.zig` already existing is okay: the user has just used `zig init` to set up
4734 // their `build.zig.zon` *after* writing their `build.zig`. So this one isn't fatal.
4735 error.PathAlreadyExists => {
4736 std.log.info("successfully populated '{s}', preserving existing '{s}'", .{ Package.Manifest.basename, Package.build_zig_basename });
4737 return cleanExit();
4738 },
4739 };
4740 std.log.info("successfully populated '{s}' and '{s}'", .{ Package.Manifest.basename, Package.build_zig_basename });
4741 return cleanExit();
4742 },
4700 }4743 }
4701 return cleanExit();
4702}4744}
47034745
4704fn sanitizeExampleName(arena: Allocator, bytes: []const u8) error{OutOfMemory}![]const u8 {4746fn sanitizeExampleName(arena: Allocator, bytes: []const u8) error{OutOfMemory}![]const u8 {
...@@ -7226,13 +7268,20 @@ fn loadManifest(...@@ -7226,13 +7268,20 @@ fn loadManifest(
7226 0,7268 0,
7227 ) catch |err| switch (err) {7269 ) catch |err| switch (err) {
7228 error.FileNotFound => {7270 error.FileNotFound => {
7229 const fingerprint: Package.Fingerprint = .generate(options.root_name);7271 writeSimpleTemplateFile(Package.Manifest.basename,
7230 var templates = findTemplates(gpa, arena, true);7272 \\.{{
7231 defer templates.deinit();7273 \\ .name = .{s},
7232 templates.write(arena, options.dir, options.root_name, Package.Manifest.basename, fingerprint) catch |e| {7274 \\ .version = "{s}",
7233 fatal("unable to write {s}: {s}", .{7275 \\ .paths = .{{""}},
7234 Package.Manifest.basename, @errorName(e),7276 \\ .fingerprint = 0x{x},
7235 });7277 \\}}
7278 \\
7279 , .{
7280 options.root_name,
7281 build_options.version,
7282 Package.Fingerprint.generate(options.root_name).int(),
7283 }) catch |e| {
7284 fatal("unable to write {s}: {s}", .{ Package.Manifest.basename, @errorName(e) });
7236 };7285 };
7237 continue;7286 continue;
7238 },7287 },
...@@ -7273,7 +7322,6 @@ const Templates = struct {...@@ -7273,7 +7322,6 @@ const Templates = struct {
7273 zig_lib_directory: Cache.Directory,7322 zig_lib_directory: Cache.Directory,
7274 dir: fs.Dir,7323 dir: fs.Dir,
7275 buffer: std.ArrayList(u8),7324 buffer: std.ArrayList(u8),
7276 strip: bool,
72777325
7278 fn deinit(templates: *Templates) void {7326 fn deinit(templates: *Templates) void {
7279 templates.zig_lib_directory.handle.close();7327 templates.zig_lib_directory.handle.close();
...@@ -7302,23 +7350,9 @@ const Templates = struct {...@@ -7302,23 +7350,9 @@ const Templates = struct {
7302 };7350 };
7303 templates.buffer.clearRetainingCapacity();7351 templates.buffer.clearRetainingCapacity();
7304 try templates.buffer.ensureUnusedCapacity(contents.len);7352 try templates.buffer.ensureUnusedCapacity(contents.len);
7305 var new_line = templates.strip;
7306 var i: usize = 0;7353 var i: usize = 0;
7307 while (i < contents.len) {7354 while (i < contents.len) {
7308 if (new_line) {7355 if (contents[i] == '_' or contents[i] == '.') {
7309 const trimmed = std.mem.trimLeft(u8, contents[i..], " ");
7310 if (std.mem.startsWith(u8, trimmed, "//")) {
7311 i += std.mem.indexOfScalar(u8, contents[i..], '\n') orelse break;
7312 i += 1;
7313 continue;
7314 } else {
7315 new_line = false;
7316 }
7317 }
7318
7319 if (templates.strip and contents[i] == '\n') {
7320 new_line = true;
7321 } else if (contents[i] == '_' or contents[i] == '.') {
7322 // Both '_' and '.' are allowed because depending on the context7356 // Both '_' and '.' are allowed because depending on the context
7323 // one prefix will be valid, while the other might not.7357 // one prefix will be valid, while the other might not.
7324 if (std.mem.startsWith(u8, contents[i + 1 ..], "NAME")) {7358 if (std.mem.startsWith(u8, contents[i + 1 ..], "NAME")) {
...@@ -7347,8 +7381,16 @@ const Templates = struct {...@@ -7347,8 +7381,16 @@ const Templates = struct {
7347 });7381 });
7348 }7382 }
7349};7383};
7384fn writeSimpleTemplateFile(file_name: []const u8, comptime fmt: []const u8, args: anytype) !void {
7385 const f = try fs.cwd().createFile(file_name, .{ .exclusive = true });
7386 defer f.close();
7387 var buf: [4096]u8 = undefined;
7388 var fw = f.writer(&buf);
7389 try fw.interface.print(fmt, args);
7390 try fw.interface.flush();
7391}
73507392
7351fn findTemplates(gpa: Allocator, arena: Allocator, strip: bool) Templates {7393fn findTemplates(gpa: Allocator, arena: Allocator) Templates {
7352 const cwd_path = introspect.getResolvedCwd(arena) catch |err| {7394 const cwd_path = introspect.getResolvedCwd(arena) catch |err| {
7353 fatal("unable to get cwd: {s}", .{@errorName(err)});7395 fatal("unable to get cwd: {s}", .{@errorName(err)});
7354 };7396 };
...@@ -7372,7 +7414,6 @@ fn findTemplates(gpa: Allocator, arena: Allocator, strip: bool) Templates {...@@ -7372,7 +7414,6 @@ fn findTemplates(gpa: Allocator, arena: Allocator, strip: bool) Templates {
7372 .zig_lib_directory = zig_lib_directory,7414 .zig_lib_directory = zig_lib_directory,
7373 .dir = template_dir,7415 .dir = template_dir,
7374 .buffer = std.ArrayList(u8).init(gpa),7416 .buffer = std.ArrayList(u8).init(gpa),
7375 .strip = strip,
7376 };7417 };
7377}7418}
73787419
src/target.zig+24-6
...@@ -248,9 +248,13 @@ pub fn selfHostedBackendIsAsRobustAsLlvm(target: *const std.Target) bool {...@@ -248,9 +248,13 @@ pub fn selfHostedBackendIsAsRobustAsLlvm(target: *const std.Target) bool {
248 return false;248 return false;
249}249}
250250
251pub fn supportsStackProbing(target: *const std.Target) bool {251pub fn supportsStackProbing(target: *const std.Target, backend: std.builtin.CompilerBackend) bool {
252 return target.os.tag != .windows and target.os.tag != .uefi and252 return switch (backend) {
253 (target.cpu.arch == .x86 or target.cpu.arch == .x86_64);253 .stage2_aarch64, .stage2_x86_64 => true,
254 .stage2_llvm => target.os.tag != .windows and target.os.tag != .uefi and
255 (target.cpu.arch == .x86 or target.cpu.arch == .x86_64),
256 else => false,
257 };
254}258}
255259
256pub fn supportsStackProtector(target: *const std.Target, backend: std.builtin.CompilerBackend) bool {260pub fn supportsStackProtector(target: *const std.Target, backend: std.builtin.CompilerBackend) bool {
...@@ -359,6 +363,7 @@ pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, have_llv...@@ -359,6 +363,7 @@ pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, have_llv
359 else => {},363 else => {},
360 }364 }
361 return switch (zigBackend(target, use_llvm)) {365 return switch (zigBackend(target, use_llvm)) {
366 .stage2_aarch64 => true,
362 .stage2_llvm => true,367 .stage2_llvm => true,
363 .stage2_x86_64 => switch (target.ofmt) {368 .stage2_x86_64 => switch (target.ofmt) {
364 .elf, .macho => true,369 .elf, .macho => true,
...@@ -368,13 +373,22 @@ pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, have_llv...@@ -368,13 +373,22 @@ pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, have_llv
368 };373 };
369}374}
370375
371pub fn canBuildLibUbsanRt(target: *const std.Target) bool {376pub fn canBuildLibUbsanRt(target: *const std.Target, use_llvm: bool, have_llvm: bool) bool {
372 switch (target.cpu.arch) {377 switch (target.cpu.arch) {
373 .spirv32, .spirv64 => return false,378 .spirv32, .spirv64 => return false,
374 // Remove this once https://github.com/ziglang/zig/issues/23715 is fixed379 // Remove this once https://github.com/ziglang/zig/issues/23715 is fixed
375 .nvptx, .nvptx64 => return false,380 .nvptx, .nvptx64 => return false,
376 else => return true,381 else => {},
377 }382 }
383 return switch (zigBackend(target, use_llvm)) {
384 .stage2_llvm => true,
385 .stage2_wasm => false,
386 .stage2_x86_64 => switch (target.ofmt) {
387 .elf, .macho => true,
388 else => have_llvm,
389 },
390 else => have_llvm,
391 };
378}392}
379393
380pub fn hasRedZone(target: *const std.Target) bool {394pub fn hasRedZone(target: *const std.Target) bool {
...@@ -405,6 +419,8 @@ pub fn libcFullLinkFlags(target: *const std.Target) []const []const u8 {...@@ -405,6 +419,8 @@ pub fn libcFullLinkFlags(target: *const std.Target) []const []const u8 {
405 .android, .androideabi, .ohos, .ohoseabi => &.{ "-lm", "-lc", "-ldl" },419 .android, .androideabi, .ohos, .ohoseabi => &.{ "-lm", "-lc", "-ldl" },
406 else => &.{ "-lm", "-lpthread", "-lc", "-ldl", "-lrt", "-lutil" },420 else => &.{ "-lm", "-lpthread", "-lc", "-ldl", "-lrt", "-lutil" },
407 },421 },
422 // On SerenityOS libc includes libm, libpthread, libdl, and libssp.
423 .serenity => &.{"-lc"},
408 else => &.{},424 else => &.{},
409 };425 };
410 return result;426 return result;
...@@ -767,6 +783,7 @@ pub fn supportsTailCall(target: *const std.Target, backend: std.builtin.Compiler...@@ -767,6 +783,7 @@ pub fn supportsTailCall(target: *const std.Target, backend: std.builtin.Compiler
767783
768pub fn supportsThreads(target: *const std.Target, backend: std.builtin.CompilerBackend) bool {784pub fn supportsThreads(target: *const std.Target, backend: std.builtin.CompilerBackend) bool {
769 return switch (backend) {785 return switch (backend) {
786 .stage2_aarch64 => false,
770 .stage2_powerpc => true,787 .stage2_powerpc => true,
771 .stage2_x86_64 => target.ofmt == .macho or target.ofmt == .elf,788 .stage2_x86_64 => target.ofmt == .macho or target.ofmt == .elf,
772 else => true,789 else => true,
...@@ -844,6 +861,7 @@ pub fn zigBackend(target: *const std.Target, use_llvm: bool) std.builtin.Compile...@@ -844,6 +861,7 @@ pub fn zigBackend(target: *const std.Target, use_llvm: bool) std.builtin.Compile
844pub inline fn backendSupportsFeature(backend: std.builtin.CompilerBackend, comptime feature: Feature) bool {861pub inline fn backendSupportsFeature(backend: std.builtin.CompilerBackend, comptime feature: Feature) bool {
845 return switch (feature) {862 return switch (feature) {
846 .panic_fn => switch (backend) {863 .panic_fn => switch (backend) {
864 .stage2_aarch64,
847 .stage2_c,865 .stage2_c,
848 .stage2_llvm,866 .stage2_llvm,
849 .stage2_x86_64,867 .stage2_x86_64,
...@@ -864,7 +882,7 @@ pub inline fn backendSupportsFeature(backend: std.builtin.CompilerBackend, compt...@@ -864,7 +882,7 @@ pub inline fn backendSupportsFeature(backend: std.builtin.CompilerBackend, compt
864 else => false,882 else => false,
865 },883 },
866 .field_reordering => switch (backend) {884 .field_reordering => switch (backend) {
867 .stage2_c, .stage2_llvm, .stage2_x86_64 => true,885 .stage2_aarch64, .stage2_c, .stage2_llvm, .stage2_x86_64 => true,
868 else => false,886 else => false,
869 },887 },
870 .separate_thread => switch (backend) {888 .separate_thread => switch (backend) {
stage1/wasm2c.c+1-1
...@@ -316,10 +316,10 @@ int main(int argc, char **argv) {...@@ -316,10 +316,10 @@ int main(int argc, char **argv) {
316 "}\n"316 "}\n"
317 "\n"317 "\n"
318 "static uint32_t memory_grow(uint8_t **m, uint32_t *p, uint32_t *c, uint32_t n) {\n"318 "static uint32_t memory_grow(uint8_t **m, uint32_t *p, uint32_t *c, uint32_t n) {\n"
319 " uint8_t *new_m = *m;\n"
320 " uint32_t r = *p;\n"319 " uint32_t r = *p;\n"
321 " uint32_t new_p = r + n;\n"320 " uint32_t new_p = r + n;\n"
322 " if (new_p > UINT32_C(0xFFFF)) return UINT32_C(0xFFFFFFFF);\n"321 " if (new_p > UINT32_C(0xFFFF)) return UINT32_C(0xFFFFFFFF);\n"
322 " uint8_t *new_m = *m;\n"
323 " uint32_t new_c = *c;\n"323 " uint32_t new_c = *c;\n"
324 " if (new_c < new_p) {\n"324 " if (new_c < new_p) {\n"
325 " do new_c += new_c / 2 + 8; while (new_c < new_p);\n"325 " do new_c += new_c / 2 + 8; while (new_c < new_p);\n"
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,7 +123,6 @@ test {
123 }123 }
124124
125 if (builtin.zig_backend != .stage2_arm and125 if (builtin.zig_backend != .stage2_arm and
126 builtin.zig_backend != .stage2_aarch64 and
127 builtin.zig_backend != .stage2_spirv)126 builtin.zig_backend != .stage2_spirv)
128 {127 {
129 _ = @import("behavior/export_keyword.zig");128 _ = @import("behavior/export_keyword.zig");
...@@ -141,7 +140,8 @@ test {...@@ -141,7 +140,8 @@ test {
141}140}
142141
143// This bug only repros in the root file142// This bug only repros in the root file
144test "deference @embedFile() of a file full of zero bytes" {143test "dereference @embedFile() of a file full of zero bytes" {
144 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
145 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;145 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
146146
147 const contents = @embedFile("behavior/zero.bin").*;147 const contents = @embedFile("behavior/zero.bin").*;
test/behavior/abs.zig+3-7
...@@ -3,7 +3,6 @@ const std = @import("std");...@@ -3,7 +3,6 @@ const std = @import("std");
3const expect = std.testing.expect;3const expect = std.testing.expect;
44
5test "@abs integers" {5test "@abs integers" {
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;8 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -50,7 +49,6 @@ fn testAbsIntegers() !void {...@@ -50,7 +49,6 @@ fn testAbsIntegers() !void {
50}49}
5150
52test "@abs unsigned integers" {51test "@abs unsigned integers" {
53 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
54 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO52 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
55 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO53 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5654
...@@ -90,7 +88,6 @@ fn testAbsUnsignedIntegers() !void {...@@ -90,7 +88,6 @@ fn testAbsUnsignedIntegers() !void {
90}88}
9189
92test "@abs big int <= 128 bits" {90test "@abs big int <= 128 bits" {
93 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
94 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO91 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
95 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO92 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
96 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO93 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
...@@ -153,7 +150,6 @@ fn testAbsUnsignedBigInt() !void {...@@ -153,7 +150,6 @@ fn testAbsUnsignedBigInt() !void {
153}150}
154151
155test "@abs floats" {152test "@abs floats" {
156 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
157 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO153 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
158 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO154 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
159155
...@@ -207,9 +203,9 @@ fn testAbsFloats(comptime T: type) !void {...@@ -207,9 +203,9 @@ fn testAbsFloats(comptime T: type) !void {
207}203}
208204
209test "@abs int vectors" {205test "@abs int vectors" {
206 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
210 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO207 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
211 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO208 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
212 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
213 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO209 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
214 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO210 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
215 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;211 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -275,8 +271,8 @@ fn testAbsIntVectors(comptime len: comptime_int) !void {...@@ -275,8 +271,8 @@ fn testAbsIntVectors(comptime len: comptime_int) !void {
275}271}
276272
277test "@abs unsigned int vectors" {273test "@abs unsigned int vectors" {
274 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
278 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO275 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
279 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
280 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO276 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
281 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO277 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
282 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;278 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -334,8 +330,8 @@ fn testAbsUnsignedIntVectors(comptime len: comptime_int) !void {...@@ -334,8 +330,8 @@ fn testAbsUnsignedIntVectors(comptime len: comptime_int) !void {
334}330}
335331
336test "@abs float vectors" {332test "@abs float vectors" {
333 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
337 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO334 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
338 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
339 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO335 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
340 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO336 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
341 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,7 +16,6 @@ test "global variable alignment" {
16}16}
1717
18test "large alignment of local constant" {18test "large alignment of local constant" {
19 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
20 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;19 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
21 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky20 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky
2221
...@@ -25,7 +24,6 @@ test "large alignment of local constant" {...@@ -25,7 +24,6 @@ test "large alignment of local constant" {
25}24}
2625
27test "slicing array of length 1 can not assume runtime index is always zero" {26test "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 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO27 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
30 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky28 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky
3129
...@@ -74,7 +72,6 @@ test "alignment of struct with pointer has same alignment as usize" {...@@ -74,7 +72,6 @@ test "alignment of struct with pointer has same alignment as usize" {
7472
75test "alignment and size of structs with 128-bit fields" {73test "alignment and size of structs with 128-bit fields" {
76 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO74 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
78 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO75 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7976
80 const A = struct {77 const A = struct {
...@@ -160,7 +157,6 @@ test "alignment and size of structs with 128-bit fields" {...@@ -160,7 +157,6 @@ test "alignment and size of structs with 128-bit fields" {
160}157}
161158
162test "implicitly decreasing slice alignment" {159test "implicitly decreasing slice alignment" {
163 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
164 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO160 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
165 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;161 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
166162
...@@ -173,7 +169,6 @@ fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 {...@@ -173,7 +169,6 @@ fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 {
173}169}
174170
175test "specifying alignment allows pointer cast" {171test "specifying alignment allows pointer cast" {
176 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
177 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO172 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
178 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;173 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
179174
...@@ -186,7 +181,6 @@ fn testBytesAlign(b: u8) !void {...@@ -186,7 +181,6 @@ fn testBytesAlign(b: u8) !void {
186}181}
187182
188test "@alignCast slices" {183test "@alignCast slices" {
189 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
190 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;184 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
191 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO185 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
192 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;186 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -205,7 +199,6 @@ fn sliceExpects4(slice: []align(4) u32) void {...@@ -205,7 +199,6 @@ fn sliceExpects4(slice: []align(4) u32) void {
205199
206test "return error union with 128-bit integer" {200test "return error union with 128-bit integer" {
207 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO201 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
208 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
209 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;202 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
210 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO203 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
211 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;204 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -218,7 +211,6 @@ fn give() anyerror!u128 {...@@ -218,7 +211,6 @@ fn give() anyerror!u128 {
218211
219test "page aligned array on stack" {212test "page aligned array on stack" {
220 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO213 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
221 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
222 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;214 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
223 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO215 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
224 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;216 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -238,7 +230,6 @@ test "page aligned array on stack" {...@@ -238,7 +230,6 @@ test "page aligned array on stack" {
238}230}
239231
240test "function alignment" {232test "function alignment" {
241 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
242 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;233 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
243 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO234 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
244 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;235 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -268,7 +259,6 @@ test "function alignment" {...@@ -268,7 +259,6 @@ test "function alignment" {
268}259}
269260
270test "implicitly decreasing fn alignment" {261test "implicitly decreasing fn alignment" {
271 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
272 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;262 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
273 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO263 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
274 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;264 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -292,7 +282,6 @@ fn alignedBig() align(16) i32 {...@@ -292,7 +282,6 @@ fn alignedBig() align(16) i32 {
292}282}
293283
294test "@alignCast functions" {284test "@alignCast functions" {
295 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
296 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;285 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
297 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO286 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
298 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;287 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -376,7 +365,6 @@ const DefaultAligned = struct {...@@ -376,7 +365,6 @@ const DefaultAligned = struct {
376365
377test "read 128-bit field from default aligned struct in stack memory" {366test "read 128-bit field from default aligned struct in stack memory" {
378 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO367 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
379 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
380 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;368 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
381 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO369 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
382 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;370 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -396,7 +384,6 @@ var default_aligned_global = DefaultAligned{...@@ -396,7 +384,6 @@ var default_aligned_global = DefaultAligned{
396384
397test "read 128-bit field from default aligned struct in global memory" {385test "read 128-bit field from default aligned struct in global memory" {
398 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO386 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
399 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
400 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;387 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
401 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO388 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
402 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,8 +392,8 @@ test "read 128-bit field from default aligned struct in global memory" {
405}392}
406393
407test "struct field explicit alignment" {394test "struct field explicit alignment" {
408 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
409 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;395 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
396 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
410 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO397 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
411 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky398 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky
412 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO399 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
...@@ -426,7 +413,6 @@ test "struct field explicit alignment" {...@@ -426,7 +413,6 @@ test "struct field explicit alignment" {
426}413}
427414
428test "align(N) on functions" {415test "align(N) on functions" {
429 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
430 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO416 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
431 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO417 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
432 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;418 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -455,7 +441,6 @@ test "comptime alloc alignment" {...@@ -455,7 +441,6 @@ test "comptime alloc alignment" {
455 // TODO: it's impossible to test this in Zig today, since comptime vars do not have runtime addresses.441 // TODO: it's impossible to test this in Zig today, since comptime vars do not have runtime addresses.
456 if (true) return error.SkipZigTest;442 if (true) return error.SkipZigTest;
457 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO443 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
458 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
459 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO444 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
460 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky445 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky
461446
...@@ -468,7 +453,6 @@ test "comptime alloc alignment" {...@@ -468,7 +453,6 @@ test "comptime alloc alignment" {
468}453}
469454
470test "@alignCast null" {455test "@alignCast null" {
471 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
472 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO456 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
473 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;457 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
474458
...@@ -484,7 +468,6 @@ test "alignment of slice element" {...@@ -484,7 +468,6 @@ test "alignment of slice element" {
484}468}
485469
486test "sub-aligned pointer field access" {470test "sub-aligned pointer field access" {
487 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
488 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;471 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
489 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;472 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
490 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;473 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -538,7 +521,6 @@ test "alignment of zero-bit types is respected" {...@@ -538,7 +521,6 @@ test "alignment of zero-bit types is respected" {
538521
539test "zero-bit fields in extern struct pad fields appropriately" {522test "zero-bit fields in extern struct pad fields appropriately" {
540 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO523 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
541 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
542 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;524 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
543 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;525 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
544 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,7 +19,6 @@ test "array to slice" {
19}19}
2020
21test "arrays" {21test "arrays" {
22 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
23 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;22 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
24 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO23 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2524
...@@ -47,7 +46,6 @@ fn getArrayLen(a: []const u32) usize {...@@ -47,7 +46,6 @@ fn getArrayLen(a: []const u32) usize {
47}46}
4847
49test "array concat with undefined" {48test "array concat with undefined" {
50 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
51 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO49 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
52 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;50 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
5351
...@@ -73,7 +71,6 @@ test "array concat with undefined" {...@@ -73,7 +71,6 @@ test "array concat with undefined" {
73test "array concat with tuple" {71test "array concat with tuple" {
74 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;72 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
75 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO73 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO74 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7875
79 const array: [2]u8 = .{ 1, 2 };76 const array: [2]u8 = .{ 1, 2 };
...@@ -89,7 +86,6 @@ test "array concat with tuple" {...@@ -89,7 +86,6 @@ test "array concat with tuple" {
8986
90test "array init with concat" {87test "array init with concat" {
91 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;88 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
92 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9389
94 const a = 'a';90 const a = 'a';
95 var i: [4]u8 = [2]u8{ a, 'b' } ++ [2]u8{ 'c', 'd' };91 var i: [4]u8 = [2]u8{ a, 'b' } ++ [2]u8{ 'c', 'd' };
...@@ -98,7 +94,6 @@ test "array init with concat" {...@@ -98,7 +94,6 @@ test "array init with concat" {
9894
99test "array init with mult" {95test "array init with mult" {
100 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;96 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
101 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
102 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO97 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10398
104 const a = 'a';99 const a = 'a';
...@@ -110,7 +105,6 @@ test "array init with mult" {...@@ -110,7 +105,6 @@ test "array init with mult" {
110}105}
111106
112test "array literal with explicit type" {107test "array literal with explicit type" {
113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
114 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO108 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
115109
116 const hex_mult: [4]u16 = .{ 4096, 256, 16, 1 };110 const hex_mult: [4]u16 = .{ 4096, 256, 16, 1 };
...@@ -138,7 +132,6 @@ const ArrayDotLenConstExpr = struct {...@@ -138,7 +132,6 @@ const ArrayDotLenConstExpr = struct {
138const some_array = [_]u8{ 0, 1, 2, 3 };132const some_array = [_]u8{ 0, 1, 2, 3 };
139133
140test "array literal with specified size" {134test "array literal with specified size" {
141 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
142 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;135 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
143 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO136 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
144137
...@@ -162,7 +155,6 @@ test "array len field" {...@@ -162,7 +155,6 @@ test "array len field" {
162155
163test "array with sentinels" {156test "array with sentinels" {
164 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;157 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
165 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
166 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO158 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
167159
168 const S = struct {160 const S = struct {
...@@ -200,7 +192,6 @@ test "void arrays" {...@@ -200,7 +192,6 @@ test "void arrays" {
200192
201test "nested arrays of strings" {193test "nested arrays of strings" {
202 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;194 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
203 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
204 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;195 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
205 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO196 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
206197
...@@ -215,7 +206,6 @@ test "nested arrays of strings" {...@@ -215,7 +206,6 @@ test "nested arrays of strings" {
215}206}
216207
217test "nested arrays of integers" {208test "nested arrays of integers" {
218 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
219 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO209 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
220210
221 const array_of_numbers = [_][2]u8{211 const array_of_numbers = [_][2]u8{
...@@ -230,7 +220,6 @@ test "nested arrays of integers" {...@@ -230,7 +220,6 @@ test "nested arrays of integers" {
230}220}
231221
232test "implicit comptime in array type size" {222test "implicit comptime in array type size" {
233 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
234 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO223 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
235224
236 var arr: [plusOne(10)]bool = undefined;225 var arr: [plusOne(10)]bool = undefined;
...@@ -243,7 +232,6 @@ fn plusOne(x: u32) u32 {...@@ -243,7 +232,6 @@ fn plusOne(x: u32) u32 {
243}232}
244233
245test "single-item pointer to array indexing and slicing" {234test "single-item pointer to array indexing and slicing" {
246 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
247 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO235 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
248 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;236 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
249237
...@@ -285,7 +273,6 @@ test "implicit cast zero sized array ptr to slice" {...@@ -285,7 +273,6 @@ test "implicit cast zero sized array ptr to slice" {
285}273}
286274
287test "anonymous list literal syntax" {275test "anonymous list literal syntax" {
288 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
289 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;276 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
290 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO277 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
291278
...@@ -308,7 +295,6 @@ const Sub = struct { b: u8 };...@@ -308,7 +295,6 @@ const Sub = struct { b: u8 };
308const Str = struct { a: []Sub };295const Str = struct { a: []Sub };
309test "set global var array via slice embedded in struct" {296test "set global var array via slice embedded in struct" {
310 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;297 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
311 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
312 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO298 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
313299
314 var s = Str{ .a = s_array[0..] };300 var s = Str{ .a = s_array[0..] };
...@@ -323,7 +309,6 @@ test "set global var array via slice embedded in struct" {...@@ -323,7 +309,6 @@ test "set global var array via slice embedded in struct" {
323}309}
324310
325test "read/write through global variable array of struct fields initialized via array mult" {311test "read/write through global variable array of struct fields initialized via array mult" {
326 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
327 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO312 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
328 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO313 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
329314
...@@ -345,7 +330,6 @@ test "read/write through global variable array of struct fields initialized via...@@ -345,7 +330,6 @@ test "read/write through global variable array of struct fields initialized via
345330
346test "implicit cast single-item pointer" {331test "implicit cast single-item pointer" {
347 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;332 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
348 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
349 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO333 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
350334
351 try testImplicitCastSingleItemPtr();335 try testImplicitCastSingleItemPtr();
...@@ -364,7 +348,6 @@ fn testArrayByValAtComptime(b: [2]u8) u8 {...@@ -364,7 +348,6 @@ fn testArrayByValAtComptime(b: [2]u8) u8 {
364}348}
365349
366test "comptime evaluating function that takes array by value" {350test "comptime evaluating function that takes array by value" {
367 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
368 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO351 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
369352
370 const arr = [_]u8{ 1, 2 };353 const arr = [_]u8{ 1, 2 };
...@@ -376,7 +359,6 @@ test "comptime evaluating function that takes array by value" {...@@ -376,7 +359,6 @@ test "comptime evaluating function that takes array by value" {
376359
377test "runtime initialize array elem and then implicit cast to slice" {360test "runtime initialize array elem and then implicit cast to slice" {
378 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;361 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
379 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
380 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO362 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
381363
382 var two: i32 = 2;364 var two: i32 = 2;
...@@ -387,7 +369,6 @@ test "runtime initialize array elem and then implicit cast to slice" {...@@ -387,7 +369,6 @@ test "runtime initialize array elem and then implicit cast to slice" {
387369
388test "array literal as argument to function" {370test "array literal as argument to function" {
389 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;371 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
390 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
391 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO372 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
392373
393 const S = struct {374 const S = struct {
...@@ -414,8 +395,8 @@ test "array literal as argument to function" {...@@ -414,8 +395,8 @@ test "array literal as argument to function" {
414}395}
415396
416test "double nested array to const slice cast in array literal" {397test "double nested array to const slice cast in array literal" {
417 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
418 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;398 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
399 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
419 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO400 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
420 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO401 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
421402
...@@ -476,7 +457,6 @@ test "double nested array to const slice cast in array literal" {...@@ -476,7 +457,6 @@ test "double nested array to const slice cast in array literal" {
476}457}
477458
478test "anonymous literal in array" {459test "anonymous literal in array" {
479 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
480 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO460 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
481 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO461 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
482462
...@@ -502,7 +482,6 @@ test "anonymous literal in array" {...@@ -502,7 +482,6 @@ test "anonymous literal in array" {
502}482}
503483
504test "access the null element of a null terminated array" {484test "access the null element of a null terminated array" {
505 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
506 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO485 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
507486
508 const S = struct {487 const S = struct {
...@@ -520,7 +499,6 @@ test "access the null element of a null terminated array" {...@@ -520,7 +499,6 @@ test "access the null element of a null terminated array" {
520}499}
521500
522test "type deduction for array subscript expression" {501test "type deduction for array subscript expression" {
523 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
524 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO502 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
525 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO503 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
526504
...@@ -540,7 +518,6 @@ test "type deduction for array subscript expression" {...@@ -540,7 +518,6 @@ test "type deduction for array subscript expression" {
540518
541test "sentinel element count towards the ABI size calculation" {519test "sentinel element count towards the ABI size calculation" {
542 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;520 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
543 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
544 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO521 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
545 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO522 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
546523
...@@ -564,7 +541,7 @@ test "sentinel element count towards the ABI size calculation" {...@@ -564,7 +541,7 @@ test "sentinel element count towards the ABI size calculation" {
564}541}
565542
566test "zero-sized array with recursive type definition" {543test "zero-sized array with recursive type definition" {
567 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO544 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
568 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO545 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
569 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;546 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
570547
...@@ -587,8 +564,8 @@ test "zero-sized array with recursive type definition" {...@@ -587,8 +564,8 @@ test "zero-sized array with recursive type definition" {
587}564}
588565
589test "type coercion of anon struct literal to array" {566test "type coercion of anon struct literal to array" {
567 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
590 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;568 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
591 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
592 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO569 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
593 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO570 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
594571
...@@ -628,7 +605,6 @@ test "array with comptime-only element type" {...@@ -628,7 +605,6 @@ test "array with comptime-only element type" {
628}605}
629606
630test "tuple to array handles sentinel" {607test "tuple to array handles sentinel" {
631 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
632 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO608 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
633 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO609 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
634610
...@@ -641,7 +617,6 @@ test "tuple to array handles sentinel" {...@@ -641,7 +617,6 @@ test "tuple to array handles sentinel" {
641617
642test "array init of container level array variable" {618test "array init of container level array variable" {
643 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;619 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
644 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
645 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO620 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
646 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO621 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
647622
...@@ -675,8 +650,8 @@ test "runtime initialized sentinel-terminated array literal" {...@@ -675,8 +650,8 @@ test "runtime initialized sentinel-terminated array literal" {
675}650}
676651
677test "array of array agregate init" {652test "array of array agregate init" {
653 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
678 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO654 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
679 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
680 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO655 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
681656
682 var a = [1]u32{11} ** 10;657 var a = [1]u32{11} ** 10;
...@@ -725,7 +700,6 @@ test "array init with no result location has result type" {...@@ -725,7 +700,6 @@ test "array init with no result location has result type" {
725}700}
726701
727test "slicing array of zero-sized values" {702test "slicing array of zero-sized values" {
728 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
729 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;703 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
730 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;704 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
731 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,7 +864,6 @@ test "tuple initialized through reference to anonymous array init provides resul
890864
891test "copied array element doesn't alias source" {865test "copied array element doesn't alias source" {
892 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO866 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
893 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
894 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO867 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
895868
896 var x: [10][10]u32 = undefined;869 var x: [10][10]u32 = undefined;
...@@ -945,7 +918,6 @@ test "array initialized with array with sentinel" {...@@ -945,7 +918,6 @@ test "array initialized with array with sentinel" {
945}918}
946919
947test "store array of array of structs at comptime" {920test "store array of array of structs at comptime" {
948 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
949 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO921 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
950 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO922 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
951923
...@@ -970,7 +942,6 @@ test "store array of array of structs at comptime" {...@@ -970,7 +942,6 @@ test "store array of array of structs at comptime" {
970}942}
971943
972test "accessing multidimensional global array at comptime" {944test "accessing multidimensional global array at comptime" {
973 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
974 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO945 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
975 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;946 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
976947
...@@ -986,8 +957,8 @@ test "accessing multidimensional global array at comptime" {...@@ -986,8 +957,8 @@ test "accessing multidimensional global array at comptime" {
986}957}
987958
988test "union that needs padding bytes inside an array" {959test "union that needs padding bytes inside an array" {
989 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
990 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;960 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
961 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
991 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;962 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
992 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO963 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
993964
...@@ -1023,7 +994,6 @@ test "runtime index of array of zero-bit values" {...@@ -1023,7 +994,6 @@ test "runtime index of array of zero-bit values" {
1023}994}
1024995
1025test "@splat array" {996test "@splat array" {
1026 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1027 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;997 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1028 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO998 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1029999
...@@ -1046,7 +1016,6 @@ test "@splat array" {...@@ -1046,7 +1016,6 @@ test "@splat array" {
10461016
1047test "@splat array with sentinel" {1017test "@splat array with sentinel" {
1048 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1018 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1049 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1050 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;1019 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1051 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1020 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10521021
...@@ -1070,7 +1039,6 @@ test "@splat array with sentinel" {...@@ -1070,7 +1039,6 @@ test "@splat array with sentinel" {
10701039
1071test "@splat zero-length array" {1040test "@splat zero-length array" {
1072 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1041 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1073 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1074 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;1042 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1075 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1043 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10761044
test/behavior/asm.zig+2-7
...@@ -7,7 +7,6 @@ const is_x86_64_linux = builtin.cpu.arch == .x86_64 and builtin.os.tag == .linux...@@ -7,7 +7,6 @@ const is_x86_64_linux = builtin.cpu.arch == .x86_64 and builtin.os.tag == .linux
77
8comptime {8comptime {
9 if (builtin.zig_backend != .stage2_arm and9 if (builtin.zig_backend != .stage2_arm and
10 builtin.zig_backend != .stage2_aarch64 and
11 !(builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) and // MSVC doesn't support inline assembly10 !(builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) and // MSVC doesn't support inline assembly
12 is_x86_64_linux)11 is_x86_64_linux)
13 {12 {
...@@ -30,7 +29,6 @@ test "module level assembly" {...@@ -30,7 +29,6 @@ test "module level assembly" {
30 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO29 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
31 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO30 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
32 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO31 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
33 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
34 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO32 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3533
36 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly34 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,9 +39,9 @@ test "module level assembly" {
41}39}
4240
43test "output constraint modifiers" {41test "output constraint modifiers" {
42 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
44 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO43 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
45 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO44 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
46 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
47 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO45 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;46 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
49 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;47 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -63,9 +61,9 @@ test "output constraint modifiers" {...@@ -63,9 +61,9 @@ test "output constraint modifiers" {
63}61}
6462
65test "alternative constraints" {63test "alternative constraints" {
64 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
66 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO65 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
67 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO66 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
68 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
69 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO67 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
70 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;68 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
71 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;69 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -83,7 +81,6 @@ test "alternative constraints" {...@@ -83,7 +81,6 @@ test "alternative constraints" {
83test "sized integer/float in asm input" {81test "sized integer/float in asm input" {
84 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO82 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
85 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO83 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
86 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO84 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
88 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;85 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
89 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;86 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -127,7 +124,6 @@ test "sized integer/float in asm input" {...@@ -127,7 +124,6 @@ test "sized integer/float in asm input" {
127test "struct/array/union types as input values" {124test "struct/array/union types as input values" {
128 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO125 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
129 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO126 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
130 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
131 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO127 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
132 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;128 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
133129
...@@ -167,7 +163,6 @@ test "rw constraint (x86_64)" {...@@ -167,7 +163,6 @@ test "rw constraint (x86_64)" {
167163
168test "asm modifiers (AArch64)" {164test "asm modifiers (AArch64)" {
169 if (!builtin.target.cpu.arch.isAARCH64()) return error.SkipZigTest;165 if (!builtin.target.cpu.arch.isAARCH64()) return error.SkipZigTest;
170 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
171166
172 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly167 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly
173168
test/behavior/atomics.zig+12-13
...@@ -12,7 +12,7 @@ const supports_128_bit_atomics = switch (builtin.cpu.arch) {...@@ -12,7 +12,7 @@ const supports_128_bit_atomics = switch (builtin.cpu.arch) {
12};12};
1313
14test "cmpxchg" {14test "cmpxchg" {
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO16 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO17 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;18 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -39,7 +39,7 @@ fn testCmpxchg() !void {...@@ -39,7 +39,7 @@ fn testCmpxchg() !void {
39}39}
4040
41test "atomicrmw and atomicload" {41test "atomicrmw and atomicload" {
42 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO42 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
43 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO43 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
44 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO44 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
45 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;45 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -68,7 +68,7 @@ fn testAtomicLoad(ptr: *u8) !void {...@@ -68,7 +68,7 @@ fn testAtomicLoad(ptr: *u8) !void {
68}68}
6969
70test "cmpxchg with ptr" {70test "cmpxchg with ptr" {
71 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO71 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
72 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO72 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
73 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO73 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
74 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;74 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -94,7 +94,7 @@ test "cmpxchg with ptr" {...@@ -94,7 +94,7 @@ test "cmpxchg with ptr" {
94}94}
9595
96test "cmpxchg with ignored result" {96test "cmpxchg with ignored result" {
97 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO97 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
98 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO98 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
99 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO99 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
100 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;100 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -110,8 +110,8 @@ test "128-bit cmpxchg" {...@@ -110,8 +110,8 @@ test "128-bit cmpxchg" {
110 // TODO: this must appear first110 // TODO: this must appear first
111 if (!supports_128_bit_atomics) return error.SkipZigTest;111 if (!supports_128_bit_atomics) return error.SkipZigTest;
112112
113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
113 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO114 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
114 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
115 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO115 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
116 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO116 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
117117
...@@ -139,7 +139,7 @@ fn test_u128_cmpxchg() !void {...@@ -139,7 +139,7 @@ fn test_u128_cmpxchg() !void {
139var a_global_variable = @as(u32, 1234);139var a_global_variable = @as(u32, 1234);
140140
141test "cmpxchg on a global variable" {141test "cmpxchg on a global variable" {
142 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO142 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
143 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO143 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
144 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO144 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
145 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;145 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -149,7 +149,7 @@ test "cmpxchg on a global variable" {...@@ -149,7 +149,7 @@ test "cmpxchg on a global variable" {
149}149}
150150
151test "atomic load and rmw with enum" {151test "atomic load and rmw with enum" {
152 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO152 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
153 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO153 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
154 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO154 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
155 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;155 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -167,7 +167,7 @@ test "atomic load and rmw with enum" {...@@ -167,7 +167,7 @@ test "atomic load and rmw with enum" {
167}167}
168168
169test "atomic store" {169test "atomic store" {
170 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO170 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
171 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO171 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
172 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO172 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
173 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;173 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -185,7 +185,7 @@ fn testAtomicStore() !void {...@@ -185,7 +185,7 @@ fn testAtomicStore() !void {
185}185}
186186
187test "atomicrmw with floats" {187test "atomicrmw with floats" {
188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
189 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO189 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
190 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO190 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
191 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;191 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -211,7 +211,7 @@ fn testAtomicRmwFloat() !void {...@@ -211,7 +211,7 @@ fn testAtomicRmwFloat() !void {
211}211}
212212
213test "atomicrmw with ints" {213test "atomicrmw with ints" {
214 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO214 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
215 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO215 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
216 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO216 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
217 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;217 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -290,7 +290,7 @@ test "atomicrmw with 128-bit ints" {...@@ -290,7 +290,7 @@ test "atomicrmw with 128-bit ints" {
290 // TODO: this must appear first290 // TODO: this must appear first
291 if (!supports_128_bit_atomics) return error.SkipZigTest;291 if (!supports_128_bit_atomics) return error.SkipZigTest;
292292
293 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO293 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
294294
295 try testAtomicRmwInt128(.signed);295 try testAtomicRmwInt128(.signed);
296 try testAtomicRmwInt128(.unsigned);296 try testAtomicRmwInt128(.unsigned);
...@@ -359,7 +359,7 @@ fn testAtomicRmwInt128(comptime signedness: std.builtin.Signedness) !void {...@@ -359,7 +359,7 @@ fn testAtomicRmwInt128(comptime signedness: std.builtin.Signedness) !void {
359}359}
360360
361test "atomics with different types" {361test "atomics with different types" {
362 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO362 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
363 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO363 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
364 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO364 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
365 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,7 +409,6 @@ fn testAtomicsWithPackedStruct(comptime T: type, a: T, b: T) !void {
409}409}
410410
411test "return @atomicStore, using it as a void value" {411test "return @atomicStore, using it as a void value" {
412 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
413 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO412 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
414 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO413 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
415 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;414 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/basic.zig+1-21
...@@ -39,7 +39,6 @@ test "truncate to non-power-of-two integers" {...@@ -39,7 +39,6 @@ test "truncate to non-power-of-two integers" {
39}39}
4040
41test "truncate to non-power-of-two integers from 128-bit" {41test "truncate to non-power-of-two integers from 128-bit" {
42 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
43 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO42 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
44 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO43 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
45 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;44 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -422,7 +421,6 @@ fn copy(src: *const u64, dst: *u64) void {...@@ -422,7 +421,6 @@ fn copy(src: *const u64, dst: *u64) void {
422}421}
423422
424test "call result of if else expression" {423test "call result of if else expression" {
425 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
426 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;424 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
427 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO425 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
428 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;426 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -448,7 +446,6 @@ fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA {...@@ -448,7 +446,6 @@ fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA {
448}446}
449447
450test "take address of parameter" {448test "take address of parameter" {
451 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
452 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;449 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
453 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO450 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
454451
...@@ -474,7 +471,6 @@ fn testPointerToVoidReturnType2() *const void {...@@ -474,7 +471,6 @@ fn testPointerToVoidReturnType2() *const void {
474}471}
475472
476test "array 2D const double ptr" {473test "array 2D const double ptr" {
477 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
478 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO474 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
479 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;475 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
480 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;476 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -487,7 +483,6 @@ test "array 2D const double ptr" {...@@ -487,7 +483,6 @@ test "array 2D const double ptr" {
487}483}
488484
489test "array 2D const double ptr with offset" {485test "array 2D const double ptr with offset" {
490 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
491 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO486 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
492 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;487 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
493 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;488 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -500,7 +495,6 @@ test "array 2D const double ptr with offset" {...@@ -500,7 +495,6 @@ test "array 2D const double ptr with offset" {
500}495}
501496
502test "array 3D const double ptr with offset" {497test "array 3D const double ptr with offset" {
503 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
504 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO498 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
505 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;499 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
506 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;500 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -536,7 +530,6 @@ fn nine() u8 {...@@ -536,7 +530,6 @@ fn nine() u8 {
536}530}
537531
538test "struct inside function" {532test "struct inside function" {
539 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
540 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO533 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
541534
542 try testStructInFn();535 try testStructInFn();
...@@ -588,7 +581,6 @@ test "global variable assignment with optional unwrapping with var initialized t...@@ -588,7 +581,6 @@ test "global variable assignment with optional unwrapping with var initialized t
588var global_foo: *i32 = undefined;581var global_foo: *i32 = undefined;
589582
590test "peer result location with typed parent, runtime condition, comptime prongs" {583test "peer result location with typed parent, runtime condition, comptime prongs" {
591 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
592 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO584 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
593585
594 const S = struct {586 const S = struct {
...@@ -719,7 +711,6 @@ test "global constant is loaded with a runtime-known index" {...@@ -719,7 +711,6 @@ test "global constant is loaded with a runtime-known index" {
719}711}
720712
721test "multiline string literal is null terminated" {713test "multiline string literal is null terminated" {
722 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
723 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;714 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
724715
725 const s1 =716 const s1 =
...@@ -732,7 +723,6 @@ test "multiline string literal is null terminated" {...@@ -732,7 +723,6 @@ test "multiline string literal is null terminated" {
732}723}
733724
734test "string escapes" {725test "string escapes" {
735 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
736 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;726 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
737 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO727 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
738 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;728 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -764,7 +754,6 @@ fn ptrEql(a: *const []const u8, b: *const []const u8) bool {...@@ -764,7 +754,6 @@ fn ptrEql(a: *const []const u8, b: *const []const u8) bool {
764}754}
765755
766test "string concatenation" {756test "string concatenation" {
767 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
768 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;757 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
769 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO758 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
770759
...@@ -787,7 +776,6 @@ test "string concatenation" {...@@ -787,7 +776,6 @@ test "string concatenation" {
787}776}
788777
789test "result location is optional inside error union" {778test "result location is optional inside error union" {
790 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
791 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO779 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
792 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO780 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
793781
...@@ -803,7 +791,6 @@ fn maybe(x: bool) anyerror!?u32 {...@@ -803,7 +791,6 @@ fn maybe(x: bool) anyerror!?u32 {
803}791}
804792
805test "auto created variables have correct alignment" {793test "auto created variables have correct alignment" {
806 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
807 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO794 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
808 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;795 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
809796
...@@ -821,7 +808,6 @@ test "auto created variables have correct alignment" {...@@ -821,7 +808,6 @@ test "auto created variables have correct alignment" {
821808
822test "extern variable with non-pointer opaque type" {809test "extern variable with non-pointer opaque type" {
823 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO810 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
824 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
825 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO811 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
826 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO812 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
827 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO813 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
...@@ -866,7 +852,6 @@ test "if expression type coercion" {...@@ -866,7 +852,6 @@ test "if expression type coercion" {
866}852}
867853
868test "discarding the result of various expressions" {854test "discarding the result of various expressions" {
869 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
870 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO855 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
871 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO856 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
872857
...@@ -908,7 +893,6 @@ test "labeled block implicitly ends in a break" {...@@ -908,7 +893,6 @@ test "labeled block implicitly ends in a break" {
908}893}
909894
910test "catch in block has correct result location" {895test "catch in block has correct result location" {
911 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
912 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO896 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
913897
914 const S = struct {898 const S = struct {
...@@ -964,7 +948,6 @@ test "vector initialized with array init syntax has proper type" {...@@ -964,7 +948,6 @@ test "vector initialized with array init syntax has proper type" {
964}948}
965949
966test "weird array and tuple initializations" {950test "weird array and tuple initializations" {
967 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
968 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO951 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
969 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO952 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
970953
...@@ -1010,7 +993,6 @@ test "generic function uses return type of other generic function" {...@@ -1010,7 +993,6 @@ test "generic function uses return type of other generic function" {
1010 // https://github.com/ziglang/zig/issues/12208993 // https://github.com/ziglang/zig/issues/12208
1011 return error.SkipZigTest;994 return error.SkipZigTest;
1012 }995 }
1013 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1014996
1015 const S = struct {997 const S = struct {
1016 fn call(998 fn call(
...@@ -1128,7 +1110,6 @@ test "returning an opaque type from a function" {...@@ -1128,7 +1110,6 @@ test "returning an opaque type from a function" {
1128}1110}
11291111
1130test "orelse coercion as function argument" {1112test "orelse coercion as function argument" {
1131 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1132 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1113 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11331114
1134 const Loc = struct { start: i32 = -1 };1115 const Loc = struct { start: i32 = -1 };
...@@ -1378,7 +1359,6 @@ test "copy array of self-referential struct" {...@@ -1378,7 +1359,6 @@ test "copy array of self-referential struct" {
13781359
1379test "break out of block based on comptime known values" {1360test "break out of block based on comptime known values" {
1380 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;1361 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1381 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1382 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1362 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13831363
1384 const S = struct {1364 const S = struct {
...@@ -1412,8 +1392,8 @@ test "break out of block based on comptime known values" {...@@ -1412,8 +1392,8 @@ test "break out of block based on comptime known values" {
1412}1392}
14131393
1414test "allocation and looping over 3-byte integer" {1394test "allocation and looping over 3-byte integer" {
1395 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1415 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1396 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1416 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1417 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1397 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1418 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1398 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1419 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1399 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,7 +112,7 @@ test "comptime shift safety check" {
112}112}
113113
114test "Saturating Shift Left where lhs is of a computed type" {114test "Saturating Shift Left where lhs is of a computed type" {
115 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO115 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
116 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO116 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
117 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO117 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
118 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;118 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -161,6 +161,7 @@ comptime {...@@ -161,6 +161,7 @@ comptime {
161}161}
162162
163test "Saturating Shift Left" {163test "Saturating Shift Left" {
164 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
164 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;165 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
165 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;166 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
166 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,7 +20,6 @@ test "@bitCast iX -> uX (32, 64)" {
20}20}
2121
22test "@bitCast iX -> uX (8, 16, 128)" {22test "@bitCast iX -> uX (8, 16, 128)" {
23 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
24 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;23 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
25 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO24 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
26 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;25 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -35,8 +34,8 @@ test "@bitCast iX -> uX (8, 16, 128)" {...@@ -35,8 +34,8 @@ test "@bitCast iX -> uX (8, 16, 128)" {
35}34}
3635
37test "@bitCast iX -> uX exotic integers" {36test "@bitCast iX -> uX exotic integers" {
38 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
39 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;37 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
38 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
40 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;39 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
41 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO40 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
42 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,8 +79,8 @@ fn conv_uN(comptime N: usize, x: std.meta.Int(.unsigned, N)) std.meta.Int(.signe
80}79}
8180
82test "bitcast uX to bytes" {81test "bitcast uX to bytes" {
83 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
84 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;82 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
83 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
85 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;84 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
86 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO85 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,9 +295,9 @@ test "triple level result location with bitcast sandwich passed as tuple element
296}295}
297296
298test "@bitCast packed struct of floats" {297test "@bitCast packed struct of floats" {
298 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
299 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;299 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
300 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;300 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
301 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
302 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;301 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
303 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO302 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
304 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;303 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -334,9 +333,9 @@ test "@bitCast packed struct of floats" {...@@ -334,9 +333,9 @@ test "@bitCast packed struct of floats" {
334}333}
335334
336test "comptime @bitCast packed struct to int and back" {335test "comptime @bitCast packed struct to int and back" {
336 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
337 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;337 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
338 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;338 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
339 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
340 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;339 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
341 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO340 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
342 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;341 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -379,7 +378,6 @@ test "comptime bitcast with fields following f80" {...@@ -379,7 +378,6 @@ test "comptime bitcast with fields following f80" {
379 }378 }
380379
381 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;380 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
382 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
383 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;381 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
384 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO382 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
385383
...@@ -393,7 +391,7 @@ test "comptime bitcast with fields following f80" {...@@ -393,7 +391,7 @@ test "comptime bitcast with fields following f80" {
393}391}
394392
395test "bitcast vector to integer and back" {393test "bitcast vector to integer and back" {
396 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO394 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
397 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO395 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
398 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO396 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
399 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO397 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
...@@ -420,7 +418,6 @@ fn bitCastWrapper128(x: f128) u128 {...@@ -420,7 +418,6 @@ fn bitCastWrapper128(x: f128) u128 {
420 return @as(u128, @bitCast(x));418 return @as(u128, @bitCast(x));
421}419}
422test "bitcast nan float does not modify signaling bit" {420test "bitcast nan float does not modify signaling bit" {
423 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
424 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO421 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
425 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO422 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
426 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;423 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -473,7 +470,7 @@ test "bitcast nan float does not modify signaling bit" {...@@ -473,7 +470,7 @@ test "bitcast nan float does not modify signaling bit" {
473}470}
474471
475test "@bitCast of packed struct of bools all true" {472test "@bitCast of packed struct of bools all true" {
476 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO473 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
477 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO474 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
478 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO475 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
479 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO476 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
...@@ -494,7 +491,7 @@ test "@bitCast of packed struct of bools all true" {...@@ -494,7 +491,7 @@ test "@bitCast of packed struct of bools all true" {
494}491}
495492
496test "@bitCast of packed struct of bools all false" {493test "@bitCast of packed struct of bools all false" {
497 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO494 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
498 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO495 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
499 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO496 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
500 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO497 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
...@@ -514,7 +511,7 @@ test "@bitCast of packed struct of bools all false" {...@@ -514,7 +511,7 @@ test "@bitCast of packed struct of bools all false" {
514}511}
515512
516test "@bitCast of packed struct containing pointer" {513test "@bitCast of packed struct containing pointer" {
517 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO514 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
518 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO515 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
519 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO516 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
520 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO517 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
...@@ -544,7 +541,7 @@ test "@bitCast of packed struct containing pointer" {...@@ -544,7 +541,7 @@ test "@bitCast of packed struct containing pointer" {
544}541}
545542
546test "@bitCast of extern struct containing pointer" {543test "@bitCast of extern struct containing pointer" {
547 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO544 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
548 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO545 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
549 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO546 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
550 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO547 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 +8,8 @@ test "@bitReverse large exotic integer" {
8}8}
99
10test "@bitReverse" {10test "@bitReverse" {
11 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
12 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
12 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
13 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO13 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;14 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
15 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;15 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -121,9 +121,9 @@ fn vector8() !void {...@@ -121,9 +121,9 @@ fn vector8() !void {
121}121}
122122
123test "bitReverse vectors u8" {123test "bitReverse vectors u8" {
124 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
124 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;125 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
125 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;126 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
126 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
127 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO127 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
128 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;128 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
129 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;129 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -141,9 +141,9 @@ fn vector16() !void {...@@ -141,9 +141,9 @@ fn vector16() !void {
141}141}
142142
143test "bitReverse vectors u16" {143test "bitReverse vectors u16" {
144 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
144 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;145 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
145 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;146 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
146 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
147 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO147 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
148 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;148 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
149 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;149 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -161,9 +161,9 @@ fn vector24() !void {...@@ -161,9 +161,9 @@ fn vector24() !void {
161}161}
162162
163test "bitReverse vectors u24" {163test "bitReverse vectors u24" {
164 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
164 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;165 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
165 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;166 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
166 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
167 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO167 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
168 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;168 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
169 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;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 +7,6 @@ var x: u8 = 1;
7// This excludes builtin functions that return void or noreturn that cannot be tested.7// This excludes builtin functions that return void or noreturn that cannot be tested.
8test {8test {
9 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO11 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,40 +3,8 @@ const builtin = @import("builtin");
3const expect = std.testing.expect;3const expect = std.testing.expect;
44
5test "@byteSwap integers" {5test "@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 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;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 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
41 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4210
...@@ -51,23 +19,44 @@ test "@byteSwap integers" {...@@ -51,23 +19,44 @@ test "@byteSwap integers" {
51 try t(u32, 0x12345678, 0x78563412);19 try t(u32, 0x12345678, 0x78563412);
52 try t(i32, @as(i32, @bitCast(@as(u32, 0xf2345678))), 0x785634f2);20 try t(i32, @as(i32, @bitCast(@as(u32, 0xf2345678))), 0x785634f2);
53 try t(i32, 0x123456f8, @as(i32, @bitCast(@as(u32, 0xf8563412))));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 try t(u64, 0x123456789abcdef1, 0xf1debc9a78563412);22 try t(u64, 0x123456789abcdef1, 0xf1debc9a78563412);
58 try t(u88, 0x123456789abcdef1112131, 0x312111f1debc9a78563412);
59 try t(u96, 0x123456789abcdef111213141, 0x41312111f1debc9a78563412);
60 try t(u128, 0x123456789abcdef11121314151617181, 0x8171615141312111f1debc9a78563412);
6123
62 try t(u0, @as(u0, 0), 0);24 try t(u0, @as(u0, 0), 0);
63 try t(i8, @as(i8, -50), -50);25 try t(i8, @as(i8, -50), -50);
64 try t(i16, @as(i16, @bitCast(@as(u16, 0x1234))), @as(i16, @bitCast(@as(u16, 0x3412))));26 try t(i16, @as(i16, @bitCast(@as(u16, 0x1234))), @as(i16, @bitCast(@as(u16, 0x3412))));
65 try t(i24, @as(i24, @bitCast(@as(u24, 0x123456))), @as(i24, @bitCast(@as(u24, 0x563412))));27 try t(i24, @as(i24, @bitCast(@as(u24, 0x123456))), @as(i24, @bitCast(@as(u24, 0x563412))));
66 try t(i32, @as(i32, @bitCast(@as(u32, 0x12345678))), @as(i32, @bitCast(@as(u32, 0x78563412))));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
39test "@byteSwap exotic integers" {
40 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
41 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
42 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
43 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
44 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
45 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
46
47 const ByteSwapIntTest = struct {
48 fn run() !void {
49 try t(u0, 0, 0);
50 try t(u40, 0x123456789a, 0x9a78563412);
51 try t(i48, 0x123456789abc, @as(i48, @bitCast(@as(u48, 0xbc9a78563412))));
52 try t(u56, 0x123456789abcde, 0xdebc9a78563412);
53 try t(u88, 0x123456789abcdef1112131, 0x312111f1debc9a78563412);
54 try t(u96, 0x123456789abcdef111213141, 0x41312111f1debc9a78563412);
55 try t(u128, 0x123456789abcdef11121314151617181, 0x8171615141312111f1debc9a78563412);
56
67 try t(u40, @as(i40, @bitCast(@as(u40, 0x123456789a))), @as(u40, 0x9a78563412));57 try t(u40, @as(i40, @bitCast(@as(u40, 0x123456789a))), @as(u40, 0x9a78563412));
68 try t(i48, @as(i48, @bitCast(@as(u48, 0x123456789abc))), @as(i48, @bitCast(@as(u48, 0xbc9a78563412))));58 try t(i48, @as(i48, @bitCast(@as(u48, 0x123456789abc))), @as(i48, @bitCast(@as(u48, 0xbc9a78563412))));
69 try t(i56, @as(i56, @bitCast(@as(u56, 0x123456789abcde))), @as(i56, @bitCast(@as(u56, 0xdebc9a78563412))));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 try t(i88, @as(i88, @bitCast(@as(u88, 0x123456789abcdef1112131))), @as(i88, @bitCast(@as(u88, 0x312111f1debc9a78563412))));60 try t(i88, @as(i88, @bitCast(@as(u88, 0x123456789abcdef1112131))), @as(i88, @bitCast(@as(u88, 0x312111f1debc9a78563412))));
72 try t(i96, @as(i96, @bitCast(@as(u96, 0x123456789abcdef111213141))), @as(i96, @bitCast(@as(u96, 0x41312111f1debc9a78563412))));61 try t(i96, @as(i96, @bitCast(@as(u96, 0x123456789abcdef111213141))), @as(i96, @bitCast(@as(u96, 0x41312111f1debc9a78563412))));
73 try t(62 try t(
...@@ -93,9 +82,9 @@ fn vector8() !void {...@@ -93,9 +82,9 @@ fn vector8() !void {
93}82}
9483
95test "@byteSwap vectors u8" {84test "@byteSwap vectors u8" {
85 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
96 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;86 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
97 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;87 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
98 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
99 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO88 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
100 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;89 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
101 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;90 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -113,9 +102,9 @@ fn vector16() !void {...@@ -113,9 +102,9 @@ fn vector16() !void {
113}102}
114103
115test "@byteSwap vectors u16" {104test "@byteSwap vectors u16" {
105 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
116 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;106 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
117 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;107 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
118 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
119 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO108 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
120 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;109 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
121 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;110 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -133,9 +122,9 @@ fn vector24() !void {...@@ -133,9 +122,9 @@ fn vector24() !void {
133}122}
134123
135test "@byteSwap vectors u24" {124test "@byteSwap vectors u24" {
125 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
136 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;126 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
137 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;127 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
138 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
139 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO128 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
140 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;129 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
141 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;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,8 +20,8 @@ test "super basic invocations" {
20}20}
2121
22test "basic invocations" {22test "basic invocations" {
23 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
23 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO24 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
24 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
25 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO25 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
26 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO26 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
27 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;27 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -60,7 +60,6 @@ test "basic invocations" {...@@ -60,7 +60,6 @@ test "basic invocations" {
60}60}
6161
62test "tuple parameters" {62test "tuple parameters" {
63 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
64 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO63 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
65 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO64 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
66 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;65 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -95,7 +94,6 @@ test "tuple parameters" {...@@ -95,7 +94,6 @@ test "tuple parameters" {
9594
96test "result location of function call argument through runtime condition and struct init" {95test "result location of function call argument through runtime condition and struct init" {
97 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO96 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
99 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO97 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10098
101 const E = enum { a, b };99 const E = enum { a, b };
...@@ -115,6 +113,7 @@ test "result location of function call argument through runtime condition and st...@@ -115,6 +113,7 @@ test "result location of function call argument through runtime condition and st
115}113}
116114
117test "function call with 40 arguments" {115test "function call with 40 arguments" {
116 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
118 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO117 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
119 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;118 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
120119
...@@ -270,7 +269,7 @@ test "arguments to comptime parameters generated in comptime blocks" {...@@ -270,7 +269,7 @@ test "arguments to comptime parameters generated in comptime blocks" {
270}269}
271270
272test "forced tail call" {271test "forced tail call" {
273 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO272 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
274 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO273 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
275 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO274 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
276 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO275 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
...@@ -305,7 +304,7 @@ test "forced tail call" {...@@ -305,7 +304,7 @@ test "forced tail call" {
305}304}
306305
307test "inline call preserves tail call" {306test "inline call preserves tail call" {
308 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO307 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
309 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO308 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
310 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO309 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
311 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO310 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
...@@ -342,7 +341,6 @@ test "inline call preserves tail call" {...@@ -342,7 +341,6 @@ test "inline call preserves tail call" {
342}341}
343342
344test "inline call doesn't re-evaluate non generic struct" {343test "inline call doesn't re-evaluate non generic struct" {
345 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
346 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO344 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
347 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;345 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
348346
...@@ -409,7 +407,6 @@ test "recursive inline call with comptime known argument" {...@@ -409,7 +407,6 @@ test "recursive inline call with comptime known argument" {
409}407}
410408
411test "inline while with @call" {409test "inline while with @call" {
412 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
413 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO410 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
414411
415 const S = struct {412 const S = struct {
...@@ -439,7 +436,6 @@ test "method call as parameter type" {...@@ -439,7 +436,6 @@ test "method call as parameter type" {
439}436}
440437
441test "non-anytype generic parameters provide result type" {438test "non-anytype generic parameters provide result type" {
442 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
443 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO439 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
444 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO440 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
445441
...@@ -468,7 +464,6 @@ test "non-anytype generic parameters provide result type" {...@@ -468,7 +464,6 @@ test "non-anytype generic parameters provide result type" {
468}464}
469465
470test "argument to generic function has correct result type" {466test "argument to generic function has correct result type" {
471 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
472 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO467 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
473 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO468 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
474469
...@@ -521,7 +516,6 @@ test "call function in comptime field" {...@@ -521,7 +516,6 @@ test "call function in comptime field" {
521516
522test "call function pointer in comptime field" {517test "call function pointer in comptime field" {
523 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO518 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
524 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
525 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO519 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
526 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;520 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
527521
...@@ -573,7 +567,6 @@ test "value returned from comptime function is comptime known" {...@@ -573,7 +567,6 @@ test "value returned from comptime function is comptime known" {
573}567}
574568
575test "registers get overwritten when ignoring return" {569test "registers get overwritten when ignoring return" {
576 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
577 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;570 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
578 if (builtin.cpu.arch != .x86_64 or builtin.os.tag != .linux) return error.SkipZigTest;571 if (builtin.cpu.arch != .x86_64 or builtin.os.tag != .linux) return error.SkipZigTest;
579572
...@@ -619,7 +612,6 @@ test "call with union with zero sized field is not memorized incorrectly" {...@@ -619,7 +612,6 @@ test "call with union with zero sized field is not memorized incorrectly" {
619}612}
620613
621test "function call with cast to anyopaque pointer" {614test "function call with cast to anyopaque pointer" {
622 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
623 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO615 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
624 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO616 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
625 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;617 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -637,6 +629,7 @@ test "function call with cast to anyopaque pointer" {...@@ -637,6 +629,7 @@ test "function call with cast to anyopaque pointer" {
637}629}
638630
639test "arguments pointed to on stack into tailcall" {631test "arguments pointed to on stack into tailcall" {
632 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
640 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;633 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
641 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;634 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
642 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;635 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -708,7 +701,7 @@ test "arguments pointed to on stack into tailcall" {...@@ -708,7 +701,7 @@ test "arguments pointed to on stack into tailcall" {
708}701}
709702
710test "tail call function pointer" {703test "tail call function pointer" {
711 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO704 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
712 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO705 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
713 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO706 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
714 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO707 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
test/behavior/cast.zig+18-100
...@@ -21,7 +21,6 @@ test "integer literal to pointer cast" {...@@ -21,7 +21,6 @@ test "integer literal to pointer cast" {
21}21}
2222
23test "peer type resolution: ?T and T" {23test "peer type resolution: ?T and T" {
24 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
25 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;24 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
26 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO25 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2726
...@@ -100,7 +99,6 @@ test "comptime_int @floatFromInt" {...@@ -100,7 +99,6 @@ test "comptime_int @floatFromInt" {
100}99}
101100
102test "@floatFromInt" {101test "@floatFromInt" {
103 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
104 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO102 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
105 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;103 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
106 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO104 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -121,7 +119,6 @@ test "@floatFromInt" {...@@ -121,7 +119,6 @@ test "@floatFromInt" {
121}119}
122120
123test "@floatFromInt(f80)" {121test "@floatFromInt(f80)" {
124 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
125 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO122 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
126 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO123 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
127 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;124 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -157,7 +154,6 @@ test "@floatFromInt(f80)" {...@@ -157,7 +154,6 @@ test "@floatFromInt(f80)" {
157}154}
158155
159test "@intFromFloat" {156test "@intFromFloat" {
160 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO157 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
162 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO158 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
163 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,7 +177,6 @@ fn expectIntFromFloat(comptime F: type, f: F, comptime I: type, i: I) !void {
181}177}
182178
183test "implicitly cast indirect pointer to maybe-indirect pointer" {179test "implicitly cast indirect pointer to maybe-indirect pointer" {
184 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
185 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO180 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
186 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;181 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
187182
...@@ -241,7 +236,6 @@ test "@floatCast comptime_int and comptime_float" {...@@ -241,7 +236,6 @@ test "@floatCast comptime_int and comptime_float" {
241}236}
242237
243test "coerce undefined to optional" {238test "coerce undefined to optional" {
244 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
245 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;239 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
246 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO240 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
247241
...@@ -262,7 +256,6 @@ fn MakeType(comptime T: type) type {...@@ -262,7 +256,6 @@ fn MakeType(comptime T: type) type {
262}256}
263257
264test "implicit cast from *[N]T to [*c]T" {258test "implicit cast from *[N]T to [*c]T" {
265 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
266 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO259 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
267 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;260 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
268261
...@@ -299,7 +292,6 @@ test "@intCast to u0 and use the result" {...@@ -299,7 +292,6 @@ test "@intCast to u0 and use the result" {
299}292}
300293
301test "peer result null and comptime_int" {294test "peer result null and comptime_int" {
302 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
303 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;295 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
304 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO296 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
305297
...@@ -324,7 +316,6 @@ test "peer result null and comptime_int" {...@@ -324,7 +316,6 @@ test "peer result null and comptime_int" {
324}316}
325317
326test "*const ?[*]const T to [*c]const [*c]const T" {318test "*const ?[*]const T to [*c]const [*c]const T" {
327 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
328 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO319 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
329 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;320 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
330 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,7 +329,6 @@ test "*const ?[*]const T to [*c]const [*c]const T" {
338}329}
339330
340test "array coercion to undefined at runtime" {331test "array coercion to undefined at runtime" {
341 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
342 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO332 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
343 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;333 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
344334
...@@ -368,7 +358,6 @@ fn implicitIntLitToOptional() void {...@@ -368,7 +358,6 @@ fn implicitIntLitToOptional() void {
368}358}
369359
370test "return u8 coercing into ?u32 return type" {360test "return u8 coercing into ?u32 return type" {
371 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
372 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;361 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
373 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO362 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
374363
...@@ -390,7 +379,6 @@ test "cast from ?[*]T to ??[*]T" {...@@ -390,7 +379,6 @@ test "cast from ?[*]T to ??[*]T" {
390}379}
391380
392test "peer type unsigned int to signed" {381test "peer type unsigned int to signed" {
393 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
394 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO382 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
395383
396 var w: u31 = 5;384 var w: u31 = 5;
...@@ -403,7 +391,6 @@ test "peer type unsigned int to signed" {...@@ -403,7 +391,6 @@ test "peer type unsigned int to signed" {
403}391}
404392
405test "expected [*c]const u8, found [*:0]const u8" {393test "expected [*c]const u8, found [*:0]const u8" {
406 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
407 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO394 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
408 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;395 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
409396
...@@ -415,7 +402,6 @@ test "expected [*c]const u8, found [*:0]const u8" {...@@ -415,7 +402,6 @@ test "expected [*c]const u8, found [*:0]const u8" {
415}402}
416403
417test "explicit cast from integer to error type" {404test "explicit cast from integer to error type" {
418 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
419 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO405 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
420 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO406 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
421 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;407 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -431,7 +417,6 @@ fn testCastIntToErr(err: anyerror) !void {...@@ -431,7 +417,6 @@ fn testCastIntToErr(err: anyerror) !void {
431}417}
432418
433test "peer resolve array and const slice" {419test "peer resolve array and const slice" {
434 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
435 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO420 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
436 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO421 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
437 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;422 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -447,7 +432,6 @@ fn testPeerResolveArrayConstSlice(b: bool) !void {...@@ -447,7 +432,6 @@ fn testPeerResolveArrayConstSlice(b: bool) !void {
447}432}
448433
449test "implicitly cast from T to anyerror!?T" {434test "implicitly cast from T to anyerror!?T" {
450 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
451 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;435 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
452 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO436 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
453437
...@@ -473,7 +457,6 @@ fn castToOptionalTypeError(z: i32) !void {...@@ -473,7 +457,6 @@ fn castToOptionalTypeError(z: i32) !void {
473}457}
474458
475test "implicitly cast from [0]T to anyerror![]T" {459test "implicitly cast from [0]T to anyerror![]T" {
476 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
477 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO460 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
478461
479 try testCastZeroArrayToErrSliceMut();462 try testCastZeroArrayToErrSliceMut();
...@@ -489,7 +472,6 @@ fn gimmeErrOrSlice() anyerror![]u8 {...@@ -489,7 +472,6 @@ fn gimmeErrOrSlice() anyerror![]u8 {
489}472}
490473
491test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" {474test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" {
492 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
493 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO475 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
494 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO476 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
495 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;477 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -522,7 +504,6 @@ fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 {...@@ -522,7 +504,6 @@ fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 {
522}504}
523505
524test "implicit cast from *const [N]T to []const T" {506test "implicit cast from *const [N]T to []const T" {
525 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
526 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO507 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
527 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;508 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
528509
...@@ -548,7 +529,6 @@ fn testCastConstArrayRefToConstSlice() !void {...@@ -548,7 +529,6 @@ fn testCastConstArrayRefToConstSlice() !void {
548}529}
549530
550test "peer type resolution: error and [N]T" {531test "peer type resolution: error and [N]T" {
551 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
552 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO532 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
553 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;533 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
554534
...@@ -573,7 +553,6 @@ fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 {...@@ -573,7 +553,6 @@ fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 {
573}553}
574554
575test "single-item pointer of array to slice to unknown length pointer" {555test "single-item pointer of array to slice to unknown length pointer" {
576 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
577 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO556 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
578 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;557 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
579558
...@@ -603,7 +582,6 @@ fn testCastPtrOfArrayToSliceAndPtr() !void {...@@ -603,7 +582,6 @@ fn testCastPtrOfArrayToSliceAndPtr() !void {
603}582}
604583
605test "cast *[1][*]const u8 to [*]const ?[*]const u8" {584test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
606 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
607 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO585 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
608 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;586 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
609587
...@@ -613,8 +591,8 @@ test "cast *[1][*]const u8 to [*]const ?[*]const u8" {...@@ -613,8 +591,8 @@ test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
613}591}
614592
615test "@intCast on vector" {593test "@intCast on vector" {
594 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
616 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO595 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
617 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
618 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO596 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
619 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO597 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
620 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;598 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -651,7 +629,6 @@ test "@intCast on vector" {...@@ -651,7 +629,6 @@ test "@intCast on vector" {
651}629}
652630
653test "@floatCast cast down" {631test "@floatCast cast down" {
654 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
655 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO632 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
656 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO633 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
657 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;634 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -670,7 +647,6 @@ test "@floatCast cast down" {...@@ -670,7 +647,6 @@ test "@floatCast cast down" {
670}647}
671648
672test "peer type resolution: unreachable, error set, unreachable" {649test "peer type resolution: unreachable, error set, unreachable" {
673 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
674 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO650 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
675651
676 const Error = error{652 const Error = error{
...@@ -704,7 +680,6 @@ test "peer cast: error set any anyerror" {...@@ -704,7 +680,6 @@ test "peer cast: error set any anyerror" {
704}680}
705681
706test "peer type resolution: error set supersets" {682test "peer type resolution: error set supersets" {
707 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
708 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO683 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
709 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO684 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
710 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;685 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -735,7 +710,6 @@ test "peer type resolution: error set supersets" {...@@ -735,7 +710,6 @@ test "peer type resolution: error set supersets" {
735710
736test "peer type resolution: disjoint error sets" {711test "peer type resolution: disjoint error sets" {
737 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO712 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
738 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
739 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO713 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
740 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;714 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
741715
...@@ -765,7 +739,6 @@ test "peer type resolution: disjoint error sets" {...@@ -765,7 +739,6 @@ test "peer type resolution: disjoint error sets" {
765739
766test "peer type resolution: error union and error set" {740test "peer type resolution: error union and error set" {
767 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO741 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
768 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
769 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO742 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
770 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;743 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
771744
...@@ -799,7 +772,6 @@ test "peer type resolution: error union and error set" {...@@ -799,7 +772,6 @@ test "peer type resolution: error union and error set" {
799772
800test "peer type resolution: error union after non-error" {773test "peer type resolution: error union after non-error" {
801 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO774 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
802 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
803 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO775 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
804 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;776 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
805777
...@@ -833,7 +805,6 @@ test "peer type resolution: error union after non-error" {...@@ -833,7 +805,6 @@ test "peer type resolution: error union after non-error" {
833805
834test "peer cast *[0]T to E![]const T" {806test "peer cast *[0]T to E![]const T" {
835 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;807 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
836 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
837 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO808 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
838 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;809 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
839810
...@@ -849,7 +820,6 @@ test "peer cast *[0]T to E![]const T" {...@@ -849,7 +820,6 @@ test "peer cast *[0]T to E![]const T" {
849820
850test "peer cast *[0]T to []const T" {821test "peer cast *[0]T to []const T" {
851 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;822 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
852 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
853 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO823 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
854 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;824 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
855825
...@@ -872,7 +842,6 @@ test "peer cast *[N]T to [*]T" {...@@ -872,7 +842,6 @@ test "peer cast *[N]T to [*]T" {
872}842}
873843
874test "peer resolution of string literals" {844test "peer resolution of string literals" {
875 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
876 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO845 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
877 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO846 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
878 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;847 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -895,7 +864,6 @@ test "peer resolution of string literals" {...@@ -895,7 +864,6 @@ test "peer resolution of string literals" {
895}864}
896865
897test "peer cast [:x]T to []T" {866test "peer cast [:x]T to []T" {
898 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
899 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO867 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
900 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;868 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
901869
...@@ -912,7 +880,6 @@ test "peer cast [:x]T to []T" {...@@ -912,7 +880,6 @@ test "peer cast [:x]T to []T" {
912}880}
913881
914test "peer cast [N:x]T to [N]T" {882test "peer cast [N:x]T to [N]T" {
915 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
916 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO883 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
917 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;884 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
918885
...@@ -929,7 +896,6 @@ test "peer cast [N:x]T to [N]T" {...@@ -929,7 +896,6 @@ test "peer cast [N:x]T to [N]T" {
929}896}
930897
931test "peer cast *[N:x]T to *[N]T" {898test "peer cast *[N:x]T to *[N]T" {
932 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
933 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO899 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
934 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;900 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
935901
...@@ -945,7 +911,6 @@ test "peer cast *[N:x]T to *[N]T" {...@@ -945,7 +911,6 @@ test "peer cast *[N:x]T to *[N]T" {
945}911}
946912
947test "peer cast [*:x]T to [*]T" {913test "peer cast [*:x]T to [*]T" {
948 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
949 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO914 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
950 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;915 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
951 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;916 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -966,7 +931,6 @@ test "peer cast [*:x]T to [*]T" {...@@ -966,7 +931,6 @@ test "peer cast [*:x]T to [*]T" {
966}931}
967932
968test "peer cast [:x]T to [*:x]T" {933test "peer cast [:x]T to [*:x]T" {
969 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
970 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO934 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
971 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO935 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
972 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;936 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -988,7 +952,6 @@ test "peer cast [:x]T to [*:x]T" {...@@ -988,7 +952,6 @@ test "peer cast [:x]T to [*:x]T" {
988}952}
989953
990test "peer type resolution implicit cast to return type" {954test "peer type resolution implicit cast to return type" {
991 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
992 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO955 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
993 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;956 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
994957
...@@ -1009,7 +972,6 @@ test "peer type resolution implicit cast to return type" {...@@ -1009,7 +972,6 @@ test "peer type resolution implicit cast to return type" {
1009}972}
1010973
1011test "peer type resolution implicit cast to variable type" {974test "peer type resolution implicit cast to variable type" {
1012 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1013 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO975 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1014 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;976 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1015977
...@@ -1035,7 +997,6 @@ test "variable initialization uses result locations properly with regards to the...@@ -1035,7 +997,6 @@ test "variable initialization uses result locations properly with regards to the
1035}997}
1036998
1037test "cast between C pointer with different but compatible types" {999test "cast between C pointer with different but compatible types" {
1038 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1039 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1000 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1040 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1001 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10411002
...@@ -1053,7 +1014,6 @@ test "cast between C pointer with different but compatible types" {...@@ -1053,7 +1014,6 @@ test "cast between C pointer with different but compatible types" {
1053}1014}
10541015
1055test "peer type resolve string lit with sentinel-terminated mutable slice" {1016test "peer type resolve string lit with sentinel-terminated mutable slice" {
1056 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1057 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1017 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1058 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1018 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10591019
...@@ -1104,7 +1064,6 @@ test "comptime float casts" {...@@ -1104,7 +1064,6 @@ test "comptime float casts" {
1104}1064}
11051065
1106test "pointer reinterpret const float to int" {1066test "pointer reinterpret const float to int" {
1107 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1108 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1067 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11091068
1110 // The hex representation is 0x3fe3333333333303.1069 // The hex representation is 0x3fe3333333333303.
...@@ -1119,7 +1078,6 @@ test "pointer reinterpret const float to int" {...@@ -1119,7 +1078,6 @@ test "pointer reinterpret const float to int" {
1119}1078}
11201079
1121test "implicit cast from [*]T to ?*anyopaque" {1080test "implicit cast from [*]T to ?*anyopaque" {
1122 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1123 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1081 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1124 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1082 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1125 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1083 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1184,7 +1142,6 @@ test "cast function with an opaque parameter" {...@@ -1184,7 +1142,6 @@ test "cast function with an opaque parameter" {
1184}1142}
11851143
1186test "implicit ptr to *anyopaque" {1144test "implicit ptr to *anyopaque" {
1187 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1188 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1145 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1189 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1146 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1190 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1147 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1199,7 +1156,6 @@ test "implicit ptr to *anyopaque" {...@@ -1199,7 +1156,6 @@ test "implicit ptr to *anyopaque" {
1199}1156}
12001157
1201test "return null from fn () anyerror!?&T" {1158test "return null from fn () anyerror!?&T" {
1202 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1203 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1159 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1204 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1160 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
12051161
...@@ -1216,7 +1172,6 @@ fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A {...@@ -1216,7 +1172,6 @@ fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A {
1216}1172}
12171173
1218test "peer type resolution: [0]u8 and []const u8" {1174test "peer type resolution: [0]u8 and []const u8" {
1219 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1220 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1175 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1221 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1176 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1222 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1177 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1237,7 +1192,6 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {...@@ -1237,7 +1192,6 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {
1237}1192}
12381193
1239test "implicitly cast from [N]T to ?[]const T" {1194test "implicitly cast from [N]T to ?[]const T" {
1240 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1241 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1195 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1242 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1196 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1243 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1197 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1251,7 +1205,6 @@ fn castToOptionalSlice() ?[]const u8 {...@@ -1251,7 +1205,6 @@ fn castToOptionalSlice() ?[]const u8 {
1251}1205}
12521206
1253test "cast u128 to f128 and back" {1207test "cast u128 to f128 and back" {
1254 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1255 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1208 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1256 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1209 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1257 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1210 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1274,7 +1227,6 @@ fn cast128Float(x: u128) f128 {...@@ -1274,7 +1227,6 @@ fn cast128Float(x: u128) f128 {
1274}1227}
12751228
1276test "implicit cast from *[N]T to ?[*]T" {1229test "implicit cast from *[N]T to ?[*]T" {
1277 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1278 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1230 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1279 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1231 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1280 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1232 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1291,7 +1243,6 @@ test "implicit cast from *[N]T to ?[*]T" {...@@ -1291,7 +1243,6 @@ test "implicit cast from *[N]T to ?[*]T" {
1291}1243}
12921244
1293test "implicit cast from *T to ?*anyopaque" {1245test "implicit cast from *T to ?*anyopaque" {
1294 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1295 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1246 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1296 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1247 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1297 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1248 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1306,7 +1257,6 @@ fn incrementVoidPtrValue(value: ?*anyopaque) void {...@@ -1306,7 +1257,6 @@ fn incrementVoidPtrValue(value: ?*anyopaque) void {
1306}1257}
13071258
1308test "implicit cast *[0]T to E![]const u8" {1259test "implicit cast *[0]T to E![]const u8" {
1309 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1310 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1260 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13111261
1312 var x = @as(anyerror![]const u8, &[0]u8{});1262 var x = @as(anyerror![]const u8, &[0]u8{});
...@@ -1330,7 +1280,6 @@ test "cast from array reference to fn: runtime fn ptr" {...@@ -1330,7 +1280,6 @@ test "cast from array reference to fn: runtime fn ptr" {
1330}1280}
13311281
1332test "*const [N]null u8 to ?[]const u8" {1282test "*const [N]null u8 to ?[]const u8" {
1333 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1334 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1283 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1335 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1284 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1336 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,7 +1316,6 @@ test "cast between [*c]T and ?[*:0]T on fn parameter" {
13671316
1368var global_struct: struct { f0: usize } = undefined;1317var global_struct: struct { f0: usize } = undefined;
1369test "assignment to optional pointer result loc" {1318test "assignment to optional pointer result loc" {
1370 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1371 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1319 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1372 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1320 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1373 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1321 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1386,7 +1334,6 @@ test "cast between *[N]void and []void" {...@@ -1386,7 +1334,6 @@ test "cast between *[N]void and []void" {
1386}1334}
13871335
1388test "peer resolve arrays of different size to const slice" {1336test "peer resolve arrays of different size to const slice" {
1389 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1390 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1337 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1391 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1338 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
13921339
...@@ -1400,7 +1347,6 @@ fn boolToStr(b: bool) []const u8 {...@@ -1400,7 +1347,6 @@ fn boolToStr(b: bool) []const u8 {
1400}1347}
14011348
1402test "cast f16 to wider types" {1349test "cast f16 to wider types" {
1403 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1404 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1350 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1405 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1351 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1406 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1352 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1421,7 +1367,6 @@ test "cast f16 to wider types" {...@@ -1421,7 +1367,6 @@ test "cast f16 to wider types" {
1421}1367}
14221368
1423test "cast f128 to narrower types" {1369test "cast f128 to narrower types" {
1424 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1425 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1370 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1426 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1371 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1427 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1372 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1441,7 +1386,6 @@ test "cast f128 to narrower types" {...@@ -1441,7 +1386,6 @@ test "cast f128 to narrower types" {
1441}1386}
14421387
1443test "peer type resolution: unreachable, null, slice" {1388test "peer type resolution: unreachable, null, slice" {
1444 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1445 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1389 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1446 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1390 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1447 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1391 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1460,7 +1404,6 @@ test "peer type resolution: unreachable, null, slice" {...@@ -1460,7 +1404,6 @@ test "peer type resolution: unreachable, null, slice" {
1460}1404}
14611405
1462test "cast i8 fn call peers to i32 result" {1406test "cast i8 fn call peers to i32 result" {
1463 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1464 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1407 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14651408
1466 const S = struct {1409 const S = struct {
...@@ -1482,7 +1425,6 @@ test "cast i8 fn call peers to i32 result" {...@@ -1482,7 +1425,6 @@ test "cast i8 fn call peers to i32 result" {
1482}1425}
14831426
1484test "cast compatible optional types" {1427test "cast compatible optional types" {
1485 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1486 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1428 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1487 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1429 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1488 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1430 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1494,7 +1436,6 @@ test "cast compatible optional types" {...@@ -1494,7 +1436,6 @@ test "cast compatible optional types" {
1494}1436}
14951437
1496test "coerce undefined single-item pointer of array to error union of slice" {1438test "coerce undefined single-item pointer of array to error union of slice" {
1497 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1498 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1439 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14991440
1500 const a = @as([*]u8, undefined)[0..0];1441 const a = @as([*]u8, undefined)[0..0];
...@@ -1513,7 +1454,6 @@ test "pointer to empty struct literal to mutable slice" {...@@ -1513,7 +1454,6 @@ test "pointer to empty struct literal to mutable slice" {
1513}1454}
15141455
1515test "coerce between pointers of compatible differently-named floats" {1456test "coerce between pointers of compatible differently-named floats" {
1516 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1517 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1457 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1518 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows and !builtin.link_libc) return error.SkipZigTest;1458 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows and !builtin.link_libc) return error.SkipZigTest;
1519 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1459 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,7 +1488,6 @@ test "peer type resolution of const and non-const pointer to array" {
1548}1488}
15491489
1550test "intFromFloat to zero-bit int" {1490test "intFromFloat to zero-bit int" {
1551 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1552 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1491 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1553 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1492 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15541493
...@@ -1573,8 +1512,6 @@ test "cast typed undefined to int" {...@@ -1573,8 +1512,6 @@ test "cast typed undefined to int" {
1573}1512}
15741513
1575// test "implicit cast from [:0]T to [*c]T" {1514// test "implicit cast from [:0]T to [*c]T" {
1576// if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1577
1578// var a: [:0]const u8 = "foo";1515// var a: [:0]const u8 = "foo";
1579// _ = &a;1516// _ = &a;
1580// const b: [*c]const u8 = a;1517// const b: [*c]const u8 = a;
...@@ -1584,7 +1521,6 @@ test "cast typed undefined to int" {...@@ -1584,7 +1521,6 @@ test "cast typed undefined to int" {
1584// }1521// }
15851522
1586test "bitcast packed struct with u0" {1523test "bitcast packed struct with u0" {
1587 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1588 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1524 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
15891525
1590 const S = packed struct(u2) { a: u0, b: u2 };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,7 +1627,6 @@ test "coercion from single-item pointer to @as to slice" {
1691}1627}
16921628
1693test "peer type resolution: const sentinel slice and mutable non-sentinel slice" {1629test "peer type resolution: const sentinel slice and mutable non-sentinel slice" {
1694 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1695 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1630 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1696 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1631 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1697 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,7 +1656,6 @@ test "peer type resolution: const sentinel slice and mutable non-sentinel slice"
1721}1656}
17221657
1723test "peer type resolution: float and comptime-known fixed-width integer" {1658test "peer type resolution: float and comptime-known fixed-width integer" {
1724 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1725 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1659 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1726 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1660 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17271661
...@@ -1743,7 +1677,7 @@ test "peer type resolution: float and comptime-known fixed-width integer" {...@@ -1743,7 +1677,7 @@ test "peer type resolution: float and comptime-known fixed-width integer" {
1743}1677}
17441678
1745test "peer type resolution: same array type with sentinel" {1679test "peer type resolution: same array type with sentinel" {
1746 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1680 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1747 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1681 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1748 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1682 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1749 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1683 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1766,7 +1700,6 @@ test "peer type resolution: same array type with sentinel" {...@@ -1766,7 +1700,6 @@ test "peer type resolution: same array type with sentinel" {
1766}1700}
17671701
1768test "peer type resolution: array with sentinel and array without sentinel" {1702test "peer type resolution: array with sentinel and array without sentinel" {
1769 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1770 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1703 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1771 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1704 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1772 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,7 +1722,7 @@ test "peer type resolution: array with sentinel and array without sentinel" {
1789}1722}
17901723
1791test "peer type resolution: array and vector with same child type" {1724test "peer type resolution: array and vector with same child type" {
1792 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1725 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1793 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1726 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1794 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1727 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1795 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,7 +1746,7 @@ test "peer type resolution: array and vector with same child type" {
1813}1746}
18141747
1815test "peer type resolution: array with smaller child type and vector with larger child type" {1748test "peer type resolution: array with smaller child type and vector with larger child type" {
1816 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1749 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1817 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1750 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1818 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1751 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1819 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1752 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,7 +1770,7 @@ test "peer type resolution: array with smaller child type and vector with larger
1837}1770}
18381771
1839test "peer type resolution: error union and optional of same type" {1772test "peer type resolution: error union and optional of same type" {
1840 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1773 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1841 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1774 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1842 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1775 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1843 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,7 +1794,6 @@ test "peer type resolution: error union and optional of same type" {
1861}1794}
18621795
1863test "peer type resolution: C pointer and @TypeOf(null)" {1796test "peer type resolution: C pointer and @TypeOf(null)" {
1864 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1865 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1797 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1866 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1798 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1867 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1799 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1884,7 +1816,6 @@ test "peer type resolution: C pointer and @TypeOf(null)" {...@@ -1884,7 +1816,6 @@ test "peer type resolution: C pointer and @TypeOf(null)" {
1884}1816}
18851817
1886test "peer type resolution: three-way resolution combines error set and optional" {1818test "peer type resolution: three-way resolution combines error set and optional" {
1887 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1888 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1819 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1889 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1820 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1890 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1821 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1927,7 +1858,7 @@ test "peer type resolution: three-way resolution combines error set and optional...@@ -1927,7 +1858,7 @@ test "peer type resolution: three-way resolution combines error set and optional
1927}1858}
19281859
1929test "peer type resolution: vector and optional vector" {1860test "peer type resolution: vector and optional vector" {
1930 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1861 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1931 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1862 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1932 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1863 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1933 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1864 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1952,7 +1883,6 @@ test "peer type resolution: vector and optional vector" {...@@ -1952,7 +1883,6 @@ test "peer type resolution: vector and optional vector" {
1952}1883}
19531884
1954test "peer type resolution: optional fixed-width int and comptime_int" {1885test "peer type resolution: optional fixed-width int and comptime_int" {
1955 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1956 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1886 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1957 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1887 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
19581888
...@@ -1974,7 +1904,7 @@ test "peer type resolution: optional fixed-width int and comptime_int" {...@@ -1974,7 +1904,7 @@ test "peer type resolution: optional fixed-width int and comptime_int" {
1974}1904}
19751905
1976test "peer type resolution: array and tuple" {1906test "peer type resolution: array and tuple" {
1977 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1907 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1978 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1908 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1979 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1909 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1980 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1910 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1998,7 +1928,7 @@ test "peer type resolution: array and tuple" {...@@ -1998,7 +1928,7 @@ test "peer type resolution: array and tuple" {
1998}1928}
19991929
2000test "peer type resolution: vector and tuple" {1930test "peer type resolution: vector and tuple" {
2001 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1931 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2002 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1932 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2003 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1933 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2004 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1934 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -2022,7 +1952,7 @@ test "peer type resolution: vector and tuple" {...@@ -2022,7 +1952,7 @@ test "peer type resolution: vector and tuple" {
2022}1952}
20231953
2024test "peer type resolution: vector and array and tuple" {1954test "peer type resolution: vector and array and tuple" {
2025 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1955 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2026 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1956 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2027 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1957 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2028 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1958 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -2066,7 +1996,6 @@ test "peer type resolution: vector and array and tuple" {...@@ -2066,7 +1996,6 @@ test "peer type resolution: vector and array and tuple" {
2066}1996}
20671997
2068test "peer type resolution: empty tuple pointer and slice" {1998test "peer type resolution: empty tuple pointer and slice" {
2069 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2070 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1999 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2071 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2000 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2072 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;2001 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -2088,7 +2017,6 @@ test "peer type resolution: empty tuple pointer and slice" {...@@ -2088,7 +2017,6 @@ test "peer type resolution: empty tuple pointer and slice" {
2088}2017}
20892018
2090test "peer type resolution: tuple pointer and slice" {2019test "peer type resolution: tuple pointer and slice" {
2091 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2092 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2020 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2093 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2021 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2094 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;2022 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -2110,7 +2038,6 @@ test "peer type resolution: tuple pointer and slice" {...@@ -2110,7 +2038,6 @@ test "peer type resolution: tuple pointer and slice" {
2110}2038}
21112039
2112test "peer type resolution: tuple pointer and optional slice" {2040test "peer type resolution: tuple pointer and optional slice" {
2113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2114 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2041 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2115 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2042 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2116 // Miscompilation on Intel's OpenCL CPU runtime.2043 // Miscompilation on Intel's OpenCL CPU runtime.
...@@ -2133,7 +2060,6 @@ test "peer type resolution: tuple pointer and optional slice" {...@@ -2133,7 +2060,6 @@ test "peer type resolution: tuple pointer and optional slice" {
2133}2060}
21342061
2135test "peer type resolution: many compatible pointers" {2062test "peer type resolution: many compatible pointers" {
2136 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2137 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2063 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2138 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2064 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2139 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;2065 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -2200,7 +2126,6 @@ test "peer type resolution: many compatible pointers" {...@@ -2200,7 +2126,6 @@ test "peer type resolution: many compatible pointers" {
2200}2126}
22012127
2202test "peer type resolution: tuples with comptime fields" {2128test "peer type resolution: tuples with comptime fields" {
2203 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2204 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2129 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2205 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2130 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2206 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO2131 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
...@@ -2232,7 +2157,6 @@ test "peer type resolution: tuples with comptime fields" {...@@ -2232,7 +2157,6 @@ test "peer type resolution: tuples with comptime fields" {
2232}2157}
22332158
2234test "peer type resolution: C pointer and many pointer" {2159test "peer type resolution: C pointer and many pointer" {
2235 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2236 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2160 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2237 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2161 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2238 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;2162 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -2256,7 +2180,6 @@ test "peer type resolution: C pointer and many pointer" {...@@ -2256,7 +2180,6 @@ test "peer type resolution: C pointer and many pointer" {
2256}2180}
22572181
2258test "peer type resolution: pointer attributes are combined correctly" {2182test "peer type resolution: pointer attributes are combined correctly" {
2259 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2260 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2183 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2261 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2184 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2262 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;2185 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -2338,7 +2261,7 @@ test "peer type resolution: pointer attributes are combined correctly" {...@@ -2338,7 +2261,7 @@ test "peer type resolution: pointer attributes are combined correctly" {
2338}2261}
23392262
2340test "peer type resolution: arrays of compatible types" {2263test "peer type resolution: arrays of compatible types" {
2341 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO2264 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2342 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2265 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2343 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2266 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2344 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;2267 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -2356,7 +2279,6 @@ test "peer type resolution: arrays of compatible types" {...@@ -2356,7 +2279,6 @@ test "peer type resolution: arrays of compatible types" {
2356}2279}
23572280
2358test "cast builtins can wrap result in optional" {2281test "cast builtins can wrap result in optional" {
2359 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2360 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2282 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2361 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2283 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2362 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;2284 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -2394,7 +2316,6 @@ test "cast builtins can wrap result in optional" {...@@ -2394,7 +2316,6 @@ test "cast builtins can wrap result in optional" {
2394}2316}
23952317
2396test "cast builtins can wrap result in error union" {2318test "cast builtins can wrap result in error union" {
2397 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2398 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2319 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2399 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2320 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
24002321
...@@ -2432,7 +2353,6 @@ test "cast builtins can wrap result in error union" {...@@ -2432,7 +2353,6 @@ test "cast builtins can wrap result in error union" {
2432}2353}
24332354
2434test "cast builtins can wrap result in error union and optional" {2355test "cast builtins can wrap result in error union and optional" {
2435 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2436 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2356 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2437 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2357 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2438 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;2358 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -2471,8 +2391,8 @@ test "cast builtins can wrap result in error union and optional" {...@@ -2471,8 +2391,8 @@ test "cast builtins can wrap result in error union and optional" {
2471}2391}
24722392
2473test "@floatCast on vector" {2393test "@floatCast on vector" {
2394 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2474 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO2395 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2475 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2476 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2396 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2477 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2397 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2478 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;2398 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -2512,8 +2432,8 @@ test "@floatCast on vector" {...@@ -2512,8 +2432,8 @@ test "@floatCast on vector" {
2512}2432}
25132433
2514test "@ptrFromInt on vector" {2434test "@ptrFromInt on vector" {
2435 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2515 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO2436 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2516 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2517 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2437 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2518 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2438 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2519 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;2439 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -2537,8 +2457,8 @@ test "@ptrFromInt on vector" {...@@ -2537,8 +2457,8 @@ test "@ptrFromInt on vector" {
2537}2457}
25382458
2539test "@intFromPtr on vector" {2459test "@intFromPtr on vector" {
2460 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2540 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO2461 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2541 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2542 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2462 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2543 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2463 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2544 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;2464 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -2562,8 +2482,8 @@ test "@intFromPtr on vector" {...@@ -2562,8 +2482,8 @@ test "@intFromPtr on vector" {
2562}2482}
25632483
2564test "@floatFromInt on vector" {2484test "@floatFromInt on vector" {
2485 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2565 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO2486 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2566 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2567 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2487 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2568 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2488 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2569 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;2489 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -2582,8 +2502,8 @@ test "@floatFromInt on vector" {...@@ -2582,8 +2502,8 @@ test "@floatFromInt on vector" {
2582}2502}
25832503
2584test "@intFromFloat on vector" {2504test "@intFromFloat on vector" {
2505 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2585 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO2506 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2586 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2587 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2507 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2588 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2508 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2589 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;2509 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -2602,8 +2522,8 @@ test "@intFromFloat on vector" {...@@ -2602,8 +2522,8 @@ test "@intFromFloat on vector" {
2602}2522}
26032523
2604test "@intFromBool on vector" {2524test "@intFromBool on vector" {
2525 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2605 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO2526 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2606 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2607 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2527 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2608 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2528 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2609 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;2529 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -2639,7 +2559,6 @@ test "15-bit int to float" {...@@ -2639,7 +2559,6 @@ test "15-bit int to float" {
2639}2559}
26402560
2641test "@as does not corrupt values with incompatible representations" {2561test "@as does not corrupt values with incompatible representations" {
2642 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2643 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2562 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2644 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2563 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
26452564
...@@ -2654,7 +2573,6 @@ test "@as does not corrupt values with incompatible representations" {...@@ -2654,7 +2573,6 @@ test "@as does not corrupt values with incompatible representations" {
2654}2573}
26552574
2656test "result information is preserved through many nested structures" {2575test "result information is preserved through many nested structures" {
2657 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2658 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2576 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2659 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2577 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2660 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;2578 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -2679,7 +2597,7 @@ test "result information is preserved through many nested structures" {...@@ -2679,7 +2597,7 @@ test "result information is preserved through many nested structures" {
2679}2597}
26802598
2681test "@intCast vector of signed integer" {2599test "@intCast vector of signed integer" {
2682 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO2600 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2683 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2601 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2684 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO2602 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2685 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2603 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -2703,7 +2621,6 @@ test "result type is preserved into comptime block" {...@@ -2703,7 +2621,6 @@ test "result type is preserved into comptime block" {
2703}2621}
27042622
2705test "bitcast vector" {2623test "bitcast vector" {
2706 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2707 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2624 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
27082625
2709 const u8x32 = @Vector(32, u8);2626 const u8x32 = @Vector(32, u8);
...@@ -2766,6 +2683,7 @@ test "@intFromFloat boundary cases" {...@@ -2766,6 +2683,7 @@ test "@intFromFloat boundary cases" {
2766}2683}
27672684
2768test "@intFromFloat vector boundary cases" {2685test "@intFromFloat vector boundary cases" {
2686 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2769 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;2687 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2770 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;2688 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
2771 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;2689 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,7 +5,6 @@ const expectEqual = std.testing.expectEqual;
5const maxInt = std.math.maxInt;5const maxInt = std.math.maxInt;
66
7test "@intCast i32 to u7" {7test "@intCast i32 to u7" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;10 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -19,7 +18,6 @@ test "@intCast i32 to u7" {...@@ -19,7 +18,6 @@ test "@intCast i32 to u7" {
19}18}
2019
21test "coerce i8 to i32 and @intCast back" {20test "coerce i8 to i32 and @intCast back" {
22 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
23 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO21 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
24 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO22 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2523
...@@ -36,6 +34,7 @@ test "coerce i8 to i32 and @intCast back" {...@@ -36,6 +34,7 @@ test "coerce i8 to i32 and @intCast back" {
3634
37test "coerce non byte-sized integers accross 32bits boundary" {35test "coerce non byte-sized integers accross 32bits boundary" {
38 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO36 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
37
39 {38 {
40 var v: u21 = 6417;39 var v: u21 = 6417;
41 _ = &v;40 _ = &v;
...@@ -164,8 +163,9 @@ const Piece = packed struct {...@@ -164,8 +163,9 @@ const Piece = packed struct {
164 }163 }
165};164};
166165
166// Originally reported at https://github.com/ziglang/zig/issues/14200
167test "load non byte-sized optional value" {167test "load non byte-sized optional value" {
168 // Originally reported at https://github.com/ziglang/zig/issues/14200168 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
169 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;169 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
170 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO170 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
171171
...@@ -181,6 +181,7 @@ test "load non byte-sized optional value" {...@@ -181,6 +181,7 @@ test "load non byte-sized optional value" {
181}181}
182182
183test "load non byte-sized value in struct" {183test "load non byte-sized value in struct" {
184 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
184 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;185 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
185 if (builtin.cpu.arch.endian() != .little) return error.SkipZigTest; // packed struct TODO186 if (builtin.cpu.arch.endian() != .little) return error.SkipZigTest; // packed struct TODO
186 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO187 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,7 +66,6 @@ fn bigToNativeEndian(comptime T: type, v: T) T {
66 return if (endian == .big) v else @byteSwap(v);66 return if (endian == .big) v else @byteSwap(v);
67}67}
68test "type pun endianness" {68test "type pun endianness" {
69 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
70 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO69 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7170
72 comptime {71 comptime {
...@@ -360,7 +359,6 @@ test "offset field ptr by enclosing array element size" {...@@ -360,7 +359,6 @@ test "offset field ptr by enclosing array element size" {
360}359}
361360
362test "accessing reinterpreted memory of parent object" {361test "accessing reinterpreted memory of parent object" {
363 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
364 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO362 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
365363
366 const S = extern struct {364 const S = extern struct {
test/behavior/const_slice_child.zig-1
...@@ -7,7 +7,6 @@ const expect = testing.expect;...@@ -7,7 +7,6 @@ const expect = testing.expect;
7var argv: [*]const [*]const u8 = undefined;7var argv: [*]const [*]const u8 = undefined;
88
9test "const slice child" {9test "const slice child" {
10 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO11 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;12 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/decl_literals.zig-1
...@@ -35,7 +35,6 @@ test "decl literal with pointer" {...@@ -35,7 +35,6 @@ test "decl literal with pointer" {
35test "call decl literal with optional" {35test "call decl literal with optional" {
36 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;36 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
37 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;37 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
38 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
39 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;38 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4039
41 const S = struct {40 const S = struct {
test/behavior/defer.zig+2-6
...@@ -32,7 +32,6 @@ test "defer and labeled break" {...@@ -32,7 +32,6 @@ test "defer and labeled break" {
32}32}
3333
34test "errdefer does not apply to fn inside fn" {34test "errdefer does not apply to fn inside fn" {
35 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
36 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO35 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3736
38 if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| try expect(e == error.Bad);37 if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| try expect(e == error.Bad);
...@@ -51,7 +50,6 @@ fn testNestedFnErrDefer() anyerror!void {...@@ -51,7 +50,6 @@ fn testNestedFnErrDefer() anyerror!void {
5150
52test "return variable while defer expression in scope to modify it" {51test "return variable while defer expression in scope to modify it" {
53 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;52 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
54 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
55 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO53 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5654
57 const S = struct {55 const S = struct {
...@@ -91,7 +89,6 @@ fn runSomeErrorDefers(x: bool) !bool {...@@ -91,7 +89,6 @@ fn runSomeErrorDefers(x: bool) !bool {
91}89}
9290
93test "mixing normal and error defers" {91test "mixing normal and error defers" {
94 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
95 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO92 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
96 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO93 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9794
...@@ -110,7 +107,7 @@ test "mixing normal and error defers" {...@@ -110,7 +107,7 @@ test "mixing normal and error defers" {
110}107}
111108
112test "errdefer with payload" {109test "errdefer with payload" {
113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO110 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
114 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO111 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
115 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO112 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
116 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;113 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -132,8 +129,8 @@ test "errdefer with payload" {...@@ -132,8 +129,8 @@ test "errdefer with payload" {
132}129}
133130
134test "reference to errdefer payload" {131test "reference to errdefer payload" {
132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
135 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO133 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
136 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
137 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO134 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
138 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO135 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
139 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;136 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -157,7 +154,6 @@ test "reference to errdefer payload" {...@@ -157,7 +154,6 @@ test "reference to errdefer payload" {
157}154}
158155
159test "simple else prong doesn't emit an error for unreachable else prong" {156test "simple else prong doesn't emit an error for unreachable else prong" {
160 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
161 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO157 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
162 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;158 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
163159
test/behavior/enum.zig+10-19
...@@ -25,7 +25,6 @@ fn testEnumFromIntEval(x: i32) !void {...@@ -25,7 +25,6 @@ fn testEnumFromIntEval(x: i32) !void {
25const EnumFromIntNumber = enum { Zero, One, Two, Three, Four };25const EnumFromIntNumber = enum { Zero, One, Two, Three, Four };
2626
27test "int to enum" {27test "int to enum" {
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
29 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO28 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3029
31 try testEnumFromIntEval(3);30 try testEnumFromIntEval(3);
...@@ -608,7 +607,6 @@ fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void {...@@ -608,7 +607,6 @@ fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void {
608}607}
609608
610test "enum with specified tag values" {609test "enum with specified tag values" {
611 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
612 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO610 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
613611
614 try testEnumWithSpecifiedTagValues(MultipleChoice.C);612 try testEnumWithSpecifiedTagValues(MultipleChoice.C);
...@@ -616,7 +614,6 @@ test "enum with specified tag values" {...@@ -616,7 +614,6 @@ test "enum with specified tag values" {
616}614}
617615
618test "non-exhaustive enum" {616test "non-exhaustive enum" {
619 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
620 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO617 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
621618
622 const S = struct {619 const S = struct {
...@@ -680,7 +677,6 @@ test "empty non-exhaustive enum" {...@@ -680,7 +677,6 @@ test "empty non-exhaustive enum" {
680}677}
681678
682test "single field non-exhaustive enum" {679test "single field non-exhaustive enum" {
683 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
684 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO680 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
685681
686 const S = struct {682 const S = struct {
...@@ -744,7 +740,6 @@ test "cast integer literal to enum" {...@@ -744,7 +740,6 @@ test "cast integer literal to enum" {
744}740}
745741
746test "enum with specified and unspecified tag values" {742test "enum with specified and unspecified tag values" {
747 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
748 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO743 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
749744
750 try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);745 try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
...@@ -904,8 +899,8 @@ test "enum value allocation" {...@@ -904,8 +899,8 @@ test "enum value allocation" {
904}899}
905900
906test "enum literal casting to tagged union" {901test "enum literal casting to tagged union" {
907 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
908 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;902 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
903 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
909 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO904 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
910905
911 const Arch = union(enum) {906 const Arch = union(enum) {
...@@ -931,7 +926,6 @@ test "enum literal casting to tagged union" {...@@ -931,7 +926,6 @@ test "enum literal casting to tagged union" {
931const Bar = enum { A, B, C, D };926const Bar = enum { A, B, C, D };
932927
933test "enum literal casting to error union with payload enum" {928test "enum literal casting to error union with payload enum" {
934 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
935 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO929 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
936930
937 var bar: error{B}!Bar = undefined;931 var bar: error{B}!Bar = undefined;
...@@ -941,8 +935,8 @@ test "enum literal casting to error union with payload enum" {...@@ -941,8 +935,8 @@ test "enum literal casting to error union with payload enum" {
941}935}
942936
943test "constant enum initialization with differing sizes" {937test "constant enum initialization with differing sizes" {
944 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
945 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;938 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
939 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
946 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO940 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
947 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;941 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
948 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;942 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -985,8 +979,8 @@ fn test3_2(f: Test3Foo) !void {...@@ -985,8 +979,8 @@ fn test3_2(f: Test3Foo) !void {
985}979}
986980
987test "@tagName" {981test "@tagName" {
988 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
989 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;982 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
983 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
990 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO984 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
991 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;985 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
992 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;986 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1002,8 +996,8 @@ fn testEnumTagNameBare(n: anytype) []const u8 {...@@ -1002,8 +996,8 @@ fn testEnumTagNameBare(n: anytype) []const u8 {
1002const BareNumber = enum { One, Two, Three };996const BareNumber = enum { One, Two, Three };
1003997
1004test "@tagName non-exhaustive enum" {998test "@tagName non-exhaustive enum" {
1005 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1006 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;999 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1000 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1007 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1001 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1008 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1002 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1009 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1003 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1014,8 +1008,8 @@ test "@tagName non-exhaustive enum" {...@@ -1014,8 +1008,8 @@ test "@tagName non-exhaustive enum" {
1014const NonExhaustive = enum(u8) { A, B, _ };1008const NonExhaustive = enum(u8) { A, B, _ };
10151009
1016test "@tagName is null-terminated" {1010test "@tagName is null-terminated" {
1017 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1018 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1011 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1012 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1019 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1013 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1020 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1014 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1021 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1015 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1030,8 +1024,8 @@ test "@tagName is null-terminated" {...@@ -1030,8 +1024,8 @@ test "@tagName is null-terminated" {
1030}1024}
10311025
1032test "tag name with assigned enum values" {1026test "tag name with assigned enum values" {
1033 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1034 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1027 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1028 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1035 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1029 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1036 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1030 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1037 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1031 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1046,7 +1040,6 @@ test "tag name with assigned enum values" {...@@ -1046,7 +1040,6 @@ test "tag name with assigned enum values" {
1046}1040}
10471041
1048test "@tagName on enum literals" {1042test "@tagName on enum literals" {
1049 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1050 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1043 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1051 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1044 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10521045
...@@ -1055,8 +1048,8 @@ test "@tagName on enum literals" {...@@ -1055,8 +1048,8 @@ test "@tagName on enum literals" {
1055}1048}
10561049
1057test "tag name with signed enum values" {1050test "tag name with signed enum values" {
1058 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1059 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1051 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1052 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1060 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1053 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1061 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1054 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1062 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1055 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1073,8 +1066,8 @@ test "tag name with signed enum values" {...@@ -1073,8 +1066,8 @@ test "tag name with signed enum values" {
1073}1066}
10741067
1075test "@tagName in callconv(.c) function" {1068test "@tagName in callconv(.c) function" {
1076 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1077 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1069 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1070 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1078 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;1071 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
1079 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1072 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1080 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1073 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1091,7 +1084,6 @@ fn testEnumTagNameCallconvC() callconv(.c) [*:0]const u8 {...@@ -1091,7 +1084,6 @@ fn testEnumTagNameCallconvC() callconv(.c) [*:0]const u8 {
10911084
1092test "enum literal casting to optional" {1085test "enum literal casting to optional" {
1093 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;1086 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1094 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1095 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1087 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10961088
1097 var bar: ?Bar = undefined;1089 var bar: ?Bar = undefined;
...@@ -1117,8 +1109,8 @@ const bit_field_1 = BitFieldOfEnums{...@@ -1117,8 +1109,8 @@ const bit_field_1 = BitFieldOfEnums{
1117};1109};
11181110
1119test "bit field access with enum fields" {1111test "bit field access with enum fields" {
1120 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1121 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1112 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1113 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1122 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1114 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1123 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1115 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1124 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO1116 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
...@@ -1158,8 +1150,8 @@ test "enum literal in array literal" {...@@ -1158,8 +1150,8 @@ test "enum literal in array literal" {
1158}1150}
11591151
1160test "tag name functions are unique" {1152test "tag name functions are unique" {
1161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1162 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1153 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1154 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1163 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1155 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1164 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1156 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1165 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1157 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1179,7 +1171,6 @@ test "tag name functions are unique" {...@@ -1179,7 +1171,6 @@ test "tag name functions are unique" {
1179}1171}
11801172
1181test "size of enum with only one tag which has explicit integer tag type" {1173test "size of enum with only one tag which has explicit integer tag type" {
1182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1183 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1174 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11841175
1185 const E = enum(u8) { nope = 10 };1176 const E = enum(u8) { nope = 10 };
test/behavior/error.zig+3-22
...@@ -402,7 +402,6 @@ fn intLiteral(str: []const u8) !?i64 {...@@ -402,7 +402,6 @@ fn intLiteral(str: []const u8) !?i64 {
402402
403test "nested error union function call in optional unwrap" {403test "nested error union function call in optional unwrap" {
404 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO404 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
405 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
406 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO405 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
407406
408 const S = struct {407 const S = struct {
...@@ -448,7 +447,6 @@ test "nested error union function call in optional unwrap" {...@@ -448,7 +447,6 @@ test "nested error union function call in optional unwrap" {
448}447}
449448
450test "return function call to error set from error union function" {449test "return function call to error set from error union function" {
451 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
452 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO450 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
453451
454 const S = struct {452 const S = struct {
...@@ -465,7 +463,6 @@ test "return function call to error set from error union function" {...@@ -465,7 +463,6 @@ test "return function call to error set from error union function" {
465}463}
466464
467test "optional error set is the same size as error set" {465test "optional error set is the same size as error set" {
468 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
469 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO466 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
470 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO467 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
471468
...@@ -481,7 +478,6 @@ test "optional error set is the same size as error set" {...@@ -481,7 +478,6 @@ test "optional error set is the same size as error set" {
481}478}
482479
483test "nested catch" {480test "nested catch" {
484 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
485 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO481 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
486482
487 const S = struct {483 const S = struct {
...@@ -530,7 +526,7 @@ test "function pointer with return type that is error union with payload which i...@@ -530,7 +526,7 @@ test "function pointer with return type that is error union with payload which i
530}526}
531527
532test "return result loc as peer result loc in inferred error set function" {528test "return result loc as peer result loc in inferred error set function" {
533 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO529 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
534 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO530 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
535 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO531 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
536532
...@@ -562,7 +558,6 @@ test "return result loc as peer result loc in inferred error set function" {...@@ -562,7 +558,6 @@ test "return result loc as peer result loc in inferred error set function" {
562558
563test "error payload type is correctly resolved" {559test "error payload type is correctly resolved" {
564 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO560 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
565 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
566 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO561 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
567562
568 const MyIntWrapper = struct {563 const MyIntWrapper = struct {
...@@ -591,7 +586,6 @@ test "error union comptime caching" {...@@ -591,7 +586,6 @@ test "error union comptime caching" {
591586
592test "@errorName" {587test "@errorName" {
593 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;588 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
594 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
595 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO589 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
596 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;590 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
597 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;591 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -606,7 +600,6 @@ fn gimmeItBroke() anyerror {...@@ -606,7 +600,6 @@ fn gimmeItBroke() anyerror {
606600
607test "@errorName sentinel length matches slice length" {601test "@errorName sentinel length matches slice length" {
608 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;602 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
609 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
610 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO603 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
611 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;604 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
612 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;605 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -701,7 +694,6 @@ test "coerce error set to the current inferred error set" {...@@ -701,7 +694,6 @@ test "coerce error set to the current inferred error set" {
701694
702test "error union payload is properly aligned" {695test "error union payload is properly aligned" {
703 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO696 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
704 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
705 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO697 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
706 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;698 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
707 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;699 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -719,7 +711,6 @@ test "error union payload is properly aligned" {...@@ -719,7 +711,6 @@ test "error union payload is properly aligned" {
719}711}
720712
721test "ret_ptr doesn't cause own inferred error set to be resolved" {713test "ret_ptr doesn't cause own inferred error set to be resolved" {
722 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
723 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO714 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
724715
725 const S = struct {716 const S = struct {
...@@ -760,7 +751,6 @@ test "simple else prong allowed even when all errors handled" {...@@ -760,7 +751,6 @@ test "simple else prong allowed even when all errors handled" {
760}751}
761752
762test "pointer to error union payload" {753test "pointer to error union payload" {
763 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
764 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO754 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
765 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO755 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
766 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;756 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -794,7 +784,6 @@ const NoReturn = struct {...@@ -794,7 +784,6 @@ const NoReturn = struct {
794};784};
795785
796test "error union of noreturn used with if" {786test "error union of noreturn used with if" {
797 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
798 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO787 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
799 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO788 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
800 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;789 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -809,7 +798,6 @@ test "error union of noreturn used with if" {...@@ -809,7 +798,6 @@ test "error union of noreturn used with if" {
809}798}
810799
811test "error union of noreturn used with try" {800test "error union of noreturn used with try" {
812 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
813 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO801 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
814 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO802 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
815 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;803 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -821,7 +809,6 @@ test "error union of noreturn used with try" {...@@ -821,7 +809,6 @@ test "error union of noreturn used with try" {
821}809}
822810
823test "error union of noreturn used with catch" {811test "error union of noreturn used with catch" {
824 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
825 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO812 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
826 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO813 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
827 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;814 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -833,7 +820,6 @@ test "error union of noreturn used with catch" {...@@ -833,7 +820,6 @@ test "error union of noreturn used with catch" {
833}820}
834821
835test "alignment of wrapping an error union payload" {822test "alignment of wrapping an error union payload" {
836 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
837 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;823 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
838 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO824 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
839 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;825 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -887,7 +873,6 @@ test "catch within a function that calls no errorable functions" {...@@ -887,7 +873,6 @@ test "catch within a function that calls no errorable functions" {
887}873}
888874
889test "error from comptime string" {875test "error from comptime string" {
890 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
891 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO876 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
892 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO877 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
893 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;878 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -913,7 +898,6 @@ test "field access of anyerror results in smaller error set" {...@@ -913,7 +898,6 @@ test "field access of anyerror results in smaller error set" {
913}898}
914899
915test "optional error union return type" {900test "optional error union return type" {
916 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
917 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO901 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
918902
919 const S = struct {903 const S = struct {
...@@ -928,7 +912,6 @@ test "optional error union return type" {...@@ -928,7 +912,6 @@ test "optional error union return type" {
928912
929test "optional error set return type" {913test "optional error set return type" {
930 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO914 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
931 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
932915
933 const E = error{ A, B };916 const E = error{ A, B };
934 const S = struct {917 const S = struct {
...@@ -953,7 +936,6 @@ test "optional error set function parameter" {...@@ -953,7 +936,6 @@ test "optional error set function parameter" {
953936
954test "returning an error union containing a type with no runtime bits" {937test "returning an error union containing a type with no runtime bits" {
955 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO938 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
956 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
957 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;939 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
958940
959 const ZeroByteType = struct {941 const ZeroByteType = struct {
...@@ -969,7 +951,7 @@ test "returning an error union containing a type with no runtime bits" {...@@ -969,7 +951,7 @@ test "returning an error union containing a type with no runtime bits" {
969}951}
970952
971test "try used in recursive function with inferred error set" {953test "try used in recursive function with inferred error set" {
972 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO954 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
973 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO955 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
974 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;956 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
975957
...@@ -1010,7 +992,6 @@ test "generic inline function returns inferred error set" {...@@ -1010,7 +992,6 @@ test "generic inline function returns inferred error set" {
1010}992}
1011993
1012test "function called at runtime is properly analyzed for inferred error set" {994test "function called at runtime is properly analyzed for inferred error set" {
1013 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1014 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO995 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1015 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO996 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1016997
...@@ -1065,8 +1046,8 @@ test "@errorCast from error union to error union" {...@@ -1065,8 +1046,8 @@ test "@errorCast from error union to error union" {
1065}1046}
10661047
1067test "result location initialization of error union with OPV payload" {1048test "result location initialization of error union with OPV payload" {
1049 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1068 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1050 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1069 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1070 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1051 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1071 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1052 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1072 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO1053 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,7 +18,6 @@ fn unwrapAndAddOne(blah: ?i32) i32 {
18}18}
19const should_be_1235 = unwrapAndAddOne(1234);19const should_be_1235 = unwrapAndAddOne(1234);
20test "static add one" {20test "static add one" {
21 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
22 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO21 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
23 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO22 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2423
...@@ -71,7 +70,6 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 {...@@ -71,7 +70,6 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 {
71}70}
7271
73test "constant expressions" {72test "constant expressions" {
74 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
75 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO73 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7674
77 var array: [array_size]u8 = undefined;75 var array: [array_size]u8 = undefined;
...@@ -93,7 +91,6 @@ fn letsTryToCompareBools(a: bool, b: bool) bool {...@@ -93,7 +91,6 @@ fn letsTryToCompareBools(a: bool, b: bool) bool {
93 return max(bool, a, b);91 return max(bool, a, b);
94}92}
95test "inlined block and runtime block phi" {93test "inlined block and runtime block phi" {
96 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
97 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO94 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9895
99 try expect(letsTryToCompareBools(true, true));96 try expect(letsTryToCompareBools(true, true));
...@@ -140,7 +137,6 @@ test "pointer to type" {...@@ -140,7 +137,6 @@ test "pointer to type" {
140}137}
141138
142test "a type constructed in a global expression" {139test "a type constructed in a global expression" {
143 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
144 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO140 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
145 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;141 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
146 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;142 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -236,7 +232,6 @@ const vertices = [_]Vertex{...@@ -236,7 +232,6 @@ const vertices = [_]Vertex{
236};232};
237233
238test "statically initialized list" {234test "statically initialized list" {
239 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
240 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO235 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
241236
242 try expect(static_point_list[0].x == 1);237 try expect(static_point_list[0].x == 1);
...@@ -342,7 +337,6 @@ fn doesAlotT(comptime T: type, value: usize) T {...@@ -342,7 +337,6 @@ fn doesAlotT(comptime T: type, value: usize) T {
342}337}
343338
344test "@setEvalBranchQuota at same scope as generic function call" {339test "@setEvalBranchQuota at same scope as generic function call" {
345 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
346 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO340 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
347341
348 try expect(doesAlotT(u32, 2) == 2);342 try expect(doesAlotT(u32, 2) == 2);
...@@ -394,7 +388,6 @@ test "return 0 from function that has u0 return type" {...@@ -394,7 +388,6 @@ test "return 0 from function that has u0 return type" {
394}388}
395389
396test "statically initialized struct" {390test "statically initialized struct" {
397 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
398 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO391 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
399392
400 st_init_str_foo.x += 1;393 st_init_str_foo.x += 1;
...@@ -444,7 +437,6 @@ fn copyWithPartialInline(s: []u32, b: []u8) void {...@@ -444,7 +437,6 @@ fn copyWithPartialInline(s: []u32, b: []u8) void {
444437
445test "binary math operator in partially inlined function" {438test "binary math operator in partially inlined function" {
446 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO439 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
447 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
448 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO440 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
449 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;441 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
450442
...@@ -462,7 +454,6 @@ test "binary math operator in partially inlined function" {...@@ -462,7 +454,6 @@ test "binary math operator in partially inlined function" {
462}454}
463455
464test "comptime shl" {456test "comptime shl" {
465 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
466 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO457 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
467 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO458 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
468 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;459 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -491,6 +482,7 @@ test "comptime bitwise operators" {...@@ -491,6 +482,7 @@ test "comptime bitwise operators" {
491}482}
492483
493test "comptime shlWithOverflow" {484test "comptime shlWithOverflow" {
485 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
494 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO486 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
495 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;487 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
496488
...@@ -503,7 +495,6 @@ test "comptime shlWithOverflow" {...@@ -503,7 +495,6 @@ test "comptime shlWithOverflow" {
503}495}
504496
505test "const ptr to variable data changes at runtime" {497test "const ptr to variable data changes at runtime" {
506 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
507 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO498 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
508 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;499 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
509500
...@@ -521,7 +512,6 @@ const foo_ref = &foo_contents;...@@ -521,7 +512,6 @@ const foo_ref = &foo_contents;
521512
522test "runtime 128 bit integer division" {513test "runtime 128 bit integer division" {
523 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO514 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
524 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
525 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO515 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
526 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO516 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
527 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;517 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -536,7 +526,6 @@ test "runtime 128 bit integer division" {...@@ -536,7 +526,6 @@ test "runtime 128 bit integer division" {
536}526}
537527
538test "@tagName of @typeInfo" {528test "@tagName of @typeInfo" {
539 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
540 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO529 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
541 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;530 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
542531
...@@ -545,7 +534,6 @@ test "@tagName of @typeInfo" {...@@ -545,7 +534,6 @@ test "@tagName of @typeInfo" {
545}534}
546535
547test "static eval list init" {536test "static eval list init" {
548 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
549 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO537 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
550 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO538 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
551539
...@@ -578,7 +566,6 @@ test "inlined loop has array literal with elided runtime scope on first iteratio...@@ -578,7 +566,6 @@ test "inlined loop has array literal with elided runtime scope on first iteratio
578}566}
579567
580test "ptr to local array argument at comptime" {568test "ptr to local array argument at comptime" {
581 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
582 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO569 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
583570
584 comptime {571 comptime {
...@@ -741,7 +728,6 @@ test "*align(1) u16 is the same as *align(1:0:2) u16" {...@@ -741,7 +728,6 @@ test "*align(1) u16 is the same as *align(1:0:2) u16" {
741728
742test "array concatenation of function calls" {729test "array concatenation of function calls" {
743 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;730 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
744 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
745 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO731 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
746 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;732 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
747733
...@@ -751,7 +737,6 @@ test "array concatenation of function calls" {...@@ -751,7 +737,6 @@ test "array concatenation of function calls" {
751737
752test "array multiplication of function calls" {738test "array multiplication of function calls" {
753 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;739 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
754 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
755 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO740 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
756 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;741 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
757742
...@@ -769,7 +754,6 @@ fn scalar(x: u32) u32 {...@@ -769,7 +754,6 @@ fn scalar(x: u32) u32 {
769754
770test "array concatenation peer resolves element types - value" {755test "array concatenation peer resolves element types - value" {
771 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;756 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
772 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
773 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO757 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
774758
775 var a = [2]u3{ 1, 7 };759 var a = [2]u3{ 1, 7 };
...@@ -786,7 +770,6 @@ test "array concatenation peer resolves element types - value" {...@@ -786,7 +770,6 @@ test "array concatenation peer resolves element types - value" {
786770
787test "array concatenation peer resolves element types - pointer" {771test "array concatenation peer resolves element types - pointer" {
788 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;772 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
789 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
790 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO773 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
791 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;774 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
792775
...@@ -803,7 +786,6 @@ test "array concatenation peer resolves element types - pointer" {...@@ -803,7 +786,6 @@ test "array concatenation peer resolves element types - pointer" {
803786
804test "array concatenation sets the sentinel - value" {787test "array concatenation sets the sentinel - value" {
805 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;788 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
806 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
807 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO789 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
808 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;790 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
809 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;791 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -823,7 +805,6 @@ test "array concatenation sets the sentinel - value" {...@@ -823,7 +805,6 @@ test "array concatenation sets the sentinel - value" {
823}805}
824806
825test "array concatenation sets the sentinel - pointer" {807test "array concatenation sets the sentinel - pointer" {
826 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
827 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO808 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
828 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;809 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
829 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;810 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -843,7 +824,6 @@ test "array concatenation sets the sentinel - pointer" {...@@ -843,7 +824,6 @@ test "array concatenation sets the sentinel - pointer" {
843824
844test "array multiplication sets the sentinel - value" {825test "array multiplication sets the sentinel - value" {
845 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;826 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
846 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
847 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO827 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
848 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;828 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
849 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;829 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -862,7 +842,6 @@ test "array multiplication sets the sentinel - value" {...@@ -862,7 +842,6 @@ test "array multiplication sets the sentinel - value" {
862842
863test "array multiplication sets the sentinel - pointer" {843test "array multiplication sets the sentinel - pointer" {
864 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;844 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
865 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
866 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO845 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
867 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;846 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
868 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;847 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -889,7 +868,6 @@ test "comptime assign int to optional int" {...@@ -889,7 +868,6 @@ test "comptime assign int to optional int" {
889868
890test "two comptime calls with array default initialized to undefined" {869test "two comptime calls with array default initialized to undefined" {
891 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO870 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
892 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
893 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO871 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
894872
895 const S = struct {873 const S = struct {
...@@ -976,7 +954,6 @@ test "const local with comptime init through array init" {...@@ -976,7 +954,6 @@ test "const local with comptime init through array init" {
976}954}
977955
978test "closure capture type of runtime-known parameter" {956test "closure capture type of runtime-known parameter" {
979 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
980 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO957 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
981958
982 const S = struct {959 const S = struct {
...@@ -992,7 +969,6 @@ test "closure capture type of runtime-known parameter" {...@@ -992,7 +969,6 @@ test "closure capture type of runtime-known parameter" {
992}969}
993970
994test "closure capture type of runtime-known var" {971test "closure capture type of runtime-known var" {
995 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
996 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO972 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
997973
998 var x: u32 = 1234;974 var x: u32 = 1234;
...@@ -1035,7 +1011,6 @@ test "comptime break passing through runtime condition converted to runtime brea...@@ -1035,7 +1011,6 @@ test "comptime break passing through runtime condition converted to runtime brea
1035}1011}
10361012
1037test "comptime break to outer loop passing through runtime condition converted to runtime break" {1013test "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 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1014 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1040 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1015 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10411016
...@@ -1088,7 +1063,6 @@ test "comptime break operand passing through runtime condition converted to runt...@@ -1088,7 +1063,6 @@ test "comptime break operand passing through runtime condition converted to runt
1088}1063}
10891064
1090test "comptime break operand passing through runtime switch converted to runtime break" {1065test "comptime break operand passing through runtime switch converted to runtime break" {
1091 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1092 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1066 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10931067
1094 const S = struct {1068 const S = struct {
...@@ -1108,7 +1082,6 @@ test "comptime break operand passing through runtime switch converted to runtime...@@ -1108,7 +1082,6 @@ test "comptime break operand passing through runtime switch converted to runtime
1108}1082}
11091083
1110test "no dependency loop for alignment of self struct" {1084test "no dependency loop for alignment of self struct" {
1111 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1112 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1085 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1113 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1086 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1114 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1087 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1147,7 +1120,6 @@ test "no dependency loop for alignment of self struct" {...@@ -1147,7 +1120,6 @@ test "no dependency loop for alignment of self struct" {
1147}1120}
11481121
1149test "no dependency loop for alignment of self bare union" {1122test "no dependency loop for alignment of self bare union" {
1150 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1151 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1123 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1152 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1124 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1153 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,7 +1158,6 @@ test "no dependency loop for alignment of self bare union" {
1186}1158}
11871159
1188test "no dependency loop for alignment of self tagged union" {1160test "no dependency loop for alignment of self tagged union" {
1189 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1190 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1161 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1191 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1162 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1192 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1163 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1230,7 +1201,6 @@ test "equality of pointers to comptime const" {...@@ -1230,7 +1201,6 @@ test "equality of pointers to comptime const" {
1230}1201}
12311202
1232test "storing an array of type in a field" {1203test "storing an array of type in a field" {
1233 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1234 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1204 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1235 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1205 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1236 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1206 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1260,7 +1230,6 @@ test "storing an array of type in a field" {...@@ -1260,7 +1230,6 @@ test "storing an array of type in a field" {
1260}1230}
12611231
1262test "pass pointer to field of comptime-only type as a runtime parameter" {1232test "pass pointer to field of comptime-only type as a runtime parameter" {
1263 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1264 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1233 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1265 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1234 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
12661235
...@@ -1387,7 +1356,6 @@ test "lazy sizeof union tag size in compare" {...@@ -1387,7 +1356,6 @@ test "lazy sizeof union tag size in compare" {
1387}1356}
13881357
1389test "lazy value is resolved as slice operand" {1358test "lazy value is resolved as slice operand" {
1390 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1391 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1359 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1392 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1360 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1393 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1361 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1568,7 +1536,7 @@ test "x or true is comptime-known true" {...@@ -1568,7 +1536,7 @@ test "x or true is comptime-known true" {
1568}1536}
15691537
1570test "non-optional and optional array elements concatenated" {1538test "non-optional and optional array elements concatenated" {
1571 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1539 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1572 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1540 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1573 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1541 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15741542
test/behavior/export_builtin.zig-4
...@@ -4,7 +4,6 @@ const expect = std.testing.expect;...@@ -4,7 +4,6 @@ const expect = std.testing.expect;
44
5test "exporting enum value" {5test "exporting enum value" {
6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
87
9 if (builtin.cpu.arch.isWasm()) {8 if (builtin.cpu.arch.isWasm()) {
10 // https://github.com/ziglang/zig/issues/48669 // https://github.com/ziglang/zig/issues/4866
...@@ -23,7 +22,6 @@ test "exporting enum value" {...@@ -23,7 +22,6 @@ test "exporting enum value" {
2322
24test "exporting with internal linkage" {23test "exporting with internal linkage" {
25 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;24 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
26 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2725
28 const S = struct {26 const S = struct {
29 fn foo() callconv(.c) void {}27 fn foo() callconv(.c) void {}
...@@ -36,7 +34,6 @@ test "exporting with internal linkage" {...@@ -36,7 +34,6 @@ test "exporting with internal linkage" {
3634
37test "exporting using namespace access" {35test "exporting using namespace access" {
38 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;36 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
39 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4037
41 if (builtin.cpu.arch.isWasm()) {38 if (builtin.cpu.arch.isWasm()) {
42 // https://github.com/ziglang/zig/issues/486639 // https://github.com/ziglang/zig/issues/4866
...@@ -57,7 +54,6 @@ test "exporting using namespace access" {...@@ -57,7 +54,6 @@ test "exporting using namespace access" {
5754
58test "exporting comptime-known value" {55test "exporting comptime-known value" {
59 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;56 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
60 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
61 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;57 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
62 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;58 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
6359
test/behavior/field_parent_ptr.zig+3
...@@ -2,6 +2,7 @@ const expect = @import("std").testing.expect;...@@ -2,6 +2,7 @@ const expect = @import("std").testing.expect;
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4test "@fieldParentPtr struct" {4test "@fieldParentPtr struct" {
5 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;6 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
6 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;7 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
78
...@@ -1339,6 +1340,7 @@ test "@fieldParentPtr packed struct last zero-bit field" {...@@ -1339,6 +1340,7 @@ test "@fieldParentPtr packed struct last zero-bit field" {
1339}1340}
13401341
1341test "@fieldParentPtr tagged union" {1342test "@fieldParentPtr tagged union" {
1343 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1342 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1344 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1343 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1345 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
13441346
...@@ -1475,6 +1477,7 @@ test "@fieldParentPtr tagged union" {...@@ -1475,6 +1477,7 @@ test "@fieldParentPtr tagged union" {
1475}1477}
14761478
1477test "@fieldParentPtr untagged union" {1479test "@fieldParentPtr untagged union" {
1480 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1478 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1481 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1479 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1482 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14801483
test/behavior/floatop.zig+18-68
...@@ -143,7 +143,6 @@ test "cmp f64" {...@@ -143,7 +143,6 @@ test "cmp f64" {
143}143}
144144
145test "cmp f128" {145test "cmp f128" {
146 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
147 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO146 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
148 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;147 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
149 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;148 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -154,7 +153,6 @@ test "cmp f128" {...@@ -154,7 +153,6 @@ test "cmp f128" {
154}153}
155154
156test "cmp f80/c_longdouble" {155test "cmp f80/c_longdouble" {
157 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
158 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO156 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
159 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;157 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
160 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;158 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
...@@ -223,6 +221,7 @@ fn testCmp(comptime T: type) !void {...@@ -223,6 +221,7 @@ fn testCmp(comptime T: type) !void {
223}221}
224222
225test "vector cmp f16" {223test "vector cmp f16" {
224 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
226 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO225 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
227 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO226 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
228 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;227 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
...@@ -236,6 +235,7 @@ test "vector cmp f16" {...@@ -236,6 +235,7 @@ test "vector cmp f16" {
236}235}
237236
238test "vector cmp f32" {237test "vector cmp f32" {
238 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
239 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;239 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
240 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO240 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
241 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO241 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -249,6 +249,7 @@ test "vector cmp f32" {...@@ -249,6 +249,7 @@ test "vector cmp f32" {
249}249}
250250
251test "vector cmp f64" {251test "vector cmp f64" {
252 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
252 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO253 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
253 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO254 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
254 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;255 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -261,8 +262,8 @@ test "vector cmp f64" {...@@ -261,8 +262,8 @@ test "vector cmp f64" {
261}262}
262263
263test "vector cmp f128" {264test "vector cmp f128" {
265 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
264 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO266 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
265 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
266 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO267 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
267 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;268 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
268 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;269 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -276,6 +277,7 @@ test "vector cmp f128" {...@@ -276,6 +277,7 @@ test "vector cmp f128" {
276}277}
277278
278test "vector cmp f80/c_longdouble" {279test "vector cmp f80/c_longdouble" {
280 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
279 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest;281 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest;
280 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .powerpc64le) return error.SkipZigTest;282 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .powerpc64le) return error.SkipZigTest;
281 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;283 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -324,7 +326,6 @@ fn testCmpVector(comptime T: type) !void {...@@ -324,7 +326,6 @@ fn testCmpVector(comptime T: type) !void {
324326
325test "different sized float comparisons" {327test "different sized float comparisons" {
326 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO328 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
327 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
328 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO329 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
329 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;330 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
330331
...@@ -371,7 +372,6 @@ test "negative f128 intFromFloat at compile-time" {...@@ -371,7 +372,6 @@ test "negative f128 intFromFloat at compile-time" {
371372
372test "@sqrt f16" {373test "@sqrt f16" {
373 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO374 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
374 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
375 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO375 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
376 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;376 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
377 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;377 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -382,7 +382,6 @@ test "@sqrt f16" {...@@ -382,7 +382,6 @@ test "@sqrt f16" {
382382
383test "@sqrt f32/f64" {383test "@sqrt f32/f64" {
384 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO384 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
385 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
386 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO385 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
387 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;386 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
388387
...@@ -394,7 +393,6 @@ test "@sqrt f32/f64" {...@@ -394,7 +393,6 @@ test "@sqrt f32/f64" {
394393
395test "@sqrt f80/f128/c_longdouble" {394test "@sqrt f80/f128/c_longdouble" {
396 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO395 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
397 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
398 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO396 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
399 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;397 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
400 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;398 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -481,9 +479,9 @@ fn testSqrt(comptime T: type) !void {...@@ -481,9 +479,9 @@ fn testSqrt(comptime T: type) !void {
481}479}
482480
483test "@sqrt with vectors" {481test "@sqrt with vectors" {
482 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
484 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO483 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
485 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO484 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
486 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
487 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;485 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
488 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;486 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
489487
...@@ -503,7 +501,6 @@ fn testSqrtWithVectors() !void {...@@ -503,7 +501,6 @@ fn testSqrtWithVectors() !void {
503501
504test "@sin f16" {502test "@sin f16" {
505 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO503 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
506 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
507 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO504 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
508 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;505 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
509 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;506 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -514,7 +511,6 @@ test "@sin f16" {...@@ -514,7 +511,6 @@ test "@sin f16" {
514511
515test "@sin f32/f64" {512test "@sin f32/f64" {
516 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO513 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
517 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
518 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO514 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
519 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;515 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
520 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;516 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -527,7 +523,6 @@ test "@sin f32/f64" {...@@ -527,7 +523,6 @@ test "@sin f32/f64" {
527523
528test "@sin f80/f128/c_longdouble" {524test "@sin f80/f128/c_longdouble" {
529 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO525 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
530 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
531 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO526 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
532 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;527 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
533 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;528 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -554,9 +549,9 @@ fn testSin(comptime T: type) !void {...@@ -554,9 +549,9 @@ fn testSin(comptime T: type) !void {
554}549}
555550
556test "@sin with vectors" {551test "@sin with vectors" {
552 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
557 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO553 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
558 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO554 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
559 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
560 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;555 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
561 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;556 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
562557
...@@ -576,7 +571,6 @@ fn testSinWithVectors() !void {...@@ -576,7 +571,6 @@ fn testSinWithVectors() !void {
576571
577test "@cos f16" {572test "@cos f16" {
578 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO573 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
579 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
580 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO574 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
581 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;575 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
582 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;576 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -587,7 +581,6 @@ test "@cos f16" {...@@ -587,7 +581,6 @@ test "@cos f16" {
587581
588test "@cos f32/f64" {582test "@cos f32/f64" {
589 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO583 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
590 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
591 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO584 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
592 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;585 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
593 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;586 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -600,7 +593,6 @@ test "@cos f32/f64" {...@@ -600,7 +593,6 @@ test "@cos f32/f64" {
600593
601test "@cos f80/f128/c_longdouble" {594test "@cos f80/f128/c_longdouble" {
602 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO595 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
603 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
604 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO596 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
605 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;597 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
606 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;598 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -627,9 +619,9 @@ fn testCos(comptime T: type) !void {...@@ -627,9 +619,9 @@ fn testCos(comptime T: type) !void {
627}619}
628620
629test "@cos with vectors" {621test "@cos with vectors" {
622 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
630 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO623 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
631 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO624 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
632 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
633 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;625 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
634 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;626 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
635627
...@@ -649,7 +641,6 @@ fn testCosWithVectors() !void {...@@ -649,7 +641,6 @@ fn testCosWithVectors() !void {
649641
650test "@tan f16" {642test "@tan f16" {
651 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO643 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
652 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
653 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO644 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
654 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;645 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
655 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;646 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -660,7 +651,6 @@ test "@tan f16" {...@@ -660,7 +651,6 @@ test "@tan f16" {
660651
661test "@tan f32/f64" {652test "@tan f32/f64" {
662 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO653 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
663 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
664 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO654 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
665 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;655 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
666 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;656 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -673,7 +663,6 @@ test "@tan f32/f64" {...@@ -673,7 +663,6 @@ test "@tan f32/f64" {
673663
674test "@tan f80/f128/c_longdouble" {664test "@tan f80/f128/c_longdouble" {
675 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO665 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
676 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
677 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO666 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
678 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;667 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
679 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;668 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -700,9 +689,9 @@ fn testTan(comptime T: type) !void {...@@ -700,9 +689,9 @@ fn testTan(comptime T: type) !void {
700}689}
701690
702test "@tan with vectors" {691test "@tan with vectors" {
692 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
703 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO693 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
704 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO694 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
705 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
706 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;695 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
707 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;696 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
708697
...@@ -722,7 +711,6 @@ fn testTanWithVectors() !void {...@@ -722,7 +711,6 @@ fn testTanWithVectors() !void {
722711
723test "@exp f16" {712test "@exp f16" {
724 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO713 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
725 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
726 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO714 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
727 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;715 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
728 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;716 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -733,7 +721,6 @@ test "@exp f16" {...@@ -733,7 +721,6 @@ test "@exp f16" {
733721
734test "@exp f32/f64" {722test "@exp f32/f64" {
735 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO723 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
736 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
737 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO724 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
738 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;725 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
739 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;726 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -746,7 +733,6 @@ test "@exp f32/f64" {...@@ -746,7 +733,6 @@ test "@exp f32/f64" {
746733
747test "@exp f80/f128/c_longdouble" {734test "@exp f80/f128/c_longdouble" {
748 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO735 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
749 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
750 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO736 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
751 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;737 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
752 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;738 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -777,9 +763,9 @@ fn testExp(comptime T: type) !void {...@@ -777,9 +763,9 @@ fn testExp(comptime T: type) !void {
777}763}
778764
779test "@exp with vectors" {765test "@exp with vectors" {
766 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
780 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO767 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
781 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO768 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
782 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
783 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;769 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
784 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;770 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
785771
...@@ -799,7 +785,6 @@ fn testExpWithVectors() !void {...@@ -799,7 +785,6 @@ fn testExpWithVectors() !void {
799785
800test "@exp2 f16" {786test "@exp2 f16" {
801 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO787 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
802 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
803 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO788 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
804 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;789 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
805 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;790 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -810,7 +795,6 @@ test "@exp2 f16" {...@@ -810,7 +795,6 @@ test "@exp2 f16" {
810795
811test "@exp2 f32/f64" {796test "@exp2 f32/f64" {
812 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO797 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
813 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
814 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO798 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
815 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;799 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
816 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;800 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -823,7 +807,6 @@ test "@exp2 f32/f64" {...@@ -823,7 +807,6 @@ test "@exp2 f32/f64" {
823807
824test "@exp2 f80/f128/c_longdouble" {808test "@exp2 f80/f128/c_longdouble" {
825 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO809 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
826 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
827 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO810 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
828 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;811 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
829 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;812 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -849,9 +832,9 @@ fn testExp2(comptime T: type) !void {...@@ -849,9 +832,9 @@ fn testExp2(comptime T: type) !void {
849}832}
850833
851test "@exp2 with @vectors" {834test "@exp2 with @vectors" {
835 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
852 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO836 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
853 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO837 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
854 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
855 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;838 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
856 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;839 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
857840
...@@ -870,7 +853,6 @@ fn testExp2WithVectors() !void {...@@ -870,7 +853,6 @@ fn testExp2WithVectors() !void {
870}853}
871854
872test "@log f16" {855test "@log f16" {
873 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
874 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO856 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
875 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO857 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
876 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;858 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -881,7 +863,6 @@ test "@log f16" {...@@ -881,7 +863,6 @@ test "@log f16" {
881}863}
882864
883test "@log f32/f64" {865test "@log f32/f64" {
884 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
885 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO866 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
886 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO867 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
887 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;868 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -894,7 +875,6 @@ test "@log f32/f64" {...@@ -894,7 +875,6 @@ test "@log f32/f64" {
894}875}
895876
896test "@log f80/f128/c_longdouble" {877test "@log f80/f128/c_longdouble" {
897 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
898 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO878 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
899 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO879 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
900 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;880 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -921,8 +901,8 @@ fn testLog(comptime T: type) !void {...@@ -921,8 +901,8 @@ fn testLog(comptime T: type) !void {
921}901}
922902
923test "@log with @vectors" {903test "@log with @vectors" {
904 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
924 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO905 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
925 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
926 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO906 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
927 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO907 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
928 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;908 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -940,7 +920,6 @@ test "@log with @vectors" {...@@ -940,7 +920,6 @@ test "@log with @vectors" {
940}920}
941921
942test "@log2 f16" {922test "@log2 f16" {
943 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
944 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO923 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
945 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO924 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
946 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;925 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -951,7 +930,6 @@ test "@log2 f16" {...@@ -951,7 +930,6 @@ test "@log2 f16" {
951}930}
952931
953test "@log2 f32/f64" {932test "@log2 f32/f64" {
954 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
955 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO933 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
956 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO934 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
957 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;935 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -964,7 +942,6 @@ test "@log2 f32/f64" {...@@ -964,7 +942,6 @@ test "@log2 f32/f64" {
964}942}
965943
966test "@log2 f80/f128/c_longdouble" {944test "@log2 f80/f128/c_longdouble" {
967 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
968 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO945 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
969 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO946 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
970 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;947 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -991,8 +968,8 @@ fn testLog2(comptime T: type) !void {...@@ -991,8 +968,8 @@ fn testLog2(comptime T: type) !void {
991}968}
992969
993test "@log2 with vectors" {970test "@log2 with vectors" {
971 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
994 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO972 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
995 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
996 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO973 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
997 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;974 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
998 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;975 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1016,7 +993,6 @@ fn testLog2WithVectors() !void {...@@ -1016,7 +993,6 @@ fn testLog2WithVectors() !void {
1016}993}
1017994
1018test "@log10 f16" {995test "@log10 f16" {
1019 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1020 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO996 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1021 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO997 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1022 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;998 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1027,7 +1003,6 @@ test "@log10 f16" {...@@ -1027,7 +1003,6 @@ test "@log10 f16" {
1027}1003}
10281004
1029test "@log10 f32/f64" {1005test "@log10 f32/f64" {
1030 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1031 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1006 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1032 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1007 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1033 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1008 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1040,7 +1015,6 @@ test "@log10 f32/f64" {...@@ -1040,7 +1015,6 @@ test "@log10 f32/f64" {
1040}1015}
10411016
1042test "@log10 f80/f128/c_longdouble" {1017test "@log10 f80/f128/c_longdouble" {
1043 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1044 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1018 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1045 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1019 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1046 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1020 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1067,8 +1041,8 @@ fn testLog10(comptime T: type) !void {...@@ -1067,8 +1041,8 @@ fn testLog10(comptime T: type) !void {
1067}1041}
10681042
1069test "@log10 with vectors" {1043test "@log10 with vectors" {
1044 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1070 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1045 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1071 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1072 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1046 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1073 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1047 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1074 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1048 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1089,7 +1063,6 @@ fn testLog10WithVectors() !void {...@@ -1089,7 +1063,6 @@ fn testLog10WithVectors() !void {
10891063
1090test "@abs f16" {1064test "@abs f16" {
1091 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1065 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1092 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1093 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1066 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1094 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1067 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10951068
...@@ -1099,7 +1072,6 @@ test "@abs f16" {...@@ -1099,7 +1072,6 @@ test "@abs f16" {
10991072
1100test "@abs f32/f64" {1073test "@abs f32/f64" {
1101 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1074 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1102 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1103 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1075 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11041076
1105 try testFabs(f32);1077 try testFabs(f32);
...@@ -1110,7 +1082,6 @@ test "@abs f32/f64" {...@@ -1110,7 +1082,6 @@ test "@abs f32/f64" {
11101082
1111test "@abs f80/f128/c_longdouble" {1083test "@abs f80/f128/c_longdouble" {
1112 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1084 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1114 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;1085 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
1115 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1086 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1116 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1087 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1190,7 +1161,7 @@ fn testFabs(comptime T: type) !void {...@@ -1190,7 +1161,7 @@ fn testFabs(comptime T: type) !void {
1190}1161}
11911162
1192test "@abs with vectors" {1163test "@abs with vectors" {
1193 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1164 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1194 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1165 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1195 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1166 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1196 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1167 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1210,7 +1181,6 @@ fn testFabsWithVectors() !void {...@@ -1210,7 +1181,6 @@ fn testFabsWithVectors() !void {
1210}1181}
12111182
1212test "@floor f16" {1183test "@floor f16" {
1213 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1214 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1184 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1215 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1185 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1216 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1186 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1220,7 +1190,6 @@ test "@floor f16" {...@@ -1220,7 +1190,6 @@ test "@floor f16" {
1220}1190}
12211191
1222test "@floor f32/f64" {1192test "@floor f32/f64" {
1223 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1224 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1193 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1225 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1194 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1226 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1195 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1232,7 +1201,6 @@ test "@floor f32/f64" {...@@ -1232,7 +1201,6 @@ test "@floor f32/f64" {
1232}1201}
12331202
1234test "@floor f80/f128/c_longdouble" {1203test "@floor f80/f128/c_longdouble" {
1235 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1236 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1204 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1237 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;1205 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
1238 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1206 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1284,7 +1252,7 @@ fn testFloor(comptime T: type) !void {...@@ -1284,7 +1252,7 @@ fn testFloor(comptime T: type) !void {
1284}1252}
12851253
1286test "@floor with vectors" {1254test "@floor with vectors" {
1287 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1255 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1288 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1256 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1289 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1257 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1290 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1258 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1304,7 +1272,6 @@ fn testFloorWithVectors() !void {...@@ -1304,7 +1272,6 @@ fn testFloorWithVectors() !void {
1304}1272}
13051273
1306test "@ceil f16" {1274test "@ceil f16" {
1307 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1308 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1275 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1309 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1276 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1310 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1277 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1314,7 +1281,6 @@ test "@ceil f16" {...@@ -1314,7 +1281,6 @@ test "@ceil f16" {
1314}1281}
13151282
1316test "@ceil f32/f64" {1283test "@ceil f32/f64" {
1317 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1318 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1284 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1319 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1285 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1320 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1286 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1326,7 +1292,6 @@ test "@ceil f32/f64" {...@@ -1326,7 +1292,6 @@ test "@ceil f32/f64" {
1326}1292}
13271293
1328test "@ceil f80/f128/c_longdouble" {1294test "@ceil f80/f128/c_longdouble" {
1329 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1330 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1295 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1331 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;1296 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
1332 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1297 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1378,7 +1343,7 @@ fn testCeil(comptime T: type) !void {...@@ -1378,7 +1343,7 @@ fn testCeil(comptime T: type) !void {
1378}1343}
13791344
1380test "@ceil with vectors" {1345test "@ceil with vectors" {
1381 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1346 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1382 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1347 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1383 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1348 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1384 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1349 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1398,7 +1363,6 @@ fn testCeilWithVectors() !void {...@@ -1398,7 +1363,6 @@ fn testCeilWithVectors() !void {
1398}1363}
13991364
1400test "@trunc f16" {1365test "@trunc f16" {
1401 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1402 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1366 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1403 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1367 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1404 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1368 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1408,7 +1372,6 @@ test "@trunc f16" {...@@ -1408,7 +1372,6 @@ test "@trunc f16" {
1408}1372}
14091373
1410test "@trunc f32/f64" {1374test "@trunc f32/f64" {
1411 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1412 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1375 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1413 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1376 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1414 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1377 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1420,7 +1383,6 @@ test "@trunc f32/f64" {...@@ -1420,7 +1383,6 @@ test "@trunc f32/f64" {
1420}1383}
14211384
1422test "@trunc f80/f128/c_longdouble" {1385test "@trunc f80/f128/c_longdouble" {
1423 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1424 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1386 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1425 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;1387 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
1426 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1388 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1472,7 +1434,7 @@ fn testTrunc(comptime T: type) !void {...@@ -1472,7 +1434,7 @@ fn testTrunc(comptime T: type) !void {
1472}1434}
14731435
1474test "@trunc with vectors" {1436test "@trunc with vectors" {
1475 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1437 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1476 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1438 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1477 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1439 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1478 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1440 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1492,7 +1454,6 @@ fn testTruncWithVectors() !void {...@@ -1492,7 +1454,6 @@ fn testTruncWithVectors() !void {
1492}1454}
14931455
1494test "neg f16" {1456test "neg f16" {
1495 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1496 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1457 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1497 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1458 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1498 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1459 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1508,7 +1469,6 @@ test "neg f16" {...@@ -1508,7 +1469,6 @@ test "neg f16" {
1508}1469}
15091470
1510test "neg f32/f64" {1471test "neg f32/f64" {
1511 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1512 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1472 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1513 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1473 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1514 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1474 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1520,7 +1480,6 @@ test "neg f32/f64" {...@@ -1520,7 +1480,6 @@ test "neg f32/f64" {
1520}1480}
15211481
1522test "neg f80/f128/c_longdouble" {1482test "neg f80/f128/c_longdouble" {
1523 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1524 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1483 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1525 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1484 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1526 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1485 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1606,7 +1565,6 @@ fn testNeg(comptime T: type) !void {...@@ -1606,7 +1565,6 @@ fn testNeg(comptime T: type) !void {
1606}1565}
16071566
1608test "eval @setFloatMode at compile-time" {1567test "eval @setFloatMode at compile-time" {
1609 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1610 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1568 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16111569
1612 const result = comptime fnWithFloatMode();1570 const result = comptime fnWithFloatMode();
...@@ -1629,7 +1587,6 @@ test "f128 at compile time is lossy" {...@@ -1629,7 +1587,6 @@ test "f128 at compile time is lossy" {
16291587
1630test "comptime fixed-width float zero divided by zero produces NaN" {1588test "comptime fixed-width float zero divided by zero produces NaN" {
1631 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1589 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1632 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1633 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1590 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1634 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1591 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1635 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;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,7 +1598,6 @@ test "comptime fixed-width float zero divided by zero produces NaN" {
16411598
1642test "comptime fixed-width float non-zero divided by zero produces signed Inf" {1599test "comptime fixed-width float non-zero divided by zero produces signed Inf" {
1643 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1600 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1644 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1645 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1601 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1646 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1602 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16471603
...@@ -1686,21 +1642,18 @@ test "comptime inf >= runtime 1" {...@@ -1686,21 +1642,18 @@ test "comptime inf >= runtime 1" {
1686 try std.testing.expect(f >= i);1642 try std.testing.expect(f >= i);
1687}1643}
1688test "comptime isNan(nan * 1)" {1644test "comptime isNan(nan * 1)" {
1689 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1690 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1645 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
16911646
1692 const nan_times_one = comptime std.math.nan(f64) * 1;1647 const nan_times_one = comptime std.math.nan(f64) * 1;
1693 try std.testing.expect(std.math.isNan(nan_times_one));1648 try std.testing.expect(std.math.isNan(nan_times_one));
1694}1649}
1695test "runtime isNan(nan * 1)" {1650test "runtime isNan(nan * 1)" {
1696 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1697 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1651 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
16981652
1699 const nan_times_one = std.math.nan(f64) * 1;1653 const nan_times_one = std.math.nan(f64) * 1;
1700 try std.testing.expect(std.math.isNan(nan_times_one));1654 try std.testing.expect(std.math.isNan(nan_times_one));
1701}1655}
1702test "comptime isNan(nan * 0)" {1656test "comptime isNan(nan * 0)" {
1703 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1704 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1657 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17051658
1706 const nan_times_zero = comptime std.math.nan(f64) * 0;1659 const nan_times_zero = comptime std.math.nan(f64) * 0;
...@@ -1709,7 +1662,6 @@ test "comptime isNan(nan * 0)" {...@@ -1709,7 +1662,6 @@ test "comptime isNan(nan * 0)" {
1709 try std.testing.expect(std.math.isNan(zero_times_nan));1662 try std.testing.expect(std.math.isNan(zero_times_nan));
1710}1663}
1711test "runtime isNan(nan * 0)" {1664test "runtime isNan(nan * 0)" {
1712 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1713 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1665 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17141666
1715 const nan_times_zero = std.math.nan(f64) * 0;1667 const nan_times_zero = std.math.nan(f64) * 0;
...@@ -1718,7 +1670,6 @@ test "runtime isNan(nan * 0)" {...@@ -1718,7 +1670,6 @@ test "runtime isNan(nan * 0)" {
1718 try std.testing.expect(std.math.isNan(zero_times_nan));1670 try std.testing.expect(std.math.isNan(zero_times_nan));
1719}1671}
1720test "comptime isNan(inf * 0)" {1672test "comptime isNan(inf * 0)" {
1721 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1722 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1673 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17231674
1724 const inf_times_zero = comptime std.math.inf(f64) * 0;1675 const inf_times_zero = comptime std.math.inf(f64) * 0;
...@@ -1727,7 +1678,6 @@ test "comptime isNan(inf * 0)" {...@@ -1727,7 +1678,6 @@ test "comptime isNan(inf * 0)" {
1727 try std.testing.expect(std.math.isNan(zero_times_inf));1678 try std.testing.expect(std.math.isNan(zero_times_inf));
1728}1679}
1729test "runtime isNan(inf * 0)" {1680test "runtime isNan(inf * 0)" {
1730 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1731 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1681 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17321682
1733 const inf_times_zero = std.math.inf(f64) * 0;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,7 +78,6 @@ test "return inner function which references comptime variable of outer function
7878
79test "discard the result of a function that returns a struct" {79test "discard the result of a function that returns a struct" {
80 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;80 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
81 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
82 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO81 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8382
84 const S = struct {83 const S = struct {
...@@ -101,7 +100,6 @@ test "discard the result of a function that returns a struct" {...@@ -101,7 +100,6 @@ test "discard the result of a function that returns a struct" {
101100
102test "inline function call that calls optional function pointer, return pointer at callsite interacts correctly with callsite return type" {101test "inline function call that calls optional function pointer, return pointer at callsite interacts correctly with callsite return type" {
103 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;102 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
104 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
105 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO103 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
106 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;104 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
107105
...@@ -179,7 +177,6 @@ fn fComplexCallconvRet(x: u32) callconv(blk: {...@@ -179,7 +177,6 @@ fn fComplexCallconvRet(x: u32) callconv(blk: {
179177
180test "function with complex callconv and return type expressions" {178test "function with complex callconv and return type expressions" {
181 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;179 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
183 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO180 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
184181
185 try expect(fComplexCallconvRet(3).x == 9);182 try expect(fComplexCallconvRet(3).x == 9);
...@@ -255,7 +252,6 @@ test "pass by non-copying value as method, at comptime" {...@@ -255,7 +252,6 @@ test "pass by non-copying value as method, at comptime" {
255252
256test "implicit cast fn call result to optional in field result" {253test "implicit cast fn call result to optional in field result" {
257 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;254 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
258 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
259 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO255 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
260 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;256 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
261257
...@@ -283,7 +279,6 @@ test "implicit cast fn call result to optional in field result" {...@@ -283,7 +279,6 @@ test "implicit cast fn call result to optional in field result" {
283279
284test "void parameters" {280test "void parameters" {
285 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;281 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
286 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
287282
288 try voidFun(1, void{}, 2, {});283 try voidFun(1, void{}, 2, {});
289}284}
...@@ -306,7 +301,6 @@ fn acceptsString(foo: []u8) void {...@@ -306,7 +301,6 @@ fn acceptsString(foo: []u8) void {
306}301}
307302
308test "function pointers" {303test "function pointers" {
309 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
310 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO304 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
311 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO305 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
312 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;306 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -345,7 +339,6 @@ fn numberLiteralArg(a: anytype) !void {...@@ -345,7 +339,6 @@ fn numberLiteralArg(a: anytype) !void {
345339
346test "function call with anon list literal" {340test "function call with anon list literal" {
347 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO341 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
348 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
349 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO342 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
350343
351 const S = struct {344 const S = struct {
...@@ -365,7 +358,6 @@ test "function call with anon list literal" {...@@ -365,7 +358,6 @@ test "function call with anon list literal" {
365358
366test "function call with anon list literal - 2D" {359test "function call with anon list literal - 2D" {
367 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO360 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
368 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
369 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO361 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
370362
371 const S = struct {363 const S = struct {
...@@ -426,7 +418,6 @@ test "import passed byref to function in return type" {...@@ -426,7 +418,6 @@ test "import passed byref to function in return type" {
426418
427test "implicit cast function to function ptr" {419test "implicit cast function to function ptr" {
428 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO420 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
429 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
430 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO421 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
431 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;422 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
432423
...@@ -485,7 +476,6 @@ test "method call with optional pointer first param" {...@@ -485,7 +476,6 @@ test "method call with optional pointer first param" {
485476
486test "using @ptrCast on function pointers" {477test "using @ptrCast on function pointers" {
487 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO478 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
488 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
489 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO479 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
490 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;480 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
491481
...@@ -524,8 +514,6 @@ test "function returns function returning type" {...@@ -524,8 +514,6 @@ test "function returns function returning type" {
524}514}
525515
526test "peer type resolution of inferred error set with non-void payload" {516test "peer type resolution of inferred error set with non-void payload" {
527 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
528
529 const S = struct {517 const S = struct {
530 fn openDataFile(mode: enum { read, write }) !u32 {518 fn openDataFile(mode: enum { read, write }) !u32 {
531 return switch (mode) {519 return switch (mode) {
...@@ -582,7 +570,6 @@ test "pass and return comptime-only types" {...@@ -582,7 +570,6 @@ test "pass and return comptime-only types" {
582570
583test "pointer to alias behaves same as pointer to function" {571test "pointer to alias behaves same as pointer to function" {
584 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;572 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
585 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
586 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;573 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
587574
588 const S = struct {575 const S = struct {
test/behavior/for.zig-20
...@@ -5,7 +5,6 @@ const expectEqual = std.testing.expectEqual;...@@ -5,7 +5,6 @@ const expectEqual = std.testing.expectEqual;
5const mem = std.mem;5const mem = std.mem;
66
7test "continue in for loop" {7test "continue in for loop" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
109
11 const array = [_]i32{ 1, 2, 3, 4, 5 };10 const array = [_]i32{ 1, 2, 3, 4, 5 };
...@@ -67,7 +66,6 @@ test "ignore lval with underscore (for loop)" {...@@ -67,7 +66,6 @@ test "ignore lval with underscore (for loop)" {
6766
68test "basic for loop" {67test "basic for loop" {
69 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;68 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
70 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
71 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO69 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
72 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;70 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
7371
...@@ -111,7 +109,6 @@ test "basic for loop" {...@@ -111,7 +109,6 @@ test "basic for loop" {
111109
112test "for with null and T peer types and inferred result location type" {110test "for with null and T peer types and inferred result location type" {
113 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;111 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
114 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
115 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO112 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
116 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;113 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
117114
...@@ -132,7 +129,6 @@ test "for with null and T peer types and inferred result location type" {...@@ -132,7 +129,6 @@ test "for with null and T peer types and inferred result location type" {
132}129}
133130
134test "2 break statements and an else" {131test "2 break statements and an else" {
135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
136 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO132 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
137133
138 const S = struct {134 const S = struct {
...@@ -152,7 +148,6 @@ test "2 break statements and an else" {...@@ -152,7 +148,6 @@ test "2 break statements and an else" {
152}148}
153149
154test "for loop with pointer elem var" {150test "for loop with pointer elem var" {
155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
156 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO151 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
157 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO152 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
158 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;153 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -180,7 +175,6 @@ fn mangleString(s: []u8) void {...@@ -180,7 +175,6 @@ fn mangleString(s: []u8) void {
180}175}
181176
182test "for copies its payload" {177test "for copies its payload" {
183 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
184 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO178 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
185179
186 const S = struct {180 const S = struct {
...@@ -198,7 +192,6 @@ test "for copies its payload" {...@@ -198,7 +192,6 @@ test "for copies its payload" {
198}192}
199193
200test "for on slice with allowzero ptr" {194test "for on slice with allowzero ptr" {
201 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
202 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO195 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
203 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO196 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
204 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;197 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -215,7 +208,6 @@ test "for on slice with allowzero ptr" {...@@ -215,7 +208,6 @@ test "for on slice with allowzero ptr" {
215}208}
216209
217test "else continue outer for" {210test "else continue outer for" {
218 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
219 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO211 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
220 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;212 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
221213
...@@ -230,8 +222,6 @@ test "else continue outer for" {...@@ -230,8 +222,6 @@ test "else continue outer for" {
230}222}
231223
232test "for loop with else branch" {224test "for loop with else branch" {
233 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
234
235 {225 {
236 var x = [_]u32{ 1, 2 };226 var x = [_]u32{ 1, 2 };
237 _ = &x;227 _ = &x;
...@@ -312,7 +302,6 @@ test "1-based counter and ptr to array" {...@@ -312,7 +302,6 @@ test "1-based counter and ptr to array" {
312test "slice and two counters, one is offset and one is runtime" {302test "slice and two counters, one is offset and one is runtime" {
313 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO303 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
314 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO304 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
315 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
316 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;305 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
317306
318 const slice: []const u8 = "blah";307 const slice: []const u8 = "blah";
...@@ -342,7 +331,6 @@ test "slice and two counters, one is offset and one is runtime" {...@@ -342,7 +331,6 @@ test "slice and two counters, one is offset and one is runtime" {
342test "two slices, one captured by-ref" {331test "two slices, one captured by-ref" {
343 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO332 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
344 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO333 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
345 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
346 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;334 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
347335
348 var buf: [10]u8 = undefined;336 var buf: [10]u8 = undefined;
...@@ -362,7 +350,6 @@ test "two slices, one captured by-ref" {...@@ -362,7 +350,6 @@ test "two slices, one captured by-ref" {
362test "raw pointer and slice" {350test "raw pointer and slice" {
363 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO351 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
364 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO352 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
365 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
366 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;353 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
367354
368 var buf: [10]u8 = undefined;355 var buf: [10]u8 = undefined;
...@@ -382,7 +369,6 @@ test "raw pointer and slice" {...@@ -382,7 +369,6 @@ test "raw pointer and slice" {
382test "raw pointer and counter" {369test "raw pointer and counter" {
383 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO370 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
384 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO371 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
385 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
386 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;372 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
387373
388 var buf: [10]u8 = undefined;374 var buf: [10]u8 = undefined;
...@@ -401,7 +387,6 @@ test "raw pointer and counter" {...@@ -401,7 +387,6 @@ test "raw pointer and counter" {
401test "inline for with slice as the comptime-known" {387test "inline for with slice as the comptime-known" {
402 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO388 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
403 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO389 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
404 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
405390
406 const comptime_slice = "hello";391 const comptime_slice = "hello";
407 var runtime_i: usize = 3;392 var runtime_i: usize = 3;
...@@ -432,7 +417,6 @@ test "inline for with slice as the comptime-known" {...@@ -432,7 +417,6 @@ test "inline for with slice as the comptime-known" {
432test "inline for with counter as the comptime-known" {417test "inline for with counter as the comptime-known" {
433 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO418 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
434 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO419 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
435 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
436 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;420 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
437421
438 var runtime_slice = "hello";422 var runtime_slice = "hello";
...@@ -464,7 +448,6 @@ test "inline for with counter as the comptime-known" {...@@ -464,7 +448,6 @@ test "inline for with counter as the comptime-known" {
464test "inline for on tuple pointer" {448test "inline for on tuple pointer" {
465 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO449 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
466 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO450 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
467 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
468 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;451 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
469452
470 const S = struct { u32, u32, u32 };453 const S = struct { u32, u32, u32 };
...@@ -480,7 +463,6 @@ test "inline for on tuple pointer" {...@@ -480,7 +463,6 @@ test "inline for on tuple pointer" {
480test "ref counter that starts at zero" {463test "ref counter that starts at zero" {
481 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO464 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
482 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO465 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
483 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
484466
485 for ([_]usize{ 0, 1, 2 }, 0..) |i, j| {467 for ([_]usize{ 0, 1, 2 }, 0..) |i, j| {
486 try expectEqual(i, j);468 try expectEqual(i, j);
...@@ -495,7 +477,6 @@ test "ref counter that starts at zero" {...@@ -495,7 +477,6 @@ test "ref counter that starts at zero" {
495test "inferred alloc ptr of for loop" {477test "inferred alloc ptr of for loop" {
496 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO478 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
497 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO479 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
498 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
499480
500 {481 {
501 var cond = false;482 var cond = false;
...@@ -516,7 +497,6 @@ test "inferred alloc ptr of for loop" {...@@ -516,7 +497,6 @@ test "inferred alloc ptr of for loop" {
516}497}
517498
518test "for loop results in a bool" {499test "for loop results in a bool" {
519 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
520 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO500 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
521501
522 try std.testing.expect(for ([1]u8{0}) |x| {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,7 +17,6 @@ fn checkSize(comptime T: type) usize {
17}17}
1818
19test "simple generic fn" {19test "simple generic fn" {
20 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
21 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO20 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2221
23 try expect(max(i32, 3, -1) == 3);22 try expect(max(i32, 3, -1) == 3);
...@@ -53,7 +52,6 @@ fn sameButWithFloats(a: f64, b: f64) f64 {...@@ -53,7 +52,6 @@ fn sameButWithFloats(a: f64, b: f64) f64 {
5352
54test "fn with comptime args" {53test "fn with comptime args" {
55 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;54 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
56 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
57 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO55 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5856
59 try expect(gimmeTheBigOne(1234, 5678) == 5678);57 try expect(gimmeTheBigOne(1234, 5678) == 5678);
...@@ -63,7 +61,6 @@ test "fn with comptime args" {...@@ -63,7 +61,6 @@ test "fn with comptime args" {
6361
64test "anytype params" {62test "anytype params" {
65 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;63 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
66 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
67 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO64 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6865
69 try expect(max_i32(12, 34) == 34);66 try expect(max_i32(12, 34) == 34);
...@@ -87,7 +84,6 @@ fn max_f64(a: f64, b: f64) f64 {...@@ -87,7 +84,6 @@ fn max_f64(a: f64, b: f64) f64 {
87}84}
8885
89test "type constructed by comptime function call" {86test "type constructed by comptime function call" {
90 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
91 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO87 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
92 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;88 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
93 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;89 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -113,7 +109,6 @@ fn SimpleList(comptime L: usize) type {...@@ -113,7 +109,6 @@ fn SimpleList(comptime L: usize) type {
113109
114test "function with return type type" {110test "function with return type type" {
115 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;111 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
116 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
117 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO112 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
118113
119 var list: List(i32) = undefined;114 var list: List(i32) = undefined;
...@@ -154,7 +149,6 @@ fn aGenericFn(comptime T: type, comptime a: T, b: T) T {...@@ -154,7 +149,6 @@ fn aGenericFn(comptime T: type, comptime a: T, b: T) T {
154149
155test "generic fn with implicit cast" {150test "generic fn with implicit cast" {
156 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;151 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
157 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
158 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO152 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
159 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;153 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
160154
...@@ -173,7 +167,6 @@ fn getFirstByte(comptime T: type, mem: []const T) u8 {...@@ -173,7 +167,6 @@ fn getFirstByte(comptime T: type, mem: []const T) u8 {
173167
174test "generic fn keeps non-generic parameter types" {168test "generic fn keeps non-generic parameter types" {
175 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;169 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
176 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
177 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO170 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
178 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;171 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
179172
...@@ -249,7 +242,6 @@ test "function parameter is generic" {...@@ -249,7 +242,6 @@ test "function parameter is generic" {
249}242}
250243
251test "generic function instantiation turns into comptime call" {244test "generic function instantiation turns into comptime call" {
252 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
253 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO245 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
254 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO246 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
255 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;247 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -300,7 +292,6 @@ test "generic function with void and comptime parameter" {...@@ -300,7 +292,6 @@ test "generic function with void and comptime parameter" {
300}292}
301293
302test "anonymous struct return type referencing comptime parameter" {294test "anonymous struct return type referencing comptime parameter" {
303 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
304 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO295 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
305296
306 const S = struct {297 const S = struct {
...@@ -318,7 +309,6 @@ test "anonymous struct return type referencing comptime parameter" {...@@ -318,7 +309,6 @@ test "anonymous struct return type referencing comptime parameter" {
318309
319test "generic function instantiation non-duplicates" {310test "generic function instantiation non-duplicates" {
320 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO311 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
321 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
322 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO312 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
323 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;313 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
324314
...@@ -339,7 +329,6 @@ test "generic function instantiation non-duplicates" {...@@ -339,7 +329,6 @@ test "generic function instantiation non-duplicates" {
339329
340test "generic instantiation of tagged union with only one field" {330test "generic instantiation of tagged union with only one field" {
341 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO331 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
342 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
343332
344 if (builtin.os.tag == .wasi) return error.SkipZigTest;333 if (builtin.os.tag == .wasi) return error.SkipZigTest;
345334
...@@ -439,8 +428,6 @@ test "null sentinel pointer passed as generic argument" {...@@ -439,8 +428,6 @@ test "null sentinel pointer passed as generic argument" {
439}428}
440429
441test "generic function passed as comptime argument" {430test "generic function passed as comptime argument" {
442 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
443
444 const S = struct {431 const S = struct {
445 fn doMath(comptime f: fn (comptime type, i32, i32) error{Overflow}!i32, a: i32, b: i32) !void {432 fn doMath(comptime f: fn (comptime type, i32, i32) error{Overflow}!i32, a: i32, b: i32) !void {
446 const result = try f(i32, a, b);433 const result = try f(i32, a, b);
...@@ -451,7 +438,6 @@ test "generic function passed as comptime argument" {...@@ -451,7 +438,6 @@ test "generic function passed as comptime argument" {
451}438}
452439
453test "return type of generic function is function pointer" {440test "return type of generic function is function pointer" {
454 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
455 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;441 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
456442
457 const S = struct {443 const S = struct {
...@@ -464,8 +450,6 @@ test "return type of generic function is function pointer" {...@@ -464,8 +450,6 @@ test "return type of generic function is function pointer" {
464}450}
465451
466test "coerced function body has inequal value with its uncoerced body" {452test "coerced function body has inequal value with its uncoerced body" {
467 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
468
469 const S = struct {453 const S = struct {
470 const A = B(i32, c);454 const A = B(i32, c);
471 fn c() !i32 {455 fn c() !i32 {
...@@ -513,7 +497,6 @@ test "union in struct captures argument" {...@@ -513,7 +497,6 @@ test "union in struct captures argument" {
513497
514test "function argument tuple used as struct field" {498test "function argument tuple used as struct field" {
515 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO499 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
516 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
517 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;500 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
518501
519 const S = struct {502 const S = struct {
...@@ -546,8 +529,8 @@ test "comptime callconv(.c) function ptr uses comptime type argument" {...@@ -546,8 +529,8 @@ test "comptime callconv(.c) function ptr uses comptime type argument" {
546}529}
547530
548test "call generic function with from function called by the generic function" {531test "call generic function with from function called by the generic function" {
549 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
550 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;532 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
533 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
551 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO534 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
552535
553 const GET = struct {536 const GET = struct {
test/behavior/globals.zig+2-4
...@@ -6,7 +6,6 @@ var pos = [2]f32{ 0.0, 0.0 };...@@ -6,7 +6,6 @@ var pos = [2]f32{ 0.0, 0.0 };
6test "store to global array" {6test "store to global array" {
7 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;7 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
109
11 try expect(pos[1] == 0.0);10 try expect(pos[1] == 0.0);
12 pos = [2]f32{ 0.0, 1.0 };11 pos = [2]f32{ 0.0, 1.0 };
...@@ -15,9 +14,9 @@ test "store to global array" {...@@ -15,9 +14,9 @@ test "store to global array" {
1514
16var vpos = @Vector(2, f32){ 0.0, 0.0 };15var vpos = @Vector(2, f32){ 0.0, 0.0 };
17test "store to global vector" {16test "store to global vector" {
17 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
18 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;18 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
19 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;19 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
20 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2120
22 try expect(vpos[1] == 0.0);21 try expect(vpos[1] == 0.0);
23 vpos = @Vector(2, f32){ 0.0, 1.0 };22 vpos = @Vector(2, f32){ 0.0, 1.0 };
...@@ -26,7 +25,6 @@ test "store to global vector" {...@@ -26,7 +25,6 @@ test "store to global vector" {
2625
27test "slices pointing at the same address as global array." {26test "slices pointing at the same address as global array." {
28 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;27 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
30 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO28 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
31 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;29 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
3230
...@@ -47,7 +45,6 @@ test "slices pointing at the same address as global array." {...@@ -47,7 +45,6 @@ test "slices pointing at the same address as global array." {
47test "global loads can affect liveness" {45test "global loads can affect liveness" {
48 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;46 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
49 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;47 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
50 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5148
52 const S = struct {49 const S = struct {
53 const ByRef = struct {50 const ByRef = struct {
...@@ -188,6 +185,7 @@ test "function pointer field call on global extern struct, conditional on global...@@ -188,6 +185,7 @@ test "function pointer field call on global extern struct, conditional on global
188}185}
189186
190test "function pointer field call on global extern struct" {187test "function pointer field call on global extern struct" {
188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
191 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;189 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
192190
193 const S = struct {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,7 +116,6 @@ test "if prongs cast to expected type instead of peer type resolution" {
116116
117test "if peer expressions inferred optional type" {117test "if peer expressions inferred optional type" {
118 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;118 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
119 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
120 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO119 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
121 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;120 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
122121
...@@ -135,7 +134,6 @@ test "if peer expressions inferred optional type" {...@@ -135,7 +134,6 @@ test "if peer expressions inferred optional type" {
135134
136test "if-else expression with runtime condition result location is inferred optional" {135test "if-else expression with runtime condition result location is inferred optional" {
137 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;136 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
138 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
139 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO137 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
140138
141 const A = struct { b: u64, c: u64 };139 const A = struct { b: u64, c: u64 };
...@@ -174,6 +172,8 @@ fn returnTrue() bool {...@@ -174,6 +172,8 @@ fn returnTrue() bool {
174}172}
175173
176test "if value shouldn't be load-elided if used later (structs)" {174test "if value shouldn't be load-elided if used later (structs)" {
175 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
176
177 const Foo = struct { x: i32 };177 const Foo = struct { x: i32 };
178178
179 var a = Foo{ .x = 1 };179 var a = Foo{ .x = 1 };
...@@ -191,6 +191,8 @@ test "if value shouldn't be load-elided if used later (structs)" {...@@ -191,6 +191,8 @@ test "if value shouldn't be load-elided if used later (structs)" {
191}191}
192192
193test "if value shouldn't be load-elided if used later (optionals)" {193test "if value shouldn't be load-elided if used later (optionals)" {
194 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
195
194 var a: ?i32 = 1;196 var a: ?i32 = 1;
195 var b: ?i32 = 1;197 var b: ?i32 = 1;
196198
test/behavior/import_c_keywords.zig-1
...@@ -27,7 +27,6 @@ extern fn @"break"() Id;...@@ -27,7 +27,6 @@ extern fn @"break"() Id;
27extern fn an_alias_of_some_non_c_keyword_function() Id;27extern fn an_alias_of_some_non_c_keyword_function() Id;
2828
29test "import c keywords" {29test "import c keywords" {
30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
31 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;30 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
32 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;31 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
33 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;32 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/inline_switch.zig-9
...@@ -3,7 +3,6 @@ const expect = std.testing.expect;...@@ -3,7 +3,6 @@ const expect = std.testing.expect;
3const builtin = @import("builtin");3const builtin = @import("builtin");
44
5test "inline scalar prongs" {5test "inline scalar prongs" {
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO6 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
87
9 var x: usize = 0;8 var x: usize = 0;
...@@ -18,7 +17,6 @@ test "inline scalar prongs" {...@@ -18,7 +17,6 @@ test "inline scalar prongs" {
18}17}
1918
20test "inline prong ranges" {19test "inline prong ranges" {
21 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
22 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO20 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2321
24 var x: usize = 0;22 var x: usize = 0;
...@@ -33,7 +31,6 @@ test "inline prong ranges" {...@@ -33,7 +31,6 @@ test "inline prong ranges" {
3331
34const E = enum { a, b, c, d };32const E = enum { a, b, c, d };
35test "inline switch enums" {33test "inline switch enums" {
36 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
37 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO34 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3835
39 var x: E = .a;36 var x: E = .a;
...@@ -46,7 +43,6 @@ test "inline switch enums" {...@@ -46,7 +43,6 @@ test "inline switch enums" {
4643
47const U = union(E) { a: void, b: u2, c: u3, d: u4 };44const U = union(E) { a: void, b: u2, c: u3, d: u4 };
48test "inline switch unions" {45test "inline switch unions" {
49 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
50 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO46 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
51 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO47 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5248
...@@ -73,7 +69,6 @@ test "inline switch unions" {...@@ -73,7 +69,6 @@ test "inline switch unions" {
73}69}
7470
75test "inline else bool" {71test "inline else bool" {
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO72 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
7873
79 var a = true;74 var a = true;
...@@ -85,7 +80,6 @@ test "inline else bool" {...@@ -85,7 +80,6 @@ test "inline else bool" {
85}80}
8681
87test "inline else error" {82test "inline else error" {
88 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
89 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO83 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9084
91 const Err = error{ a, b, c };85 const Err = error{ a, b, c };
...@@ -98,7 +92,6 @@ test "inline else error" {...@@ -98,7 +92,6 @@ test "inline else error" {
98}92}
9993
100test "inline else enum" {94test "inline else enum" {
101 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
102 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO95 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10396
104 const E2 = enum(u8) { a = 2, b = 3, c = 4, d = 5 };97 const E2 = enum(u8) { a = 2, b = 3, c = 4, d = 5 };
...@@ -111,7 +104,6 @@ test "inline else enum" {...@@ -111,7 +104,6 @@ test "inline else enum" {
111}104}
112105
113test "inline else int with gaps" {106test "inline else int with gaps" {
114 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
115 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO107 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
116 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO108 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
117109
...@@ -130,7 +122,6 @@ test "inline else int with gaps" {...@@ -130,7 +122,6 @@ test "inline else int with gaps" {
130}122}
131123
132test "inline else int all values" {124test "inline else int all values" {
133 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
134 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO125 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
135126
136 var a: u2 = 0;127 var a: u2 = 0;
test/behavior/int128.zig-5
...@@ -5,7 +5,6 @@ const minInt = std.math.minInt;...@@ -5,7 +5,6 @@ const minInt = std.math.minInt;
5const builtin = @import("builtin");5const builtin = @import("builtin");
66
7test "uint128" {7test "uint128" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;10 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -25,7 +24,6 @@ test "uint128" {...@@ -25,7 +24,6 @@ test "uint128" {
25}24}
2625
27test "undefined 128 bit int" {26test "undefined 128 bit int" {
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
29 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO27 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
30 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO28 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
31 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;29 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -45,7 +43,6 @@ test "undefined 128 bit int" {...@@ -45,7 +43,6 @@ test "undefined 128 bit int" {
45}43}
4644
47test "int128" {45test "int128" {
48 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
49 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO46 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
50 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO47 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
51 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;48 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -68,7 +65,6 @@ test "int128" {...@@ -68,7 +65,6 @@ test "int128" {
68}65}
6966
70test "truncate int128" {67test "truncate int128" {
71 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
72 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO68 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
73 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO69 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
74 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;70 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -92,7 +88,6 @@ test "truncate int128" {...@@ -92,7 +88,6 @@ test "truncate int128" {
92}88}
9389
94test "shift int128" {90test "shift int128" {
95 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
96 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO91 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
97 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO92 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,7 +15,6 @@ test "int comparison elision" {
1515
16 // TODO: support int types > 128 bits wide in other backends16 // TODO: support int types > 128 bits wide in other backends
17 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO17 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
18 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
19 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO18 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
20 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;19 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2120
test/behavior/ir_block_deps.zig-1
...@@ -18,7 +18,6 @@ fn getErrInt() anyerror!i32 {...@@ -18,7 +18,6 @@ fn getErrInt() anyerror!i32 {
18}18}
1919
20test "ir block deps" {20test "ir block deps" {
21 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
22 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO21 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
23 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO22 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2423
test/behavior/lower_strlit_to_vector.zig-1
...@@ -3,7 +3,6 @@ const builtin = @import("builtin");...@@ -3,7 +3,6 @@ const builtin = @import("builtin");
33
4test "strlit to vector" {4test "strlit to vector" {
5 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO5 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO6 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,11 +62,11 @@ fn assertFalse(b: bool) !void {
62}62}
6363
64test "@clz" {64test "@clz" {
65 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
66 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO65 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
67 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO66 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
68 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;67 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
69 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO68 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
69
70 try testClz();70 try testClz();
71 try comptime testClz();71 try comptime testClz();
72}72}
...@@ -80,7 +80,6 @@ fn testClz() !void {...@@ -80,7 +80,6 @@ fn testClz() !void {
80}80}
8181
82test "@clz big ints" {82test "@clz big ints" {
83 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
84 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO83 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
85 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO84 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
86 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;85 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -100,8 +99,8 @@ fn testOneClz(comptime T: type, x: T) u32 {...@@ -100,8 +99,8 @@ fn testOneClz(comptime T: type, x: T) u32 {
100}99}
101100
102test "@clz vectors" {101test "@clz vectors" {
102 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
103 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO103 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
104 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
105 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO104 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
106 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO105 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
107 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;106 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -146,7 +145,6 @@ fn expectVectorsEqual(a: anytype, b: anytype) !void {...@@ -146,7 +145,6 @@ fn expectVectorsEqual(a: anytype, b: anytype) !void {
146}145}
147146
148test "@ctz" {147test "@ctz" {
149 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
150 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO148 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
151 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO149 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
152 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;150 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -170,7 +168,7 @@ fn testOneCtz(comptime T: type, x: T) u32 {...@@ -170,7 +168,7 @@ fn testOneCtz(comptime T: type, x: T) u32 {
170}168}
171169
172test "@ctz 128-bit integers" {170test "@ctz 128-bit integers" {
173 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO171 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
174 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO172 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
175 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO173 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
176 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;174 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -188,8 +186,8 @@ fn testCtz128() !void {...@@ -188,8 +186,8 @@ fn testCtz128() !void {
188}186}
189187
190test "@ctz vectors" {188test "@ctz vectors" {
189 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
191 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO190 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
192 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
193 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO191 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
194 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO192 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
195 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;193 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -227,7 +225,6 @@ test "const number literal" {...@@ -227,7 +225,6 @@ test "const number literal" {
227const ten = 10;225const ten = 10;
228226
229test "float equality" {227test "float equality" {
230 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
231 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO228 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
232 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO229 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
233230
...@@ -433,7 +430,6 @@ test "binary not" {...@@ -433,7 +430,6 @@ test "binary not" {
433}430}
434431
435test "binary not big int <= 128 bits" {432test "binary not big int <= 128 bits" {
436 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
437 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO433 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
438 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO434 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
439 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;435 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -467,7 +463,7 @@ test "binary not big int <= 128 bits" {...@@ -467,7 +463,7 @@ test "binary not big int <= 128 bits" {
467}463}
468464
469test "division" {465test "division" {
470 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO466 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
471 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO467 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
472 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO468 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
473 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;469 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -609,7 +605,6 @@ test "large integer division" {...@@ -609,7 +605,6 @@ test "large integer division" {
609}605}
610606
611test "division half-precision floats" {607test "division half-precision floats" {
612 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
613 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO608 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
614 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO609 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
615 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;610 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -696,7 +691,6 @@ fn testUnsignedNegationWrappingEval(x: u16) !void {...@@ -696,7 +691,6 @@ fn testUnsignedNegationWrappingEval(x: u16) !void {
696}691}
697692
698test "negation wrapping" {693test "negation wrapping" {
699 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
700 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO694 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
701 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;695 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
702696
...@@ -749,7 +743,6 @@ fn testShrTrunc(x: u16) !void {...@@ -749,7 +743,6 @@ fn testShrTrunc(x: u16) !void {
749}743}
750744
751test "f128" {745test "f128" {
752 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
753 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO746 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
754 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO747 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
755 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;748 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -778,6 +771,7 @@ fn should_not_be_zero(x: f128) !void {...@@ -778,6 +771,7 @@ fn should_not_be_zero(x: f128) !void {
778}771}
779772
780test "umax wrapped squaring" {773test "umax wrapped squaring" {
774 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
781 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;775 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
782 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;776 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
783777
...@@ -834,7 +828,6 @@ test "umax wrapped squaring" {...@@ -834,7 +828,6 @@ test "umax wrapped squaring" {
834}828}
835829
836test "128-bit multiplication" {830test "128-bit multiplication" {
837 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
838 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO831 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
839 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO832 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
840 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;833 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -869,7 +862,6 @@ fn testAddWithOverflow(comptime T: type, a: T, b: T, add: T, bit: u1) !void {...@@ -869,7 +862,6 @@ fn testAddWithOverflow(comptime T: type, a: T, b: T, add: T, bit: u1) !void {
869}862}
870863
871test "@addWithOverflow" {864test "@addWithOverflow" {
872 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
873 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO865 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
874 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO866 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
875 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO867 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
...@@ -888,7 +880,6 @@ test "@addWithOverflow" {...@@ -888,7 +880,6 @@ test "@addWithOverflow" {
888}880}
889881
890test "@addWithOverflow > 64 bits" {882test "@addWithOverflow > 64 bits" {
891 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
892 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO883 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
893 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO884 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
894 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;885 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -960,7 +951,7 @@ fn testMulWithOverflow(comptime T: type, a: T, b: T, mul: T, bit: u1) !void {...@@ -960,7 +951,7 @@ fn testMulWithOverflow(comptime T: type, a: T, b: T, mul: T, bit: u1) !void {
960}951}
961952
962test "basic @mulWithOverflow" {953test "basic @mulWithOverflow" {
963 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO954 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
964 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO955 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
965 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO956 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
966957
...@@ -972,7 +963,7 @@ test "basic @mulWithOverflow" {...@@ -972,7 +963,7 @@ test "basic @mulWithOverflow" {
972}963}
973964
974test "extensive @mulWithOverflow" {965test "extensive @mulWithOverflow" {
975 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO966 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
976 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO967 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
977 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;968 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
978 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;969 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1012,11 +1003,9 @@ test "extensive @mulWithOverflow" {...@@ -1012,11 +1003,9 @@ test "extensive @mulWithOverflow" {
1012}1003}
10131004
1014test "@mulWithOverflow bitsize > 32" {1005test "@mulWithOverflow bitsize > 32" {
1015 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1006 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1016
1017 // aarch64 fails on a release build of the compiler.
1018 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1019 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1007 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1008 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1020 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1009 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10211010
1022 try testMulWithOverflow(u40, 3, 0x55_5555_5555, 0xff_ffff_ffff, 0);1011 try testMulWithOverflow(u40, 3, 0x55_5555_5555, 0xff_ffff_ffff, 0);
...@@ -1043,9 +1032,9 @@ test "@mulWithOverflow bitsize > 32" {...@@ -1043,9 +1032,9 @@ test "@mulWithOverflow bitsize > 32" {
1043}1032}
10441033
1045test "@mulWithOverflow bitsize 128 bits" {1034test "@mulWithOverflow bitsize 128 bits" {
1035 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1046 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;1036 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1047 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1037 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1048 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1049 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1038 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1050 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1039 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1051 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO1040 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
...@@ -1070,6 +1059,7 @@ test "@mulWithOverflow bitsize 128 bits" {...@@ -1070,6 +1059,7 @@ test "@mulWithOverflow bitsize 128 bits" {
1070}1059}
10711060
1072test "@mulWithOverflow bitsize 256 bits" {1061test "@mulWithOverflow bitsize 256 bits" {
1062 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1073 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;1063 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1074 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;1064 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
1075 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1065 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1116,7 +1106,6 @@ fn testSubWithOverflow(comptime T: type, a: T, b: T, sub: T, bit: u1) !void {...@@ -1116,7 +1106,6 @@ fn testSubWithOverflow(comptime T: type, a: T, b: T, sub: T, bit: u1) !void {
1116}1106}
11171107
1118test "@subWithOverflow" {1108test "@subWithOverflow" {
1119 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1120 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1109 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1121 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1110 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11221111
...@@ -1133,7 +1122,6 @@ test "@subWithOverflow" {...@@ -1133,7 +1122,6 @@ test "@subWithOverflow" {
1133}1122}
11341123
1135test "@subWithOverflow > 64 bits" {1124test "@subWithOverflow > 64 bits" {
1136 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1137 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1125 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1138 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1126 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1139 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1127 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1181,7 +1169,7 @@ fn testShlWithOverflow(comptime T: type, a: T, b: math.Log2Int(T), shl: T, bit:...@@ -1181,7 +1169,7 @@ fn testShlWithOverflow(comptime T: type, a: T, b: math.Log2Int(T), shl: T, bit:
1181}1169}
11821170
1183test "@shlWithOverflow" {1171test "@shlWithOverflow" {
1184 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1172 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1185 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1173 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1186 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1174 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1187 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1175 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1200,7 +1188,7 @@ test "@shlWithOverflow" {...@@ -1200,7 +1188,7 @@ test "@shlWithOverflow" {
1200}1188}
12011189
1202test "@shlWithOverflow > 64 bits" {1190test "@shlWithOverflow > 64 bits" {
1203 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1191 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1204 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1192 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1205 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1193 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1206 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1194 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1269,7 +1257,6 @@ test "allow signed integer division/remainder when values are comptime-known and...@@ -1269,7 +1257,6 @@ test "allow signed integer division/remainder when values are comptime-known and
1269}1257}
12701258
1271test "quad hex float literal parsing accurate" {1259test "quad hex float literal parsing accurate" {
1272 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1273 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1260 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1274 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1261 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1275 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1262 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1427,8 +1414,8 @@ test "comptime float rem int" {...@@ -1427,8 +1414,8 @@ test "comptime float rem int" {
1427}1414}
14281415
1429test "remainder division" {1416test "remainder division" {
1417 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1430 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1418 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1431 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1432 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1419 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1433 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1420 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1434 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;1421 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
...@@ -1467,7 +1454,6 @@ fn remdivOne(comptime T: type, a: T, b: T, c: T) !void {...@@ -1467,7 +1454,6 @@ fn remdivOne(comptime T: type, a: T, b: T, c: T) !void {
14671454
1468test "float remainder division using @rem" {1455test "float remainder division using @rem" {
1469 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1456 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1470 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1471 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1457 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1472 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1458 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1473 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1459 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1508,8 +1494,8 @@ fn fremOne(comptime T: type, a: T, b: T, c: T, epsilon: T) !void {...@@ -1508,8 +1494,8 @@ fn fremOne(comptime T: type, a: T, b: T, c: T, epsilon: T) !void {
1508}1494}
15091495
1510test "float modulo division using @mod" {1496test "float modulo division using @mod" {
1497 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1511 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1498 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1512 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1513 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1499 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1514 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1500 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1515 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;1501 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
...@@ -1552,7 +1538,6 @@ fn fmodOne(comptime T: type, a: T, b: T, c: T, epsilon: T) !void {...@@ -1552,7 +1538,6 @@ fn fmodOne(comptime T: type, a: T, b: T, c: T, epsilon: T) !void {
15521538
1553test "@round f16" {1539test "@round f16" {
1554 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1540 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1555 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1556 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1541 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1557 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1542 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
15581543
...@@ -1562,7 +1547,6 @@ test "@round f16" {...@@ -1562,7 +1547,6 @@ test "@round f16" {
15621547
1563test "@round f32/f64" {1548test "@round f32/f64" {
1564 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1549 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1565 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1566 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1550 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1567 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1551 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
15681552
...@@ -1579,7 +1563,6 @@ test "@round f32/f64" {...@@ -1579,7 +1563,6 @@ test "@round f32/f64" {
15791563
1580test "@round f80" {1564test "@round f80" {
1581 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1565 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1582 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1583 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1566 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1584 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1567 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1585 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;1568 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
...@@ -1591,7 +1574,6 @@ test "@round f80" {...@@ -1591,7 +1574,6 @@ test "@round f80" {
15911574
1592test "@round f128" {1575test "@round f128" {
1593 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1576 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1594 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1595 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1577 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1596 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1578 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1597 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;1579 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
...@@ -1608,9 +1590,9 @@ fn testRound(comptime T: type, x: T) !void {...@@ -1608,9 +1590,9 @@ fn testRound(comptime T: type, x: T) !void {
1608}1590}
16091591
1610test "vector integer addition" {1592test "vector integer addition" {
1593 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1611 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1594 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1612 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1595 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1613 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1614 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1596 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1615 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1597 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1616 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1598 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1632,7 +1614,6 @@ test "vector integer addition" {...@@ -1632,7 +1614,6 @@ test "vector integer addition" {
16321614
1633test "NaN comparison" {1615test "NaN comparison" {
1634 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1616 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1635 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1636 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1617 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1637 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1618 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1638 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1619 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1650,7 +1631,6 @@ test "NaN comparison" {...@@ -1650,7 +1631,6 @@ test "NaN comparison" {
16501631
1651test "NaN comparison f80" {1632test "NaN comparison f80" {
1652 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1633 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1653 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1654 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1634 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1655 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1635 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1656 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1636 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1672,9 +1652,9 @@ fn testNanEqNan(comptime F: type) !void {...@@ -1672,9 +1652,9 @@ fn testNanEqNan(comptime F: type) !void {
1672}1652}
16731653
1674test "vector comparison" {1654test "vector comparison" {
1655 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1675 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1656 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1676 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1657 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1677 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1678 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1658 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1679 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1659 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1680 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1660 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1705,7 +1685,6 @@ test "compare undefined literal with comptime_int" {...@@ -1705,7 +1685,6 @@ test "compare undefined literal with comptime_int" {
17051685
1706test "signed zeros are represented properly" {1686test "signed zeros are represented properly" {
1707 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1687 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1708 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1709 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1688 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1710 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1689 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1711 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1690 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1737,7 +1716,6 @@ test "signed zeros are represented properly" {...@@ -1737,7 +1716,6 @@ test "signed zeros are represented properly" {
17371716
1738test "absFloat" {1717test "absFloat" {
1739 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1718 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1740 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1741 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1719 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17421720
1743 try testAbsFloat();1721 try testAbsFloat();
...@@ -1767,8 +1745,8 @@ test "mod lazy values" {...@@ -1767,8 +1745,8 @@ test "mod lazy values" {
1767}1745}
17681746
1769test "@clz works on both vector and scalar inputs" {1747test "@clz works on both vector and scalar inputs" {
1748 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1770 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1749 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1771 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1772 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1750 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1773 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1751 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1774 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1752 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1786,7 +1764,6 @@ test "@clz works on both vector and scalar inputs" {...@@ -1786,7 +1764,6 @@ test "@clz works on both vector and scalar inputs" {
17861764
1787test "runtime comparison to NaN is comptime-known" {1765test "runtime comparison to NaN is comptime-known" {
1788 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1766 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1789 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1790 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1767 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1791 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1768 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1792 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1769 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1816,7 +1793,6 @@ test "runtime comparison to NaN is comptime-known" {...@@ -1816,7 +1793,6 @@ test "runtime comparison to NaN is comptime-known" {
18161793
1817test "runtime int comparison to inf is comptime-known" {1794test "runtime int comparison to inf is comptime-known" {
1818 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1795 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1819 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1820 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1796 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1821 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1797 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1822 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1798 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1845,8 +1821,8 @@ test "runtime int comparison to inf is comptime-known" {...@@ -1845,8 +1821,8 @@ test "runtime int comparison to inf is comptime-known" {
1845}1821}
18461822
1847test "float divide by zero" {1823test "float divide by zero" {
1824 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1848 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1825 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1849 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1850 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1826 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1851 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1827 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1852 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1828 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1880,8 +1856,8 @@ test "float divide by zero" {...@@ -1880,8 +1856,8 @@ test "float divide by zero" {
1880}1856}
18811857
1882test "partially-runtime integer vector division would be illegal if vector elements were reordered" {1858test "partially-runtime integer vector division would be illegal if vector elements were reordered" {
1859 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1883 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1860 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1884 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1885 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1861 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1886 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1862 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1887 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1863 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1909,8 +1885,8 @@ test "partially-runtime integer vector division would be illegal if vector eleme...@@ -1909,8 +1885,8 @@ test "partially-runtime integer vector division would be illegal if vector eleme
1909}1885}
19101886
1911test "float vector division of comptime zero by runtime nan is nan" {1887test "float vector division of comptime zero by runtime nan is nan" {
1888 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1912 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1889 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1913 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1914 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1890 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1915 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1891 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1916 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1892 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1927,8 +1903,8 @@ test "float vector division of comptime zero by runtime nan is nan" {...@@ -1927,8 +1903,8 @@ test "float vector division of comptime zero by runtime nan is nan" {
1927}1903}
19281904
1929test "float vector multiplication of comptime zero by runtime nan is nan" {1905test "float vector multiplication of comptime zero by runtime nan is nan" {
1906 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1930 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1907 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1931 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1932 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1908 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1933 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1909 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1934 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1910 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1945,7 +1921,6 @@ test "float vector multiplication of comptime zero by runtime nan is nan" {...@@ -1945,7 +1921,6 @@ test "float vector multiplication of comptime zero by runtime nan is nan" {
19451921
1946test "comptime float vector division of zero by nan is nan" {1922test "comptime float vector division of zero by nan is nan" {
1947 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1923 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1948 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1949 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1924 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1950 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1925 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1951 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1926 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1961,7 +1936,6 @@ test "comptime float vector division of zero by nan is nan" {...@@ -1961,7 +1936,6 @@ test "comptime float vector division of zero by nan is nan" {
19611936
1962test "comptime float vector multiplication of zero by nan is nan" {1937test "comptime float vector multiplication of zero by nan is nan" {
1963 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1938 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1964 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1965 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1939 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1966 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1940 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1967 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1941 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 +7,6 @@ const expectEqual = std.testing.expectEqual;
77
8test "@max" {8test "@max" {
9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;11 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1312
...@@ -28,9 +27,9 @@ test "@max" {...@@ -28,9 +27,9 @@ test "@max" {
28}27}
2928
30test "@max on vectors" {29test "@max on vectors" {
30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
31 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO31 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
32 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO32 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
33 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
34 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO33 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
35 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;34 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
36 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;35 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -61,7 +60,6 @@ test "@max on vectors" {...@@ -61,7 +60,6 @@ test "@max on vectors" {
61}60}
6261
63test "@min" {62test "@min" {
64 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
65 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO63 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
66 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO64 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
67 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;65 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -83,8 +81,8 @@ test "@min" {...@@ -83,8 +81,8 @@ test "@min" {
83}81}
8482
85test "@min for vectors" {83test "@min for vectors" {
84 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
86 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO85 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
88 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO86 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
89 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO87 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
90 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;88 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -116,7 +114,6 @@ test "@min for vectors" {...@@ -116,7 +114,6 @@ test "@min for vectors" {
116}114}
117115
118test "@min/max for floats" {116test "@min/max for floats" {
119 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
120 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO117 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
121 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO118 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
122 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;119 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -167,8 +164,8 @@ test "@min/@max more than two arguments" {...@@ -167,8 +164,8 @@ test "@min/@max more than two arguments" {
167}164}
168165
169test "@min/@max more than two vector arguments" {166test "@min/@max more than two vector arguments" {
167 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
170 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO168 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
171 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
172 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO169 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
173 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO170 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
174 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;171 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -181,7 +178,6 @@ test "@min/@max more than two vector arguments" {...@@ -181,7 +178,6 @@ test "@min/@max more than two vector arguments" {
181}178}
182179
183test "@min/@max notices bounds" {180test "@min/@max notices bounds" {
184 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
185 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO181 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
186 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO182 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
187183
...@@ -198,8 +194,8 @@ test "@min/@max notices bounds" {...@@ -198,8 +194,8 @@ test "@min/@max notices bounds" {
198}194}
199195
200test "@min/@max notices vector bounds" {196test "@min/@max notices vector bounds" {
197 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
201 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO198 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
202 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
203 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO199 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
204 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO200 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
205 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;201 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -217,7 +213,6 @@ test "@min/@max notices vector bounds" {...@@ -217,7 +213,6 @@ test "@min/@max notices vector bounds" {
217}213}
218214
219test "@min/@max on comptime_int" {215test "@min/@max on comptime_int" {
220 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
221 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO216 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
222 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO217 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
223218
...@@ -231,7 +226,6 @@ test "@min/@max on comptime_int" {...@@ -231,7 +226,6 @@ test "@min/@max on comptime_int" {
231}226}
232227
233test "@min/@max notices bounds from types" {228test "@min/@max notices bounds from types" {
234 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
235 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO229 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
236 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO230 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
237231
...@@ -251,8 +245,8 @@ test "@min/@max notices bounds from types" {...@@ -251,8 +245,8 @@ test "@min/@max notices bounds from types" {
251}245}
252246
253test "@min/@max notices bounds from vector types" {247test "@min/@max notices bounds from vector types" {
248 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
254 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO249 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
255 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
256 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO250 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
257 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO251 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
258 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;252 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -273,7 +267,6 @@ test "@min/@max notices bounds from vector types" {...@@ -273,7 +267,6 @@ test "@min/@max notices bounds from vector types" {
273}267}
274268
275test "@min/@max notices bounds from types when comptime-known value is undef" {269test "@min/@max notices bounds from types when comptime-known value is undef" {
276 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
277 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO270 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
278 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO271 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
279 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;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,8 +286,8 @@ test "@min/@max notices bounds from types when comptime-known value is undef" {
293}286}
294287
295test "@min/@max notices bounds from vector types when element of comptime-known vector is undef" {288test "@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 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO290 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
297 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
298 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO291 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
299 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO292 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
300 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;293 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -333,7 +326,6 @@ test "@min/@max of signed and unsigned runtime integers" {...@@ -333,7 +326,6 @@ test "@min/@max of signed and unsigned runtime integers" {
333}326}
334327
335test "@min resulting in u0" {328test "@min resulting in u0" {
336 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
337 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO329 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
338 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO330 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
339331
...@@ -364,8 +356,8 @@ test "@min/@max with runtime signed and unsigned integers of same size" {...@@ -364,8 +356,8 @@ test "@min/@max with runtime signed and unsigned integers of same size" {
364}356}
365357
366test "@min/@max with runtime vectors of signed and unsigned integers of same size" {358test "@min/@max with runtime vectors of signed and unsigned integers of same size" {
359 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
367 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO360 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
368 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
369 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO361 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
370 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO362 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
371 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;363 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/member_func.zig-2
...@@ -28,7 +28,6 @@ const HasFuncs = struct {...@@ -28,7 +28,6 @@ const HasFuncs = struct {
2828
29test "standard field calls" {29test "standard field calls" {
30 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;30 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
31 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
32 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO31 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
33 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;32 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
3433
...@@ -72,7 +71,6 @@ test "standard field calls" {...@@ -72,7 +71,6 @@ test "standard field calls" {
7271
73test "@field field calls" {72test "@field field calls" {
74 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;73 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
75 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
76 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO74 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;75 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
7876
test/behavior/memcpy.zig+1-4
...@@ -4,7 +4,6 @@ const expect = std.testing.expect;...@@ -4,7 +4,6 @@ const expect = std.testing.expect;
4const assert = std.debug.assert;4const assert = std.debug.assert;
55
6test "memcpy and memset intrinsics" {6test "memcpy and memset intrinsics" {
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -26,7 +25,6 @@ fn testMemcpyMemset() !void {...@@ -26,7 +25,6 @@ fn testMemcpyMemset() !void {
26}25}
2726
28test "@memcpy with both operands single-ptr-to-array, one is null-terminated" {27test "@memcpy with both operands single-ptr-to-array, one is null-terminated" {
29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
30 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;28 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
31 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;29 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
32 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;30 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -47,7 +45,6 @@ fn testMemcpyBothSinglePtrArrayOneIsNullTerminated() !void {...@@ -47,7 +45,6 @@ fn testMemcpyBothSinglePtrArrayOneIsNullTerminated() !void {
47}45}
4846
49test "@memcpy dest many pointer" {47test "@memcpy dest many pointer" {
50 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
51 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;48 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
52 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;49 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
53 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;50 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -70,7 +67,6 @@ fn testMemcpyDestManyPtr() !void {...@@ -70,7 +67,6 @@ fn testMemcpyDestManyPtr() !void {
70}67}
7168
72test "@memcpy C pointer" {69test "@memcpy C pointer" {
73 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
74 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;70 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
75 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;71 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
76 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;72 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -156,6 +152,7 @@ test "@memcpy zero-bit type with aliasing" {...@@ -156,6 +152,7 @@ test "@memcpy zero-bit type with aliasing" {
156}152}
157153
158test "@memcpy with sentinel" {154test "@memcpy with sentinel" {
155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
159 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;156 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
160157
161 const S = struct {158 const S = struct {
test/behavior/memmove.zig-3
...@@ -3,7 +3,6 @@ const builtin = @import("builtin");...@@ -3,7 +3,6 @@ const builtin = @import("builtin");
3const expect = std.testing.expect;3const expect = std.testing.expect;
44
5test "memmove and memset intrinsics" {5test "memmove and memset intrinsics" {
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;8 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -32,7 +31,6 @@ fn testMemmoveMemset() !void {...@@ -32,7 +31,6 @@ fn testMemmoveMemset() !void {
32}31}
3332
34test "@memmove with both operands single-ptr-to-array, one is null-terminated" {33test "@memmove with both operands single-ptr-to-array, one is null-terminated" {
35 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
36 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;34 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
37 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;35 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
38 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;36 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -77,7 +75,6 @@ fn testMemmoveBothSinglePtrArrayOneIsNullTerminated() !void {...@@ -77,7 +75,6 @@ fn testMemmoveBothSinglePtrArrayOneIsNullTerminated() !void {
77}75}
7876
79test "@memmove dest many pointer" {77test "@memmove dest many pointer" {
80 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
81 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;78 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
82 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;79 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
83 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;80 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/memset.zig-7
...@@ -3,7 +3,6 @@ const builtin = @import("builtin");...@@ -3,7 +3,6 @@ const builtin = @import("builtin");
3const expect = std.testing.expect;3const expect = std.testing.expect;
44
5test "@memset on array pointers" {5test "@memset on array pointers" {
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;7 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;8 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -32,7 +31,6 @@ fn testMemsetArray() !void {...@@ -32,7 +31,6 @@ fn testMemsetArray() !void {
32}31}
3332
34test "@memset on slices" {33test "@memset on slices" {
35 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
36 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;34 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
37 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;35 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
38 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;36 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -68,7 +66,6 @@ fn testMemsetSlice() !void {...@@ -68,7 +66,6 @@ fn testMemsetSlice() !void {
68}66}
6967
70test "memset with bool element" {68test "memset with bool element" {
71 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
72 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;69 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
73 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;70 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
74 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;71 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -80,7 +77,6 @@ test "memset with bool element" {...@@ -80,7 +77,6 @@ test "memset with bool element" {
80}77}
8178
82test "memset with 1-byte struct element" {79test "memset with 1-byte struct element" {
83 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
84 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;80 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
85 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;81 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
86 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;82 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -94,7 +90,6 @@ test "memset with 1-byte struct element" {...@@ -94,7 +90,6 @@ test "memset with 1-byte struct element" {
94}90}
9591
96test "memset with 1-byte array element" {92test "memset with 1-byte array element" {
97 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
98 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;93 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
99 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;94 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
100 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;95 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -145,7 +140,6 @@ test "memset with large array element, comptime known" {...@@ -145,7 +140,6 @@ test "memset with large array element, comptime known" {
145}140}
146141
147test "@memset provides result type" {142test "@memset provides result type" {
148 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
149 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;143 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
150 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;144 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
151 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;145 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -164,7 +158,6 @@ test "@memset provides result type" {...@@ -164,7 +158,6 @@ test "@memset provides result type" {
164}158}
165159
166test "zero keys with @memset" {160test "zero keys with @memset" {
167 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
168 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
169 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO162 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
170 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,7 +4,6 @@ const expect = std.testing.expect;
44
5test "@mulAdd" {5test "@mulAdd" {
6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;8 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -32,7 +31,6 @@ fn testMulAdd() !void {...@@ -32,7 +31,6 @@ fn testMulAdd() !void {
3231
33test "@mulAdd f16" {32test "@mulAdd f16" {
34 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO33 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
35 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
36 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO34 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
37 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;35 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
38 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;36 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -51,7 +49,6 @@ fn testMulAdd16() !void {...@@ -51,7 +49,6 @@ fn testMulAdd16() !void {
5149
52test "@mulAdd f80" {50test "@mulAdd f80" {
53 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO51 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
54 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
55 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO52 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
56 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;53 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
57 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;54 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
...@@ -71,7 +68,6 @@ fn testMulAdd80() !void {...@@ -71,7 +68,6 @@ fn testMulAdd80() !void {
7168
72test "@mulAdd f128" {69test "@mulAdd f128" {
73 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO70 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
74 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
75 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO71 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
76 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;72 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
77 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;73 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
...@@ -103,9 +99,9 @@ fn vector16() !void {...@@ -103,9 +99,9 @@ fn vector16() !void {
103}99}
104100
105test "vector f16" {101test "vector f16" {
102 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
106 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO103 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
107 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO104 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
108 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO105 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
110 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;106 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
111 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;107 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -128,9 +124,9 @@ fn vector32() !void {...@@ -128,9 +124,9 @@ fn vector32() !void {
128}124}
129125
130test "vector f32" {126test "vector f32" {
127 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
131 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO128 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
132 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO129 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
133 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
134 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO130 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
135 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;131 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
136 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;132 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -153,9 +149,9 @@ fn vector64() !void {...@@ -153,9 +149,9 @@ fn vector64() !void {
153}149}
154150
155test "vector f64" {151test "vector f64" {
152 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
156 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO153 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
157 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO154 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
158 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
159 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO155 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
160 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;156 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
161 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;157 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -177,9 +173,9 @@ fn vector80() !void {...@@ -177,9 +173,9 @@ fn vector80() !void {
177}173}
178174
179test "vector f80" {175test "vector f80" {
176 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
180 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO177 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
181 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO178 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
183 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO179 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
184 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;180 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
185 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;181 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;
...@@ -203,9 +199,9 @@ fn vector128() !void {...@@ -203,9 +199,9 @@ fn vector128() !void {
203}199}
204200
205test "vector f128" {201test "vector f128" {
202 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
206 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO203 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
207 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO204 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
208 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
209 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO205 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
210 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;206 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
211 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest;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,7 +11,6 @@ comptime {
11const builtin = @import("builtin");11const builtin = @import("builtin");
1212
13test "call extern function defined with conflicting type" {13test "call extern function defined with conflicting type" {
14 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO14 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
16 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO15 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,7 +23,6 @@ const snan_f128: f128 = math.snan(f128);
2323
24test "nan memory equality" {24test "nan memory equality" {
25 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;25 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
26 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
27 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;26 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
28 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;27 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2928
test/behavior/null.zig+2-4
...@@ -29,8 +29,8 @@ test "optional type" {...@@ -29,8 +29,8 @@ test "optional type" {
29}29}
3030
31test "test maybe object and get a pointer to the inner value" {31test "test maybe object and get a pointer to the inner value" {
32 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
33 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;32 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
33 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
34 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO34 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
35 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;35 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3636
...@@ -51,7 +51,6 @@ test "rhs maybe unwrap return" {...@@ -51,7 +51,6 @@ test "rhs maybe unwrap return" {
5151
52test "maybe return" {52test "maybe return" {
53 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;53 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
54 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
55 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO54 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5655
57 try maybeReturnImpl();56 try maybeReturnImpl();
...@@ -140,8 +139,8 @@ test "optional pointer to 0 bit type null value at runtime" {...@@ -140,8 +139,8 @@ test "optional pointer to 0 bit type null value at runtime" {
140}139}
141140
142test "if var maybe pointer" {141test "if var maybe pointer" {
143 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
144 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;142 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
143 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
145 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO144 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
146 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;145 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
147146
...@@ -185,7 +184,6 @@ const here_is_a_null_literal = SillyStruct{ .context = null };...@@ -185,7 +184,6 @@ const here_is_a_null_literal = SillyStruct{ .context = null };
185184
186test "unwrap optional which is field of global var" {185test "unwrap optional which is field of global var" {
187 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;186 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
189 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO187 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
190188
191 struct_with_optional.field = null;189 struct_with_optional.field = null;
test/behavior/optional.zig+8-12
...@@ -59,6 +59,7 @@ fn testNullPtrsEql() !void {...@@ -59,6 +59,7 @@ fn testNullPtrsEql() !void {
59}59}
6060
61test "optional with zero-bit type" {61test "optional with zero-bit type" {
62 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
62 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;63 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
6364
64 const S = struct {65 const S = struct {
...@@ -109,7 +110,6 @@ test "optional with zero-bit type" {...@@ -109,7 +110,6 @@ test "optional with zero-bit type" {
109}110}
110111
111test "address of unwrap optional" {112test "address of unwrap optional" {
112 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
113 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO113 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
114 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO114 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
115 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;115 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -132,7 +132,6 @@ test "address of unwrap optional" {...@@ -132,7 +132,6 @@ test "address of unwrap optional" {
132}132}
133133
134test "nested optional field in struct" {134test "nested optional field in struct" {
135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
136 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO135 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
137 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO136 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
138137
...@@ -210,6 +209,7 @@ test "equality compare optionals and non-optionals" {...@@ -210,6 +209,7 @@ test "equality compare optionals and non-optionals" {
210}209}
211210
212test "compare optionals with modified payloads" {211test "compare optionals with modified payloads" {
212 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
213 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;213 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
214214
215 var lhs: ?bool = false;215 var lhs: ?bool = false;
...@@ -319,7 +319,6 @@ test "assigning to an unwrapped optional field in an inline loop" {...@@ -319,7 +319,6 @@ test "assigning to an unwrapped optional field in an inline loop" {
319}319}
320320
321test "coerce an anon struct literal to optional struct" {321test "coerce an anon struct literal to optional struct" {
322 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
323 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO322 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
324 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO323 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
325 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;324 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -339,7 +338,6 @@ test "coerce an anon struct literal to optional struct" {...@@ -339,7 +338,6 @@ test "coerce an anon struct literal to optional struct" {
339}338}
340339
341test "0-bit child type coerced to optional return ptr result location" {340test "0-bit child type coerced to optional return ptr result location" {
342 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
343 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO341 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
344 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO342 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
345343
...@@ -365,6 +363,7 @@ test "0-bit child type coerced to optional return ptr result location" {...@@ -365,6 +363,7 @@ test "0-bit child type coerced to optional return ptr result location" {
365}363}
366364
367test "0-bit child type coerced to optional" {365test "0-bit child type coerced to optional" {
366 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
368 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO367 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
369 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;368 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
370369
...@@ -391,7 +390,7 @@ test "0-bit child type coerced to optional" {...@@ -391,7 +390,7 @@ test "0-bit child type coerced to optional" {
391}390}
392391
393test "array of optional unaligned types" {392test "array of optional unaligned types" {
394 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO393 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
395 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO394 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
396 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO395 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
397 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;396 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -428,8 +427,8 @@ test "array of optional unaligned types" {...@@ -428,8 +427,8 @@ test "array of optional unaligned types" {
428}427}
429428
430test "optional pointer to zero bit optional payload" {429test "optional pointer to zero bit optional payload" {
430 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
431 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO431 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
432 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
433 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO432 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
434 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;433 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
435434
...@@ -448,7 +447,6 @@ test "optional pointer to zero bit optional payload" {...@@ -448,7 +447,6 @@ test "optional pointer to zero bit optional payload" {
448447
449test "optional pointer to zero bit error union payload" {448test "optional pointer to zero bit error union payload" {
450 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO449 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
451 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
452 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO450 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
453 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;451 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
454 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;452 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -543,7 +541,6 @@ test "alignment of wrapping an optional payload" {...@@ -543,7 +541,6 @@ test "alignment of wrapping an optional payload" {
543}541}
544542
545test "Optional slice size is optimized" {543test "Optional slice size is optimized" {
546 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
547 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;544 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
548 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO545 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
549 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;546 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -556,7 +553,7 @@ test "Optional slice size is optimized" {...@@ -556,7 +553,7 @@ test "Optional slice size is optimized" {
556}553}
557554
558test "Optional slice passed to function" {555test "Optional slice passed to function" {
559 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO556 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
560 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO557 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
561 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO558 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
562 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;559 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -574,7 +571,6 @@ test "Optional slice passed to function" {...@@ -574,7 +571,6 @@ test "Optional slice passed to function" {
574}571}
575572
576test "peer type resolution in nested if expressions" {573test "peer type resolution in nested if expressions" {
577 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
578 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;574 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
579575
580 const Thing = struct { n: i32 };576 const Thing = struct { n: i32 };
...@@ -623,8 +619,8 @@ test "variable of optional of noreturn" {...@@ -623,8 +619,8 @@ test "variable of optional of noreturn" {
623}619}
624620
625test "copied optional doesn't alias source" {621test "copied optional doesn't alias source" {
622 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
626 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO623 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
627 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
628 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO624 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
629 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;625 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
630626
...@@ -637,8 +633,8 @@ test "copied optional doesn't alias source" {...@@ -637,8 +633,8 @@ test "copied optional doesn't alias source" {
637}633}
638634
639test "result location initialization of optional with OPV payload" {635test "result location initialization of optional with OPV payload" {
636 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
640 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO637 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
641 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
642 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO638 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
643 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;639 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
644 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO640 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,7 +120,6 @@ test "consistent size of packed structs" {
120}120}
121121
122test "correct sizeOf and offsets in packed structs" {122test "correct sizeOf and offsets in packed structs" {
123 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
124 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO123 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
125 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO124 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
126125
...@@ -187,7 +186,6 @@ test "correct sizeOf and offsets in packed structs" {...@@ -187,7 +186,6 @@ test "correct sizeOf and offsets in packed structs" {
187}186}
188187
189test "nested packed structs" {188test "nested packed structs" {
190 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
191 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO189 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
192 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO190 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
193191
...@@ -484,7 +482,6 @@ test "load pointer from packed struct" {...@@ -484,7 +482,6 @@ test "load pointer from packed struct" {
484}482}
485483
486test "@intFromPtr on a packed struct field" {484test "@intFromPtr on a packed struct field" {
487 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
488 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;485 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
489 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO486 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
490 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;487 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -507,7 +504,6 @@ test "@intFromPtr on a packed struct field" {...@@ -507,7 +504,6 @@ test "@intFromPtr on a packed struct field" {
507}504}
508505
509test "@intFromPtr on a packed struct field unaligned and nested" {506test "@intFromPtr on a packed struct field unaligned and nested" {
510 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
511 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;507 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
512 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO508 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
513 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,6 +613,7 @@ test "@intFromPtr on a packed struct field unaligned and nested" {
617}613}
618614
619test "packed struct fields modification" {615test "packed struct fields modification" {
616 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
620 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;617 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
621618
622 // Originally reported at https://github.com/ziglang/zig/issues/16615619 // Originally reported at https://github.com/ziglang/zig/issues/16615
...@@ -656,9 +653,9 @@ test "optional pointer in packed struct" {...@@ -656,9 +653,9 @@ test "optional pointer in packed struct" {
656}653}
657654
658test "nested packed struct field access test" {655test "nested packed struct field access test" {
656 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
659 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO657 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
660 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO packed structs larger than 64 bits658 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 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO659 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
663 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO660 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
664 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;661 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -777,6 +774,7 @@ test "nested packed struct field access test" {...@@ -777,6 +774,7 @@ test "nested packed struct field access test" {
777}774}
778775
779test "nested packed struct at non-zero offset" {776test "nested packed struct at non-zero offset" {
777 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
780 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO778 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
781 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;779 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
782780
...@@ -915,7 +913,6 @@ test "packed struct passed to callconv(.c) function" {...@@ -915,7 +913,6 @@ test "packed struct passed to callconv(.c) function" {
915}913}
916914
917test "overaligned pointer to packed struct" {915test "overaligned pointer to packed struct" {
918 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
919 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;916 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
920 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO917 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
921 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;918 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -937,7 +934,7 @@ test "overaligned pointer to packed struct" {...@@ -937,7 +934,7 @@ test "overaligned pointer to packed struct" {
937}934}
938935
939test "packed struct initialized in bitcast" {936test "packed struct initialized in bitcast" {
940 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO937 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
941 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO938 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
942 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO939 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
943 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;940 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -986,8 +983,8 @@ test "store undefined to packed result location" {...@@ -986,8 +983,8 @@ test "store undefined to packed result location" {
986 try expectEqual(x, s.x);983 try expectEqual(x, s.x);
987}984}
988985
986// Originally reported at https://github.com/ziglang/zig/issues/9914
989test "bitcast back and forth" {987test "bitcast back and forth" {
990 // Originally reported at https://github.com/ziglang/zig/issues/9914
991 const S = packed struct { one: u6, two: u1 };988 const S = packed struct { one: u6, two: u1 };
992 const s = S{ .one = 0b110101, .two = 0b1 };989 const s = S{ .one = 0b110101, .two = 0b1 };
993 const u: u7 = @bitCast(s);990 const u: u7 = @bitCast(s);
...@@ -996,8 +993,9 @@ test "bitcast back and forth" {...@@ -996,8 +993,9 @@ test "bitcast back and forth" {
996 try expect(s.two == s2.two);993 try expect(s.two == s2.two);
997}994}
998995
996// Originally reported at https://github.com/ziglang/zig/issues/14200
999test "field access of packed struct smaller than its abi size inside struct initialized with rls" {997test "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/14200998 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1001 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;999 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1002 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO1000 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
10031001
...@@ -1015,8 +1013,8 @@ test "field access of packed struct smaller than its abi size inside struct init...@@ -1015,8 +1013,8 @@ test "field access of packed struct smaller than its abi size inside struct init
1015 try expect(@as(i2, 1) == s.ps.y);1013 try expect(@as(i2, 1) == s.ps.y);
1016}1014}
10171015
1016// Originally reported at https://github.com/ziglang/zig/issues/14632
1018test "modify nested packed struct aligned field" {1017test "modify nested packed struct aligned field" {
1019 // Originally reported at https://github.com/ziglang/zig/issues/14632
1020 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;1018 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1021 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;1019 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1022 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;1020 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
...@@ -1045,10 +1043,10 @@ test "modify nested packed struct aligned field" {...@@ -1045,10 +1043,10 @@ test "modify nested packed struct aligned field" {
1045 try std.testing.expect(!opts.baz);1043 try std.testing.expect(!opts.baz);
1046}1044}
10471045
1046// Originally reported at https://github.com/ziglang/zig/issues/9674
1048test "assigning packed struct inside another packed struct" {1047test "assigning packed struct inside another packed struct" {
1048 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1049 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1049 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1050
1051 // Originally reported at https://github.com/ziglang/zig/issues/9674
1052 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1050 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10531051
1054 const S = struct {1052 const S = struct {
...@@ -1078,7 +1076,6 @@ test "assigning packed struct inside another packed struct" {...@@ -1078,7 +1076,6 @@ test "assigning packed struct inside another packed struct" {
1078}1076}
10791077
1080test "packed struct used as part of anon decl name" {1078test "packed struct used as part of anon decl name" {
1081 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1082 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1079 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1083 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1080 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1084 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1081 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1104,7 +1101,13 @@ test "packed struct acts as a namespace" {...@@ -1104,7 +1101,13 @@ test "packed struct acts as a namespace" {
1104}1101}
11051102
1106test "pointer loaded correctly from packed struct" {1103test "pointer loaded correctly from packed struct" {
1104 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1105 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1107 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1106 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1107 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
1108 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1109
1110 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // crashes MSVC
11081111
1109 const RAM = struct {1112 const RAM = struct {
1110 data: [0xFFFF + 1]u8,1113 data: [0xFFFF + 1]u8,
...@@ -1132,12 +1135,6 @@ test "pointer loaded correctly from packed struct" {...@@ -1132,12 +1135,6 @@ test "pointer loaded correctly from packed struct" {
1132 }1135 }
1133 }1136 }
1134 };1137 };
1135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1136 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1137 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
1138 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1139
1140 if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // crashes MSVC
11411138
1142 var ram = try RAM.new();1139 var ram = try RAM.new();
1143 var cpu = try CPU.new(&ram);1140 var cpu = try CPU.new(&ram);
...@@ -1146,7 +1143,7 @@ test "pointer loaded correctly from packed struct" {...@@ -1146,7 +1143,7 @@ test "pointer loaded correctly from packed struct" {
1146}1143}
11471144
1148test "assignment to non-byte-aligned field in packed struct" {1145test "assignment to non-byte-aligned field in packed struct" {
1149 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1146 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1150 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1147 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1151 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1148 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1152 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO1149 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
...@@ -1167,7 +1164,6 @@ test "assignment to non-byte-aligned field in packed struct" {...@@ -1167,7 +1164,6 @@ test "assignment to non-byte-aligned field in packed struct" {
1167}1164}
11681165
1169test "packed struct field pointer aligned properly" {1166test "packed struct field pointer aligned properly" {
1170 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1171 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1167 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1172 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1168 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1173 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO1169 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
...@@ -1186,7 +1182,7 @@ test "packed struct field pointer aligned properly" {...@@ -1186,7 +1182,7 @@ test "packed struct field pointer aligned properly" {
1186}1182}
11871183
1188test "load flag from packed struct in union" {1184test "load flag from packed struct in union" {
1189 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1185 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1190 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1186 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1191 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1187 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1192 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1188 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1311,6 +1307,7 @@ test "packed struct equality" {...@@ -1311,6 +1307,7 @@ test "packed struct equality" {
1311}1307}
13121308
1313test "packed struct equality ignores padding bits" {1309test "packed struct equality ignores padding bits" {
1310 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1314 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;1311 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1315 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1312 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
13161313
...@@ -1322,6 +1319,8 @@ test "packed struct equality ignores padding bits" {...@@ -1322,6 +1319,8 @@ test "packed struct equality ignores padding bits" {
1322}1319}
13231320
1324test "packed struct with signed field" {1321test "packed struct with signed field" {
1322 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1323
1325 var s: packed struct {1324 var s: packed struct {
1326 a: i2,1325 a: i2,
1327 b: u6,1326 b: u6,
...@@ -1332,6 +1331,7 @@ test "packed struct with signed field" {...@@ -1332,6 +1331,7 @@ test "packed struct with signed field" {
1332}1331}
13331332
1334test "assign packed struct initialized with RLS to packed struct literal field" {1333test "assign packed struct initialized with RLS to packed struct literal field" {
1334 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1335 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isWasm()) return error.SkipZigTest;1335 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isWasm()) return error.SkipZigTest;
1336 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1336 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1337 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1337 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1349,6 +1349,7 @@ test "assign packed struct initialized with RLS to packed struct literal field"...@@ -1349,6 +1349,7 @@ test "assign packed struct initialized with RLS to packed struct literal field"
1349}1349}
13501350
1351test "byte-aligned packed relocation" {1351test "byte-aligned packed relocation" {
1352 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1352 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;1353 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1353 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;1354 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
1354 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1355 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1363,6 +1364,7 @@ test "byte-aligned packed relocation" {...@@ -1363,6 +1364,7 @@ test "byte-aligned packed relocation" {
1363}1364}
13641365
1365test "packed struct store of comparison result" {1366test "packed struct store of comparison result" {
1367 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1366 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1368 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1367 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO1369 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
13681370
test/behavior/packed-union.zig+3-3
...@@ -99,10 +99,10 @@ fn testFlagsInPackedUnionAtOffset() !void {...@@ -99,10 +99,10 @@ fn testFlagsInPackedUnionAtOffset() !void {
99 try expectEqual(false, test_bits.adv_flags.adv.flags.enable_2);99 try expectEqual(false, test_bits.adv_flags.adv.flags.enable_2);
100}100}
101101
102// Originally reported at https://github.com/ziglang/zig/issues/16581
102test "packed union in packed struct" {103test "packed union in packed struct" {
104 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
103 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;105 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
104
105 // Originally reported at https://github.com/ziglang/zig/issues/16581
106 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;106 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
107107
108 try testPackedUnionInPackedStruct();108 try testPackedUnionInPackedStruct();
...@@ -136,7 +136,7 @@ fn testPackedUnionInPackedStruct() !void {...@@ -136,7 +136,7 @@ fn testPackedUnionInPackedStruct() !void {
136}136}
137137
138test "packed union initialized with a runtime value" {138test "packed union initialized with a runtime value" {
139 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO139 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
140 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO140 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
141 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO141 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
142 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;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,7 +5,6 @@ const expectEqual = std.testing.expectEqual;
5const native_endian = builtin.cpu.arch.endian();5const native_endian = builtin.cpu.arch.endian();
66
7test "packed struct explicit backing integer" {7test "packed struct explicit backing integer" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1110
test/behavior/pointers.zig+1-13
...@@ -18,7 +18,6 @@ fn testDerefPtr() !void {...@@ -18,7 +18,6 @@ fn testDerefPtr() !void {
18}18}
1919
20test "pointer-integer arithmetic" {20test "pointer-integer arithmetic" {
21 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
22 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO21 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
23 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;22 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
24 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,7 +231,6 @@ test "peer type resolution with C pointer and const pointer" {
232231
233test "implicit casting between C pointer and optional non-C pointer" {232test "implicit casting between C pointer and optional non-C pointer" {
234 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;233 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
235 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
236 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO234 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
237 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;235 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
238 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,8 +246,8 @@ test "implicit casting between C pointer and optional non-C pointer" {
248}246}
249247
250test "implicit cast error unions with non-optional to optional pointer" {248test "implicit cast error unions with non-optional to optional pointer" {
249 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
251 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO250 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
252 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
253 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO251 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
254 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;252 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
255 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;253 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -298,7 +296,6 @@ test "allowzero pointer and slice" {...@@ -298,7 +296,6 @@ test "allowzero pointer and slice" {
298296
299test "assign null directly to C pointer and test null equality" {297test "assign null directly to C pointer and test null equality" {
300 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO298 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
301 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
302 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO299 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
303 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;300 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
304301
...@@ -366,7 +363,6 @@ test "array initialization types" {...@@ -366,7 +363,6 @@ test "array initialization types" {
366}363}
367364
368test "null terminated pointer" {365test "null terminated pointer" {
369 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
370 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO366 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
371 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;367 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
372368
...@@ -384,7 +380,6 @@ test "null terminated pointer" {...@@ -384,7 +380,6 @@ test "null terminated pointer" {
384}380}
385381
386test "allow any sentinel" {382test "allow any sentinel" {
387 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
388 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO383 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
389 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;384 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
390 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;385 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -401,7 +396,6 @@ test "allow any sentinel" {...@@ -401,7 +396,6 @@ test "allow any sentinel" {
401}396}
402397
403test "pointer sentinel with enums" {398test "pointer sentinel with enums" {
404 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
405 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO399 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
406 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;400 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
407 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;401 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -442,7 +436,6 @@ test "pointer sentinel with optional element" {...@@ -442,7 +436,6 @@ test "pointer sentinel with optional element" {
442}436}
443437
444test "pointer sentinel with +inf" {438test "pointer sentinel with +inf" {
445 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
446 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO439 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
447 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO440 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
448 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;441 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -515,7 +508,6 @@ test "@intFromPtr on null optional at comptime" {...@@ -515,7 +508,6 @@ test "@intFromPtr on null optional at comptime" {
515}508}
516509
517test "indexing array with sentinel returns correct type" {510test "indexing array with sentinel returns correct type" {
518 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
519 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO511 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
520 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO512 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
521 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;513 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -525,7 +517,6 @@ test "indexing array with sentinel returns correct type" {...@@ -525,7 +517,6 @@ test "indexing array with sentinel returns correct type" {
525}517}
526518
527test "element pointer to slice" {519test "element pointer to slice" {
528 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
529 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO520 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
530 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;521 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
531522
...@@ -548,7 +539,6 @@ test "element pointer to slice" {...@@ -548,7 +539,6 @@ test "element pointer to slice" {
548}539}
549540
550test "element pointer arithmetic to slice" {541test "element pointer arithmetic to slice" {
551 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
552 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO542 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
553 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;543 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
554544
...@@ -604,7 +594,6 @@ test "pointer to constant decl preserves alignment" {...@@ -604,7 +594,6 @@ test "pointer to constant decl preserves alignment" {
604594
605test "ptrCast comptime known slice to C pointer" {595test "ptrCast comptime known slice to C pointer" {
606 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO596 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
607 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
608 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO597 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
609 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;598 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
610599
...@@ -625,7 +614,6 @@ test "pointer alignment and element type include call expression" {...@@ -625,7 +614,6 @@ test "pointer alignment and element type include call expression" {
625}614}
626615
627test "pointer to array has explicit alignment" {616test "pointer to array has explicit alignment" {
628 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
629 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;617 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
630618
631 const S = struct {619 const S = struct {
test/behavior/popcount.zig+2-3
...@@ -4,7 +4,6 @@ const expect = std.testing.expect;...@@ -4,7 +4,6 @@ const expect = std.testing.expect;
4const expectEqual = std.testing.expectEqual;4const expectEqual = std.testing.expectEqual;
55
6test "@popCount integers" {6test "@popCount integers" {
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -15,7 +14,7 @@ test "@popCount integers" {...@@ -15,7 +14,7 @@ test "@popCount integers" {
15}14}
1615
17test "@popCount 128bit integer" {16test "@popCount 128bit integer" {
18 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO17 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
19 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO18 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
20 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO19 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
21 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;20 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -77,8 +76,8 @@ fn testPopCountIntegers() !void {...@@ -77,8 +76,8 @@ fn testPopCountIntegers() !void {
77}76}
7877
79test "@popCount vectors" {78test "@popCount vectors" {
79 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
80 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO80 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
81 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
82 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO81 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
83 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO82 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
84 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;83 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/ptrcast.zig+10-19
...@@ -22,7 +22,6 @@ fn testReinterpretBytesAsInteger() !void {...@@ -22,7 +22,6 @@ fn testReinterpretBytesAsInteger() !void {
2222
23test "reinterpret an array over multiple elements, with no well-defined layout" {23test "reinterpret an array over multiple elements, with no well-defined layout" {
24 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO24 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
25 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
26 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO25 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
27 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;26 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2827
...@@ -56,7 +55,6 @@ fn testReinterpretStructWrappedBytesAsInteger() !void {...@@ -56,7 +55,6 @@ fn testReinterpretStructWrappedBytesAsInteger() !void {
56}55}
5756
58test "reinterpret bytes of an array into an extern struct" {57test "reinterpret bytes of an array into an extern struct" {
59 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
60 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO58 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
61 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;59 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
6260
...@@ -130,7 +128,6 @@ fn testReinterpretOverAlignedExternStructAsExternStruct() !void {...@@ -130,7 +128,6 @@ fn testReinterpretOverAlignedExternStructAsExternStruct() !void {
130128
131test "lower reinterpreted comptime field ptr (with under-aligned fields)" {129test "lower reinterpreted comptime field ptr (with under-aligned fields)" {
132 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO130 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
133 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
134 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO131 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
135132
136 // Test lowering a field ptr133 // Test lowering a field ptr
...@@ -152,7 +149,6 @@ test "lower reinterpreted comptime field ptr (with under-aligned fields)" {...@@ -152,7 +149,6 @@ test "lower reinterpreted comptime field ptr (with under-aligned fields)" {
152149
153test "lower reinterpreted comptime field ptr" {150test "lower reinterpreted comptime field ptr" {
154 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO151 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
156 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO152 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
157153
158 // Test lowering a field ptr154 // Test lowering a field ptr
...@@ -174,7 +170,6 @@ test "lower reinterpreted comptime field ptr" {...@@ -174,7 +170,6 @@ test "lower reinterpreted comptime field ptr" {
174170
175test "reinterpret struct field at comptime" {171test "reinterpret struct field at comptime" {
176 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO172 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
177 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
178 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;173 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
179174
180 const numNative = comptime Bytes.init(0x12345678);175 const numNative = comptime Bytes.init(0x12345678);
...@@ -232,7 +227,6 @@ test "ptrcast of const integer has the correct object size" {...@@ -232,7 +227,6 @@ test "ptrcast of const integer has the correct object size" {
232test "implicit optional pointer to optional anyopaque pointer" {227test "implicit optional pointer to optional anyopaque pointer" {
233 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO228 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
234 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO229 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
235 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
236 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;230 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
237231
238 var buf: [4]u8 = "aoeu".*;232 var buf: [4]u8 = "aoeu".*;
...@@ -244,7 +238,6 @@ test "implicit optional pointer to optional anyopaque pointer" {...@@ -244,7 +238,6 @@ test "implicit optional pointer to optional anyopaque pointer" {
244238
245test "@ptrCast slice to slice" {239test "@ptrCast slice to slice" {
246 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO240 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
247 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
248 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO241 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
249 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;242 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
250243
...@@ -262,7 +255,6 @@ test "@ptrCast slice to slice" {...@@ -262,7 +255,6 @@ test "@ptrCast slice to slice" {
262255
263test "comptime @ptrCast a subset of an array, then write through it" {256test "comptime @ptrCast a subset of an array, then write through it" {
264 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO257 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
265 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
266 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO258 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
267259
268 comptime {260 comptime {
...@@ -354,7 +346,6 @@ test "@ptrCast restructures sliced comptime-only array" {...@@ -354,7 +346,6 @@ test "@ptrCast restructures sliced comptime-only array" {
354346
355test "@ptrCast slice multiplying length" {347test "@ptrCast slice multiplying length" {
356 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO348 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
357 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
358 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO349 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
359 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;350 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
360351
...@@ -372,7 +363,6 @@ test "@ptrCast slice multiplying length" {...@@ -372,7 +363,6 @@ test "@ptrCast slice multiplying length" {
372363
373test "@ptrCast array pointer to slice multiplying length" {364test "@ptrCast array pointer to slice multiplying length" {
374 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO365 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
375 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
376 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO366 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
377 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;367 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
378368
...@@ -390,7 +380,6 @@ test "@ptrCast array pointer to slice multiplying length" {...@@ -390,7 +380,6 @@ test "@ptrCast array pointer to slice multiplying length" {
390380
391test "@ptrCast slice dividing length" {381test "@ptrCast slice dividing length" {
392 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO382 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
393 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
394 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO383 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
395 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;384 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
396385
...@@ -408,7 +397,6 @@ test "@ptrCast slice dividing length" {...@@ -408,7 +397,6 @@ test "@ptrCast slice dividing length" {
408397
409test "@ptrCast array pointer to slice dividing length" {398test "@ptrCast array pointer to slice dividing length" {
410 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO399 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
411 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
412 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO400 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
413 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;401 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
414402
...@@ -426,7 +414,6 @@ test "@ptrCast array pointer to slice dividing length" {...@@ -426,7 +414,6 @@ test "@ptrCast array pointer to slice dividing length" {
426414
427test "@ptrCast slice with complex length increase" {415test "@ptrCast slice with complex length increase" {
428 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO416 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
429 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
430 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO417 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
431 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;418 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
432419
...@@ -447,7 +434,6 @@ test "@ptrCast slice with complex length increase" {...@@ -447,7 +434,6 @@ test "@ptrCast slice with complex length increase" {
447434
448test "@ptrCast array pointer to slice with complex length increase" {435test "@ptrCast array pointer to slice with complex length increase" {
449 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO436 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
450 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
451 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO437 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
452 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;438 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
453439
...@@ -468,7 +454,6 @@ test "@ptrCast array pointer to slice with complex length increase" {...@@ -468,7 +454,6 @@ test "@ptrCast array pointer to slice with complex length increase" {
468454
469test "@ptrCast slice with complex length decrease" {455test "@ptrCast slice with complex length decrease" {
470 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO456 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
471 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
472 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO457 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
473 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;458 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
474459
...@@ -489,7 +474,6 @@ test "@ptrCast slice with complex length decrease" {...@@ -489,7 +474,6 @@ test "@ptrCast slice with complex length decrease" {
489474
490test "@ptrCast array pointer to slice with complex length decrease" {475test "@ptrCast array pointer to slice with complex length decrease" {
491 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO476 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
492 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
493 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO477 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
494 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;478 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
495479
...@@ -510,7 +494,6 @@ test "@ptrCast array pointer to slice with complex length decrease" {...@@ -510,7 +494,6 @@ test "@ptrCast array pointer to slice with complex length decrease" {
510494
511test "@ptrCast slice of zero-bit type to different slice" {495test "@ptrCast slice of zero-bit type to different slice" {
512 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO496 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
513 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
514 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO497 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
515 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;498 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
516499
...@@ -530,7 +513,6 @@ test "@ptrCast slice of zero-bit type to different slice" {...@@ -530,7 +513,6 @@ test "@ptrCast slice of zero-bit type to different slice" {
530513
531test "@ptrCast single-item pointer to slice with length 1" {514test "@ptrCast single-item pointer to slice with length 1" {
532 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO515 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
533 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
534 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO516 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
535 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;517 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
536 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO518 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,7 +534,6 @@ test "@ptrCast single-item pointer to slice with length 1" {
552534
553test "@ptrCast single-item pointer to slice of bytes" {535test "@ptrCast single-item pointer to slice of bytes" {
554 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO536 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
555 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
556 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO537 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
557 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;538 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
558 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO539 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
...@@ -571,3 +552,13 @@ test "@ptrCast single-item pointer to slice of bytes" {...@@ -571,3 +552,13 @@ test "@ptrCast single-item pointer to slice of bytes" {
571 try comptime S.doTheTest(void, &{});552 try comptime S.doTheTest(void, &{});
572 try comptime S.doTheTest(struct { x: u32 }, &.{ .x = 123 });553 try comptime S.doTheTest(struct { x: u32 }, &.{ .x = 123 });
573}554}
555
556test "@ptrCast array pointer removing sentinel" {
557 const in: *const [4:0]u8 = &.{ 1, 2, 3, 4 };
558 const out: []const i8 = @ptrCast(in);
559 comptime assert(out.len == 4);
560 comptime assert(out[0] == 1);
561 comptime assert(out[1] == 2);
562 comptime assert(out[2] == 3);
563 comptime assert(out[3] == 4);
564}
test/behavior/ptrfromint.zig-3
...@@ -17,7 +17,6 @@ fn addressToFunction() void {...@@ -17,7 +17,6 @@ fn addressToFunction() void {
1717
18test "mutate through ptr initialized with constant ptrFromInt value" {18test "mutate through ptr initialized with constant ptrFromInt value" {
19 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;19 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
20 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
21 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO20 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
22 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;21 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2322
...@@ -35,7 +34,6 @@ fn forceCompilerAnalyzeBranchHardCodedPtrDereference(x: bool) void {...@@ -35,7 +34,6 @@ fn forceCompilerAnalyzeBranchHardCodedPtrDereference(x: bool) void {
3534
36test "@ptrFromInt creates null pointer" {35test "@ptrFromInt creates null pointer" {
37 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;36 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
38 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
39 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO37 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
40 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;38 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4139
...@@ -45,7 +43,6 @@ test "@ptrFromInt creates null pointer" {...@@ -45,7 +43,6 @@ test "@ptrFromInt creates null pointer" {
4543
46test "@ptrFromInt creates allowzero zero pointer" {44test "@ptrFromInt creates allowzero zero pointer" {
47 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;45 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
48 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
49 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO46 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5047
51 const ptr = @as(*allowzero u32, @ptrFromInt(0));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,7 +6,6 @@ const mem = std.mem;
6var ok: bool = false;6var ok: bool = false;
7test "reference a variable in an if after an if in the 2nd switch prong" {7test "reference a variable in an if after an if in the 2nd switch prong" {
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;10 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1211
test/behavior/reflection.zig-1
...@@ -26,7 +26,6 @@ fn dummy(a: bool, b: i32, c: f32) i32 {...@@ -26,7 +26,6 @@ fn dummy(a: bool, b: i32, c: f32) i32 {
26}26}
2727
28test "reflection: @field" {28test "reflection: @field" {
29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
30 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO29 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3130
32 var f = Foo{31 var f = Foo{
test/behavior/return_address.zig-1
...@@ -6,7 +6,6 @@ fn retAddr() usize {...@@ -6,7 +6,6 @@ fn retAddr() usize {
6}6}
77
8test "return address" {8test "return address" {
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;11 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,7 +5,7 @@ const maxInt = std.math.maxInt;
5const expect = std.testing.expect;5const expect = std.testing.expect;
66
7test "saturating add" {7test "saturating add" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;11 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -52,8 +52,8 @@ test "saturating add" {...@@ -52,8 +52,8 @@ test "saturating add" {
52}52}
5353
54test "saturating add 128bit" {54test "saturating add 128bit" {
55 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
55 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO56 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
56 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
57 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO57 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
58 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO58 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
59 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;59 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -79,7 +79,7 @@ test "saturating add 128bit" {...@@ -79,7 +79,7 @@ test "saturating add 128bit" {
79}79}
8080
81test "saturating subtraction" {81test "saturating subtraction" {
82 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO82 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
83 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO83 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
84 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO84 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
85 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;85 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -125,8 +125,8 @@ test "saturating subtraction" {...@@ -125,8 +125,8 @@ test "saturating subtraction" {
125}125}
126126
127test "saturating subtraction 128bit" {127test "saturating subtraction 128bit" {
128 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
128 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO129 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
129 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
130 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO130 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
131 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO131 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
132 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,7 +158,6 @@ fn testSatMul(comptime T: type, a: T, b: T, expected: T) !void {
158}158}
159159
160test "saturating multiplication <= 32 bits" {160test "saturating multiplication <= 32 bits" {
161 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
162 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
163 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO162 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
164 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;163 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -229,6 +228,7 @@ test "saturating multiplication <= 32 bits" {...@@ -229,6 +228,7 @@ test "saturating multiplication <= 32 bits" {
229}228}
230229
231test "saturating mul i64, i128" {230test "saturating mul i64, i128" {
231 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
232 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;232 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
233 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;233 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
234234
...@@ -256,8 +256,8 @@ test "saturating mul i64, i128" {...@@ -256,8 +256,8 @@ test "saturating mul i64, i128" {
256}256}
257257
258test "saturating multiplication" {258test "saturating multiplication" {
259 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
259 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO260 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
260 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
261 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO261 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
262 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO262 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
263 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;263 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -295,7 +295,7 @@ test "saturating multiplication" {...@@ -295,7 +295,7 @@ test "saturating multiplication" {
295}295}
296296
297test "saturating shift-left" {297test "saturating shift-left" {
298 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO298 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
299 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO299 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
300 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO300 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
301 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;301 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -340,6 +340,7 @@ test "saturating shift-left" {...@@ -340,6 +340,7 @@ test "saturating shift-left" {
340}340}
341341
342test "saturating shift-left large rhs" {342test "saturating shift-left large rhs" {
343 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
343 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;344 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
344 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;345 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
345 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;346 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -357,7 +358,7 @@ test "saturating shift-left large rhs" {...@@ -357,7 +358,7 @@ test "saturating shift-left large rhs" {
357}358}
358359
359test "saturating shl uses the LHS type" {360test "saturating shl uses the LHS type" {
360 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO361 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
361 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO362 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
362 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO363 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
363 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,9 +4,9 @@ const mem = std.mem;
4const expect = std.testing.expect;4const expect = std.testing.expect;
55
6test "@select vectors" {6test "@select vectors" {
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;11 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;12 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -35,9 +35,9 @@ fn selectVectors() !void {...@@ -35,9 +35,9 @@ fn selectVectors() !void {
35}35}
3636
37test "@select arrays" {37test "@select arrays" {
38 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
38 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO39 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
39 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO40 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
40 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
41 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO41 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
42 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;42 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
43 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;43 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -66,6 +66,7 @@ fn selectArrays() !void {...@@ -66,6 +66,7 @@ fn selectArrays() !void {
66}66}
6767
68test "@select compare result" {68test "@select compare result" {
69 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
69 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;70 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
70 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;71 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
71 if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest;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,7 +5,7 @@ const expect = std.testing.expect;
5const expectEqual = std.testing.expectEqual;5const expectEqual = std.testing.expectEqual;
66
7test "@shuffle int" {7test "@shuffle int" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;11 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -50,8 +50,8 @@ test "@shuffle int" {...@@ -50,8 +50,8 @@ test "@shuffle int" {
50}50}
5151
52test "@shuffle int strange sizes" {52test "@shuffle int strange sizes" {
53 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
53 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO54 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
54 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
55 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO55 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
56 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO56 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
57 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;57 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -132,8 +132,8 @@ fn testShuffle(...@@ -132,8 +132,8 @@ fn testShuffle(
132}132}
133133
134test "@shuffle bool 1" {134test "@shuffle bool 1" {
135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
135 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO136 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
136 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
137 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO137 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
138 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO138 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
139 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;139 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -155,8 +155,8 @@ test "@shuffle bool 1" {...@@ -155,8 +155,8 @@ test "@shuffle bool 1" {
155}155}
156156
157test "@shuffle bool 2" {157test "@shuffle bool 2" {
158 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
158 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO159 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
159 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
160 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO160 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
161 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO161 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
162 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;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,7 +270,6 @@ test "bitSizeOf comptime_int" {
270}270}
271271
272test "runtime instructions inside typeof in comptime only scope" {272test "runtime instructions inside typeof in comptime only scope" {
273 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
274 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;273 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
275 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO274 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
276275
...@@ -326,7 +325,6 @@ test "lazy abi size used in comparison" {...@@ -326,7 +325,6 @@ test "lazy abi size used in comparison" {
326}325}
327326
328test "peer type resolution with @TypeOf doesn't trigger dependency loop check" {327test "peer type resolution with @TypeOf doesn't trigger dependency loop check" {
329 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
330 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO328 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
331 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;329 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
332330
...@@ -437,7 +435,6 @@ test "Peer resolution of extern function calls in @TypeOf" {...@@ -437,7 +435,6 @@ test "Peer resolution of extern function calls in @TypeOf" {
437}435}
438436
439test "Extern function calls, dereferences and field access in @TypeOf" {437test "Extern function calls, dereferences and field access in @TypeOf" {
440 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
441 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO438 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
442439
443 const Test = struct {440 const Test = struct {
test/behavior/slice.zig+2-22
...@@ -211,7 +211,6 @@ test "comptime pointer cast array and then slice" {...@@ -211,7 +211,6 @@ test "comptime pointer cast array and then slice" {
211}211}
212212
213test "slicing zero length array" {213test "slicing zero length array" {
214 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
215 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO214 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
216 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;215 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
217216
...@@ -273,7 +272,6 @@ test "result location zero sized array inside struct field implicit cast to slic...@@ -273,7 +272,6 @@ test "result location zero sized array inside struct field implicit cast to slic
273}272}
274273
275test "runtime safety lets us slice from len..len" {274test "runtime safety lets us slice from len..len" {
276 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
277 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;275 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
278 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO276 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
279 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,7 +285,6 @@ fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 {
287}285}
288286
289test "C pointer" {287test "C pointer" {
290 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
291 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO288 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
292 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;289 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
293290
...@@ -299,7 +296,6 @@ test "C pointer" {...@@ -299,7 +296,6 @@ test "C pointer" {
299}296}
300297
301test "C pointer slice access" {298test "C pointer slice access" {
302 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
303 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;299 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
304 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO300 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
305 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;301 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -331,7 +327,6 @@ fn sliceSum(comptime q: []const u8) i32 {...@@ -331,7 +327,6 @@ fn sliceSum(comptime q: []const u8) i32 {
331}327}
332328
333test "slice type with custom alignment" {329test "slice type with custom alignment" {
334 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
335 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO330 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
336 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;331 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
337332
...@@ -390,7 +385,6 @@ test "empty array to slice" {...@@ -390,7 +385,6 @@ test "empty array to slice" {
390}385}
391386
392test "@ptrCast slice to pointer" {387test "@ptrCast slice to pointer" {
393 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
394 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO388 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
395 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;389 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
396390
...@@ -445,7 +439,6 @@ test "slice multi-pointer without end" {...@@ -445,7 +439,6 @@ test "slice multi-pointer without end" {
445}439}
446440
447test "slice syntax resulting in pointer-to-array" {441test "slice syntax resulting in pointer-to-array" {
448 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
449 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO442 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
450 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO443 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
451 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;444 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -665,7 +658,6 @@ test "slice syntax resulting in pointer-to-array" {...@@ -665,7 +658,6 @@ test "slice syntax resulting in pointer-to-array" {
665}658}
666659
667test "slice pointer-to-array null terminated" {660test "slice pointer-to-array null terminated" {
668 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
669 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO661 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
670 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;662 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
671663
...@@ -718,7 +710,7 @@ test "slice pointer-to-array zero length" {...@@ -718,7 +710,7 @@ test "slice pointer-to-array zero length" {
718}710}
719711
720test "type coercion of pointer to anon struct literal to pointer to slice" {712test "type coercion of pointer to anon struct literal to pointer to slice" {
721 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO713 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
722 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO714 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
723 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO715 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
724 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;716 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -812,7 +804,6 @@ test "slice sentinel access at comptime" {...@@ -812,7 +804,6 @@ test "slice sentinel access at comptime" {
812}804}
813805
814test "slicing array with sentinel as end index" {806test "slicing array with sentinel as end index" {
815 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
816 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO807 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
817 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;808 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
818809
...@@ -831,7 +822,6 @@ test "slicing array with sentinel as end index" {...@@ -831,7 +822,6 @@ test "slicing array with sentinel as end index" {
831}822}
832823
833test "slicing slice with sentinel as end index" {824test "slicing slice with sentinel as end index" {
834 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
835 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO825 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
836 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;826 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
837827
...@@ -888,7 +878,7 @@ test "slice field ptr var" {...@@ -888,7 +878,7 @@ test "slice field ptr var" {
888}878}
889879
890test "global slice field access" {880test "global slice field access" {
891 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO881 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
892 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO882 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
893 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO883 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
894 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;884 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -929,7 +919,6 @@ test "slice with dereferenced value" {...@@ -929,7 +919,6 @@ test "slice with dereferenced value" {
929}919}
930920
931test "empty slice ptr is non null" {921test "empty slice ptr is non null" {
932 if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest; // TODO
933 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // Test assumes `undefined` is non-zero922 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // Test assumes `undefined` is non-zero
934923
935 {924 {
...@@ -947,7 +936,6 @@ test "empty slice ptr is non null" {...@@ -947,7 +936,6 @@ test "empty slice ptr is non null" {
947}936}
948937
949test "slice decays to many pointer" {938test "slice decays to many pointer" {
950 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
951 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;939 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
952 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;940 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
953941
...@@ -957,7 +945,6 @@ test "slice decays to many pointer" {...@@ -957,7 +945,6 @@ test "slice decays to many pointer" {
957}945}
958946
959test "write through pointer to optional slice arg" {947test "write through pointer to optional slice arg" {
960 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
961 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;948 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
962 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;949 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
963 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;950 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -977,7 +964,6 @@ test "write through pointer to optional slice arg" {...@@ -977,7 +964,6 @@ test "write through pointer to optional slice arg" {
977}964}
978965
979test "modify slice length at comptime" {966test "modify slice length at comptime" {
980 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
981 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;967 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
982 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;968 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
983 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;969 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -994,7 +980,6 @@ test "modify slice length at comptime" {...@@ -994,7 +980,6 @@ test "modify slice length at comptime" {
994}980}
995981
996test "slicing zero length array field of struct" {982test "slicing zero length array field of struct" {
997 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
998 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO983 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
999 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;984 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1000 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;985 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1010,7 +995,6 @@ test "slicing zero length array field of struct" {...@@ -1010,7 +995,6 @@ test "slicing zero length array field of struct" {
1010}995}
1011996
1012test "slicing slices gives correct result" {997test "slicing slices gives correct result" {
1013 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1014 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO998 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1015 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;999 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10161000
...@@ -1024,7 +1008,6 @@ test "slicing slices gives correct result" {...@@ -1024,7 +1008,6 @@ test "slicing slices gives correct result" {
1024}1008}
10251009
1026test "get address of element of zero-sized slice" {1010test "get address of element of zero-sized slice" {
1027 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1028 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1011 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1029 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1012 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10301013
...@@ -1037,7 +1020,6 @@ test "get address of element of zero-sized slice" {...@@ -1037,7 +1020,6 @@ test "get address of element of zero-sized slice" {
1037}1020}
10381021
1039test "sentinel-terminated 0-length slices" {1022test "sentinel-terminated 0-length slices" {
1040 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1041 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1023 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1042 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1024 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10431025
...@@ -1058,8 +1040,6 @@ test "sentinel-terminated 0-length slices" {...@@ -1058,8 +1040,6 @@ test "sentinel-terminated 0-length slices" {
1058}1040}
10591041
1060test "peer slices keep abi alignment with empty struct" {1042test "peer slices keep abi alignment with empty struct" {
1061 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1062
1063 var cond: bool = undefined;1043 var cond: bool = undefined;
1064 cond = false;1044 cond = false;
1065 const slice = if (cond) &[1]u32{42} else &.{};1045 const slice = if (cond) &[1]u32{42} else &.{};
test/behavior/src.zig-1
...@@ -16,7 +16,6 @@ const expect = std.testing.expect;...@@ -16,7 +16,6 @@ const expect = std.testing.expect;
16const expectEqualStrings = std.testing.expectEqualStrings;16const expectEqualStrings = std.testing.expectEqualStrings;
1717
18test "@src" {18test "@src" {
19 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
20 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO19 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
21 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO20 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
22 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,7 +6,6 @@ const tag_name = @tagName(TestEnum.TestEnumValue);
6const ptr_tag_name: [*:0]const u8 = tag_name;6const ptr_tag_name: [*:0]const u8 = tag_name;
77
8test "@tagName() returns a string literal" {8test "@tagName() returns a string literal" {
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;10 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1211
...@@ -20,7 +19,6 @@ const error_name = @errorName(TestError.TestErrorCode);...@@ -20,7 +19,6 @@ const error_name = @errorName(TestError.TestErrorCode);
20const ptr_error_name: [*:0]const u8 = error_name;19const ptr_error_name: [*:0]const u8 = error_name;
2120
22test "@errorName() returns a string literal" {21test "@errorName() returns a string literal" {
23 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
24 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO22 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
25 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;23 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2624
...@@ -34,7 +32,6 @@ const type_name = @typeName(TestType);...@@ -34,7 +32,6 @@ const type_name = @typeName(TestType);
34const ptr_type_name: [*:0]const u8 = type_name;32const ptr_type_name: [*:0]const u8 = type_name;
3533
36test "@typeName() returns a string literal" {34test "@typeName() returns a string literal" {
37 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
38 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO35 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
39 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;36 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4037
...@@ -48,7 +45,6 @@ const ptr_actual_contents: [*:0]const u8 = actual_contents;...@@ -48,7 +45,6 @@ const ptr_actual_contents: [*:0]const u8 = actual_contents;
48const expected_contents = "hello zig\n";45const expected_contents = "hello zig\n";
4946
50test "@embedFile() returns a string literal" {47test "@embedFile() returns a string literal" {
51 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
52 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO48 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
53 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;49 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
54 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;50 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -64,7 +60,7 @@ fn testFnForSrc() std.builtin.SourceLocation {...@@ -64,7 +60,7 @@ fn testFnForSrc() std.builtin.SourceLocation {
64}60}
6561
66test "@src() returns a struct containing 0-terminated string slices" {62test "@src() returns a struct containing 0-terminated string slices" {
67 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO63 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
68 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO64 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
69 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;65 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
7066
test/behavior/struct.zig+13-46
...@@ -10,7 +10,6 @@ const maxInt = std.math.maxInt;...@@ -10,7 +10,6 @@ const maxInt = std.math.maxInt;
10top_level_field: i32,10top_level_field: i32,
1111
12test "top level fields" {12test "top level fields" {
13 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO13 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1514
16 var instance = @This(){15 var instance = @This(){
...@@ -87,7 +86,6 @@ const StructFoo = struct {...@@ -87,7 +86,6 @@ const StructFoo = struct {
87};86};
8887
89test "structs" {88test "structs" {
90 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
91 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;89 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
92 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO90 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
93 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;91 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -200,7 +198,6 @@ const MemberFnRand = struct {...@@ -200,7 +198,6 @@ const MemberFnRand = struct {
200};198};
201199
202test "return struct byval from function" {200test "return struct byval from function" {
203 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
204 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO201 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
205202
206 const Bar = struct {203 const Bar = struct {
...@@ -237,7 +234,6 @@ test "call method with mutable reference to struct with no fields" {...@@ -237,7 +234,6 @@ test "call method with mutable reference to struct with no fields" {
237}234}
238235
239test "struct field init with catch" {236test "struct field init with catch" {
240 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
241 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO237 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
242238
243 const S = struct {239 const S = struct {
...@@ -280,7 +276,6 @@ const Val = struct {...@@ -280,7 +276,6 @@ const Val = struct {
280};276};
281277
282test "struct point to self" {278test "struct point to self" {
283 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
284 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO279 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
285 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;280 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
286281
...@@ -297,7 +292,6 @@ test "struct point to self" {...@@ -297,7 +292,6 @@ test "struct point to self" {
297}292}
298293
299test "void struct fields" {294test "void struct fields" {
300 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
301 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO295 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
302296
303 const foo = VoidStructFieldsFoo{297 const foo = VoidStructFieldsFoo{
...@@ -335,7 +329,6 @@ fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize {...@@ -335,7 +329,6 @@ fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize {
335}329}
336330
337test "self-referencing struct via array member" {331test "self-referencing struct via array member" {
338 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
339 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO332 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
340 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO333 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
341 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;334 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -492,7 +485,7 @@ const Bitfields = packed struct {...@@ -492,7 +485,7 @@ const Bitfields = packed struct {
492};485};
493486
494test "packed struct fields are ordered from LSB to MSB" {487test "packed struct fields are ordered from LSB to MSB" {
495 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO488 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
496 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO489 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
497 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO490 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
498 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;491 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -610,7 +603,6 @@ fn getC(data: *const BitField1) u2 {...@@ -610,7 +603,6 @@ fn getC(data: *const BitField1) u2 {
610}603}
611604
612test "default struct initialization fields" {605test "default struct initialization fields" {
613 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
614 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO606 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
615607
616 const S = struct {608 const S = struct {
...@@ -634,8 +626,8 @@ test "default struct initialization fields" {...@@ -634,8 +626,8 @@ test "default struct initialization fields" {
634}626}
635627
636test "packed array 24bits" {628test "packed array 24bits" {
637 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
638 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;629 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
630 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
639 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO631 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
640 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;632 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
641633
...@@ -701,8 +693,8 @@ const FooArrayOfAligned = packed struct {...@@ -701,8 +693,8 @@ const FooArrayOfAligned = packed struct {
701};693};
702694
703test "pointer to packed struct member in a stack variable" {695test "pointer to packed struct member in a stack variable" {
696 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
704 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO697 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
705 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
706 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO698 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
707 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;699 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
708 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO700 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
...@@ -731,7 +723,6 @@ test "packed struct with u0 field access" {...@@ -731,7 +723,6 @@ test "packed struct with u0 field access" {
731}723}
732724
733test "access to global struct fields" {725test "access to global struct fields" {
734 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
735 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO726 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
736727
737 g_foo.bar.value = 42;728 g_foo.bar.value = 42;
...@@ -753,8 +744,8 @@ const S0 = struct {...@@ -753,8 +744,8 @@ const S0 = struct {
753var g_foo: S0 = S0.init();744var g_foo: S0 = S0.init();
754745
755test "packed struct with fp fields" {746test "packed struct with fp fields" {
747 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
756 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO748 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
757 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
758 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO749 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
759 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;750 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
760 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;751 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -783,7 +774,6 @@ test "packed struct with fp fields" {...@@ -783,7 +774,6 @@ test "packed struct with fp fields" {
783774
784test "fn with C calling convention returns struct by value" {775test "fn with C calling convention returns struct by value" {
785 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO776 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
786 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
787 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO777 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
788778
789 const S = struct {779 const S = struct {
...@@ -807,7 +797,6 @@ test "fn with C calling convention returns struct by value" {...@@ -807,7 +797,6 @@ test "fn with C calling convention returns struct by value" {
807}797}
808798
809test "non-packed struct with u128 entry in union" {799test "non-packed struct with u128 entry in union" {
810 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
811 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO800 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
812 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO801 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
813 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;802 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -834,8 +823,8 @@ test "non-packed struct with u128 entry in union" {...@@ -834,8 +823,8 @@ test "non-packed struct with u128 entry in union" {
834}823}
835824
836test "packed struct field passed to generic function" {825test "packed struct field passed to generic function" {
826 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
837 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO827 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
838 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
839 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO828 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
840 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;829 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
841830
...@@ -859,7 +848,6 @@ test "packed struct field passed to generic function" {...@@ -859,7 +848,6 @@ test "packed struct field passed to generic function" {
859}848}
860849
861test "anonymous struct literal syntax" {850test "anonymous struct literal syntax" {
862 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
863 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO851 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
864852
865 const S = struct {853 const S = struct {
...@@ -951,7 +939,6 @@ test "comptime struct field" {...@@ -951,7 +939,6 @@ test "comptime struct field" {
951test "tuple element initialized with fn call" {939test "tuple element initialized with fn call" {
952 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;940 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
953 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO941 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
954 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
955 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO942 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
956943
957 const S = struct {944 const S = struct {
...@@ -968,8 +955,8 @@ test "tuple element initialized with fn call" {...@@ -968,8 +955,8 @@ test "tuple element initialized with fn call" {
968}955}
969956
970test "struct with union field" {957test "struct with union field" {
958 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
971 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;959 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
972 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
973 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO960 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
974 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO961 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
975962
...@@ -990,7 +977,6 @@ test "struct with union field" {...@@ -990,7 +977,6 @@ test "struct with union field" {
990}977}
991978
992test "struct with 0-length union array field" {979test "struct with 0-length union array field" {
993 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
994 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO980 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
995 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO981 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
996982
...@@ -1078,7 +1064,7 @@ test "for loop over pointers to struct, getting field from struct pointer" {...@@ -1078,7 +1064,7 @@ test "for loop over pointers to struct, getting field from struct pointer" {
1078}1064}
10791065
1080test "anon init through error unions and optionals" {1066test "anon init through error unions and optionals" {
1081 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1067 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1082 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1068 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1083 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1069 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1084 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1070 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1105,7 +1091,6 @@ test "anon init through error unions and optionals" {...@@ -1105,7 +1091,6 @@ test "anon init through error unions and optionals" {
1105}1091}
11061092
1107test "anon init through optional" {1093test "anon init through optional" {
1108 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1109 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1094 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1095 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1111 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1096 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1125,7 +1110,6 @@ test "anon init through optional" {...@@ -1125,7 +1110,6 @@ test "anon init through optional" {
1125}1110}
11261111
1127test "anon init through error union" {1112test "anon init through error union" {
1128 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1129 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1113 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1130 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1114 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1131 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1115 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1145,7 +1129,7 @@ test "anon init through error union" {...@@ -1145,7 +1129,7 @@ test "anon init through error union" {
1145}1129}
11461130
1147test "typed init through error unions and optionals" {1131test "typed init through error unions and optionals" {
1148 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1149 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1133 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1150 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1134 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11511135
...@@ -1171,7 +1155,6 @@ test "typed init through error unions and optionals" {...@@ -1171,7 +1155,6 @@ test "typed init through error unions and optionals" {
1171}1155}
11721156
1173test "initialize struct with empty literal" {1157test "initialize struct with empty literal" {
1174 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1175 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1158 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11761159
1177 const S = struct { x: i32 = 1234 };1160 const S = struct { x: i32 = 1234 };
...@@ -1206,7 +1189,7 @@ test "loading a struct pointer perfoms a copy" {...@@ -1206,7 +1189,7 @@ test "loading a struct pointer perfoms a copy" {
1206}1189}
12071190
1208test "packed struct aggregate init" {1191test "packed struct aggregate init" {
1209 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1192 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1210 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1193 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1211 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1194 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1212 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1195 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1226,7 +1209,7 @@ test "packed struct aggregate init" {...@@ -1226,7 +1209,7 @@ test "packed struct aggregate init" {
1226}1209}
12271210
1228test "packed struct field access via pointer" {1211test "packed struct field access via pointer" {
1229 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1212 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1230 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1213 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1231 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1214 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1232 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1215 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1267,7 +1250,6 @@ test "store to comptime field" {...@@ -1267,7 +1250,6 @@ test "store to comptime field" {
1267}1250}
12681251
1269test "struct field init value is size of the struct" {1252test "struct field init value is size of the struct" {
1270 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1271 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1253 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12721254
1273 const namespace = struct {1255 const namespace = struct {
...@@ -1282,7 +1264,6 @@ test "struct field init value is size of the struct" {...@@ -1282,7 +1264,6 @@ test "struct field init value is size of the struct" {
1282}1264}
12831265
1284test "under-aligned struct field" {1266test "under-aligned struct field" {
1285 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1286 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1267 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1287 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1268 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1288 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1269 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1306,7 +1287,6 @@ test "under-aligned struct field" {...@@ -1306,7 +1287,6 @@ test "under-aligned struct field" {
1306}1287}
13071288
1308test "fieldParentPtr of a zero-bit field" {1289test "fieldParentPtr of a zero-bit field" {
1309 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1310 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1290 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1311 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1291 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1312 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1292 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1357,7 +1337,6 @@ test "fieldParentPtr of a zero-bit field" {...@@ -1357,7 +1337,6 @@ test "fieldParentPtr of a zero-bit field" {
13571337
1358test "struct field has a pointer to an aligned version of itself" {1338test "struct field has a pointer to an aligned version of itself" {
1359 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1339 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1360 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13611340
1362 const E = struct {1341 const E = struct {
1363 next: *align(1) @This(),1342 next: *align(1) @This(),
...@@ -1415,7 +1394,6 @@ test "struct has only one reference" {...@@ -1415,7 +1394,6 @@ test "struct has only one reference" {
1415}1394}
14161395
1417test "no dependency loop on pointer to optional struct" {1396test "no dependency loop on pointer to optional struct" {
1418 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1419 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1397 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1420 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1398 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14211399
...@@ -1437,7 +1415,6 @@ test "discarded struct initialization works as expected" {...@@ -1437,7 +1415,6 @@ test "discarded struct initialization works as expected" {
1437}1415}
14381416
1439test "function pointer in struct returns the struct" {1417test "function pointer in struct returns the struct" {
1440 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1441 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1418 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
14421419
1443 const A = struct {1420 const A = struct {
...@@ -1455,7 +1432,6 @@ test "function pointer in struct returns the struct" {...@@ -1455,7 +1432,6 @@ test "function pointer in struct returns the struct" {
14551432
1456test "no dependency loop on optional field wrapped in generic function" {1433test "no dependency loop on optional field wrapped in generic function" {
1457 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1434 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1458 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14591435
1460 const S = struct {1436 const S = struct {
1461 fn Atomic(comptime T: type) type {1437 fn Atomic(comptime T: type) type {
...@@ -1473,7 +1449,6 @@ test "no dependency loop on optional field wrapped in generic function" {...@@ -1473,7 +1449,6 @@ test "no dependency loop on optional field wrapped in generic function" {
1473}1449}
14741450
1475test "optional field init with tuple" {1451test "optional field init with tuple" {
1476 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1477 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1452 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14781453
1479 const S = struct {1454 const S = struct {
...@@ -1488,8 +1463,6 @@ test "optional field init with tuple" {...@@ -1488,8 +1463,6 @@ test "optional field init with tuple" {
1488}1463}
14891464
1490test "if inside struct init inside if" {1465test "if inside struct init inside if" {
1491 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1492
1493 const MyStruct = struct { x: u32 };1466 const MyStruct = struct { x: u32 };
1494 const b: u32 = 5;1467 const b: u32 = 5;
1495 var i: u32 = 1;1468 var i: u32 = 1;
...@@ -1580,7 +1553,6 @@ test "instantiate struct with comptime field" {...@@ -1580,7 +1553,6 @@ test "instantiate struct with comptime field" {
1580test "struct field pointer has correct alignment" {1553test "struct field pointer has correct alignment" {
1581 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO1554 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1582 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1555 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1583 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1584 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1556 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15851557
1586 const S = struct {1558 const S = struct {
...@@ -1610,7 +1582,6 @@ test "struct field pointer has correct alignment" {...@@ -1610,7 +1582,6 @@ test "struct field pointer has correct alignment" {
1610test "extern struct field pointer has correct alignment" {1582test "extern struct field pointer has correct alignment" {
1611 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO1583 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1612 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1584 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1613 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1614 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1585 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16151586
1616 const S = struct {1587 const S = struct {
...@@ -1828,7 +1799,6 @@ test "tuple with comptime-only field" {...@@ -1828,7 +1799,6 @@ test "tuple with comptime-only field" {
1828}1799}
18291800
1830test "extern struct fields are aligned to 1" {1801test "extern struct fields are aligned to 1" {
1831 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1832 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1802 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18331803
1834 const Foo = extern struct {1804 const Foo = extern struct {
...@@ -1845,7 +1815,7 @@ test "extern struct fields are aligned to 1" {...@@ -1845,7 +1815,7 @@ test "extern struct fields are aligned to 1" {
1845}1815}
18461816
1847test "assign to slice.len of global variable" {1817test "assign to slice.len of global variable" {
1848 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1818 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1849 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1819 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1850 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1820 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1851 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1821 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1897,7 +1867,6 @@ test "array of structs inside struct initialized with undefined" {...@@ -1897,7 +1867,6 @@ test "array of structs inside struct initialized with undefined" {
1897}1867}
18981868
1899test "runtime call in nested initializer" {1869test "runtime call in nested initializer" {
1900 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1901 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1870 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1902 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1871 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
19031872
...@@ -1929,7 +1898,6 @@ test "runtime call in nested initializer" {...@@ -1929,7 +1898,6 @@ test "runtime call in nested initializer" {
1929}1898}
19301899
1931test "runtime value in nested initializer passed as pointer to function" {1900test "runtime value in nested initializer passed as pointer to function" {
1932 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1933 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1901 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
19341902
1935 const Bar = struct {1903 const Bar = struct {
...@@ -1953,7 +1921,7 @@ test "runtime value in nested initializer passed as pointer to function" {...@@ -1953,7 +1921,7 @@ test "runtime value in nested initializer passed as pointer to function" {
1953}1921}
19541922
1955test "struct field default value is a call" {1923test "struct field default value is a call" {
1956 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1924 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1957 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1925 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1958 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1926 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
19591927
...@@ -2001,7 +1969,6 @@ test "aggregate initializers should allow initializing comptime fields, verifyin...@@ -2001,7 +1969,6 @@ test "aggregate initializers should allow initializing comptime fields, verifyin
20011969
2002test "assignment of field with padding" {1970test "assignment of field with padding" {
2003 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;1971 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2004 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2005 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1972 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
20061973
2007 const Mesh = extern struct {1974 const Mesh = extern struct {
...@@ -2031,7 +1998,6 @@ test "assignment of field with padding" {...@@ -2031,7 +1998,6 @@ test "assignment of field with padding" {
20311998
2032test "initiate global variable with runtime value" {1999test "initiate global variable with runtime value" {
2033 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;2000 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
2034 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2035 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2001 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
20362002
2037 const S = struct {2003 const S = struct {
...@@ -2126,6 +2092,7 @@ test "anonymous struct equivalence" {...@@ -2126,6 +2092,7 @@ test "anonymous struct equivalence" {
2126}2092}
21272093
2128test "field access through mem ptr arg" {2094test "field access through mem ptr arg" {
2095 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2129 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;2096 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
21302097
2131 const S = struct {2098 const S = struct {
test/behavior/struct_contains_null_ptr_itself.zig-1
...@@ -3,7 +3,6 @@ const expect = std.testing.expect;...@@ -3,7 +3,6 @@ const expect = std.testing.expect;
3const builtin = @import("builtin");3const builtin = @import("builtin");
44
5test "struct contains null pointer which contains original struct" {5test "struct contains null pointer which contains original struct" {
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO6 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;7 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
98
test/behavior/struct_contains_slice_of_itself.zig+2-1
...@@ -12,6 +12,7 @@ const NodeAligned = struct {...@@ -12,6 +12,7 @@ const NodeAligned = struct {
12};12};
1313
14test "struct contains slice of itself" {14test "struct contains slice of itself" {
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
15 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO16 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
16 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;17 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1718
...@@ -52,7 +53,7 @@ test "struct contains slice of itself" {...@@ -52,7 +53,7 @@ test "struct contains slice of itself" {
52}53}
5354
54test "struct contains aligned slice of itself" {55test "struct contains aligned slice of itself" {
55 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO56 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
56 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO57 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
57 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;58 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
5859
test/behavior/switch.zig+25-13
...@@ -43,7 +43,7 @@ fn testSwitchWithAllRanges(x: u32, y: u32) u32 {...@@ -43,7 +43,7 @@ fn testSwitchWithAllRanges(x: u32, y: u32) u32 {
43}43}
4444
45test "switch arbitrary int size" {45test "switch arbitrary int size" {
46 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO46 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
47 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO47 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO48 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
49 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO49 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
...@@ -274,8 +274,8 @@ const SwitchProngWithVarEnum = union(enum) {...@@ -274,8 +274,8 @@ const SwitchProngWithVarEnum = union(enum) {
274};274};
275275
276test "switch prong with variable" {276test "switch prong with variable" {
277 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
277 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO278 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
278 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
279 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO279 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
280 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;280 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
281281
...@@ -300,7 +300,6 @@ fn switchProngWithVarFn(a: SwitchProngWithVarEnum) !void {...@@ -300,7 +300,6 @@ fn switchProngWithVarFn(a: SwitchProngWithVarEnum) !void {
300300
301test "switch on enum using pointer capture" {301test "switch on enum using pointer capture" {
302 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO302 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
303 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
304 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO303 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
305304
306 try testSwitchEnumPtrCapture();305 try testSwitchEnumPtrCapture();
...@@ -361,7 +360,6 @@ fn testSwitchHandleAllCasesRange(x: u8) u8 {...@@ -361,7 +360,6 @@ fn testSwitchHandleAllCasesRange(x: u8) u8 {
361360
362test "switch on union with some prongs capturing" {361test "switch on union with some prongs capturing" {
363 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO362 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
364 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
365 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO363 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
366364
367 const X = union(enum) {365 const X = union(enum) {
...@@ -398,7 +396,6 @@ test "switch on const enum with var" {...@@ -398,7 +396,6 @@ test "switch on const enum with var" {
398}396}
399397
400test "anon enum literal used in switch on union enum" {398test "anon enum literal used in switch on union enum" {
401 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
402 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO399 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
403400
404 const Foo = union(enum) {401 const Foo = union(enum) {
...@@ -469,8 +466,8 @@ test "switch on integer with else capturing expr" {...@@ -469,8 +466,8 @@ test "switch on integer with else capturing expr" {
469}466}
470467
471test "else prong of switch on error set excludes other cases" {468test "else prong of switch on error set excludes other cases" {
469 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
472 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO470 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
473 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
474 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO471 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
475 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;472 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
476 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;473 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -505,8 +502,8 @@ test "else prong of switch on error set excludes other cases" {...@@ -505,8 +502,8 @@ test "else prong of switch on error set excludes other cases" {
505}502}
506503
507test "switch prongs with error set cases make a new error set type for capture value" {504test "switch prongs with error set cases make a new error set type for capture value" {
505 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
508 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO506 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
509 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
510 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO507 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
511 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;508 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
512 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;509 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -563,7 +560,6 @@ test "return result loc and then switch with range implicit casted to error unio...@@ -563,7 +560,6 @@ test "return result loc and then switch with range implicit casted to error unio
563560
564test "switch with null and T peer types and inferred result location type" {561test "switch with null and T peer types and inferred result location type" {
565 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO562 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
566 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
567 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO563 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
568564
569 const S = struct {565 const S = struct {
...@@ -582,7 +578,7 @@ test "switch with null and T peer types and inferred result location type" {...@@ -582,7 +578,7 @@ test "switch with null and T peer types and inferred result location type" {
582}578}
583579
584test "switch prongs with cases with identical payload types" {580test "switch prongs with cases with identical payload types" {
585 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO581 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
586 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO582 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
587 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO583 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
588584
...@@ -689,7 +685,7 @@ test "switch prong pointer capture alignment" {...@@ -689,7 +685,7 @@ test "switch prong pointer capture alignment" {
689}685}
690686
691test "switch on pointer type" {687test "switch on pointer type" {
692 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO688 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
693 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO689 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
694 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;690 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
695691
...@@ -737,8 +733,8 @@ test "switch on error set with single else" {...@@ -737,8 +733,8 @@ test "switch on error set with single else" {
737}733}
738734
739test "switch capture copies its payload" {735test "switch capture copies its payload" {
736 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
740 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO737 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
741 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
742 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO738 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
743 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;739 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
744740
...@@ -831,6 +827,7 @@ test "comptime inline switch" {...@@ -831,6 +827,7 @@ test "comptime inline switch" {
831}827}
832828
833test "switch capture peer type resolution" {829test "switch capture peer type resolution" {
830 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
834 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;831 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
835832
836 const U = union(enum) {833 const U = union(enum) {
...@@ -848,6 +845,8 @@ test "switch capture peer type resolution" {...@@ -848,6 +845,8 @@ test "switch capture peer type resolution" {
848}845}
849846
850test "switch capture peer type resolution for in-memory coercible payloads" {847test "switch capture peer type resolution for in-memory coercible payloads" {
848 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
849
851 const T1 = c_int;850 const T1 = c_int;
852 const T2 = @Type(@typeInfo(T1));851 const T2 = @Type(@typeInfo(T1));
853852
...@@ -868,6 +867,8 @@ test "switch capture peer type resolution for in-memory coercible payloads" {...@@ -868,6 +867,8 @@ test "switch capture peer type resolution for in-memory coercible payloads" {
868}867}
869868
870test "switch pointer capture peer type resolution" {869test "switch pointer capture peer type resolution" {
870 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
871
871 const T1 = c_int;872 const T1 = c_int;
872 const T2 = @Type(@typeInfo(T1));873 const T2 = @Type(@typeInfo(T1));
873874
...@@ -904,6 +905,7 @@ test "inline switch range that includes the maximum value of the switched type"...@@ -904,6 +905,7 @@ test "inline switch range that includes the maximum value of the switched type"
904}905}
905906
906test "nested break ignores switch conditions and breaks instead" {907test "nested break ignores switch conditions and breaks instead" {
908 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
907 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;909 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
908 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;910 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
909911
...@@ -926,6 +928,7 @@ test "nested break ignores switch conditions and breaks instead" {...@@ -926,6 +928,7 @@ test "nested break ignores switch conditions and breaks instead" {
926}928}
927929
928test "peer type resolution on switch captures ignores unused payload bits" {930test "peer type resolution on switch captures ignores unused payload bits" {
931 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
929 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;932 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
930 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;933 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
931934
...@@ -951,7 +954,6 @@ test "peer type resolution on switch captures ignores unused payload bits" {...@@ -951,7 +954,6 @@ test "peer type resolution on switch captures ignores unused payload bits" {
951}954}
952955
953test "switch prong captures range" {956test "switch prong captures range" {
954 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
955 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO957 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
956 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO958 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
957959
...@@ -1042,7 +1044,7 @@ test "labeled switch with break" {...@@ -1042,7 +1044,7 @@ test "labeled switch with break" {
1042}1044}
10431045
1044test "unlabeled break ignores switch" {1046test "unlabeled break ignores switch" {
1045 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1047 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1046 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1048 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1047 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1049 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1048 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO1050 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
...@@ -1065,3 +1067,13 @@ test "switch on a signed value smaller than the smallest prong value" {...@@ -1065,3 +1067,13 @@ test "switch on a signed value smaller than the smallest prong value" {
1065 else => {},1067 else => {},
1066 }1068 }
1067}1069}
1070
1071test "switch on 8-bit mod result" {
1072 var x: u8 = undefined;
1073 x = 16;
1074 switch (x % 4) {
1075 0 => {},
1076 1, 2, 3 => return error.TestFailed,
1077 else => unreachable,
1078 }
1079}
test/behavior/switch_loop.zig+32-9
...@@ -3,7 +3,7 @@ const std = @import("std");...@@ -3,7 +3,7 @@ const std = @import("std");
3const expect = std.testing.expect;3const expect = std.testing.expect;
44
5test "simple switch loop" {5test "simple switch loop" {
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
...@@ -27,7 +27,7 @@ test "simple switch loop" {...@@ -27,7 +27,7 @@ test "simple switch loop" {
27}27}
2828
29test "switch loop with ranges" {29test "switch loop with ranges" {
30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO30 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
31 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO31 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
32 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO32 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
33 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO33 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
...@@ -48,7 +48,7 @@ test "switch loop with ranges" {...@@ -48,7 +48,7 @@ test "switch loop with ranges" {
48}48}
4949
50test "switch loop on enum" {50test "switch loop on enum" {
51 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO51 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
52 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO52 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
53 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO53 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
54 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO54 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
...@@ -72,7 +72,7 @@ test "switch loop on enum" {...@@ -72,7 +72,7 @@ test "switch loop on enum" {
72}72}
7373
74test "switch loop with error set" {74test "switch loop with error set" {
75 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO75 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
76 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO76 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO77 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
78 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO78 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
...@@ -96,7 +96,7 @@ test "switch loop with error set" {...@@ -96,7 +96,7 @@ test "switch loop with error set" {
96}96}
9797
98test "switch loop on tagged union" {98test "switch loop on tagged union" {
99 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO99 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
100 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO100 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
101 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO101 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
102 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO102 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
...@@ -129,7 +129,7 @@ test "switch loop on tagged union" {...@@ -129,7 +129,7 @@ test "switch loop on tagged union" {
129}129}
130130
131test "switch loop dispatching instructions" {131test "switch loop dispatching instructions" {
132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
133 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO133 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
134 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO134 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
135 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO135 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
...@@ -179,7 +179,7 @@ test "switch loop dispatching instructions" {...@@ -179,7 +179,7 @@ test "switch loop dispatching instructions" {
179}179}
180180
181test "switch loop with pointer capture" {181test "switch loop with pointer capture" {
182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
183 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO183 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
184 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO184 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
185 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO185 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
...@@ -218,11 +218,34 @@ test "switch loop with pointer capture" {...@@ -218,11 +218,34 @@ test "switch loop with pointer capture" {
218}218}
219219
220test "unanalyzed continue with operand" {220test "unanalyzed continue with operand" {
221 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
222
223 @setRuntimeSafety(false);221 @setRuntimeSafety(false);
224 label: switch (false) {222 label: switch (false) {
225 false => if (false) continue :label true,223 false => if (false) continue :label true,
226 true => {},224 true => {},
227 }225 }
228}226}
227
228test "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+1
...@@ -300,6 +300,7 @@ test "switch on error union catch capture" {...@@ -300,6 +300,7 @@ test "switch on error union catch capture" {
300}300}
301301
302test "switch on error union if else capture" {302test "switch on error union if else capture" {
303 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
303 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;304 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
304 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;305 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
305306
test/behavior/switch_prong_err_enum.zig+1-1
...@@ -21,8 +21,8 @@ fn doThing(form_id: u64) anyerror!FormValue {...@@ -21,8 +21,8 @@ fn doThing(form_id: u64) anyerror!FormValue {
21}21}
2222
23test "switch prong returns error enum" {23test "switch prong returns error enum" {
24 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
25 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;24 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
25 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
26 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO26 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
27 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;27 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2828
test/behavior/switch_prong_implicit_cast.zig+1-1
...@@ -15,8 +15,8 @@ fn foo(id: u64) !FormValue {...@@ -15,8 +15,8 @@ fn foo(id: u64) !FormValue {
15}15}
1616
17test "switch prong implicit cast" {17test "switch prong implicit cast" {
18 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
19 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;18 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
19 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
20 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO20 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2121
22 const result = switch (foo(2) catch unreachable) {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,7 +26,6 @@ test "this refer to module call private fn" {
26}26}
2727
28test "this refer to container" {28test "this refer to container" {
29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
30 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO29 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3130
32 var pt: Point(i32) = undefined;31 var pt: Point(i32) = undefined;
...@@ -47,7 +46,6 @@ fn prev(p: ?State) void {...@@ -47,7 +46,6 @@ fn prev(p: ?State) void {
47}46}
4847
49test "this used as optional function parameter" {48test "this used as optional function parameter" {
50 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
51 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;49 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
52 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO50 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
53 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,7 +4,6 @@ const expect = std.testing.expect;
44
5test "thread local variable" {5test "thread local variable" {
6 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO6 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -25,7 +24,6 @@ test "thread local variable" {...@@ -25,7 +24,6 @@ test "thread local variable" {
2524
26test "pointer to thread local array" {25test "pointer to thread local array" {
27 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO26 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
29 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO27 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
30 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO28 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
31 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;29 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -40,7 +38,6 @@ threadlocal var buffer: [11]u8 = undefined;...@@ -40,7 +38,6 @@ threadlocal var buffer: [11]u8 = undefined;
4038
41test "reference a global threadlocal variable" {39test "reference a global threadlocal variable" {
42 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO40 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
43 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
44 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO41 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
45 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO42 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
46 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,8 +65,8 @@ test "truncate on comptime integer" {
65}65}
6666
67test "truncate on vectors" {67test "truncate on vectors" {
68 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
69 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;68 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
69 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
70 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;70 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
71 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO71 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
72 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;72 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/try.zig+80-2
...@@ -47,7 +47,7 @@ test "try then not executed with assignment" {...@@ -47,7 +47,7 @@ test "try then not executed with assignment" {
47}47}
4848
49test "`try`ing an if/else expression" {49test "`try`ing an if/else expression" {
50 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO50 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
51 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO51 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
52 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;52 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
53 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;53 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -68,7 +68,6 @@ test "`try`ing an if/else expression" {...@@ -68,7 +68,6 @@ test "`try`ing an if/else expression" {
68}68}
6969
70test "'return try' of empty error set in function returning non-error" {70test "'return try' of empty error set in function returning non-error" {
71 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
72 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO71 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
73 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;72 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
7473
...@@ -122,3 +121,82 @@ test "'return try' through conditional" {...@@ -122,3 +121,82 @@ test "'return try' through conditional" {
122 comptime std.debug.assert(result == 123);121 comptime std.debug.assert(result == 123);
123 }122 }
124}123}
124
125test "try ptr propagation const" {
126 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
127 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
128 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
129 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
130 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
131
132 const S = struct {
133 fn foo0() !u32 {
134 return 0;
135 }
136
137 fn foo1() error{Bad}!u32 {
138 return 1;
139 }
140
141 fn foo2() anyerror!u32 {
142 return 2;
143 }
144
145 fn doTheTest() !void {
146 const res0: *const u32 = &(try foo0());
147 const res1: *const u32 = &(try foo1());
148 const res2: *const u32 = &(try foo2());
149 try expect(res0.* == 0);
150 try expect(res1.* == 1);
151 try expect(res2.* == 2);
152 }
153 };
154 try S.doTheTest();
155 try comptime S.doTheTest();
156}
157
158test "try ptr propagation mutate" {
159 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
160 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
161 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
162 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
163 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
164
165 const S = struct {
166 fn foo0() !u32 {
167 return 0;
168 }
169
170 fn foo1() error{Bad}!u32 {
171 return 1;
172 }
173
174 fn foo2() anyerror!u32 {
175 return 2;
176 }
177
178 fn doTheTest() !void {
179 var f0 = foo0();
180 var f1 = foo1();
181 var f2 = foo2();
182
183 const res0: *u32 = &(try f0);
184 const res1: *u32 = &(try f1);
185 const res2: *u32 = &(try f2);
186
187 res0.* += 1;
188 res1.* += 1;
189 res2.* += 1;
190
191 try expect(f0 catch unreachable == 1);
192 try expect(f1 catch unreachable == 2);
193 try expect(f2 catch unreachable == 3);
194
195 try expect(res0.* == 1);
196 try expect(res1.* == 2);
197 try expect(res2.* == 3);
198 }
199 };
200 try S.doTheTest();
201 try comptime S.doTheTest();
202}
test/behavior/tuple.zig+2-20
...@@ -8,7 +8,6 @@ const expectEqual = std.testing.expectEqual;...@@ -8,7 +8,6 @@ const expectEqual = std.testing.expectEqual;
88
9test "tuple concatenation" {9test "tuple concatenation" {
10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO11 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1312
14 const S = struct {13 const S = struct {
...@@ -51,7 +50,6 @@ test "tuple multiplication" {...@@ -51,7 +50,6 @@ test "tuple multiplication" {
51}50}
5251
53test "more tuple concatenation" {52test "more tuple concatenation" {
54 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
55 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO53 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
56 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO54 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
57 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;55 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -129,7 +127,6 @@ test "tuple initializer for var" {...@@ -129,7 +127,6 @@ test "tuple initializer for var" {
129}127}
130128
131test "array-like initializer for tuple types" {129test "array-like initializer for tuple types" {
132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
133 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO130 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
134 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;131 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
135132
...@@ -216,7 +213,6 @@ test "initializing anon struct with explicit type" {...@@ -216,7 +213,6 @@ test "initializing anon struct with explicit type" {
216}213}
217214
218test "fieldParentPtr of tuple" {215test "fieldParentPtr of tuple" {
219 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
220 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;216 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
221 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO217 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
222 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;218 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -229,7 +225,6 @@ test "fieldParentPtr of tuple" {...@@ -229,7 +225,6 @@ test "fieldParentPtr of tuple" {
229}225}
230226
231test "fieldParentPtr of anon struct" {227test "fieldParentPtr of anon struct" {
232 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
233 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;228 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
234 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO229 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
235 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;230 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -256,7 +251,6 @@ test "offsetOf anon struct" {...@@ -256,7 +251,6 @@ test "offsetOf anon struct" {
256}251}
257252
258test "initializing tuple with mixed comptime-runtime fields" {253test "initializing tuple with mixed comptime-runtime fields" {
259 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
260 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;254 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
261255
262 var x: u32 = 15;256 var x: u32 = 15;
...@@ -268,7 +262,6 @@ test "initializing tuple with mixed comptime-runtime fields" {...@@ -268,7 +262,6 @@ test "initializing tuple with mixed comptime-runtime fields" {
268}262}
269263
270test "initializing anon struct with mixed comptime-runtime fields" {264test "initializing anon struct with mixed comptime-runtime fields" {
271 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
272 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;265 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
273266
274 var x: u32 = 15;267 var x: u32 = 15;
...@@ -280,7 +273,6 @@ test "initializing anon struct with mixed comptime-runtime fields" {...@@ -280,7 +273,6 @@ test "initializing anon struct with mixed comptime-runtime fields" {
280}273}
281274
282test "tuple in tuple passed to generic function" {275test "tuple in tuple passed to generic function" {
283 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
284 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO276 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
285 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO277 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
286 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;278 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -300,7 +292,6 @@ test "tuple in tuple passed to generic function" {...@@ -300,7 +292,6 @@ test "tuple in tuple passed to generic function" {
300}292}
301293
302test "coerce tuple to tuple" {294test "coerce tuple to tuple" {
303 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
304 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO295 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
305 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO296 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
306 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;297 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -315,7 +306,6 @@ test "coerce tuple to tuple" {...@@ -315,7 +306,6 @@ test "coerce tuple to tuple" {
315}306}
316307
317test "tuple type with void field" {308test "tuple type with void field" {
318 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
319 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO309 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
320 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO310 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
321 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;311 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -353,7 +343,6 @@ test "zero sized struct in tuple handled correctly" {...@@ -353,7 +343,6 @@ test "zero sized struct in tuple handled correctly" {
353}343}
354344
355test "tuple type with void field and a runtime field" {345test "tuple type with void field and a runtime field" {
356 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
357 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO346 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
358 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;347 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
359348
...@@ -364,7 +353,6 @@ test "tuple type with void field and a runtime field" {...@@ -364,7 +353,6 @@ test "tuple type with void field and a runtime field" {
364}353}
365354
366test "branching inside tuple literal" {355test "branching inside tuple literal" {
367 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
368 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO356 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
369 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO357 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
370358
...@@ -410,7 +398,6 @@ test "tuple of struct concatenation and coercion to array" {...@@ -410,7 +398,6 @@ test "tuple of struct concatenation and coercion to array" {
410}398}
411399
412test "nested runtime conditionals in tuple initializer" {400test "nested runtime conditionals in tuple initializer" {
413 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
414 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO401 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
415 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO402 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
416 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;403 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -446,7 +433,6 @@ test "sentinel slice in tuple" {...@@ -446,7 +433,6 @@ test "sentinel slice in tuple" {
446}433}
447434
448test "tuple pointer is indexable" {435test "tuple pointer is indexable" {
449 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
450 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO436 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
451 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO437 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
452 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;438 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -470,7 +456,6 @@ test "tuple pointer is indexable" {...@@ -470,7 +456,6 @@ test "tuple pointer is indexable" {
470}456}
471457
472test "coerce anon tuple to tuple" {458test "coerce anon tuple to tuple" {
473 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
474 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO459 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
475 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO460 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
476461
...@@ -496,14 +481,12 @@ test "empty tuple type" {...@@ -496,14 +481,12 @@ test "empty tuple type" {
496}481}
497482
498test "tuple with comptime fields with non empty initializer" {483test "tuple with comptime fields with non empty initializer" {
499 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
500
501 const a: struct { comptime comptime_int = 0 } = .{0};484 const a: struct { comptime comptime_int = 0 } = .{0};
502 _ = a;485 _ = a;
503}486}
504487
505test "tuple with runtime value coerced into a slice with a sentinel" {488test "tuple with runtime value coerced into a slice with a sentinel" {
506 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO489 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
507 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO490 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
508 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO491 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
509 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;492 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -578,7 +561,6 @@ test "comptime fields in tuple can be initialized" {...@@ -578,7 +561,6 @@ test "comptime fields in tuple can be initialized" {
578561
579test "empty struct in tuple" {562test "empty struct in tuple" {
580 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO563 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
581 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
582 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;564 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
583 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;565 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
584566
...@@ -591,7 +573,6 @@ test "empty struct in tuple" {...@@ -591,7 +573,6 @@ test "empty struct in tuple" {
591573
592test "empty union in tuple" {574test "empty union in tuple" {
593 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO575 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
594 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
595 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;576 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
596 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;577 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
597578
...@@ -604,6 +585,7 @@ test "empty union in tuple" {...@@ -604,6 +585,7 @@ test "empty union in tuple" {
604585
605test "field pointer of underaligned tuple" {586test "field pointer of underaligned tuple" {
606 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;587 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
588
607 const S = struct {589 const S = struct {
608 fn doTheTest() !void {590 fn doTheTest() !void {
609 const T = struct { u8, u32 };591 const T = struct { u8, u32 };
test/behavior/tuple_declarations.zig-2
...@@ -5,7 +5,6 @@ const expect = testing.expect;...@@ -5,7 +5,6 @@ const expect = testing.expect;
5const expectEqualStrings = testing.expectEqualStrings;5const expectEqualStrings = testing.expectEqualStrings;
66
7test "tuple declaration type info" {7test "tuple declaration type info" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1110
...@@ -34,7 +33,6 @@ test "tuple declaration type info" {...@@ -34,7 +33,6 @@ test "tuple declaration type info" {
34}33}
3534
36test "tuple declaration usage" {35test "tuple declaration usage" {
37 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
38 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;36 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
39 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;37 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4038
test/behavior/type.zig+3-6
...@@ -200,8 +200,8 @@ test "Type.ErrorUnion" {...@@ -200,8 +200,8 @@ test "Type.ErrorUnion" {
200}200}
201201
202test "Type.Opaque" {202test "Type.Opaque" {
203 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
203 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO204 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
204 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
205 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO205 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
206 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;206 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
207207
...@@ -258,8 +258,8 @@ test "Type.ErrorSet" {...@@ -258,8 +258,8 @@ test "Type.ErrorSet" {
258}258}
259259
260test "Type.Struct" {260test "Type.Struct" {
261 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
261 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO262 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
262 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
263 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO263 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
264 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;264 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
265265
...@@ -348,7 +348,6 @@ test "Type.Struct" {...@@ -348,7 +348,6 @@ test "Type.Struct" {
348348
349test "Type.Enum" {349test "Type.Enum" {
350 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO350 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
351 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
352 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;351 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
353352
354 const Foo = @Type(.{353 const Foo = @Type(.{
...@@ -409,8 +408,8 @@ test "Type.Enum" {...@@ -409,8 +408,8 @@ test "Type.Enum" {
409}408}
410409
411test "Type.Union" {410test "Type.Union" {
411 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
412 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO412 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
413 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
414 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;413 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
415414
416 const Untagged = @Type(.{415 const Untagged = @Type(.{
...@@ -547,7 +546,6 @@ test "Type.Union from empty Type.Enum" {...@@ -547,7 +546,6 @@ test "Type.Union from empty Type.Enum" {
547546
548test "Type.Fn" {547test "Type.Fn" {
549 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO548 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
550 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
551549
552 const some_opaque = opaque {};550 const some_opaque = opaque {};
553 const some_ptr = *some_opaque;551 const some_ptr = *some_opaque;
...@@ -724,7 +722,6 @@ test "@Type should resolve its children types" {...@@ -724,7 +722,6 @@ test "@Type should resolve its children types" {
724}722}
725723
726test "struct field names sliced at comptime from larger string" {724test "struct field names sliced at comptime from larger string" {
727 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
728 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO725 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
729726
730 const text =727 const text =
test/behavior/type_info.zig+2-4
...@@ -158,7 +158,6 @@ fn testArray() !void {...@@ -158,7 +158,6 @@ fn testArray() !void {
158}158}
159159
160test "type info: error set, error union info, anyerror" {160test "type info: error set, error union info, anyerror" {
161 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
162 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
163 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO162 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
164 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;163 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -190,7 +189,6 @@ fn testErrorSet() !void {...@@ -190,7 +189,6 @@ fn testErrorSet() !void {
190}189}
191190
192test "type info: error set single value" {191test "type info: error set single value" {
193 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
194 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO192 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
195 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO193 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
196 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;194 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -204,7 +202,6 @@ test "type info: error set single value" {...@@ -204,7 +202,6 @@ test "type info: error set single value" {
204}202}
205203
206test "type info: error set merged" {204test "type info: error set merged" {
207 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
208 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO205 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
209 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO206 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
210 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;207 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -221,7 +218,6 @@ test "type info: error set merged" {...@@ -221,7 +218,6 @@ test "type info: error set merged" {
221218
222test "type info: enum info" {219test "type info: enum info" {
223 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;220 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
224 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
225 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO221 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
226 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;222 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
227223
...@@ -362,6 +358,8 @@ test "type info: function type info" {...@@ -362,6 +358,8 @@ test "type info: function type info" {
362}358}
363359
364fn testFunction() !void {360fn testFunction() !void {
361 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
362
365 const S = struct {363 const S = struct {
366 export fn typeInfoFoo() callconv(.c) usize {364 export fn typeInfoFoo() callconv(.c) usize {
367 unreachable;365 unreachable;
test/behavior/typename.zig-8
...@@ -12,7 +12,6 @@ const expectStringStartsWith = std.testing.expectStringStartsWith;...@@ -12,7 +12,6 @@ const expectStringStartsWith = std.testing.expectStringStartsWith;
12// failures.12// failures.
1313
14test "anon fn param" {14test "anon fn param" {
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO15 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO16 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
18 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;17 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -38,7 +37,6 @@ test "anon fn param" {...@@ -38,7 +37,6 @@ test "anon fn param" {
38}37}
3938
40test "anon field init" {39test "anon field init" {
41 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
42 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO40 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
43 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO41 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
44 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;42 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -64,7 +62,6 @@ test "anon field init" {...@@ -64,7 +62,6 @@ test "anon field init" {
64}62}
6563
66test "basic" {64test "basic" {
67 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
68 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO65 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
69 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO66 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
70 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;67 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -86,7 +83,6 @@ test "basic" {...@@ -86,7 +83,6 @@ test "basic" {
86}83}
8784
88test "top level decl" {85test "top level decl" {
89 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
90 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO86 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
91 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO87 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
92 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;88 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -136,7 +132,6 @@ const B = struct {...@@ -136,7 +132,6 @@ const B = struct {
136};132};
137133
138test "fn param" {134test "fn param" {
139 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
140 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO135 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
141 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO136 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
142 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;137 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -216,7 +211,6 @@ pub fn expectEqualStringsIgnoreDigits(expected: []const u8, actual: []const u8)...@@ -216,7 +211,6 @@ pub fn expectEqualStringsIgnoreDigits(expected: []const u8, actual: []const u8)
216}211}
217212
218test "local variable" {213test "local variable" {
219 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
220 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO214 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
221 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO215 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
222 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;216 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -235,7 +229,6 @@ test "local variable" {...@@ -235,7 +229,6 @@ test "local variable" {
235}229}
236230
237test "comptime parameters not converted to anytype in function type" {231test "comptime parameters not converted to anytype in function type" {
238 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
239 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO232 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
240 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO233 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
241 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,7 +238,6 @@ test "comptime parameters not converted to anytype in function type" {
245}238}
246239
247test "anon name strategy used in sub expression" {240test "anon name strategy used in sub expression" {
248 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
249 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO241 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
250 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO242 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
251 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,7 +46,6 @@ fn setFooX(foo: *Foo) void {
4646
47test "assign undefined to struct" {47test "assign undefined to struct" {
48 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;48 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
49 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
50 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO49 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5150
52 comptime {51 comptime {
...@@ -63,7 +62,6 @@ test "assign undefined to struct" {...@@ -63,7 +62,6 @@ test "assign undefined to struct" {
6362
64test "assign undefined to struct with method" {63test "assign undefined to struct with method" {
65 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;64 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
66 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
67 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO65 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6866
69 comptime {67 comptime {
...@@ -89,7 +87,6 @@ test "type name of undefined" {...@@ -89,7 +87,6 @@ test "type name of undefined" {
89var buf: []u8 = undefined;87var buf: []u8 = undefined;
9088
91test "reslice of undefined global var slice" {89test "reslice of undefined global var slice" {
92 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
93 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO90 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
94 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;91 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
9592
...@@ -100,7 +97,6 @@ test "reslice of undefined global var slice" {...@@ -100,7 +97,6 @@ test "reslice of undefined global var slice" {
100}97}
10198
102test "returned undef is 0xaa bytes when runtime safety is enabled" {99test "returned undef is 0xaa bytes when runtime safety is enabled" {
103 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
104 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO100 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
105 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;101 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
106 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;102 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
test/behavior/union.zig+43-61
...@@ -12,8 +12,8 @@ const FooWithFloats = union {...@@ -12,8 +12,8 @@ const FooWithFloats = union {
12};12};
1313
14test "basic unions with floats" {14test "basic unions with floats" {
15 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
16 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
17 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO17 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
18 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;18 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
19 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;19 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -29,8 +29,8 @@ fn setFloat(foo: *FooWithFloats, x: f64) void {...@@ -29,8 +29,8 @@ fn setFloat(foo: *FooWithFloats, x: f64) void {
29}29}
3030
31test "init union with runtime value - floats" {31test "init union with runtime value - floats" {
32 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
33 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;32 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
33 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
34 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO34 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
35 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;35 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
3636
...@@ -60,8 +60,8 @@ const Foo = union {...@@ -60,8 +60,8 @@ const Foo = union {
60};60};
6161
62test "init union with runtime value" {62test "init union with runtime value" {
63 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
64 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;63 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
64 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
65 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO65 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
66 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;66 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
67 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;67 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -161,7 +161,6 @@ test "unions embedded in aggregate types" {...@@ -161,7 +161,6 @@ test "unions embedded in aggregate types" {
161161
162test "constant tagged union with payload" {162test "constant tagged union with payload" {
163 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;163 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
164 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
165 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO164 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
166165
167 var empty = TaggedUnionWithPayload{ .Empty = {} };166 var empty = TaggedUnionWithPayload{ .Empty = {} };
...@@ -210,8 +209,8 @@ const Payload = union(Letter) {...@@ -210,8 +209,8 @@ const Payload = union(Letter) {
210};209};
211210
212test "union with specified enum tag" {211test "union with specified enum tag" {
213 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
214 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;212 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
213 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
215 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO214 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
216 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;215 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
217 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;216 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -221,8 +220,8 @@ test "union with specified enum tag" {...@@ -221,8 +220,8 @@ test "union with specified enum tag" {
221}220}
222221
223test "packed union generates correctly aligned type" {222test "packed union generates correctly aligned type" {
224 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
225 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;223 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
224 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
226 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO225 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
227 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;226 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
228 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;227 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -264,7 +263,6 @@ fn testComparison() !void {...@@ -264,7 +263,6 @@ fn testComparison() !void {
264263
265test "comparison between union and enum literal" {264test "comparison between union and enum literal" {
266 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;265 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
267 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
268 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO266 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
269 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;267 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
270268
...@@ -280,7 +278,6 @@ const TheUnion = union(TheTag) {...@@ -280,7 +278,6 @@ const TheUnion = union(TheTag) {
280};278};
281test "cast union to tag type of union" {279test "cast union to tag type of union" {
282 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;280 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
283 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
284 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO281 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
285282
286 try testCastUnionToTag();283 try testCastUnionToTag();
...@@ -301,7 +298,6 @@ test "union field access gives the enum values" {...@@ -301,7 +298,6 @@ test "union field access gives the enum values" {
301298
302test "cast tag type of union to union" {299test "cast tag type of union to union" {
303 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;300 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
304 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
305 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO301 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
306302
307 var x: Value2 = Letter2.B;303 var x: Value2 = Letter2.B;
...@@ -317,7 +313,6 @@ const Value2 = union(Letter2) {...@@ -317,7 +313,6 @@ const Value2 = union(Letter2) {
317313
318test "implicit cast union to its tag type" {314test "implicit cast union to its tag type" {
319 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;315 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
320 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
321 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO316 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
322317
323 var x: Value2 = Letter2.B;318 var x: Value2 = Letter2.B;
...@@ -337,8 +332,8 @@ pub const PackThis = union(enum) {...@@ -337,8 +332,8 @@ pub const PackThis = union(enum) {
337};332};
338333
339test "constant packed union" {334test "constant packed union" {
340 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
341 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;335 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
336 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
342 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO337 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
343 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;338 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
344339
...@@ -357,7 +352,6 @@ const MultipleChoice = union(enum(u32)) {...@@ -357,7 +352,6 @@ const MultipleChoice = union(enum(u32)) {
357};352};
358test "simple union(enum(u32))" {353test "simple union(enum(u32))" {
359 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;354 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
360 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
361 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO355 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
362356
363 var x = MultipleChoice.C;357 var x = MultipleChoice.C;
...@@ -403,7 +397,6 @@ test "assigning to union with zero size field" {...@@ -403,7 +397,6 @@ test "assigning to union with zero size field" {
403397
404test "tagged union initialization with runtime void" {398test "tagged union initialization with runtime void" {
405 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;399 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
406 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
407 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO400 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
408401
409 try expect(testTaggedUnionInit({}));402 try expect(testTaggedUnionInit({}));
...@@ -423,7 +416,6 @@ pub const UnionEnumNoPayloads = union(enum) { A, B };...@@ -423,7 +416,6 @@ pub const UnionEnumNoPayloads = union(enum) { A, B };
423416
424test "tagged union with no payloads" {417test "tagged union with no payloads" {
425 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;418 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
426 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
427 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO419 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
428420
429 const a = UnionEnumNoPayloads{ .B = {} };421 const a = UnionEnumNoPayloads{ .B = {} };
...@@ -470,7 +462,6 @@ var glbl: Foo1 = undefined;...@@ -470,7 +462,6 @@ var glbl: Foo1 = undefined;
470462
471test "global union with single field is correctly initialized" {463test "global union with single field is correctly initialized" {
472 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;464 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
473 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
474 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO465 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
475466
476 glbl = Foo1{467 glbl = Foo1{
...@@ -487,8 +478,8 @@ pub const FooUnion = union(enum) {...@@ -487,8 +478,8 @@ pub const FooUnion = union(enum) {
487var glbl_array: [2]FooUnion = undefined;478var glbl_array: [2]FooUnion = undefined;
488479
489test "initialize global array of union" {480test "initialize global array of union" {
490 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
491 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;481 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
482 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
492 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO483 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
493 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;484 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
494485
...@@ -500,7 +491,6 @@ test "initialize global array of union" {...@@ -500,7 +491,6 @@ test "initialize global array of union" {
500491
501test "update the tag value for zero-sized unions" {492test "update the tag value for zero-sized unions" {
502 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;493 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
503 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
504 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO494 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
505495
506 const S = union(enum) {496 const S = union(enum) {
...@@ -515,7 +505,6 @@ test "update the tag value for zero-sized unions" {...@@ -515,7 +505,6 @@ test "update the tag value for zero-sized unions" {
515505
516test "union initializer generates padding only if needed" {506test "union initializer generates padding only if needed" {
517 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;507 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
518 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
519 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO508 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
520509
521 const U = union(enum) {510 const U = union(enum) {
...@@ -528,7 +517,6 @@ test "union initializer generates padding only if needed" {...@@ -528,7 +517,6 @@ test "union initializer generates padding only if needed" {
528}517}
529518
530test "runtime tag name with single field" {519test "runtime tag name with single field" {
531 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
532 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO520 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
533 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;521 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
534522
...@@ -543,7 +531,6 @@ test "runtime tag name with single field" {...@@ -543,7 +531,6 @@ test "runtime tag name with single field" {
543531
544test "method call on an empty union" {532test "method call on an empty union" {
545 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;533 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
546 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
547 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO534 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
548535
549 const S = struct {536 const S = struct {
...@@ -604,8 +591,8 @@ test "tagged union type" {...@@ -604,8 +591,8 @@ test "tagged union type" {
604}591}
605592
606test "tagged union as return value" {593test "tagged union as return value" {
607 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
608 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;594 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
595 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
609 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO596 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
610 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;597 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
611 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;598 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -621,8 +608,8 @@ fn returnAnInt(x: i32) TaggedFoo {...@@ -621,8 +608,8 @@ fn returnAnInt(x: i32) TaggedFoo {
621}608}
622609
623test "tagged union with all void fields but a meaningful tag" {610test "tagged union with all void fields but a meaningful tag" {
624 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
625 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;611 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
612 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
626 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO613 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
627614
628 const S = struct {615 const S = struct {
...@@ -649,8 +636,8 @@ test "tagged union with all void fields but a meaningful tag" {...@@ -649,8 +636,8 @@ test "tagged union with all void fields but a meaningful tag" {
649}636}
650637
651test "union(enum(u32)) with specified and unspecified tag values" {638test "union(enum(u32)) with specified and unspecified tag values" {
652 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
653 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;639 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
640 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
654 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO641 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
655 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;642 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
656643
...@@ -687,7 +674,6 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void {...@@ -687,7 +674,6 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void {
687}674}
688675
689test "switch on union with only 1 field" {676test "switch on union with only 1 field" {
690 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
691 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO677 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
692 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO678 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
693679
...@@ -743,7 +729,6 @@ test "union with only 1 field casted to its enum type which has enum value speci...@@ -743,7 +729,6 @@ test "union with only 1 field casted to its enum type which has enum value speci
743729
744test "@intFromEnum works on unions" {730test "@intFromEnum works on unions" {
745 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO731 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
746 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
747 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO732 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
748733
749 const Bar = union(enum) {734 const Bar = union(enum) {
...@@ -801,8 +786,8 @@ fn Setter(comptime attr: Attribute) type {...@@ -801,8 +786,8 @@ fn Setter(comptime attr: Attribute) type {
801}786}
802787
803test "return union init with void payload" {788test "return union init with void payload" {
804 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
805 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;789 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
790 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
806 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO791 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
807792
808 const S = struct {793 const S = struct {
...@@ -825,7 +810,7 @@ test "return union init with void payload" {...@@ -825,7 +810,7 @@ test "return union init with void payload" {
825}810}
826811
827test "@unionInit stored to a const" {812test "@unionInit stored to a const" {
828 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO813 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
829 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO814 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
830 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO815 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
831 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;816 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -856,7 +841,6 @@ test "@unionInit stored to a const" {...@@ -856,7 +841,6 @@ test "@unionInit stored to a const" {
856}841}
857842
858test "@unionInit can modify a union type" {843test "@unionInit can modify a union type" {
859 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
860 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO844 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
861 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO845 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
862846
...@@ -879,7 +863,6 @@ test "@unionInit can modify a union type" {...@@ -879,7 +863,6 @@ test "@unionInit can modify a union type" {
879}863}
880864
881test "@unionInit can modify a pointer value" {865test "@unionInit can modify a pointer value" {
882 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
883 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO866 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
884 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO867 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
885868
...@@ -899,7 +882,6 @@ test "@unionInit can modify a pointer value" {...@@ -899,7 +882,6 @@ test "@unionInit can modify a pointer value" {
899}882}
900883
901test "union no tag with struct member" {884test "union no tag with struct member" {
902 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
903 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO885 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
904 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO886 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
905 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;887 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -935,8 +917,8 @@ test "extern union doesn't trigger field check at comptime" {...@@ -935,8 +917,8 @@ test "extern union doesn't trigger field check at comptime" {
935}917}
936918
937test "anonymous union literal syntax" {919test "anonymous union literal syntax" {
920 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
938 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO921 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
939 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
940 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO922 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
941 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;923 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
942 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;924 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -964,8 +946,8 @@ test "anonymous union literal syntax" {...@@ -964,8 +946,8 @@ test "anonymous union literal syntax" {
964}946}
965947
966test "function call result coerces from tagged union to the tag" {948test "function call result coerces from tagged union to the tag" {
949 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
967 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO950 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
968 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
969 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO951 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
970952
971 const S = struct {953 const S = struct {
...@@ -1000,7 +982,6 @@ test "function call result coerces from tagged union to the tag" {...@@ -1000,7 +982,6 @@ test "function call result coerces from tagged union to the tag" {
1000982
1001test "switching on non exhaustive union" {983test "switching on non exhaustive union" {
1002 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO984 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1003 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1004 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO985 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1005986
1006 const S = struct {987 const S = struct {
...@@ -1028,7 +1009,6 @@ test "switching on non exhaustive union" {...@@ -1028,7 +1009,6 @@ test "switching on non exhaustive union" {
10281009
1029test "containers with single-field enums" {1010test "containers with single-field enums" {
1030 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1011 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1031 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1032 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1012 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10331013
1034 const S = struct {1014 const S = struct {
...@@ -1057,8 +1037,8 @@ test "containers with single-field enums" {...@@ -1057,8 +1037,8 @@ test "containers with single-field enums" {
1057}1037}
10581038
1059test "@unionInit on union with tag but no fields" {1039test "@unionInit on union with tag but no fields" {
1040 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1060 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1041 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1061 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1062 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1042 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10631043
1064 const S = struct {1044 const S = struct {
...@@ -1106,7 +1086,7 @@ test "union enum type gets a separate scope" {...@@ -1106,7 +1086,7 @@ test "union enum type gets a separate scope" {
1106}1086}
11071087
1108test "global variable struct contains union initialized to non-most-aligned field" {1088test "global variable struct contains union initialized to non-most-aligned field" {
1109 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1089 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1110 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1090 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1111 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1091 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1112 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1092 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1133,8 +1113,8 @@ test "global variable struct contains union initialized to non-most-aligned fiel...@@ -1133,8 +1113,8 @@ test "global variable struct contains union initialized to non-most-aligned fiel
1133}1113}
11341114
1135test "union with no result loc initiated with a runtime value" {1115test "union with no result loc initiated with a runtime value" {
1116 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1136 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1117 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1137 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1138 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1118 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1139 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1119 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11401120
...@@ -1151,8 +1131,8 @@ test "union with no result loc initiated with a runtime value" {...@@ -1151,8 +1131,8 @@ test "union with no result loc initiated with a runtime value" {
1151}1131}
11521132
1153test "union with a large struct field" {1133test "union with a large struct field" {
1134 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1154 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1135 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1156 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1136 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1157 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1137 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11581138
...@@ -1187,7 +1167,6 @@ test "comptime equality of extern unions with same tag" {...@@ -1187,7 +1167,6 @@ test "comptime equality of extern unions with same tag" {
11871167
1188test "union tag is set when initiated as a temporary value at runtime" {1168test "union tag is set when initiated as a temporary value at runtime" {
1189 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1169 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1190 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1191 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1170 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1192 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1171 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
11931172
...@@ -1206,8 +1185,8 @@ test "union tag is set when initiated as a temporary value at runtime" {...@@ -1206,8 +1185,8 @@ test "union tag is set when initiated as a temporary value at runtime" {
1206}1185}
12071186
1208test "extern union most-aligned field is smaller" {1187test "extern union most-aligned field is smaller" {
1188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1209 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1189 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1210 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1211 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1190 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1212 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1191 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
12131192
...@@ -1227,7 +1206,6 @@ test "extern union most-aligned field is smaller" {...@@ -1227,7 +1206,6 @@ test "extern union most-aligned field is smaller" {
12271206
1228test "return an extern union from C calling convention" {1207test "return an extern union from C calling convention" {
1229 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1208 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1230 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1231 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1209 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1232 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1210 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
12331211
...@@ -1258,7 +1236,6 @@ test "return an extern union from C calling convention" {...@@ -1258,7 +1236,6 @@ test "return an extern union from C calling convention" {
1258}1236}
12591237
1260test "noreturn field in union" {1238test "noreturn field in union" {
1261 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1262 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1239 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1263 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1240 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
12641241
...@@ -1309,7 +1286,7 @@ test "noreturn field in union" {...@@ -1309,7 +1286,7 @@ test "noreturn field in union" {
1309}1286}
13101287
1311test "@unionInit uses tag value instead of field index" {1288test "@unionInit uses tag value instead of field index" {
1312 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1289 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1313 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1290 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1314 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1291 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1315 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1292 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1339,7 +1316,6 @@ test "@unionInit uses tag value instead of field index" {...@@ -1339,7 +1316,6 @@ test "@unionInit uses tag value instead of field index" {
1339}1316}
13401317
1341test "union field ptr - zero sized payload" {1318test "union field ptr - zero sized payload" {
1342 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1343 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1319 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1344 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1320 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1345 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1321 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1354,7 +1330,6 @@ test "union field ptr - zero sized payload" {...@@ -1354,7 +1330,6 @@ test "union field ptr - zero sized payload" {
1354}1330}
13551331
1356test "union field ptr - zero sized field" {1332test "union field ptr - zero sized field" {
1357 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1358 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1333 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1359 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1334 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1360 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1335 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1369,7 +1344,7 @@ test "union field ptr - zero sized field" {...@@ -1369,7 +1344,7 @@ test "union field ptr - zero sized field" {
1369}1344}
13701345
1371test "packed union in packed struct" {1346test "packed union in packed struct" {
1372 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1347 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1373 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1348 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1374 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1349 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13751350
...@@ -1420,8 +1395,8 @@ test "union int tag type is properly managed" {...@@ -1420,8 +1395,8 @@ test "union int tag type is properly managed" {
1420}1395}
14211396
1422test "no dependency loop when function pointer in union returns the union" {1397test "no dependency loop when function pointer in union returns the union" {
1398 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1423 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1399 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1424 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1425 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1400 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1426 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1401 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14271402
...@@ -1442,7 +1417,7 @@ test "no dependency loop when function pointer in union returns the union" {...@@ -1442,7 +1417,7 @@ test "no dependency loop when function pointer in union returns the union" {
1442}1417}
14431418
1444test "union reassignment can use previous value" {1419test "union reassignment can use previous value" {
1445 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1420 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1446 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1421 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1447 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1422 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
14481423
...@@ -1456,7 +1431,7 @@ test "union reassignment can use previous value" {...@@ -1456,7 +1431,7 @@ test "union reassignment can use previous value" {
1456}1431}
14571432
1458test "packed union with zero-bit field" {1433test "packed union with zero-bit field" {
1459 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1434 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1460 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1435 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1461 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1436 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14621437
...@@ -1475,7 +1450,7 @@ test "packed union with zero-bit field" {...@@ -1475,7 +1450,7 @@ test "packed union with zero-bit field" {
1475}1450}
14761451
1477test "reinterpreting enum value inside packed union" {1452test "reinterpreting enum value inside packed union" {
1478 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1453 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1479 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1454 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14801455
1481 const U = packed union {1456 const U = packed union {
...@@ -1493,8 +1468,6 @@ test "reinterpreting enum value inside packed union" {...@@ -1493,8 +1468,6 @@ test "reinterpreting enum value inside packed union" {
1493}1468}
14941469
1495test "access the tag of a global tagged union" {1470test "access the tag of a global tagged union" {
1496 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1497
1498 const U = union(enum) {1471 const U = union(enum) {
1499 a,1472 a,
1500 b: u8,1473 b: u8,
...@@ -1504,7 +1477,7 @@ test "access the tag of a global tagged union" {...@@ -1504,7 +1477,7 @@ test "access the tag of a global tagged union" {
1504}1477}
15051478
1506test "coerce enum literal to union in result loc" {1479test "coerce enum literal to union in result loc" {
1507 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1480 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
15081481
1509 const U = union(enum) {1482 const U = union(enum) {
1510 a,1483 a,
...@@ -1522,7 +1495,6 @@ test "coerce enum literal to union in result loc" {...@@ -1522,7 +1495,6 @@ test "coerce enum literal to union in result loc" {
1522test "defined-layout union field pointer has correct alignment" {1495test "defined-layout union field pointer has correct alignment" {
1523 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO1496 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1524 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1497 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1525 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1526 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1498 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15271499
1528 const S = struct {1500 const S = struct {
...@@ -1557,7 +1529,6 @@ test "defined-layout union field pointer has correct alignment" {...@@ -1557,7 +1529,6 @@ test "defined-layout union field pointer has correct alignment" {
1557test "undefined-layout union field pointer has correct alignment" {1529test "undefined-layout union field pointer has correct alignment" {
1558 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO1530 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1559 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1531 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1560 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1561 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1532 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15621533
1563 const S = struct {1534 const S = struct {
...@@ -1590,8 +1561,8 @@ test "undefined-layout union field pointer has correct alignment" {...@@ -1590,8 +1561,8 @@ test "undefined-layout union field pointer has correct alignment" {
1590}1561}
15911562
1592test "packed union field pointer has correct alignment" {1563test "packed union field pointer has correct alignment" {
1564 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1593 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1565 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1594 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1595 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1566 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1596 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO1567 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
15971568
...@@ -1624,6 +1595,7 @@ test "packed union field pointer has correct alignment" {...@@ -1624,6 +1595,7 @@ test "packed union field pointer has correct alignment" {
1624}1595}
16251596
1626test "union with 128 bit integer" {1597test "union with 128 bit integer" {
1598 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1627 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1599 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16281600
1629 const ValueTag = enum { int, other };1601 const ValueTag = enum { int, other };
...@@ -1647,6 +1619,7 @@ test "union with 128 bit integer" {...@@ -1647,6 +1619,7 @@ test "union with 128 bit integer" {
1647}1619}
16481620
1649test "memset extern union" {1621test "memset extern union" {
1622 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1650 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1623 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16511624
1652 const U = extern union {1625 const U = extern union {
...@@ -1668,6 +1641,7 @@ test "memset extern union" {...@@ -1668,6 +1641,7 @@ test "memset extern union" {
1668}1641}
16691642
1670test "memset packed union" {1643test "memset packed union" {
1644 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1671 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1645 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16721646
1673 const U = packed union {1647 const U = packed union {
...@@ -1768,6 +1742,7 @@ test "reinterpret extern union" {...@@ -1768,6 +1742,7 @@ test "reinterpret extern union" {
1768}1742}
17691743
1770test "reinterpret packed union" {1744test "reinterpret packed union" {
1745 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1771 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1746 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
17721747
1773 const U = packed union {1748 const U = packed union {
...@@ -1840,6 +1815,7 @@ test "reinterpret packed union" {...@@ -1840,6 +1815,7 @@ test "reinterpret packed union" {
1840}1815}
18411816
1842test "reinterpret packed union inside packed struct" {1817test "reinterpret packed union inside packed struct" {
1818 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1843 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1819 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
1844 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO1820 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
18451821
...@@ -1945,6 +1921,8 @@ test "extern union initialized via reintepreted struct field initializer" {...@@ -1945,6 +1921,8 @@ test "extern union initialized via reintepreted struct field initializer" {
1945}1921}
19461922
1947test "packed union initialized via reintepreted struct field initializer" {1923test "packed union initialized via reintepreted struct field initializer" {
1924 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1925
1948 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };1926 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
19491927
1950 const U = packed union {1928 const U = packed union {
...@@ -1963,6 +1941,7 @@ test "packed union initialized via reintepreted struct field initializer" {...@@ -1963,6 +1941,7 @@ test "packed union initialized via reintepreted struct field initializer" {
1963}1941}
19641942
1965test "store of comptime reinterpreted memory to extern union" {1943test "store of comptime reinterpreted memory to extern union" {
1944 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1966 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1945 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
19671946
1968 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };1947 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
...@@ -1985,6 +1964,8 @@ test "store of comptime reinterpreted memory to extern union" {...@@ -1985,6 +1964,8 @@ test "store of comptime reinterpreted memory to extern union" {
1985}1964}
19861965
1987test "store of comptime reinterpreted memory to packed union" {1966test "store of comptime reinterpreted memory to packed union" {
1967 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1968
1988 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };1969 const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd };
19891970
1990 const U = packed union {1971 const U = packed union {
...@@ -2005,7 +1986,6 @@ test "store of comptime reinterpreted memory to packed union" {...@@ -2005,7 +1986,6 @@ test "store of comptime reinterpreted memory to packed union" {
2005}1986}
20061987
2007test "union field is a pointer to an aligned version of itself" {1988test "union field is a pointer to an aligned version of itself" {
2008 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2009 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1989 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2010 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1990 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
20111991
...@@ -2019,6 +1999,7 @@ test "union field is a pointer to an aligned version of itself" {...@@ -2019,6 +1999,7 @@ test "union field is a pointer to an aligned version of itself" {
2019}1999}
20202000
2021test "pass register-sized field as non-register-sized union" {2001test "pass register-sized field as non-register-sized union" {
2002 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2022 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;2003 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2023 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;2004 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
20242005
...@@ -2067,6 +2048,7 @@ test "circular dependency through pointer field of a union" {...@@ -2067,6 +2048,7 @@ test "circular dependency through pointer field of a union" {
2067}2048}
20682049
2069test "pass nested union with rls" {2050test "pass nested union with rls" {
2051 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2070 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;2052 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
2071 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;2053 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
20722054
...@@ -2088,8 +2070,8 @@ test "pass nested union with rls" {...@@ -2088,8 +2070,8 @@ test "pass nested union with rls" {
2088}2070}
20892071
2090test "runtime union init, most-aligned field != largest" {2072test "runtime union init, most-aligned field != largest" {
2073 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2091 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2074 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2092 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2093 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2075 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2094 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;2076 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2095 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;2077 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -2115,7 +2097,6 @@ test "runtime union init, most-aligned field != largest" {...@@ -2115,7 +2097,6 @@ test "runtime union init, most-aligned field != largest" {
21152097
2116test "copied union field doesn't alias source" {2098test "copied union field doesn't alias source" {
2117 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2099 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2118 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2119 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO2100 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2120 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;2101 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
21212102
...@@ -2134,7 +2115,7 @@ test "copied union field doesn't alias source" {...@@ -2134,7 +2115,7 @@ test "copied union field doesn't alias source" {
2134}2115}
21352116
2136test "create union(enum) from other union(enum)" {2117test "create union(enum) from other union(enum)" {
2137 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO2118 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2138 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2119 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2139 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;2120 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2140 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;2121 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -2258,7 +2239,7 @@ test "matching captures causes union equivalence" {...@@ -2258,7 +2239,7 @@ test "matching captures causes union equivalence" {
2258}2239}
22592240
2260test "signed enum tag with negative value" {2241test "signed enum tag with negative value" {
2261 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO2242 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2262 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO2243 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2263 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;2244 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2264 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;2245 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -2315,6 +2296,7 @@ test "extern union @FieldType" {...@@ -2315,6 +2296,7 @@ test "extern union @FieldType" {
2315}2296}
23162297
2317test "assign global tagged union" {2298test "assign global tagged union" {
2299 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
2318 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;2300 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
23192301
2320 const U = union(enum) {2302 const U = union(enum) {
test/behavior/union_with_members.zig-1
...@@ -18,7 +18,6 @@ const ET = union(enum) {...@@ -18,7 +18,6 @@ const ET = union(enum) {
1818
19test "enum with members" {19test "enum with members" {
20 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO20 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
21 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
22 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO21 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
23 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;22 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
2423
test/behavior/var_args.zig+6-12
...@@ -28,7 +28,6 @@ test "send void arg to var args" {...@@ -28,7 +28,6 @@ test "send void arg to var args" {
28}28}
2929
30test "pass args directly" {30test "pass args directly" {
31 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
32 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO31 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
3332
34 try expect(addSomeStuff(.{ @as(i32, 1), @as(i32, 2), @as(i32, 3), @as(i32, 4) }) == 10);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,7 +40,6 @@ fn addSomeStuff(args: anytype) i32 {
41}40}
4241
43test "runtime parameter before var args" {42test "runtime parameter before var args" {
44 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
45 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO43 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4644
47 try expect((try extraFn(10, .{})) == 0);45 try expect((try extraFn(10, .{})) == 0);
...@@ -94,13 +92,12 @@ fn doNothingWithFirstArg(args: anytype) void {...@@ -94,13 +92,12 @@ fn doNothingWithFirstArg(args: anytype) void {
94}92}
9593
96test "simple variadic function" {94test "simple variadic function" {
97 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO95 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
99 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO96 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
100 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO97 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
101 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;98 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
102 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;99 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
103 if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {100 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
104 // https://github.com/ziglang/zig/issues/14096101 // https://github.com/ziglang/zig/issues/14096
105 return error.SkipZigTest;102 return error.SkipZigTest;
106 }103 }
...@@ -156,13 +153,12 @@ test "simple variadic function" {...@@ -156,13 +153,12 @@ test "simple variadic function" {
156}153}
157154
158test "coerce reference to var arg" {155test "coerce reference to var arg" {
159 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
160 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO156 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO157 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
162 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO158 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
163 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;159 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
164 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;160 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
165 if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {161 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
166 // https://github.com/ziglang/zig/issues/14096162 // https://github.com/ziglang/zig/issues/14096
167 return error.SkipZigTest;163 return error.SkipZigTest;
168 }164 }
...@@ -189,13 +185,13 @@ test "coerce reference to var arg" {...@@ -189,13 +185,13 @@ test "coerce reference to var arg" {
189}185}
190186
191test "variadic functions" {187test "variadic functions" {
192 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
193 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO189 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
194 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO190 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
195 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO191 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
196 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;192 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
197 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;193 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
198 if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {194 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
199 // https://github.com/ziglang/zig/issues/14096195 // https://github.com/ziglang/zig/issues/14096
200 return error.SkipZigTest;196 return error.SkipZigTest;
201 }197 }
...@@ -236,12 +232,11 @@ test "variadic functions" {...@@ -236,12 +232,11 @@ test "variadic functions" {
236}232}
237233
238test "copy VaList" {234test "copy VaList" {
239 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
240 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO235 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
241 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO236 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
242 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;237 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
243 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;238 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
244 if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {239 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
245 // https://github.com/ziglang/zig/issues/14096240 // https://github.com/ziglang/zig/issues/14096
246 return error.SkipZigTest;241 return error.SkipZigTest;
247 }242 }
...@@ -271,12 +266,11 @@ test "copy VaList" {...@@ -271,12 +266,11 @@ test "copy VaList" {
271}266}
272267
273test "unused VaList arg" {268test "unused VaList arg" {
274 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
275 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO269 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
276 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO270 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
277 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;271 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
278 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;272 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
279 if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {273 if (builtin.zig_backend == .stage2_llvm and builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) {
280 // https://github.com/ziglang/zig/issues/14096274 // https://github.com/ziglang/zig/issues/14096
281 return error.SkipZigTest;275 return error.SkipZigTest;
282 }276 }
test/behavior/vector.zig+43-55
...@@ -8,7 +8,6 @@ const expectEqual = std.testing.expectEqual;...@@ -8,7 +8,6 @@ const expectEqual = std.testing.expectEqual;
88
9test "implicit cast vector to array - bool" {9test "implicit cast vector to array - bool" {
10 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO11 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
13 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO12 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
14 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;13 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -25,8 +24,8 @@ test "implicit cast vector to array - bool" {...@@ -25,8 +24,8 @@ test "implicit cast vector to array - bool" {
25}24}
2625
27test "vector wrap operators" {26test "vector wrap operators" {
27 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
28 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO28 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
29 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
30 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO29 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
31 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO30 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
32 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;31 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -49,8 +48,8 @@ test "vector wrap operators" {...@@ -49,8 +48,8 @@ test "vector wrap operators" {
49}48}
5049
51test "vector bin compares with mem.eql" {50test "vector bin compares with mem.eql" {
51 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
52 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO52 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
53 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
54 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO53 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
55 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO54 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
56 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;55 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -74,8 +73,8 @@ test "vector bin compares with mem.eql" {...@@ -74,8 +73,8 @@ test "vector bin compares with mem.eql" {
74}73}
7574
76test "vector int operators" {75test "vector int operators" {
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
77 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO77 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
78 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
79 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO78 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
80 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO79 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
81 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;80 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -97,8 +96,8 @@ test "vector int operators" {...@@ -97,8 +96,8 @@ test "vector int operators" {
97}96}
9897
99test "vector float operators" {98test "vector float operators" {
99 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
100 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO100 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
101 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
102 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO101 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
103 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO102 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
104 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;103 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -141,8 +140,8 @@ test "vector float operators" {...@@ -141,8 +140,8 @@ test "vector float operators" {
141}140}
142141
143test "vector bit operators" {142test "vector bit operators" {
143 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
144 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO144 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
145 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
146 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO145 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
147 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO146 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
148 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;147 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -173,7 +172,7 @@ test "vector bit operators" {...@@ -173,7 +172,7 @@ test "vector bit operators" {
173}172}
174173
175test "implicit cast vector to array" {174test "implicit cast vector to array" {
176 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO175 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
177 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO176 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
178 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO177 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
179 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;178 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -193,7 +192,7 @@ test "implicit cast vector to array" {...@@ -193,7 +192,7 @@ test "implicit cast vector to array" {
193}192}
194193
195test "array to vector" {194test "array to vector" {
196 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO195 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
197 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO196 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
198 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO197 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
199 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;198 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -212,7 +211,7 @@ test "array to vector" {...@@ -212,7 +211,7 @@ test "array to vector" {
212}211}
213212
214test "array vector coercion - odd sizes" {213test "array vector coercion - odd sizes" {
215 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO214 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
216 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO215 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
217 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO216 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
218 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;217 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
...@@ -251,7 +250,7 @@ test "array vector coercion - odd sizes" {...@@ -251,7 +250,7 @@ test "array vector coercion - odd sizes" {
251}250}
252251
253test "array to vector with element type coercion" {252test "array to vector with element type coercion" {
254 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO253 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
255 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO254 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
256 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO255 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
257 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO256 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
...@@ -273,7 +272,6 @@ test "array to vector with element type coercion" {...@@ -273,7 +272,6 @@ test "array to vector with element type coercion" {
273272
274test "peer type resolution with coercible element types" {273test "peer type resolution with coercible element types" {
275 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO274 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
276 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
277 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO275 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
278 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO276 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
279277
...@@ -291,8 +289,8 @@ test "peer type resolution with coercible element types" {...@@ -291,8 +289,8 @@ test "peer type resolution with coercible element types" {
291}289}
292290
293test "tuple to vector" {291test "tuple to vector" {
292 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
294 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO293 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
295 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
296 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO294 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
297 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO295 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
298 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;296 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -314,8 +312,8 @@ test "tuple to vector" {...@@ -314,8 +312,8 @@ test "tuple to vector" {
314}312}
315313
316test "vector casts of sizes not divisible by 8" {314test "vector casts of sizes not divisible by 8" {
315 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
317 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO316 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
318 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
319 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO317 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
320 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO318 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
321 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;319 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -354,7 +352,7 @@ test "vector casts of sizes not divisible by 8" {...@@ -354,7 +352,7 @@ test "vector casts of sizes not divisible by 8" {
354}352}
355353
356test "vector @splat" {354test "vector @splat" {
357 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO355 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
358 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO356 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
359 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO357 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
360 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;358 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -395,7 +393,7 @@ test "vector @splat" {...@@ -395,7 +393,7 @@ test "vector @splat" {
395}393}
396394
397test "load vector elements via comptime index" {395test "load vector elements via comptime index" {
398 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO396 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
399 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO397 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
400 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO398 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
401399
...@@ -416,7 +414,7 @@ test "load vector elements via comptime index" {...@@ -416,7 +414,7 @@ test "load vector elements via comptime index" {
416}414}
417415
418test "store vector elements via comptime index" {416test "store vector elements via comptime index" {
419 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO417 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
420 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO418 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
421 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO419 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
422420
...@@ -443,7 +441,6 @@ test "store vector elements via comptime index" {...@@ -443,7 +441,6 @@ test "store vector elements via comptime index" {
443}441}
444442
445test "load vector elements via runtime index" {443test "load vector elements via runtime index" {
446 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
447 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO444 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
448 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO445 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
449446
...@@ -465,7 +462,7 @@ test "load vector elements via runtime index" {...@@ -465,7 +462,7 @@ test "load vector elements via runtime index" {
465}462}
466463
467test "store vector elements via runtime index" {464test "store vector elements via runtime index" {
468 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO465 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
469 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO466 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
470 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO467 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
471468
...@@ -487,7 +484,6 @@ test "store vector elements via runtime index" {...@@ -487,7 +484,6 @@ test "store vector elements via runtime index" {
487}484}
488485
489test "initialize vector which is a struct field" {486test "initialize vector which is a struct field" {
490 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
491 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO487 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
492 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO488 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
493489
...@@ -508,8 +504,8 @@ test "initialize vector which is a struct field" {...@@ -508,8 +504,8 @@ test "initialize vector which is a struct field" {
508}504}
509505
510test "vector comparison operators" {506test "vector comparison operators" {
507 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
511 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO508 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
512 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
513 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO509 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
514 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO510 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
515 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;511 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -554,8 +550,8 @@ test "vector comparison operators" {...@@ -554,8 +550,8 @@ test "vector comparison operators" {
554}550}
555551
556test "vector division operators" {552test "vector division operators" {
553 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
557 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO554 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
558 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
559 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO555 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
560 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO556 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
561 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;557 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -647,9 +643,9 @@ test "vector division operators" {...@@ -647,9 +643,9 @@ test "vector division operators" {
647}643}
648644
649test "vector bitwise not operator" {645test "vector bitwise not operator" {
646 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
650 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO647 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
651 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;648 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
652 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
653 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO649 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
654 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO650 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
655 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;651 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -681,9 +677,9 @@ test "vector bitwise not operator" {...@@ -681,9 +677,9 @@ test "vector bitwise not operator" {
681}677}
682678
683test "vector boolean not operator" {679test "vector boolean not operator" {
680 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
684 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO681 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
685 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;682 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
686 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
687 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO683 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
688 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO684 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
689 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;685 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -705,8 +701,8 @@ test "vector boolean not operator" {...@@ -705,8 +701,8 @@ test "vector boolean not operator" {
705}701}
706702
707test "vector shift operators" {703test "vector shift operators" {
704 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
708 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO705 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
709 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
710 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO706 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
711 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO707 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
712 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;708 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -776,8 +772,8 @@ test "vector shift operators" {...@@ -776,8 +772,8 @@ test "vector shift operators" {
776}772}
777773
778test "vector reduce operation" {774test "vector reduce operation" {
775 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
779 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO776 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
780 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
781 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO777 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
782 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO778 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
783 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;779 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -908,7 +904,6 @@ test "vector reduce operation" {...@@ -908,7 +904,6 @@ test "vector reduce operation" {
908904
909test "vector @reduce comptime" {905test "vector @reduce comptime" {
910 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO906 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
911 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
912 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO907 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
913 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO908 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
914909
...@@ -924,7 +919,7 @@ test "vector @reduce comptime" {...@@ -924,7 +919,7 @@ test "vector @reduce comptime" {
924}919}
925920
926test "mask parameter of @shuffle is comptime scope" {921test "mask parameter of @shuffle is comptime scope" {
927 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO922 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
928 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO923 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
929 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO924 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
930 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;925 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -946,8 +941,8 @@ test "mask parameter of @shuffle is comptime scope" {...@@ -946,8 +941,8 @@ test "mask parameter of @shuffle is comptime scope" {
946}941}
947942
948test "saturating add" {943test "saturating add" {
944 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
949 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO945 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
950 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
951 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO946 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
952 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO947 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
953 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;948 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -980,8 +975,8 @@ test "saturating add" {...@@ -980,8 +975,8 @@ test "saturating add" {
980}975}
981976
982test "saturating subtraction" {977test "saturating subtraction" {
978 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
983 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO979 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
984 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
985 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO980 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
986 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO981 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
987 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;982 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1004,8 +999,8 @@ test "saturating subtraction" {...@@ -1004,8 +999,8 @@ test "saturating subtraction" {
1004}999}
10051000
1006test "saturating multiplication" {1001test "saturating multiplication" {
1002 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1007 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1003 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1008 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1009 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1004 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1010 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1005 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1011 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1006 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1032,8 +1027,8 @@ test "saturating multiplication" {...@@ -1032,8 +1027,8 @@ test "saturating multiplication" {
1032}1027}
10331028
1034test "saturating shift-left" {1029test "saturating shift-left" {
1030 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1035 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1031 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1036 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1037 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1032 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1038 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1033 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1039 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1034 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1056,8 +1051,8 @@ test "saturating shift-left" {...@@ -1056,8 +1051,8 @@ test "saturating shift-left" {
1056}1051}
10571052
1058test "multiplication-assignment operator with an array operand" {1053test "multiplication-assignment operator with an array operand" {
1054 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1059 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1055 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1060 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1061 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1056 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1062 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1057 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1063 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1058 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1077,8 +1072,8 @@ test "multiplication-assignment operator with an array operand" {...@@ -1077,8 +1072,8 @@ test "multiplication-assignment operator with an array operand" {
1077}1072}
10781073
1079test "@addWithOverflow" {1074test "@addWithOverflow" {
1075 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1080 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1076 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1081 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1082 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1077 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1083 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1078 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1084 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1079 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1127,8 +1122,8 @@ test "@addWithOverflow" {...@@ -1127,8 +1122,8 @@ test "@addWithOverflow" {
1127}1122}
11281123
1129test "@subWithOverflow" {1124test "@subWithOverflow" {
1125 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1130 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1126 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1131 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1132 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1127 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1133 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1128 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1134 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1129 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1161,8 +1156,8 @@ test "@subWithOverflow" {...@@ -1161,8 +1156,8 @@ test "@subWithOverflow" {
1161}1156}
11621157
1163test "@mulWithOverflow" {1158test "@mulWithOverflow" {
1159 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1164 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1160 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1165 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1166 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1167 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1162 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1168 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1163 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1184,8 +1179,8 @@ test "@mulWithOverflow" {...@@ -1184,8 +1179,8 @@ test "@mulWithOverflow" {
1184}1179}
11851180
1186test "@shlWithOverflow" {1181test "@shlWithOverflow" {
1182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1187 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1183 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1189 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1184 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1190 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1185 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1191 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1186 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1229,8 +1224,8 @@ test "alignment of vectors" {...@@ -1229,8 +1224,8 @@ test "alignment of vectors" {
1229}1224}
12301225
1231test "loading the second vector from a slice of vectors" {1226test "loading the second vector from a slice of vectors" {
1227 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1232 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1228 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1233 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1234 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1229 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1235 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1230 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1236 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,8 +1241,8 @@ test "loading the second vector from a slice of vectors" {
1246}1241}
12471242
1248test "array of vectors is copied" {1243test "array of vectors is copied" {
1244 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1249 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1245 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1250 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1251 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1246 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1252 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1247 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1253 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1248 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -1270,8 +1265,8 @@ test "array of vectors is copied" {...@@ -1270,8 +1265,8 @@ test "array of vectors is copied" {
1270}1265}
12711266
1272test "byte vector initialized in inline function" {1267test "byte vector initialized in inline function" {
1268 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1273 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1269 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1274 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1275 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1270 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1276 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1271 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1277 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1272 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1297,7 +1292,6 @@ test "byte vector initialized in inline function" {...@@ -1297,7 +1292,6 @@ test "byte vector initialized in inline function" {
12971292
1298test "zero divisor" {1293test "zero divisor" {
1299 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1294 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1300 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1301 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1295 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1302 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1296 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
13031297
...@@ -1317,7 +1311,6 @@ test "zero divisor" {...@@ -1317,7 +1311,6 @@ test "zero divisor" {
13171311
1318test "zero multiplicand" {1312test "zero multiplicand" {
1319 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1313 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1320 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1321 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1314 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1322 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1315 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1323 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO1316 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
...@@ -1341,7 +1334,6 @@ test "zero multiplicand" {...@@ -1341,7 +1334,6 @@ test "zero multiplicand" {
13411334
1342test "@intCast to u0" {1335test "@intCast to u0" {
1343 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1336 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1344 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1345 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1337 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1346 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1338 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1347 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1339 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1364,8 +1356,8 @@ test "modRem with zero divisor" {...@@ -1364,8 +1356,8 @@ test "modRem with zero divisor" {
1364}1356}
13651357
1366test "array operands to shuffle are coerced to vectors" {1358test "array operands to shuffle are coerced to vectors" {
1359 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1367 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1360 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1368 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1369 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1361 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1370 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1362 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1371 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1363 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
...@@ -1379,7 +1371,7 @@ test "array operands to shuffle are coerced to vectors" {...@@ -1379,7 +1371,7 @@ test "array operands to shuffle are coerced to vectors" {
1379}1371}
13801372
1381test "load packed vector element" {1373test "load packed vector element" {
1382 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1374 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1383 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1375 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1384 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1376 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1385 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1377 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
...@@ -1391,7 +1383,7 @@ test "load packed vector element" {...@@ -1391,7 +1383,7 @@ test "load packed vector element" {
1391}1383}
13921384
1393test "store packed vector element" {1385test "store packed vector element" {
1394 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1386 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1395 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1387 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1396 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1388 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1397 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1389 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
...@@ -1408,7 +1400,7 @@ test "store packed vector element" {...@@ -1408,7 +1400,7 @@ test "store packed vector element" {
1408}1400}
14091401
1410test "store to vector in slice" {1402test "store to vector in slice" {
1411 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1403 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1412 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1404 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1413 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1405 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1414 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1406 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1426,7 +1418,7 @@ test "store to vector in slice" {...@@ -1426,7 +1418,7 @@ test "store to vector in slice" {
1426}1418}
14271419
1428test "store vector with memset" {1420test "store vector with memset" {
1429 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1421 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1430 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1422 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1431 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1423 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1432 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1424 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1459,7 +1451,7 @@ test "store vector with memset" {...@@ -1459,7 +1451,7 @@ test "store vector with memset" {
1459}1451}
14601452
1461test "addition of vectors represented as strings" {1453test "addition of vectors represented as strings" {
1462 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1454 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1463 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1455 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14641456
1465 const V = @Vector(3, u8);1457 const V = @Vector(3, u8);
...@@ -1469,7 +1461,7 @@ test "addition of vectors represented as strings" {...@@ -1469,7 +1461,7 @@ test "addition of vectors represented as strings" {
1469}1461}
14701462
1471test "compare vectors with different element types" {1463test "compare vectors with different element types" {
1472 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1464 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1473 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1465 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1474 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1466 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1475 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1467 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1482,7 +1474,6 @@ test "compare vectors with different element types" {...@@ -1482,7 +1474,6 @@ test "compare vectors with different element types" {
1482}1474}
14831475
1484test "vector pointer is indexable" {1476test "vector pointer is indexable" {
1485 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1486 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1477 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1487 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1478 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1488 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1479 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1506,7 +1497,6 @@ test "vector pointer is indexable" {...@@ -1506,7 +1497,6 @@ test "vector pointer is indexable" {
1506}1497}
15071498
1508test "boolean vector with 2 or more booleans" {1499test "boolean vector with 2 or more booleans" {
1509 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1510 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1500 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1511 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1501 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1512 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1502 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1519,7 +1509,7 @@ test "boolean vector with 2 or more booleans" {...@@ -1519,7 +1509,7 @@ test "boolean vector with 2 or more booleans" {
1519}1509}
15201510
1521test "bitcast to vector with different child type" {1511test "bitcast to vector with different child type" {
1522 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1512 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1523 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1513 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1524 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1514 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1525 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1515 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -1551,7 +1541,6 @@ test "index into comptime-known vector is comptime-known" {...@@ -1551,7 +1541,6 @@ test "index into comptime-known vector is comptime-known" {
15511541
1552test "arithmetic on zero-length vectors" {1542test "arithmetic on zero-length vectors" {
1553 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1543 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1554 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1555 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1544 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
15561545
1557 {1546 {
...@@ -1568,7 +1557,6 @@ test "arithmetic on zero-length vectors" {...@@ -1568,7 +1557,6 @@ test "arithmetic on zero-length vectors" {
15681557
1569test "@reduce on bool vector" {1558test "@reduce on bool vector" {
1570 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1559 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1571 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1572 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1560 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15731561
1574 const a = @Vector(2, bool){ true, true };1562 const a = @Vector(2, bool){ true, true };
...@@ -1578,7 +1566,7 @@ test "@reduce on bool vector" {...@@ -1578,7 +1566,7 @@ test "@reduce on bool vector" {
1578}1566}
15791567
1580test "bitcast vector to array of smaller vectors" {1568test "bitcast vector to array of smaller vectors" {
1581 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1569 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1582 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1570 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1583 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1571 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
15841572
test/behavior/void.zig-1
...@@ -36,7 +36,6 @@ fn times(n: usize) []const void {...@@ -36,7 +36,6 @@ fn times(n: usize) []const void {
3636
37test "void optional" {37test "void optional" {
38 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;38 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
39 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
40 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO39 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
4140
42 var x: ?void = {};41 var x: ?void = {};
test/behavior/while.zig-9
...@@ -124,8 +124,6 @@ test "while copies its payload" {...@@ -124,8 +124,6 @@ test "while copies its payload" {
124}124}
125125
126test "continue and break" {126test "continue and break" {
127 if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
128
129 try runContinueAndBreakTest();127 try runContinueAndBreakTest();
130 try expect(continue_and_break_counter == 8);128 try expect(continue_and_break_counter == 8);
131}129}
...@@ -209,7 +207,6 @@ test "while on bool with else result follow break prong" {...@@ -209,7 +207,6 @@ test "while on bool with else result follow break prong" {
209207
210test "while on optional with else result follow else prong" {208test "while on optional with else result follow else prong" {
211 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;209 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
212 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
213 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO210 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
214211
215 const result = while (returnNull()) |value| {212 const result = while (returnNull()) |value| {
...@@ -220,7 +217,6 @@ test "while on optional with else result follow else prong" {...@@ -220,7 +217,6 @@ test "while on optional with else result follow else prong" {
220217
221test "while on optional with else result follow break prong" {218test "while on optional with else result follow break prong" {
222 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;219 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
223 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
224 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO220 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
225221
226 const result = while (returnOptional(10)) |value| {222 const result = while (returnOptional(10)) |value| {
...@@ -292,7 +288,6 @@ test "while bool 2 break statements and an else" {...@@ -292,7 +288,6 @@ test "while bool 2 break statements and an else" {
292288
293test "while optional 2 break statements and an else" {289test "while optional 2 break statements and an else" {
294 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO290 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
295 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
296 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO291 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
297292
298 const S = struct {293 const S = struct {
...@@ -311,7 +306,6 @@ test "while optional 2 break statements and an else" {...@@ -311,7 +306,6 @@ test "while optional 2 break statements and an else" {
311306
312test "while error 2 break statements and an else" {307test "while error 2 break statements and an else" {
313 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO308 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
314 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
315 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO309 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
316310
317 const S = struct {311 const S = struct {
...@@ -349,7 +343,6 @@ test "else continue outer while" {...@@ -349,7 +343,6 @@ test "else continue outer while" {
349343
350test "try terminating an infinite loop" {344test "try terminating an infinite loop" {
351 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO345 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
352 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
353 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;346 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
354347
355 // Test coverage for https://github.com/ziglang/zig/issues/13546348 // Test coverage for https://github.com/ziglang/zig/issues/13546
...@@ -376,7 +369,6 @@ test "while loop with comptime true condition needs no else block to return valu...@@ -376,7 +369,6 @@ test "while loop with comptime true condition needs no else block to return valu
376}369}
377370
378test "int returned from switch in while" {371test "int returned from switch in while" {
379 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
380 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO372 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
381373
382 var x: u32 = 3;374 var x: u32 = 3;
...@@ -389,7 +381,6 @@ test "int returned from switch in while" {...@@ -389,7 +381,6 @@ test "int returned from switch in while" {
389381
390test "breaking from a loop in an if statement" {382test "breaking from a loop in an if statement" {
391 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;383 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
392 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
393 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO384 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
394385
395 const S = struct {386 const S = struct {
test/behavior/widening.zig-5
...@@ -4,7 +4,6 @@ const mem = std.mem;...@@ -4,7 +4,6 @@ const mem = std.mem;
4const builtin = @import("builtin");4const builtin = @import("builtin");
55
6test "integer widening" {6test "integer widening" {
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -29,7 +28,6 @@ test "integer widening u0 to u8" {...@@ -29,7 +28,6 @@ test "integer widening u0 to u8" {
29}28}
3029
31test "implicit unsigned integer to signed integer" {30test "implicit unsigned integer to signed integer" {
32 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
33 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO31 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
34 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;32 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
3533
...@@ -40,7 +38,6 @@ test "implicit unsigned integer to signed integer" {...@@ -40,7 +38,6 @@ test "implicit unsigned integer to signed integer" {
40}38}
4139
42test "float widening" {40test "float widening" {
43 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
44 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO41 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
45 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO42 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
46 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;43 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -60,7 +57,6 @@ test "float widening" {...@@ -60,7 +57,6 @@ test "float widening" {
60}57}
6158
62test "float widening f16 to f128" {59test "float widening f16 to f128" {
63 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
64 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO60 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
65 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO61 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
66 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;62 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
...@@ -73,7 +69,6 @@ test "float widening f16 to f128" {...@@ -73,7 +69,6 @@ test "float widening f16 to f128" {
73}69}
7470
75test "cast small unsigned to larger signed" {71test "cast small unsigned to larger signed" {
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
77 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO72 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
78 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO73 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
79 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;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,7 +25,6 @@ test "casting to void with a macro" {
2525
26test "initializer list expression" {26test "initializer list expression" {
27 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO27 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
29 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO28 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
30 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;29 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
3130
...@@ -38,7 +37,6 @@ test "initializer list expression" {...@@ -38,7 +37,6 @@ test "initializer list expression" {
38}37}
3938
40test "sizeof in macros" {39test "sizeof in macros" {
41 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
42 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO40 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
43 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;41 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
4442
...@@ -55,7 +53,6 @@ test "reference to a struct type" {...@@ -55,7 +53,6 @@ test "reference to a struct type" {
5553
56test "cast negative integer to pointer" {54test "cast negative integer to pointer" {
57 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO55 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
58 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
59 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO56 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
60 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;57 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
6158
...@@ -64,7 +61,6 @@ test "cast negative integer to pointer" {...@@ -64,7 +61,6 @@ test "cast negative integer to pointer" {
6461
65test "casting to union with a macro" {62test "casting to union with a macro" {
66 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO63 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
67 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
68 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO64 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
69 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;65 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
7066
...@@ -80,7 +76,6 @@ test "casting to union with a macro" {...@@ -80,7 +76,6 @@ test "casting to union with a macro" {
8076
81test "casting or calling a value with a paren-surrounded macro" {77test "casting or calling a value with a paren-surrounded macro" {
82 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO78 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
83 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
84 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO79 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
85 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;80 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
8681
...@@ -99,7 +94,6 @@ test "casting or calling a value with a paren-surrounded macro" {...@@ -99,7 +94,6 @@ test "casting or calling a value with a paren-surrounded macro" {
9994
100test "nested comma operator" {95test "nested comma operator" {
101 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO96 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
102 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
103 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO97 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
104 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;98 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
10599
...@@ -109,7 +103,6 @@ test "nested comma operator" {...@@ -109,7 +103,6 @@ test "nested comma operator" {
109103
110test "cast functions" {104test "cast functions" {
111 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO105 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
112 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
113 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO106 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
114 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;107 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
115108
...@@ -123,7 +116,6 @@ test "cast functions" {...@@ -123,7 +116,6 @@ test "cast functions" {
123test "large integer macro" {116test "large integer macro" {
124 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO117 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
125 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO118 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
126 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
127 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO119 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
128 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;120 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
129121
...@@ -132,7 +124,6 @@ test "large integer macro" {...@@ -132,7 +124,6 @@ test "large integer macro" {
132124
133test "string literal macro with embedded tab character" {125test "string literal macro with embedded tab character" {
134 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO126 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
135 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
136 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO127 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
137 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;128 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
138129
...@@ -141,7 +132,6 @@ test "string literal macro with embedded tab character" {...@@ -141,7 +132,6 @@ test "string literal macro with embedded tab character" {
141132
142test "string and char literals that are not UTF-8 encoded. Issue #12784" {133test "string and char literals that are not UTF-8 encoded. Issue #12784" {
143 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO134 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
144 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
145 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO135 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
146 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;136 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
147137
...@@ -152,7 +142,6 @@ test "string and char literals that are not UTF-8 encoded. Issue #12784" {...@@ -152,7 +142,6 @@ test "string and char literals that are not UTF-8 encoded. Issue #12784" {
152test "Macro that uses division operator. Issue #13162" {142test "Macro that uses division operator. Issue #13162" {
153 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO143 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
154 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO144 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
155 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
156 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO145 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
157 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;146 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
158 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;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,7 +185,6 @@ test "Macro that uses division operator. Issue #13162" {
196test "Macro that uses remainder operator. Issue #13346" {185test "Macro that uses remainder operator. Issue #13346" {
197 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO186 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
198 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO187 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
199 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
200 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO188 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
201 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;189 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
202190
test/cases/array_in_anon_struct.zig+1-1
...@@ -19,4 +19,4 @@ pub fn main() !void {...@@ -19,4 +19,4 @@ pub fn main() !void {
1919
20// run20// run
21// backend=stage2,llvm21// backend=stage2,llvm
22// target=native22// target=x86_64-linux,aarch64-linux
test/cases/compile_errors/callconv_interrupt_on_unsupported_platform.zig+2-2
...@@ -7,5 +7,5 @@ export fn entry3() callconv(.avr_interrupt) void {}...@@ -7,5 +7,5 @@ export fn entry3() callconv(.avr_interrupt) void {}
7// target=aarch64-linux-none7// target=aarch64-linux-none
8//8//
9// :1:30: error: calling convention 'x86_64_interrupt' only available on architectures 'x86_64'9// :1:30: error: calling convention 'x86_64_interrupt' only available on architectures 'x86_64'
10// :1:30: error: calling convention 'x86_interrupt' only available on architectures 'x86'10// :2:30: error: calling convention 'x86_interrupt' only available on architectures 'x86'
11// :1:30: error: calling convention 'avr_interrupt' only available on architectures 'avr'11// :3:30: error: calling convention 'avr_interrupt' only available on architectures 'avr'
test/cases/compile_errors/error_set_membership.zig+1-1
...@@ -25,7 +25,7 @@ pub fn main() Error!void {...@@ -25,7 +25,7 @@ pub fn main() Error!void {
2525
26// error26// error
27// backend=stage227// backend=stage2
28// target=native28// target=x86_64-linux
29//29//
30// :23:29: error: expected type 'error{InvalidCharacter}', found '@typeInfo(@typeInfo(@TypeOf(tmp.fooey)).@"fn".return_type.?).error_union.error_set'30// :23:29: error: expected type 'error{InvalidCharacter}', found '@typeInfo(@typeInfo(@TypeOf(tmp.fooey)).@"fn".return_type.?).error_union.error_set'
31// :23:29: note: 'error.InvalidDirection' not a member of destination error set31// :23:29: note: 'error.InvalidDirection' not a member of destination error set
test/cases/compile_errors/function_ptr_alignment.zig+1-1
...@@ -10,7 +10,7 @@ comptime {...@@ -10,7 +10,7 @@ comptime {
1010
11// error11// error
12// backend=stage212// backend=stage2
13// target=native13// target=x86_64-linux
14//14//
15// :8:41: error: expected type '*align(2) const fn () void', found '*const fn () void'15// :8:41: error: expected type '*align(2) const fn () void', found '*const fn () void'
16// :8:41: note: pointer alignment '1' cannot cast into pointer alignment '2'16// :8:41: note: pointer alignment '1' cannot cast into pointer alignment '2'
test/cases/compile_errors/issue_15572_break_on_inline_while.zig+1-1
...@@ -15,6 +15,6 @@ pub fn main() void {...@@ -15,6 +15,6 @@ pub fn main() void {
1515
16// error16// error
17// backend=stage217// backend=stage2
18// target=native18// target=x86_64-linux
19//19//
20// :9:28: error: incompatible types: 'builtin.Type.EnumField' and 'void'20// :9:28: error: incompatible types: 'builtin.Type.EnumField' and 'void'
test/cases/compile_errors/switch_on_non_err_union.zig+1-1
...@@ -6,6 +6,6 @@ pub fn main() void {...@@ -6,6 +6,6 @@ pub fn main() void {
66
7// error7// error
8// backend=stage28// backend=stage2
9// target=native9// target=x86_64-linux
10//10//
11// :2:23: error: expected error union type, found 'bool'11// :2:23: error: expected error union type, found 'bool'
test/cases/pic_freestanding.zig+1-1
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const std = @import("std");2const std = @import("std");
33
4fn _start() callconv(.naked) void {}4pub fn _start() callconv(.naked) void {}
55
6comptime {6comptime {
7 @export(&_start, .{ .name = if (builtin.cpu.arch.isMIPS()) "__start" else "_start" });7 @export(&_start, .{ .name = if (builtin.cpu.arch.isMIPS()) "__start" else "_start" });
test/cases/safety/@alignCast misaligned.zig +1-1
...@@ -22,4 +22,4 @@ fn foo(bytes: []u8) u32 {...@@ -22,4 +22,4 @@ fn foo(bytes: []u8) u32 {
22}22}
23// run23// run
24// backend=stage2,llvm24// backend=stage2,llvm
25// target=native25// target=x86_64-linux,aarch64-linux
test/cases/safety/@enumFromInt - no matching tag value.zig +1-1
...@@ -23,4 +23,4 @@ fn baz(_: Foo) void {}...@@ -23,4 +23,4 @@ fn baz(_: Foo) void {}
2323
24// run24// run
25// backend=stage2,llvm25// backend=stage2,llvm
26// target=native26// target=x86_64-linux
test/cases/safety/@enumFromInt truncated bits - exhaustive.zig +1-1
...@@ -20,4 +20,4 @@ pub fn main() u8 {...@@ -20,4 +20,4 @@ pub fn main() u8 {
2020
21// run21// run
22// backend=stage2,llvm22// backend=stage2,llvm
23// target=native23// target=x86_64-linux
test/cases/safety/@enumFromInt truncated bits - nonexhaustive.zig +1-1
...@@ -20,4 +20,4 @@ pub fn main() u8 {...@@ -20,4 +20,4 @@ pub fn main() u8 {
2020
21// run21// run
22// backend=stage2,llvm22// backend=stage2,llvm
23// target=native23// target=x86_64-linux
test/cases/safety/@errorCast error not present in destination.zig +1-1
...@@ -18,4 +18,4 @@ fn foo(set1: Set1) Set2 {...@@ -18,4 +18,4 @@ fn foo(set1: Set1) Set2 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux
test/cases/safety/@errorCast error union casted to disjoint set.zig +1-1
...@@ -17,4 +17,4 @@ fn foo() anyerror!i32 {...@@ -17,4 +17,4 @@ fn foo() anyerror!i32 {
17}17}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux
test/cases/safety/@intCast to u0.zig +1-1
...@@ -19,4 +19,4 @@ fn bar(one: u1, not_zero: i32) void {...@@ -19,4 +19,4 @@ fn bar(one: u1, not_zero: i32) void {
19}19}
20// run20// run
21// backend=stage2,llvm21// backend=stage2,llvm
22// target=native22// target=x86_64-linux,aarch64-linux
test/cases/safety/@intFromFloat cannot fit - boundary case - i0 max.zig +1-1
...@@ -13,4 +13,4 @@ pub fn main() !void {...@@ -13,4 +13,4 @@ pub fn main() !void {
13}13}
14// run14// run
15// backend=stage2,llvm15// backend=stage2,llvm
16// target=native16// target=x86_64-linux,aarch64-linux
test/cases/safety/@intFromFloat cannot fit - boundary case - i0 min.zig +1-1
...@@ -13,4 +13,4 @@ pub fn main() !void {...@@ -13,4 +13,4 @@ pub fn main() !void {
13}13}
14// run14// run
15// backend=stage2,llvm15// backend=stage2,llvm
16// target=native16// target=x86_64-linux,aarch64-linux
test/cases/safety/@intFromFloat cannot fit - boundary case - signed max.zig +1-1
...@@ -13,4 +13,4 @@ pub fn main() !void {...@@ -13,4 +13,4 @@ pub fn main() !void {
13}13}
14// run14// run
15// backend=stage2,llvm15// backend=stage2,llvm
16// target=native16// target=x86_64-linux
test/cases/safety/@intFromFloat cannot fit - boundary case - signed min.zig +1-1
...@@ -13,4 +13,4 @@ pub fn main() !void {...@@ -13,4 +13,4 @@ pub fn main() !void {
13}13}
14// run14// run
15// backend=stage2,llvm15// backend=stage2,llvm
16// target=native16// target=x86_64-linux
test/cases/safety/@intFromFloat cannot fit - boundary case - u0 max.zig +1-1
...@@ -13,4 +13,4 @@ pub fn main() !void {...@@ -13,4 +13,4 @@ pub fn main() !void {
13}13}
14// run14// run
15// backend=stage2,llvm15// backend=stage2,llvm
16// target=native16// target=x86_64-linux,aarch64-linux
test/cases/safety/@intFromFloat cannot fit - boundary case - u0 min.zig +1-1
...@@ -13,4 +13,4 @@ pub fn main() !void {...@@ -13,4 +13,4 @@ pub fn main() !void {
13}13}
14// run14// run
15// backend=stage2,llvm15// backend=stage2,llvm
16// target=native16// target=x86_64-linux,aarch64-linux
test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned max.zig +1-1
...@@ -13,4 +13,4 @@ pub fn main() !void {...@@ -13,4 +13,4 @@ pub fn main() !void {
13}13}
14// run14// run
15// backend=stage2,llvm15// backend=stage2,llvm
16// target=native16// target=x86_64-linux
test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned min.zig +1-1
...@@ -13,4 +13,4 @@ pub fn main() !void {...@@ -13,4 +13,4 @@ pub fn main() !void {
13}13}
14// run14// run
15// backend=stage2,llvm15// backend=stage2,llvm
16// target=native16// target=x86_64-linux
test/cases/safety/@intFromFloat cannot fit - boundary case - vector max.zig +1-1
...@@ -13,4 +13,4 @@ pub fn main() !void {...@@ -13,4 +13,4 @@ pub fn main() !void {
13}13}
14// run14// run
15// backend=stage2,llvm15// backend=stage2,llvm
16// target=native16// target=x86_64-linux
test/cases/safety/@intFromFloat cannot fit - boundary case - vector min.zig +1-1
...@@ -13,4 +13,4 @@ pub fn main() !void {...@@ -13,4 +13,4 @@ pub fn main() !void {
13}13}
14// run14// run
15// backend=stage2,llvm15// backend=stage2,llvm
16// target=native16// target=x86_64-linux
test/cases/safety/@intFromFloat cannot fit - negative out of range.zig +1-1
...@@ -17,4 +17,4 @@ fn bar(a: f32) i8 {...@@ -17,4 +17,4 @@ fn bar(a: f32) i8 {
17fn baz(_: i8) void {}17fn baz(_: i8) void {}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux
test/cases/safety/@intFromFloat cannot fit - negative to unsigned.zig +1-1
...@@ -17,4 +17,4 @@ fn bar(a: f32) u8 {...@@ -17,4 +17,4 @@ fn bar(a: f32) u8 {
17fn baz(_: u8) void {}17fn baz(_: u8) void {}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux
test/cases/safety/@intFromFloat cannot fit - positive out of range.zig +1-1
...@@ -17,4 +17,4 @@ fn bar(a: f32) u8 {...@@ -17,4 +17,4 @@ fn bar(a: f32) u8 {
17fn baz(_: u8) void {}17fn baz(_: u8) void {}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux
test/cases/safety/@ptrFromInt address zero to non-optional byte-aligned pointer.zig +1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/safety/@ptrFromInt address zero to non-optional pointer.zig +1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/safety/@ptrFromInt with misaligned address.zig +1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/safety/@tagName on corrupted enum value.zig +1-1
...@@ -23,4 +23,4 @@ pub fn main() !void {...@@ -23,4 +23,4 @@ pub fn main() !void {
2323
24// run24// run
25// backend=stage2,llvm25// backend=stage2,llvm
26// target=native26// target=x86_64-linux
test/cases/safety/@tagName on corrupted union value.zig +1-1
...@@ -24,4 +24,4 @@ pub fn main() !void {...@@ -24,4 +24,4 @@ pub fn main() !void {
2424
25// run25// run
26// backend=stage2,llvm26// backend=stage2,llvm
27// target=native27// target=x86_64-linux
test/cases/safety/array slice sentinel mismatch vector.zig +1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux
test/cases/safety/array slice sentinel mismatch.zig +1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/safety/bad union field access.zig +1-1
...@@ -24,4 +24,4 @@ fn bar(f: *Foo) void {...@@ -24,4 +24,4 @@ fn bar(f: *Foo) void {
24}24}
25// run25// run
26// backend=stage2,llvm26// backend=stage2,llvm
27// target=native27// target=x86_64-linux
test/cases/safety/calling panic.zig +1-1
...@@ -13,4 +13,4 @@ pub fn main() !void {...@@ -13,4 +13,4 @@ pub fn main() !void {
13}13}
14// run14// run
15// backend=stage2,llvm15// backend=stage2,llvm
16// target=native16// target=x86_64-linux,aarch64-linux
test/cases/safety/cast []u8 to bigger slice of wrong size.zig +1-1
...@@ -18,4 +18,4 @@ fn widenSlice(slice: []align(1) const u8) []align(1) const i32 {...@@ -18,4 +18,4 @@ fn widenSlice(slice: []align(1) const u8) []align(1) const i32 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/cast integer to global error and no code matches.zig +1-1
...@@ -16,4 +16,4 @@ fn bar(x: u16) anyerror {...@@ -16,4 +16,4 @@ fn bar(x: u16) anyerror {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/safety/empty slice with sentinel out of bounds.zig +1-1
...@@ -18,4 +18,4 @@ pub fn main() !void {...@@ -18,4 +18,4 @@ pub fn main() !void {
1818
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/exact division failure - vectors.zig +1-1
...@@ -20,4 +20,4 @@ fn divExact(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {...@@ -20,4 +20,4 @@ fn divExact(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
20}20}
21// run21// run
22// backend=stage2,llvm22// backend=stage2,llvm
23// target=native23// target=x86_64-linux
test/cases/safety/exact division failure.zig +1-1
...@@ -18,4 +18,4 @@ fn divExact(a: i32, b: i32) i32 {...@@ -18,4 +18,4 @@ fn divExact(a: i32, b: i32) i32 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/for_len_mismatch.zig+1-1
...@@ -22,4 +22,4 @@ pub fn main() !void {...@@ -22,4 +22,4 @@ pub fn main() !void {
22}22}
23// run23// run
24// backend=stage2,llvm24// backend=stage2,llvm
25// target=native25// target=x86_64-linux,aarch64-linux
test/cases/safety/for_len_mismatch_three.zig+1-1
...@@ -21,4 +21,4 @@ pub fn main() !void {...@@ -21,4 +21,4 @@ pub fn main() !void {
21}21}
22// run22// run
23// backend=stage2,llvm23// backend=stage2,llvm
24// target=native24// target=x86_64-linux,aarch64-linux
test/cases/safety/ignored expression integer overflow.zig +1-1
...@@ -18,4 +18,4 @@ pub fn main() !void {...@@ -18,4 +18,4 @@ pub fn main() !void {
1818
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux
test/cases/safety/integer addition overflow.zig +1-1
...@@ -20,4 +20,4 @@ fn add(a: u16, b: u16) u16 {...@@ -20,4 +20,4 @@ fn add(a: u16, b: u16) u16 {
2020
21// run21// run
22// backend=stage2,llvm22// backend=stage2,llvm
23// target=native23// target=x86_64-linux,aarch64-linux
test/cases/safety/integer division by zero - vectors.zig +1-1
...@@ -19,4 +19,4 @@ fn div0(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {...@@ -19,4 +19,4 @@ fn div0(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
19}19}
20// run20// run
21// backend=stage2,llvm21// backend=stage2,llvm
22// target=native22// target=x86_64-linux
test/cases/safety/integer division by zero.zig +1-1
...@@ -17,4 +17,4 @@ fn div0(a: i32, b: i32) i32 {...@@ -17,4 +17,4 @@ fn div0(a: i32, b: i32) i32 {
17}17}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux,aarch64-linux
test/cases/safety/integer multiplication overflow.zig +1-1
...@@ -18,4 +18,4 @@ fn mul(a: u16, b: u16) u16 {...@@ -18,4 +18,4 @@ fn mul(a: u16, b: u16) u16 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/integer negation overflow.zig +1-1
...@@ -18,4 +18,4 @@ fn neg(a: i16) i16 {...@@ -18,4 +18,4 @@ fn neg(a: i16) i16 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/integer subtraction overflow.zig +1-1
...@@ -18,4 +18,4 @@ fn sub(a: u16, b: u16) u16 {...@@ -18,4 +18,4 @@ fn sub(a: u16, b: u16) u16 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/memcpy_alias.zig+1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/safety/memcpy_len_mismatch.zig+1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/safety/memmove_len_mismatch.zig+1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/safety/memset_array_undefined_bytes.zig+1-1
...@@ -15,4 +15,4 @@ pub fn main() !void {...@@ -15,4 +15,4 @@ pub fn main() !void {
15}15}
16// run16// run
17// backend=stage2,llvm17// backend=stage2,llvm
18// target=native18// target=x86_64-linux,aarch64-linux
test/cases/safety/memset_array_undefined_large.zig+1-1
...@@ -15,4 +15,4 @@ pub fn main() !void {...@@ -15,4 +15,4 @@ pub fn main() !void {
15}15}
16// run16// run
17// backend=stage2,llvm17// backend=stage2,llvm
18// target=native18// target=x86_64-linux,aarch64-linux
test/cases/safety/memset_slice_undefined_bytes.zig+1-1
...@@ -17,4 +17,4 @@ pub fn main() !void {...@@ -17,4 +17,4 @@ pub fn main() !void {
17}17}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux,aarch64-linux
test/cases/safety/memset_slice_undefined_large.zig+1-1
...@@ -17,4 +17,4 @@ pub fn main() !void {...@@ -17,4 +17,4 @@ pub fn main() !void {
17}17}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux,aarch64-linux
test/cases/safety/modrem by zero.zig +1-1
...@@ -17,4 +17,4 @@ fn div0(a: u32, b: u32) u32 {...@@ -17,4 +17,4 @@ fn div0(a: u32, b: u32) u32 {
17}17}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux,aarch64-linux
test/cases/safety/modulus by zero.zig +1-1
...@@ -17,4 +17,4 @@ fn mod0(a: i32, b: i32) i32 {...@@ -17,4 +17,4 @@ fn mod0(a: i32, b: i32) i32 {
17}17}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux
test/cases/safety/noreturn returned.zig +1-1
...@@ -20,4 +20,4 @@ pub fn main() void {...@@ -20,4 +20,4 @@ pub fn main() void {
20}20}
21// run21// run
22// backend=stage2,llvm22// backend=stage2,llvm
23// target=native23// target=x86_64-linux,aarch64-linux
test/cases/safety/optional unwrap operator on C pointer.zig +1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/safety/optional unwrap operator on null pointer.zig +1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/safety/optional_empty_error_set.zig+1-1
...@@ -19,4 +19,4 @@ fn foo() !void {...@@ -19,4 +19,4 @@ fn foo() !void {
19}19}
20// run20// run
21// backend=stage2,llvm21// backend=stage2,llvm
22// target=native22// target=x86_64-linux,aarch64-linux
test/cases/safety/out of bounds array slice by length.zig +1-1
...@@ -17,4 +17,4 @@ fn foo(a: u32) u32 {...@@ -17,4 +17,4 @@ fn foo(a: u32) u32 {
17}17}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux,aarch64-linux
test/cases/safety/out of bounds slice access.zig +1-1
...@@ -18,4 +18,4 @@ fn bar(a: []const i32) i32 {...@@ -18,4 +18,4 @@ fn bar(a: []const i32) i32 {
18fn baz(_: i32) void {}18fn baz(_: i32) void {}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/pointer casting null to non-optional pointer.zig +1-1
...@@ -18,4 +18,4 @@ pub fn main() !void {...@@ -18,4 +18,4 @@ pub fn main() !void {
1818
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/pointer casting to null function pointer.zig +1-1
...@@ -20,4 +20,4 @@ pub fn main() !void {...@@ -20,4 +20,4 @@ pub fn main() !void {
2020
21// run21// run
22// backend=stage2,llvm22// backend=stage2,llvm
23// target=native23// target=x86_64-linux,aarch64-linux
test/cases/safety/pointer slice sentinel mismatch.zig +1-1
...@@ -18,4 +18,4 @@ pub fn main() !void {...@@ -18,4 +18,4 @@ pub fn main() !void {
1818
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/remainder division by zero.zig +1-1
...@@ -17,4 +17,4 @@ fn rem0(a: i32, b: i32) i32 {...@@ -17,4 +17,4 @@ fn rem0(a: i32, b: i32) i32 {
17}17}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux,aarch64-linux
test/cases/safety/shift left by huge amount.zig +1-1
...@@ -19,4 +19,4 @@ pub fn main() !void {...@@ -19,4 +19,4 @@ pub fn main() !void {
1919
20// run20// run
21// backend=stage2,llvm21// backend=stage2,llvm
22// target=native22// target=x86_64-linux,aarch64-linux
test/cases/safety/shift right by huge amount.zig +1-1
...@@ -19,4 +19,4 @@ pub fn main() !void {...@@ -19,4 +19,4 @@ pub fn main() !void {
1919
20// run20// run
21// backend=stage2,llvm21// backend=stage2,llvm
22// target=native22// target=x86_64-linux,aarch64-linux
test/cases/safety/signed integer division overflow - vectors.zig +1-1
...@@ -20,4 +20,4 @@ fn div(a: @Vector(4, i16), b: @Vector(4, i16)) @Vector(4, i16) {...@@ -20,4 +20,4 @@ fn div(a: @Vector(4, i16), b: @Vector(4, i16)) @Vector(4, i16) {
20}20}
21// run21// run
22// backend=stage2,llvm22// backend=stage2,llvm
23// target=native23// target=x86_64-linux
test/cases/safety/signed integer division overflow.zig +1-1
...@@ -18,4 +18,4 @@ fn div(a: i16, b: i16) i16 {...@@ -18,4 +18,4 @@ fn div(a: i16, b: i16) i16 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig +1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux
test/cases/safety/signed integer not fitting in cast to unsigned integer.zig +1-1
...@@ -17,4 +17,4 @@ fn unsigned_cast(x: i32) u32 {...@@ -17,4 +17,4 @@ fn unsigned_cast(x: i32) u32 {
17}17}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux,aarch64-linux
test/cases/safety/signed shift left overflow.zig +1-1
...@@ -18,4 +18,4 @@ fn shl(a: i16, b: u4) i16 {...@@ -18,4 +18,4 @@ fn shl(a: i16, b: u4) i16 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux
test/cases/safety/signed shift right overflow.zig +1-1
...@@ -18,4 +18,4 @@ fn shr(a: i16, b: u4) i16 {...@@ -18,4 +18,4 @@ fn shr(a: i16, b: u4) i16 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/signed-unsigned vector cast.zig +1-1
...@@ -18,4 +18,4 @@ pub fn main() !void {...@@ -18,4 +18,4 @@ pub fn main() !void {
1818
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux
test/cases/safety/slice by length sentinel mismatch on lhs.zig +1-1
...@@ -15,4 +15,4 @@ pub fn main() !void {...@@ -15,4 +15,4 @@ pub fn main() !void {
15}15}
16// run16// run
17// backend=stage2,llvm17// backend=stage2,llvm
18// target=native18// target=x86_64-linux,aarch64-linux
test/cases/safety/slice by length sentinel mismatch on rhs.zig +1-1
...@@ -15,4 +15,4 @@ pub fn main() !void {...@@ -15,4 +15,4 @@ pub fn main() !void {
15}15}
16// run16// run
17// backend=stage2,llvm17// backend=stage2,llvm
18// target=native18// target=x86_64-linux,aarch64-linux
test/cases/safety/slice sentinel mismatch - floats.zig +1-1
...@@ -17,4 +17,4 @@ pub fn main() !void {...@@ -17,4 +17,4 @@ pub fn main() !void {
1717
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux
test/cases/safety/slice sentinel mismatch - optional pointers.zig +1-1
...@@ -17,4 +17,4 @@ pub fn main() !void {...@@ -17,4 +17,4 @@ pub fn main() !void {
1717
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux,aarch64-linux
test/cases/safety/slice slice sentinel mismatch.zig +1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/safety/slice start index greater than end index.zig +1-1
...@@ -21,4 +21,4 @@ pub fn main() !void {...@@ -21,4 +21,4 @@ pub fn main() !void {
2121
22// run22// run
23// backend=stage2,llvm23// backend=stage2,llvm
24// target=native24// target=x86_64-linux,aarch64-linux
test/cases/safety/slice with sentinel out of bounds - runtime len.zig +1-1
...@@ -20,4 +20,4 @@ pub fn main() !void {...@@ -20,4 +20,4 @@ pub fn main() !void {
2020
21// run21// run
22// backend=stage2,llvm22// backend=stage2,llvm
23// target=native23// target=x86_64-linux,aarch64-linux
test/cases/safety/slice with sentinel out of bounds.zig +1-1
...@@ -18,4 +18,4 @@ pub fn main() !void {...@@ -18,4 +18,4 @@ pub fn main() !void {
1818
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/slice_cast_change_len_0.zig+1-1
...@@ -24,4 +24,4 @@ const std = @import("std");...@@ -24,4 +24,4 @@ const std = @import("std");
2424
25// run25// run
26// backend=stage2,llvm26// backend=stage2,llvm
27// target=x86_64-linux27// target=x86_64-linux,aarch64-linux
test/cases/safety/slice_cast_change_len_1.zig+1-1
...@@ -24,4 +24,4 @@ const std = @import("std");...@@ -24,4 +24,4 @@ const std = @import("std");
2424
25// run25// run
26// backend=stage2,llvm26// backend=stage2,llvm
27// target=x86_64-linux27// target=x86_64-linux,aarch64-linux
test/cases/safety/slice_cast_change_len_2.zig+1-1
...@@ -24,4 +24,4 @@ const std = @import("std");...@@ -24,4 +24,4 @@ const std = @import("std");
2424
25// run25// run
26// backend=stage2,llvm26// backend=stage2,llvm
27// target=x86_64-linux27// target=x86_64-linux,aarch64-linux
test/cases/safety/slicing null C pointer - runtime len.zig +1-1
...@@ -18,4 +18,4 @@ pub fn main() !void {...@@ -18,4 +18,4 @@ pub fn main() !void {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/slicing null C pointer.zig +1-1
...@@ -17,4 +17,4 @@ pub fn main() !void {...@@ -17,4 +17,4 @@ pub fn main() !void {
17}17}
18// run18// run
19// backend=stage2,llvm19// backend=stage2,llvm
20// target=native20// target=x86_64-linux,aarch64-linux
test/cases/safety/switch else on corrupt enum value - one prong.zig +1-1
...@@ -21,4 +21,4 @@ pub fn main() !void {...@@ -21,4 +21,4 @@ pub fn main() !void {
21}21}
22// run22// run
23// backend=stage2,llvm23// backend=stage2,llvm
24// target=native24// target=x86_64-linux
test/cases/safety/switch else on corrupt enum value - union.zig +1-1
...@@ -26,4 +26,4 @@ pub fn main() !void {...@@ -26,4 +26,4 @@ pub fn main() !void {
26}26}
27// run27// run
28// backend=stage2,llvm28// backend=stage2,llvm
29// target=native29// target=x86_64-linux
test/cases/safety/switch else on corrupt enum value.zig +1-1
...@@ -20,4 +20,4 @@ pub fn main() !void {...@@ -20,4 +20,4 @@ pub fn main() !void {
20}20}
21// run21// run
22// backend=stage2,llvm22// backend=stage2,llvm
23// target=native23// target=x86_64-linux
test/cases/safety/switch on corrupted enum value.zig +1-1
...@@ -24,4 +24,4 @@ pub fn main() !void {...@@ -24,4 +24,4 @@ pub fn main() !void {
2424
25// run25// run
26// backend=stage2,llvm26// backend=stage2,llvm
27// target=native27// target=x86_64-linux,aarch64-linux
test/cases/safety/switch on corrupted union value.zig +1-1
...@@ -24,4 +24,4 @@ pub fn main() !void {...@@ -24,4 +24,4 @@ pub fn main() !void {
2424
25// run25// run
26// backend=stage2,llvm26// backend=stage2,llvm
27// target=native27// target=x86_64-linux
test/cases/safety/truncating vector cast.zig +1-1
...@@ -18,4 +18,4 @@ pub fn main() !void {...@@ -18,4 +18,4 @@ pub fn main() !void {
1818
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux
test/cases/safety/unreachable.zig+1-1
...@@ -12,4 +12,4 @@ pub fn main() !void {...@@ -12,4 +12,4 @@ pub fn main() !void {
12}12}
13// run13// run
14// backend=stage2,llvm14// backend=stage2,llvm
15// target=native15// target=x86_64-linux,aarch64-linux
test/cases/safety/unsigned integer not fitting in cast to signed integer - same bit count.zig +1-1
...@@ -16,4 +16,4 @@ pub fn main() !void {...@@ -16,4 +16,4 @@ pub fn main() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux
test/cases/safety/unsigned shift left overflow.zig +1-1
...@@ -18,4 +18,4 @@ fn shl(a: u16, b: u4) u16 {...@@ -18,4 +18,4 @@ fn shl(a: u16, b: u4) u16 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux
test/cases/safety/unsigned shift right overflow.zig +1-1
...@@ -18,4 +18,4 @@ fn shr(a: u16, b: u4) u16 {...@@ -18,4 +18,4 @@ fn shr(a: u16, b: u4) u16 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/unsigned-signed vector cast.zig +1-1
...@@ -18,4 +18,4 @@ pub fn main() !void {...@@ -18,4 +18,4 @@ pub fn main() !void {
1818
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux
test/cases/safety/unwrap error switch.zig +1-1
...@@ -18,4 +18,4 @@ fn bar() !void {...@@ -18,4 +18,4 @@ fn bar() !void {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/unwrap error.zig +1-1
...@@ -16,4 +16,4 @@ fn bar() !void {...@@ -16,4 +16,4 @@ fn bar() !void {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/safety/value does not fit in shortening cast - u0.zig +1-1
...@@ -18,4 +18,4 @@ fn shorten_cast(x: u8) u0 {...@@ -18,4 +18,4 @@ fn shorten_cast(x: u8) u0 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/value does not fit in shortening cast.zig +1-1
...@@ -18,4 +18,4 @@ fn shorten_cast(x: i32) i8 {...@@ -18,4 +18,4 @@ fn shorten_cast(x: i32) i8 {
18}18}
19// run19// run
20// backend=stage2,llvm20// backend=stage2,llvm
21// target=native21// target=x86_64-linux,aarch64-linux
test/cases/safety/vector integer addition overflow.zig +1-1
...@@ -19,4 +19,4 @@ fn add(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {...@@ -19,4 +19,4 @@ fn add(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) {
19}19}
20// run20// run
21// backend=stage2,llvm21// backend=stage2,llvm
22// target=native22// target=x86_64-linux
test/cases/safety/vector integer multiplication overflow.zig +1-1
...@@ -19,4 +19,4 @@ fn mul(a: @Vector(4, u8), b: @Vector(4, u8)) @Vector(4, u8) {...@@ -19,4 +19,4 @@ fn mul(a: @Vector(4, u8), b: @Vector(4, u8)) @Vector(4, u8) {
19}19}
20// run20// run
21// backend=stage2,llvm21// backend=stage2,llvm
22// target=native22// target=x86_64-linux
test/cases/safety/vector integer negation overflow.zig +1-1
...@@ -19,4 +19,4 @@ fn neg(a: @Vector(4, i16)) @Vector(4, i16) {...@@ -19,4 +19,4 @@ fn neg(a: @Vector(4, i16)) @Vector(4, i16) {
19}19}
20// run20// run
21// backend=stage2,llvm21// backend=stage2,llvm
22// target=native22// target=x86_64-linux
test/cases/safety/vector integer subtraction overflow.zig +1-1
...@@ -19,4 +19,4 @@ fn sub(a: @Vector(4, u32), b: @Vector(4, u32)) @Vector(4, u32) {...@@ -19,4 +19,4 @@ fn sub(a: @Vector(4, u32), b: @Vector(4, u32)) @Vector(4, u32) {
19}19}
20// run20// run
21// backend=stage2,llvm21// backend=stage2,llvm
22// target=native22// target=x86_64-linux
test/cases/safety/zero casted to error.zig +1-1
...@@ -16,4 +16,4 @@ fn bar(x: u16) anyerror {...@@ -16,4 +16,4 @@ fn bar(x: u16) anyerror {
16}16}
17// run17// run
18// backend=stage2,llvm18// backend=stage2,llvm
19// target=native19// target=x86_64-linux,aarch64-linux
test/cases/taking_pointer_of_global_tagged_union.zig+1-1
...@@ -23,4 +23,4 @@ pub fn main() !void {...@@ -23,4 +23,4 @@ pub fn main() !void {
2323
24// run24// run
25// backend=stage2,llvm25// backend=stage2,llvm
26// target=native26// target=x86_64-linux
test/incremental/fix_many_errors deleted-71
...@@ -1,71 +0,0 @@
1#target=x86_64-linux-selfhosted
2#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe
4#update=initial version
5#file=main.zig
6pub fn main() !void {}
7comptime { @compileError("c0"); }
8comptime { @compileError("c1"); }
9comptime { @compileError("c2"); }
10comptime { @compileError("c3"); }
11comptime { @compileError("c4"); }
12comptime { @compileError("c5"); }
13comptime { @compileError("c6"); }
14comptime { @compileError("c7"); }
15comptime { @compileError("c8"); }
16comptime { @compileError("c9"); }
17export fn f0() void { @compileError("f0"); }
18export fn f1() void { @compileError("f1"); }
19export fn f2() void { @compileError("f2"); }
20export fn f3() void { @compileError("f3"); }
21export fn f4() void { @compileError("f4"); }
22export fn f5() void { @compileError("f5"); }
23export fn f6() void { @compileError("f6"); }
24export fn f7() void { @compileError("f7"); }
25export fn f8() void { @compileError("f8"); }
26export fn f9() void { @compileError("f9"); }
27#expect_error=main.zig:2:12: error: c0
28#expect_error=main.zig:3:12: error: c1
29#expect_error=main.zig:4:12: error: c2
30#expect_error=main.zig:5:12: error: c3
31#expect_error=main.zig:6:12: error: c4
32#expect_error=main.zig:7:12: error: c5
33#expect_error=main.zig:8:12: error: c6
34#expect_error=main.zig:9:12: error: c7
35#expect_error=main.zig:10:12: error: c8
36#expect_error=main.zig:11:12: error: c9
37#expect_error=main.zig:12:23: error: f0
38#expect_error=main.zig:13:23: error: f1
39#expect_error=main.zig:14:23: error: f2
40#expect_error=main.zig:15:23: error: f3
41#expect_error=main.zig:16:23: error: f4
42#expect_error=main.zig:17:23: error: f5
43#expect_error=main.zig:18:23: error: f6
44#expect_error=main.zig:19:23: error: f7
45#expect_error=main.zig:20:23: error: f8
46#expect_error=main.zig:21:23: error: f9
47#update=fix all the errors
48#file=main.zig
49pub fn main() !void {}
50comptime {}
51comptime {}
52comptime {}
53comptime {}
54comptime {}
55comptime {}
56comptime {}
57comptime {}
58comptime {}
59comptime {}
60export fn f0() void {}
61export fn f1() void {}
62export fn f2() void {}
63export fn f3() void {}
64export fn f4() void {}
65export fn f5() void {}
66export fn f6() void {}
67export fn f7() void {}
68export fn f8() void {}
69export fn f9() void {}
70const std = @import("std");
71#expect_stdout=""
test/link/build.zig.zon+2-1
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1.{1.{
2 .name = "link_test_cases",2 .name = .link_test_cases,
3 .fingerprint = 0x404f657576fec9f2,
3 .version = "0.0.0",4 .version = "0.0.0",
4 .dependencies = .{5 .dependencies = .{
5 .bss = .{6 .bss = .{
test/link/elf.zig+369-369
...@@ -210,8 +210,8 @@ fn testAbsSymbols(b: *Build, opts: Options) *Step {...@@ -210,8 +210,8 @@ fn testAbsSymbols(b: *Build, opts: Options) *Step {
210 \\}210 \\}
211 ,211 ,
212 });212 });
213 exe.addObject(obj);213 exe.root_module.addObject(obj);
214 exe.linkLibC();214 exe.root_module.link_libc = true;
215215
216 const run = addRunArtifact(exe);216 const run = addRunArtifact(exe);
217 run.expectExitCode(0);217 run.expectExitCode(0);
...@@ -235,7 +235,7 @@ fn testAsNeeded(b: *Build, opts: Options) *Step {...@@ -235,7 +235,7 @@ fn testAsNeeded(b: *Build, opts: Options) *Step {
235 \\235 \\
236 ,236 ,
237 });237 });
238 main_o.linkLibC();238 main_o.root_module.link_libc = true;
239239
240 const libfoo = addSharedLibrary(b, opts, .{ .name = "foo" });240 const libfoo = addSharedLibrary(b, opts, .{ .name = "foo" });
241 addCSourceBytes(libfoo, "int foo() { return 42; }", &.{});241 addCSourceBytes(libfoo, "int foo() { return 42; }", &.{});
...@@ -253,17 +253,17 @@ fn testAsNeeded(b: *Build, opts: Options) *Step {...@@ -253,17 +253,17 @@ fn testAsNeeded(b: *Build, opts: Options) *Step {
253 const exe = addExecutable(b, opts, .{253 const exe = addExecutable(b, opts, .{
254 .name = "test",254 .name = "test",
255 });255 });
256 exe.addObject(main_o);256 exe.root_module.addObject(main_o);
257 exe.linkSystemLibrary2("foo", .{ .needed = true });257 exe.root_module.linkSystemLibrary("foo", .{ .needed = true });
258 exe.addLibraryPath(libfoo.getEmittedBinDirectory());258 exe.root_module.addLibraryPath(libfoo.getEmittedBinDirectory());
259 exe.addRPath(libfoo.getEmittedBinDirectory());259 exe.root_module.addRPath(libfoo.getEmittedBinDirectory());
260 exe.linkSystemLibrary2("bar", .{ .needed = true });260 exe.root_module.linkSystemLibrary("bar", .{ .needed = true });
261 exe.addLibraryPath(libbar.getEmittedBinDirectory());261 exe.root_module.addLibraryPath(libbar.getEmittedBinDirectory());
262 exe.addRPath(libbar.getEmittedBinDirectory());262 exe.root_module.addRPath(libbar.getEmittedBinDirectory());
263 exe.linkSystemLibrary2("baz", .{ .needed = true });263 exe.root_module.linkSystemLibrary("baz", .{ .needed = true });
264 exe.addLibraryPath(libbaz.getEmittedBinDirectory());264 exe.root_module.addLibraryPath(libbaz.getEmittedBinDirectory());
265 exe.addRPath(libbaz.getEmittedBinDirectory());265 exe.root_module.addRPath(libbaz.getEmittedBinDirectory());
266 exe.linkLibC();266 exe.root_module.link_libc = true;
267267
268 const run = addRunArtifact(exe);268 const run = addRunArtifact(exe);
269 run.expectStdOutEqual("42\n");269 run.expectStdOutEqual("42\n");
...@@ -281,17 +281,17 @@ fn testAsNeeded(b: *Build, opts: Options) *Step {...@@ -281,17 +281,17 @@ fn testAsNeeded(b: *Build, opts: Options) *Step {
281 const exe = addExecutable(b, opts, .{281 const exe = addExecutable(b, opts, .{
282 .name = "test",282 .name = "test",
283 });283 });
284 exe.addObject(main_o);284 exe.root_module.addObject(main_o);
285 exe.linkSystemLibrary2("foo", .{ .needed = false });285 exe.root_module.linkSystemLibrary("foo", .{ .needed = false });
286 exe.addLibraryPath(libfoo.getEmittedBinDirectory());286 exe.root_module.addLibraryPath(libfoo.getEmittedBinDirectory());
287 exe.addRPath(libfoo.getEmittedBinDirectory());287 exe.root_module.addRPath(libfoo.getEmittedBinDirectory());
288 exe.linkSystemLibrary2("bar", .{ .needed = false });288 exe.root_module.linkSystemLibrary("bar", .{ .needed = false });
289 exe.addLibraryPath(libbar.getEmittedBinDirectory());289 exe.root_module.addLibraryPath(libbar.getEmittedBinDirectory());
290 exe.addRPath(libbar.getEmittedBinDirectory());290 exe.root_module.addRPath(libbar.getEmittedBinDirectory());
291 exe.linkSystemLibrary2("baz", .{ .needed = false });291 exe.root_module.linkSystemLibrary("baz", .{ .needed = false });
292 exe.addLibraryPath(libbaz.getEmittedBinDirectory());292 exe.root_module.addLibraryPath(libbaz.getEmittedBinDirectory());
293 exe.addRPath(libbaz.getEmittedBinDirectory());293 exe.root_module.addRPath(libbaz.getEmittedBinDirectory());
294 exe.linkLibC();294 exe.root_module.link_libc = true;
295295
296 const run = addRunArtifact(exe);296 const run = addRunArtifact(exe);
297 run.expectStdOutEqual("42\n");297 run.expectStdOutEqual("42\n");
...@@ -351,15 +351,15 @@ fn testCanonicalPlt(b: *Build, opts: Options) *Step {...@@ -351,15 +351,15 @@ fn testCanonicalPlt(b: *Build, opts: Options) *Step {
351 ,351 ,
352 .pic = false,352 .pic = false,
353 });353 });
354 main_o.linkLibC();354 main_o.root_module.link_libc = true;
355355
356 const exe = addExecutable(b, opts, .{356 const exe = addExecutable(b, opts, .{
357 .name = "main",357 .name = "main",
358 });358 });
359 exe.addObject(main_o);359 exe.root_module.addObject(main_o);
360 exe.addObject(b_o);360 exe.root_module.addObject(b_o);
361 exe.linkLibrary(dso);361 exe.root_module.linkLibrary(dso);
362 exe.linkLibC();362 exe.root_module.link_libc = true;
363 exe.pie = false;363 exe.pie = false;
364364
365 const run = addRunArtifact(exe);365 const run = addRunArtifact(exe);
...@@ -384,7 +384,7 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {...@@ -384,7 +384,7 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
384 \\}384 \\}
385 ,385 ,
386 });386 });
387 a_o.linkLibCpp();387 a_o.root_module.link_libcpp = true;
388388
389 const main_o = addObject(b, opts, .{389 const main_o = addObject(b, opts, .{
390 .name = "main",390 .name = "main",
...@@ -401,13 +401,13 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {...@@ -401,13 +401,13 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
401 \\}401 \\}
402 ,402 ,
403 });403 });
404 main_o.linkLibCpp();404 main_o.root_module.link_libcpp = true;
405405
406 {406 {
407 const exe = addExecutable(b, opts, .{ .name = "main1" });407 const exe = addExecutable(b, opts, .{ .name = "main1" });
408 exe.addObject(a_o);408 exe.root_module.addObject(a_o);
409 exe.addObject(main_o);409 exe.root_module.addObject(main_o);
410 exe.linkLibCpp();410 exe.root_module.link_libcpp = true;
411411
412 const run = addRunArtifact(exe);412 const run = addRunArtifact(exe);
413 run.expectStdOutEqual(413 run.expectStdOutEqual(
...@@ -420,9 +420,9 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {...@@ -420,9 +420,9 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
420420
421 {421 {
422 const exe = addExecutable(b, opts, .{ .name = "main2" });422 const exe = addExecutable(b, opts, .{ .name = "main2" });
423 exe.addObject(main_o);423 exe.root_module.addObject(main_o);
424 exe.addObject(a_o);424 exe.root_module.addObject(a_o);
425 exe.linkLibCpp();425 exe.root_module.link_libcpp = true;
426426
427 const run = addRunArtifact(exe);427 const run = addRunArtifact(exe);
428 run.expectStdOutEqual(428 run.expectStdOutEqual(
...@@ -435,12 +435,12 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {...@@ -435,12 +435,12 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
435435
436 {436 {
437 const c_o = addObject(b, opts, .{ .name = "c" });437 const c_o = addObject(b, opts, .{ .name = "c" });
438 c_o.addObject(main_o);438 c_o.root_module.addObject(main_o);
439 c_o.addObject(a_o);439 c_o.root_module.addObject(a_o);
440440
441 const exe = addExecutable(b, opts, .{ .name = "main3" });441 const exe = addExecutable(b, opts, .{ .name = "main3" });
442 exe.addObject(c_o);442 exe.root_module.addObject(c_o);
443 exe.linkLibCpp();443 exe.root_module.link_libcpp = true;
444444
445 const run = addRunArtifact(exe);445 const run = addRunArtifact(exe);
446 run.expectStdOutEqual(446 run.expectStdOutEqual(
...@@ -453,12 +453,12 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {...@@ -453,12 +453,12 @@ fn testComdatElimination(b: *Build, opts: Options) *Step {
453453
454 {454 {
455 const d_o = addObject(b, opts, .{ .name = "d" });455 const d_o = addObject(b, opts, .{ .name = "d" });
456 d_o.addObject(a_o);456 d_o.root_module.addObject(a_o);
457 d_o.addObject(main_o);457 d_o.root_module.addObject(main_o);
458458
459 const exe = addExecutable(b, opts, .{ .name = "main4" });459 const exe = addExecutable(b, opts, .{ .name = "main4" });
460 exe.addObject(d_o);460 exe.root_module.addObject(d_o);
461 exe.linkLibCpp();461 exe.root_module.link_libcpp = true;
462462
463 const run = addRunArtifact(exe);463 const run = addRunArtifact(exe);
464 run.expectStdOutEqual(464 run.expectStdOutEqual(
...@@ -522,7 +522,7 @@ fn testCommonSymbols(b: *Build, opts: Options) *Step {...@@ -522,7 +522,7 @@ fn testCommonSymbols(b: *Build, opts: Options) *Step {
522 \\ printf("%d %d %d\n", foo, bar, baz);522 \\ printf("%d %d %d\n", foo, bar, baz);
523 \\}523 \\}
524 , &.{"-fcommon"});524 , &.{"-fcommon"});
525 exe.linkLibC();525 exe.root_module.link_libc = true;
526526
527 const run = addRunArtifact(exe);527 const run = addRunArtifact(exe);
528 run.expectStdOutEqual("0 5 42\n");528 run.expectStdOutEqual("0 5 42\n");
...@@ -549,7 +549,7 @@ fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step {...@@ -549,7 +549,7 @@ fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step {
549 ,549 ,
550 .c_source_flags = &.{"-fcommon"},550 .c_source_flags = &.{"-fcommon"},
551 });551 });
552 a_o.linkLibC();552 a_o.root_module.link_libc = true;
553553
554 const b_o = addObject(b, opts, .{554 const b_o = addObject(b, opts, .{
555 .name = "b",555 .name = "b",
...@@ -575,16 +575,16 @@ fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step {...@@ -575,16 +575,16 @@ fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step {
575 });575 });
576576
577 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });577 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
578 lib.addObject(b_o);578 lib.root_module.addObject(b_o);
579 lib.addObject(c_o);579 lib.root_module.addObject(c_o);
580 lib.addObject(d_o);580 lib.root_module.addObject(d_o);
581581
582 const exe = addExecutable(b, opts, .{582 const exe = addExecutable(b, opts, .{
583 .name = "test",583 .name = "test",
584 });584 });
585 exe.addObject(a_o);585 exe.root_module.addObject(a_o);
586 exe.linkLibrary(lib);586 exe.root_module.linkLibrary(lib);
587 exe.linkLibC();587 exe.root_module.link_libc = true;
588588
589 const run = addRunArtifact(exe);589 const run = addRunArtifact(exe);
590 run.expectStdOutEqual("5 0 0 -1\n");590 run.expectStdOutEqual("5 0 0 -1\n");
...@@ -603,15 +603,15 @@ fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step {...@@ -603,15 +603,15 @@ fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step {
603 });603 });
604604
605 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });605 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
606 lib.addObject(b_o);606 lib.root_module.addObject(b_o);
607 lib.addObject(e_o);607 lib.root_module.addObject(e_o);
608608
609 const exe = addExecutable(b, opts, .{609 const exe = addExecutable(b, opts, .{
610 .name = "test",610 .name = "test",
611 });611 });
612 exe.addObject(a_o);612 exe.root_module.addObject(a_o);
613 exe.linkLibrary(lib);613 exe.root_module.linkLibrary(lib);
614 exe.linkLibC();614 exe.root_module.link_libc = true;
615615
616 const run = addRunArtifact(exe);616 const run = addRunArtifact(exe);
617 run.expectStdOutEqual("5 0 7 2\n");617 run.expectStdOutEqual("5 0 7 2\n");
...@@ -641,8 +641,8 @@ fn testCopyrel(b: *Build, opts: Options) *Step {...@@ -641,8 +641,8 @@ fn testCopyrel(b: *Build, opts: Options) *Step {
641 \\}641 \\}
642 ,642 ,
643 });643 });
644 exe.linkLibrary(dso);644 exe.root_module.linkLibrary(dso);
645 exe.linkLibC();645 exe.root_module.link_libc = true;
646646
647 const run = addRunArtifact(exe);647 const run = addRunArtifact(exe);
648 run.expectStdOutEqual("3 5\n");648 run.expectStdOutEqual("3 5\n");
...@@ -679,8 +679,8 @@ fn testCopyrelAlias(b: *Build, opts: Options) *Step {...@@ -679,8 +679,8 @@ fn testCopyrelAlias(b: *Build, opts: Options) *Step {
679 \\extern int bar;679 \\extern int bar;
680 \\int *get_bar() { return &bar; }680 \\int *get_bar() { return &bar; }
681 , &.{});681 , &.{});
682 exe.linkLibrary(dso);682 exe.root_module.linkLibrary(dso);
683 exe.linkLibC();683 exe.root_module.link_libc = true;
684 exe.pie = false;684 exe.pie = false;
685685
686 const run = addRunArtifact(exe);686 const run = addRunArtifact(exe);
...@@ -712,15 +712,15 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step {...@@ -712,15 +712,15 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step {
712 ,712 ,
713 .pic = false,713 .pic = false,
714 });714 });
715 obj.linkLibC();715 obj.root_module.link_libc = true;
716716
717 const exp_stdout = "5\n";717 const exp_stdout = "5\n";
718718
719 {719 {
720 const exe = addExecutable(b, opts, .{ .name = "main" });720 const exe = addExecutable(b, opts, .{ .name = "main" });
721 exe.addObject(obj);721 exe.root_module.addObject(obj);
722 exe.linkLibrary(a_so);722 exe.root_module.linkLibrary(a_so);
723 exe.linkLibC();723 exe.root_module.link_libc = true;
724 exe.pie = false;724 exe.pie = false;
725725
726 const run = addRunArtifact(exe);726 const run = addRunArtifact(exe);
...@@ -737,9 +737,9 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step {...@@ -737,9 +737,9 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step {
737737
738 {738 {
739 const exe = addExecutable(b, opts, .{ .name = "main" });739 const exe = addExecutable(b, opts, .{ .name = "main" });
740 exe.addObject(obj);740 exe.root_module.addObject(obj);
741 exe.linkLibrary(b_so);741 exe.root_module.linkLibrary(b_so);
742 exe.linkLibC();742 exe.root_module.link_libc = true;
743 exe.pie = false;743 exe.pie = false;
744744
745 const run = addRunArtifact(exe);745 const run = addRunArtifact(exe);
...@@ -756,9 +756,9 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step {...@@ -756,9 +756,9 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step {
756756
757 {757 {
758 const exe = addExecutable(b, opts, .{ .name = "main" });758 const exe = addExecutable(b, opts, .{ .name = "main" });
759 exe.addObject(obj);759 exe.root_module.addObject(obj);
760 exe.linkLibrary(c_so);760 exe.root_module.linkLibrary(c_so);
761 exe.linkLibC();761 exe.root_module.link_libc = true;
762 exe.pie = false;762 exe.pie = false;
763763
764 const run = addRunArtifact(exe);764 const run = addRunArtifact(exe);
...@@ -793,7 +793,7 @@ fn testDsoPlt(b: *Build, opts: Options) *Step {...@@ -793,7 +793,7 @@ fn testDsoPlt(b: *Build, opts: Options) *Step {
793 \\ real_hello();793 \\ real_hello();
794 \\}794 \\}
795 , &.{});795 , &.{});
796 dso.linkLibC();796 dso.root_module.link_libc = true;
797797
798 const exe = addExecutable(b, opts, .{ .name = "test" });798 const exe = addExecutable(b, opts, .{ .name = "test" });
799 addCSourceBytes(exe,799 addCSourceBytes(exe,
...@@ -806,8 +806,8 @@ fn testDsoPlt(b: *Build, opts: Options) *Step {...@@ -806,8 +806,8 @@ fn testDsoPlt(b: *Build, opts: Options) *Step {
806 \\ hello();806 \\ hello();
807 \\}807 \\}
808 , &.{});808 , &.{});
809 exe.linkLibrary(dso);809 exe.root_module.linkLibrary(dso);
810 exe.linkLibC();810 exe.root_module.link_libc = true;
811811
812 const run = addRunArtifact(exe);812 const run = addRunArtifact(exe);
813 run.expectStdOutEqual("Hello WORLD\n");813 run.expectStdOutEqual("Hello WORLD\n");
...@@ -825,7 +825,7 @@ fn testDsoUndef(b: *Build, opts: Options) *Step {...@@ -825,7 +825,7 @@ fn testDsoUndef(b: *Build, opts: Options) *Step {
825 \\int bar = 5;825 \\int bar = 5;
826 \\int baz() { return foo; }826 \\int baz() { return foo; }
827 , &.{});827 , &.{});
828 dso.linkLibC();828 dso.root_module.link_libc = true;
829829
830 const obj = addObject(b, opts, .{830 const obj = addObject(b, opts, .{
831 .name = "obj",831 .name = "obj",
...@@ -833,18 +833,18 @@ fn testDsoUndef(b: *Build, opts: Options) *Step {...@@ -833,18 +833,18 @@ fn testDsoUndef(b: *Build, opts: Options) *Step {
833 });833 });
834834
835 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });835 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
836 lib.addObject(obj);836 lib.root_module.addObject(obj);
837837
838 const exe = addExecutable(b, opts, .{ .name = "test" });838 const exe = addExecutable(b, opts, .{ .name = "test" });
839 exe.linkLibrary(dso);839 exe.root_module.linkLibrary(dso);
840 exe.linkLibrary(lib);840 exe.root_module.linkLibrary(lib);
841 addCSourceBytes(exe,841 addCSourceBytes(exe,
842 \\extern int bar;842 \\extern int bar;
843 \\int main() {843 \\int main() {
844 \\ return bar - 5;844 \\ return bar - 5;
845 \\}845 \\}
846 , &.{});846 , &.{});
847 exe.linkLibC();847 exe.root_module.link_libc = true;
848848
849 const run = addRunArtifact(exe);849 const run = addRunArtifact(exe);
850 run.expectExitCode(0);850 run.expectExitCode(0);
...@@ -871,7 +871,7 @@ fn testEmitRelocatable(b: *Build, opts: Options) *Step {...@@ -871,7 +871,7 @@ fn testEmitRelocatable(b: *Build, opts: Options) *Step {
871 \\ std.debug.print("foo={d}\n", .{foo()});871 \\ std.debug.print("foo={d}\n", .{foo()});
872 \\}872 \\}
873 });873 });
874 a_o.linkLibC();874 a_o.root_module.link_libc = true;
875875
876 const b_o = addObject(b, opts, .{ .name = "b", .c_source_bytes = 876 const b_o = addObject(b, opts, .{ .name = "b", .c_source_bytes =
877 \\#include <stdio.h>877 \\#include <stdio.h>
...@@ -880,11 +880,11 @@ fn testEmitRelocatable(b: *Build, opts: Options) *Step {...@@ -880,11 +880,11 @@ fn testEmitRelocatable(b: *Build, opts: Options) *Step {
880 \\ fprintf(stderr, "bar=%d\n", bar);880 \\ fprintf(stderr, "bar=%d\n", bar);
881 \\}881 \\}
882 });882 });
883 b_o.linkLibC();883 b_o.root_module.link_libc = true;
884884
885 const c_o = addObject(b, opts, .{ .name = "c" });885 const c_o = addObject(b, opts, .{ .name = "c" });
886 c_o.addObject(a_o);886 c_o.root_module.addObject(a_o);
887 c_o.addObject(b_o);887 c_o.root_module.addObject(b_o);
888888
889 const exe = addExecutable(b, opts, .{ .name = "test", .zig_source_bytes = 889 const exe = addExecutable(b, opts, .{ .name = "test", .zig_source_bytes =
890 \\const std = @import("std");890 \\const std = @import("std");
...@@ -895,8 +895,8 @@ fn testEmitRelocatable(b: *Build, opts: Options) *Step {...@@ -895,8 +895,8 @@ fn testEmitRelocatable(b: *Build, opts: Options) *Step {
895 \\ printBar();895 \\ printBar();
896 \\}896 \\}
897 });897 });
898 exe.addObject(c_o);898 exe.root_module.addObject(c_o);
899 exe.linkLibC();899 exe.root_module.link_libc = true;
900900
901 const run = addRunArtifact(exe);901 const run = addRunArtifact(exe);
902 run.expectStdErrEqual(902 run.expectStdErrEqual(
...@@ -944,9 +944,9 @@ fn testEmitStaticLib(b: *Build, opts: Options) *Step {...@@ -944,9 +944,9 @@ fn testEmitStaticLib(b: *Build, opts: Options) *Step {
944 });944 });
945945
946 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });946 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
947 lib.addObject(obj1);947 lib.root_module.addObject(obj1);
948 lib.addObject(obj2);948 lib.root_module.addObject(obj2);
949 lib.addObject(obj3);949 lib.root_module.addObject(obj3);
950950
951 const check = lib.checkObject();951 const check = lib.checkObject();
952 check.checkInArchiveSymtab();952 check.checkInArchiveSymtab();
...@@ -996,7 +996,7 @@ fn testEmitStaticLibZig(b: *Build, opts: Options) *Step {...@@ -996,7 +996,7 @@ fn testEmitStaticLibZig(b: *Build, opts: Options) *Step {
996 \\}996 \\}
997 ,997 ,
998 });998 });
999 lib.addObject(obj1);999 lib.root_module.addObject(obj1);
10001000
1001 const exe = addExecutable(b, opts, .{1001 const exe = addExecutable(b, opts, .{
1002 .name = "test",1002 .name = "test",
...@@ -1008,7 +1008,7 @@ fn testEmitStaticLibZig(b: *Build, opts: Options) *Step {...@@ -1008,7 +1008,7 @@ fn testEmitStaticLibZig(b: *Build, opts: Options) *Step {
1008 \\}1008 \\}
1009 ,1009 ,
1010 });1010 });
1011 exe.linkLibrary(lib);1011 exe.root_module.linkLibrary(lib);
10121012
1013 const run = addRunArtifact(exe);1013 const run = addRunArtifact(exe);
1014 run.expectStdErrEqual("44");1014 run.expectStdErrEqual("44");
...@@ -1023,7 +1023,7 @@ fn testEmptyObject(b: *Build, opts: Options) *Step {...@@ -1023,7 +1023,7 @@ fn testEmptyObject(b: *Build, opts: Options) *Step {
1023 const exe = addExecutable(b, opts, .{ .name = "test" });1023 const exe = addExecutable(b, opts, .{ .name = "test" });
1024 addCSourceBytes(exe, "int main() { return 0; }", &.{});1024 addCSourceBytes(exe, "int main() { return 0; }", &.{});
1025 addCSourceBytes(exe, "", &.{});1025 addCSourceBytes(exe, "", &.{});
1026 exe.linkLibC();1026 exe.root_module.link_libc = true;
10271027
1028 const run = addRunArtifact(exe);1028 const run = addRunArtifact(exe);
1029 run.expectExitCode(0);1029 run.expectExitCode(0);
...@@ -1052,8 +1052,8 @@ fn testEntryPoint(b: *Build, opts: Options) *Step {...@@ -1052,8 +1052,8 @@ fn testEntryPoint(b: *Build, opts: Options) *Step {
10521052
1053 {1053 {
1054 const exe = addExecutable(b, opts, .{ .name = "main" });1054 const exe = addExecutable(b, opts, .{ .name = "main" });
1055 exe.addObject(a_o);1055 exe.root_module.addObject(a_o);
1056 exe.addObject(b_o);1056 exe.root_module.addObject(b_o);
1057 exe.entry = .{ .symbol_name = "foo" };1057 exe.entry = .{ .symbol_name = "foo" };
10581058
1059 const check = exe.checkObject();1059 const check = exe.checkObject();
...@@ -1068,8 +1068,8 @@ fn testEntryPoint(b: *Build, opts: Options) *Step {...@@ -1068,8 +1068,8 @@ fn testEntryPoint(b: *Build, opts: Options) *Step {
1068 // cause an artifact collision taking the cached executable from the above1068 // cause an artifact collision taking the cached executable from the above
1069 // step instead of generating a new one.1069 // step instead of generating a new one.
1070 const exe = addExecutable(b, opts, .{ .name = "other" });1070 const exe = addExecutable(b, opts, .{ .name = "other" });
1071 exe.addObject(a_o);1071 exe.root_module.addObject(a_o);
1072 exe.addObject(b_o);1072 exe.root_module.addObject(b_o);
1073 exe.entry = .{ .symbol_name = "bar" };1073 exe.entry = .{ .symbol_name = "bar" };
10741074
1075 const check = exe.checkObject();1075 const check = exe.checkObject();
...@@ -1113,8 +1113,8 @@ fn testExportDynamic(b: *Build, opts: Options) *Step {...@@ -1113,8 +1113,8 @@ fn testExportDynamic(b: *Build, opts: Options) *Step {
1113 \\ return baz;1113 \\ return baz;
1114 \\}1114 \\}
1115 , &.{});1115 , &.{});
1116 exe.addObject(obj);1116 exe.root_module.addObject(obj);
1117 exe.linkLibrary(dso);1117 exe.root_module.linkLibrary(dso);
1118 exe.rdynamic = true;1118 exe.rdynamic = true;
11191119
1120 const check = exe.checkObject();1120 const check = exe.checkObject();
...@@ -1152,8 +1152,8 @@ fn testExportSymbolsFromExe(b: *Build, opts: Options) *Step {...@@ -1152,8 +1152,8 @@ fn testExportSymbolsFromExe(b: *Build, opts: Options) *Step {
1152 \\ foo();1152 \\ foo();
1153 \\}1153 \\}
1154 , &.{});1154 , &.{});
1155 exe.linkLibrary(dso);1155 exe.root_module.linkLibrary(dso);
1156 exe.linkLibC();1156 exe.root_module.link_libc = true;
11571157
1158 const check = exe.checkObject();1158 const check = exe.checkObject();
1159 check.checkInDynamicSymtab();1159 check.checkInDynamicSymtab();
...@@ -1181,7 +1181,7 @@ fn testFuncAddress(b: *Build, opts: Options) *Step {...@@ -1181,7 +1181,7 @@ fn testFuncAddress(b: *Build, opts: Options) *Step {
1181 \\ assert(fn == ptr);1181 \\ assert(fn == ptr);
1182 \\}1182 \\}
1183 , &.{});1183 , &.{});
1184 exe.linkLibrary(dso);1184 exe.root_module.linkLibrary(dso);
1185 exe.root_module.pic = false;1185 exe.root_module.pic = false;
1186 exe.pie = false;1186 exe.pie = false;
11871187
...@@ -1216,15 +1216,15 @@ fn testGcSections(b: *Build, opts: Options) *Step {...@@ -1216,15 +1216,15 @@ fn testGcSections(b: *Build, opts: Options) *Step {
1216 });1216 });
1217 obj.link_function_sections = true;1217 obj.link_function_sections = true;
1218 obj.link_data_sections = true;1218 obj.link_data_sections = true;
1219 obj.linkLibC();1219 obj.root_module.link_libc = true;
1220 obj.linkLibCpp();1220 obj.root_module.link_libcpp = true;
12211221
1222 {1222 {
1223 const exe = addExecutable(b, opts, .{ .name = "test" });1223 const exe = addExecutable(b, opts, .{ .name = "test" });
1224 exe.addObject(obj);1224 exe.root_module.addObject(obj);
1225 exe.link_gc_sections = false;1225 exe.link_gc_sections = false;
1226 exe.linkLibC();1226 exe.root_module.link_libc = true;
1227 exe.linkLibCpp();1227 exe.root_module.link_libcpp = true;
12281228
1229 const run = addRunArtifact(exe);1229 const run = addRunArtifact(exe);
1230 run.expectStdOutEqual("1 2\n");1230 run.expectStdOutEqual("1 2\n");
...@@ -1252,10 +1252,10 @@ fn testGcSections(b: *Build, opts: Options) *Step {...@@ -1252,10 +1252,10 @@ fn testGcSections(b: *Build, opts: Options) *Step {
12521252
1253 {1253 {
1254 const exe = addExecutable(b, opts, .{ .name = "test" });1254 const exe = addExecutable(b, opts, .{ .name = "test" });
1255 exe.addObject(obj);1255 exe.root_module.addObject(obj);
1256 exe.link_gc_sections = true;1256 exe.link_gc_sections = true;
1257 exe.linkLibC();1257 exe.root_module.link_libc = true;
1258 exe.linkLibCpp();1258 exe.root_module.link_libcpp = true;
12591259
1260 const run = addRunArtifact(exe);1260 const run = addRunArtifact(exe);
1261 run.expectStdOutEqual("1 2\n");1261 run.expectStdOutEqual("1 2\n");
...@@ -1321,7 +1321,7 @@ fn testGcSectionsZig(b: *Build, opts: Options) *Step {...@@ -1321,7 +1321,7 @@ fn testGcSectionsZig(b: *Build, opts: Options) *Step {
1321 \\}1321 \\}
1322 ,1322 ,
1323 });1323 });
1324 exe.addObject(obj);1324 exe.root_module.addObject(obj);
1325 exe.link_gc_sections = false;1325 exe.link_gc_sections = false;
13261326
1327 const run = addRunArtifact(exe);1327 const run = addRunArtifact(exe);
...@@ -1363,7 +1363,7 @@ fn testGcSectionsZig(b: *Build, opts: Options) *Step {...@@ -1363,7 +1363,7 @@ fn testGcSectionsZig(b: *Build, opts: Options) *Step {
1363 \\}1363 \\}
1364 ,1364 ,
1365 });1365 });
1366 exe.addObject(obj);1366 exe.root_module.addObject(obj);
1367 exe.link_gc_sections = true;1367 exe.link_gc_sections = true;
13681368
1369 const run = addRunArtifact(exe);1369 const run = addRunArtifact(exe);
...@@ -1427,7 +1427,7 @@ fn testIFuncAlias(b: *Build, opts: Options) *Step {...@@ -1427,7 +1427,7 @@ fn testIFuncAlias(b: *Build, opts: Options) *Step {
1427 \\}1427 \\}
1428 , &.{});1428 , &.{});
1429 exe.root_module.pic = true;1429 exe.root_module.pic = true;
1430 exe.linkLibC();1430 exe.root_module.link_libc = true;
14311431
1432 const run = addRunArtifact(exe);1432 const run = addRunArtifact(exe);
1433 run.expectExitCode(0);1433 run.expectExitCode(0);
...@@ -1467,9 +1467,9 @@ fn testIFuncDlopen(b: *Build, opts: Options) *Step {...@@ -1467,9 +1467,9 @@ fn testIFuncDlopen(b: *Build, opts: Options) *Step {
1467 \\ assert(foo == p);1467 \\ assert(foo == p);
1468 \\}1468 \\}
1469 , &.{});1469 , &.{});
1470 exe.linkLibrary(dso);1470 exe.root_module.linkLibrary(dso);
1471 exe.linkLibC();1471 exe.root_module.link_libc = true;
1472 exe.linkSystemLibrary2("dl", .{});1472 exe.root_module.linkSystemLibrary("dl", .{});
1473 exe.root_module.pic = false;1473 exe.root_module.pic = false;
1474 exe.pie = false;1474 exe.pie = false;
14751475
...@@ -1498,7 +1498,7 @@ fn testIFuncDso(b: *Build, opts: Options) *Step {...@@ -1498,7 +1498,7 @@ fn testIFuncDso(b: *Build, opts: Options) *Step {
1498 \\}1498 \\}
1499 ,1499 ,
1500 });1500 });
1501 dso.linkLibC();1501 dso.root_module.link_libc = true;
15021502
1503 const exe = addExecutable(b, opts, .{1503 const exe = addExecutable(b, opts, .{
1504 .name = "main",1504 .name = "main",
...@@ -1509,7 +1509,7 @@ fn testIFuncDso(b: *Build, opts: Options) *Step {...@@ -1509,7 +1509,7 @@ fn testIFuncDso(b: *Build, opts: Options) *Step {
1509 \\}1509 \\}
1510 ,1510 ,
1511 });1511 });
1512 exe.linkLibrary(dso);1512 exe.root_module.linkLibrary(dso);
15131513
1514 const run = addRunArtifact(exe);1514 const run = addRunArtifact(exe);
1515 run.expectStdOutEqual("Hello world\n");1515 run.expectStdOutEqual("Hello world\n");
...@@ -1540,7 +1540,7 @@ fn testIFuncDynamic(b: *Build, opts: Options) *Step {...@@ -1540,7 +1540,7 @@ fn testIFuncDynamic(b: *Build, opts: Options) *Step {
1540 {1540 {
1541 const exe = addExecutable(b, opts, .{ .name = "main" });1541 const exe = addExecutable(b, opts, .{ .name = "main" });
1542 addCSourceBytes(exe, main_c, &.{});1542 addCSourceBytes(exe, main_c, &.{});
1543 exe.linkLibC();1543 exe.root_module.link_libc = true;
1544 exe.link_z_lazy = true;1544 exe.link_z_lazy = true;
15451545
1546 const run = addRunArtifact(exe);1546 const run = addRunArtifact(exe);
...@@ -1550,7 +1550,7 @@ fn testIFuncDynamic(b: *Build, opts: Options) *Step {...@@ -1550,7 +1550,7 @@ fn testIFuncDynamic(b: *Build, opts: Options) *Step {
1550 {1550 {
1551 const exe = addExecutable(b, opts, .{ .name = "other" });1551 const exe = addExecutable(b, opts, .{ .name = "other" });
1552 addCSourceBytes(exe, main_c, &.{});1552 addCSourceBytes(exe, main_c, &.{});
1553 exe.linkLibC();1553 exe.root_module.link_libc = true;
15541554
1555 const run = addRunArtifact(exe);1555 const run = addRunArtifact(exe);
1556 run.expectStdOutEqual("Hello world\n");1556 run.expectStdOutEqual("Hello world\n");
...@@ -1576,7 +1576,7 @@ fn testIFuncExport(b: *Build, opts: Options) *Step {...@@ -1576,7 +1576,7 @@ fn testIFuncExport(b: *Build, opts: Options) *Step {
1576 \\ return real_foobar;1576 \\ return real_foobar;
1577 \\}1577 \\}
1578 , &.{});1578 , &.{});
1579 dso.linkLibC();1579 dso.root_module.link_libc = true;
15801580
1581 const check = dso.checkObject();1581 const check = dso.checkObject();
1582 check.checkInDynamicSymtab();1582 check.checkInDynamicSymtab();
...@@ -1613,7 +1613,7 @@ fn testIFuncFuncPtr(b: *Build, opts: Options) *Step {...@@ -1613,7 +1613,7 @@ fn testIFuncFuncPtr(b: *Build, opts: Options) *Step {
1613 \\}1613 \\}
1614 , &.{});1614 , &.{});
1615 exe.root_module.pic = true;1615 exe.root_module.pic = true;
1616 exe.linkLibC();1616 exe.root_module.link_libc = true;
16171617
1618 const run = addRunArtifact(exe);1618 const run = addRunArtifact(exe);
1619 run.expectStdOutEqual("3\n");1619 run.expectStdOutEqual("3\n");
...@@ -1642,7 +1642,7 @@ fn testIFuncNoPlt(b: *Build, opts: Options) *Step {...@@ -1642,7 +1642,7 @@ fn testIFuncNoPlt(b: *Build, opts: Options) *Step {
1642 \\}1642 \\}
1643 , &.{"-fno-plt"});1643 , &.{"-fno-plt"});
1644 exe.root_module.pic = true;1644 exe.root_module.pic = true;
1645 exe.linkLibC();1645 exe.root_module.link_libc = true;
16461646
1647 const run = addRunArtifact(exe);1647 const run = addRunArtifact(exe);
1648 run.expectStdOutEqual("Hello world\n");1648 run.expectStdOutEqual("Hello world\n");
...@@ -1669,7 +1669,7 @@ fn testIFuncStatic(b: *Build, opts: Options) *Step {...@@ -1669,7 +1669,7 @@ fn testIFuncStatic(b: *Build, opts: Options) *Step {
1669 \\ return 0;1669 \\ return 0;
1670 \\}1670 \\}
1671 , &.{});1671 , &.{});
1672 exe.linkLibC();1672 exe.root_module.link_libc = true;
1673 exe.linkage = .static;1673 exe.linkage = .static;
16741674
1675 const run = addRunArtifact(exe);1675 const run = addRunArtifact(exe);
...@@ -1700,7 +1700,7 @@ fn testIFuncStaticPie(b: *Build, opts: Options) *Step {...@@ -1700,7 +1700,7 @@ fn testIFuncStaticPie(b: *Build, opts: Options) *Step {
1700 exe.linkage = .static;1700 exe.linkage = .static;
1701 exe.root_module.pic = true;1701 exe.root_module.pic = true;
1702 exe.pie = true;1702 exe.pie = true;
1703 exe.linkLibC();1703 exe.root_module.link_libc = true;
17041704
1705 const run = addRunArtifact(exe);1705 const run = addRunArtifact(exe);
1706 run.expectStdOutEqual("Hello world\n");1706 run.expectStdOutEqual("Hello world\n");
...@@ -1733,7 +1733,7 @@ fn testImageBase(b: *Build, opts: Options) *Step {...@@ -1733,7 +1733,7 @@ fn testImageBase(b: *Build, opts: Options) *Step {
1733 \\ return 0;1733 \\ return 0;
1734 \\}1734 \\}
1735 , &.{});1735 , &.{});
1736 exe.linkLibC();1736 exe.root_module.link_libc = true;
1737 exe.image_base = 0x8000000;1737 exe.image_base = 0x8000000;
17381738
1739 const run = addRunArtifact(exe);1739 const run = addRunArtifact(exe);
...@@ -1779,7 +1779,7 @@ fn testImportingDataDynamic(b: *Build, opts: Options) *Step {...@@ -1779,7 +1779,7 @@ fn testImportingDataDynamic(b: *Build, opts: Options) *Step {
1779 \\void printFoo() { fprintf(stderr, "lib foo=%d\n", foo); }1779 \\void printFoo() { fprintf(stderr, "lib foo=%d\n", foo); }
1780 ,1780 ,
1781 });1781 });
1782 dso.linkLibC();1782 dso.root_module.link_libc = true;
17831783
1784 const main = addExecutable(b, opts, .{1784 const main = addExecutable(b, opts, .{
1785 .name = "main",1785 .name = "main",
...@@ -1798,7 +1798,7 @@ fn testImportingDataDynamic(b: *Build, opts: Options) *Step {...@@ -1798,7 +1798,7 @@ fn testImportingDataDynamic(b: *Build, opts: Options) *Step {
1798 .strip = true, // TODO temp hack1798 .strip = true, // TODO temp hack
1799 });1799 });
1800 main.pie = true;1800 main.pie = true;
1801 main.linkLibrary(dso);1801 main.root_module.linkLibrary(dso);
18021802
1803 const run = addRunArtifact(main);1803 const run = addRunArtifact(main);
1804 run.expectStdErrEqual(1804 run.expectStdErrEqual(
...@@ -1832,7 +1832,7 @@ fn testImportingDataStatic(b: *Build, opts: Options) *Step {...@@ -1832,7 +1832,7 @@ fn testImportingDataStatic(b: *Build, opts: Options) *Step {
1832 }, .{1832 }, .{
1833 .name = "a",1833 .name = "a",
1834 });1834 });
1835 lib.addObject(obj);1835 lib.root_module.addObject(obj);
18361836
1837 const main = addExecutable(b, opts, .{1837 const main = addExecutable(b, opts, .{
1838 .name = "main",1838 .name = "main",
...@@ -1844,8 +1844,8 @@ fn testImportingDataStatic(b: *Build, opts: Options) *Step {...@@ -1844,8 +1844,8 @@ fn testImportingDataStatic(b: *Build, opts: Options) *Step {
1844 ,1844 ,
1845 .strip = true, // TODO temp hack1845 .strip = true, // TODO temp hack
1846 });1846 });
1847 main.linkLibrary(lib);1847 main.root_module.linkLibrary(lib);
1848 main.linkLibC();1848 main.root_module.link_libc = true;
18491849
1850 const run = addRunArtifact(main);1850 const run = addRunArtifact(main);
1851 run.expectStdErrEqual("42\n");1851 run.expectStdErrEqual("42\n");
...@@ -1864,7 +1864,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {...@@ -1864,7 +1864,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
1864 \\__attribute__((constructor(10000))) void init4() { printf("1"); }1864 \\__attribute__((constructor(10000))) void init4() { printf("1"); }
1865 ,1865 ,
1866 });1866 });
1867 a_o.linkLibC();1867 a_o.root_module.link_libc = true;
18681868
1869 const b_o = addObject(b, opts, .{1869 const b_o = addObject(b, opts, .{
1870 .name = "b",1870 .name = "b",
...@@ -1873,7 +1873,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {...@@ -1873,7 +1873,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
1873 \\__attribute__((constructor(1000))) void init3() { printf("2"); }1873 \\__attribute__((constructor(1000))) void init3() { printf("2"); }
1874 ,1874 ,
1875 });1875 });
1876 b_o.linkLibC();1876 b_o.root_module.link_libc = true;
18771877
1878 const c_o = addObject(b, opts, .{1878 const c_o = addObject(b, opts, .{
1879 .name = "c",1879 .name = "c",
...@@ -1882,7 +1882,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {...@@ -1882,7 +1882,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
1882 \\__attribute__((constructor)) void init1() { printf("3"); }1882 \\__attribute__((constructor)) void init1() { printf("3"); }
1883 ,1883 ,
1884 });1884 });
1885 c_o.linkLibC();1885 c_o.root_module.link_libc = true;
18861886
1887 const d_o = addObject(b, opts, .{1887 const d_o = addObject(b, opts, .{
1888 .name = "d",1888 .name = "d",
...@@ -1891,7 +1891,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {...@@ -1891,7 +1891,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
1891 \\__attribute__((constructor)) void init2() { printf("4"); }1891 \\__attribute__((constructor)) void init2() { printf("4"); }
1892 ,1892 ,
1893 });1893 });
1894 d_o.linkLibC();1894 d_o.root_module.link_libc = true;
18951895
1896 const e_o = addObject(b, opts, .{1896 const e_o = addObject(b, opts, .{
1897 .name = "e",1897 .name = "e",
...@@ -1900,7 +1900,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {...@@ -1900,7 +1900,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
1900 \\__attribute__((destructor(10000))) void fini4() { printf("5"); }1900 \\__attribute__((destructor(10000))) void fini4() { printf("5"); }
1901 ,1901 ,
1902 });1902 });
1903 e_o.linkLibC();1903 e_o.root_module.link_libc = true;
19041904
1905 const f_o = addObject(b, opts, .{1905 const f_o = addObject(b, opts, .{
1906 .name = "f",1906 .name = "f",
...@@ -1909,7 +1909,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {...@@ -1909,7 +1909,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
1909 \\__attribute__((destructor(1000))) void fini3() { printf("6"); }1909 \\__attribute__((destructor(1000))) void fini3() { printf("6"); }
1910 ,1910 ,
1911 });1911 });
1912 f_o.linkLibC();1912 f_o.root_module.link_libc = true;
19131913
1914 const g_o = addObject(b, opts, .{1914 const g_o = addObject(b, opts, .{
1915 .name = "g",1915 .name = "g",
...@@ -1918,24 +1918,24 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {...@@ -1918,24 +1918,24 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step {
1918 \\__attribute__((destructor)) void fini1() { printf("7"); }1918 \\__attribute__((destructor)) void fini1() { printf("7"); }
1919 ,1919 ,
1920 });1920 });
1921 g_o.linkLibC();1921 g_o.root_module.link_libc = true;
19221922
1923 const h_o = addObject(b, opts, .{ .name = "h", .c_source_bytes = 1923 const h_o = addObject(b, opts, .{ .name = "h", .c_source_bytes =
1924 \\#include <stdio.h>1924 \\#include <stdio.h>
1925 \\__attribute__((destructor)) void fini2() { printf("8"); }1925 \\__attribute__((destructor)) void fini2() { printf("8"); }
1926 });1926 });
1927 h_o.linkLibC();1927 h_o.root_module.link_libc = true;
19281928
1929 const exe = addExecutable(b, opts, .{ .name = "main" });1929 const exe = addExecutable(b, opts, .{ .name = "main" });
1930 addCSourceBytes(exe, "int main() { return 0; }", &.{});1930 addCSourceBytes(exe, "int main() { return 0; }", &.{});
1931 exe.addObject(a_o);1931 exe.root_module.addObject(a_o);
1932 exe.addObject(b_o);1932 exe.root_module.addObject(b_o);
1933 exe.addObject(c_o);1933 exe.root_module.addObject(c_o);
1934 exe.addObject(d_o);1934 exe.root_module.addObject(d_o);
1935 exe.addObject(e_o);1935 exe.root_module.addObject(e_o);
1936 exe.addObject(f_o);1936 exe.root_module.addObject(f_o);
1937 exe.addObject(g_o);1937 exe.root_module.addObject(g_o);
1938 exe.addObject(h_o);1938 exe.root_module.addObject(h_o);
19391939
1940 if (opts.target.result.isGnuLibC()) {1940 if (opts.target.result.isGnuLibC()) {
1941 // TODO I think we need to clarify our use of `-fPIC -fPIE` flags for different targets1941 // TODO I think we need to clarify our use of `-fPIC -fPIE` flags for different targets
...@@ -1970,7 +1970,7 @@ fn testLargeAlignmentDso(b: *Build, opts: Options) *Step {...@@ -1970,7 +1970,7 @@ fn testLargeAlignmentDso(b: *Build, opts: Options) *Step {
1970 \\}1970 \\}
1971 , &.{});1971 , &.{});
1972 dso.link_function_sections = true;1972 dso.link_function_sections = true;
1973 dso.linkLibC();1973 dso.root_module.link_libc = true;
19741974
1975 const check = dso.checkObject();1975 const check = dso.checkObject();
1976 check.checkInSymtab();1976 check.checkInSymtab();
...@@ -1986,8 +1986,8 @@ fn testLargeAlignmentDso(b: *Build, opts: Options) *Step {...@@ -1986,8 +1986,8 @@ fn testLargeAlignmentDso(b: *Build, opts: Options) *Step {
1986 \\void greet();1986 \\void greet();
1987 \\int main() { greet(); }1987 \\int main() { greet(); }
1988 , &.{});1988 , &.{});
1989 exe.linkLibrary(dso);1989 exe.root_module.linkLibrary(dso);
1990 exe.linkLibC();1990 exe.root_module.link_libc = true;
19911991
1992 const run = addRunArtifact(exe);1992 const run = addRunArtifact(exe);
1993 run.expectStdOutEqual("Hello world");1993 run.expectStdOutEqual("Hello world");
...@@ -2021,7 +2021,7 @@ fn testLargeAlignmentExe(b: *Build, opts: Options) *Step {...@@ -2021,7 +2021,7 @@ fn testLargeAlignmentExe(b: *Build, opts: Options) *Step {
2021 \\}2021 \\}
2022 , &.{});2022 , &.{});
2023 exe.link_function_sections = true;2023 exe.link_function_sections = true;
2024 exe.linkLibC();2024 exe.root_module.link_libc = true;
20252025
2026 const check = exe.checkObject();2026 const check = exe.checkObject();
2027 check.checkInSymtab();2027 check.checkInSymtab();
...@@ -2049,7 +2049,7 @@ fn testLargeBss(b: *Build, opts: Options) *Step {...@@ -2049,7 +2049,7 @@ fn testLargeBss(b: *Build, opts: Options) *Step {
2049 \\ return arr[2000];2049 \\ return arr[2000];
2050 \\}2050 \\}
2051 , &.{});2051 , &.{});
2052 exe.linkLibC();2052 exe.root_module.link_libc = true;
2053 // Disabled to work around the ELF linker crashing.2053 // Disabled to work around the ELF linker crashing.
2054 // Can be reproduced on a x86_64-linux host by commenting out the line below.2054 // Can be reproduced on a x86_64-linux host by commenting out the line below.
2055 exe.root_module.sanitize_c = .off;2055 exe.root_module.sanitize_c = .off;
...@@ -2071,10 +2071,10 @@ fn testLinkOrder(b: *Build, opts: Options) *Step {...@@ -2071,10 +2071,10 @@ fn testLinkOrder(b: *Build, opts: Options) *Step {
2071 });2071 });
20722072
2073 const dso = addSharedLibrary(b, opts, .{ .name = "a" });2073 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
2074 dso.addObject(obj);2074 dso.root_module.addObject(obj);
20752075
2076 const lib = addStaticLibrary(b, opts, .{ .name = "b" });2076 const lib = addStaticLibrary(b, opts, .{ .name = "b" });
2077 lib.addObject(obj);2077 lib.root_module.addObject(obj);
20782078
2079 const main_o = addObject(b, opts, .{2079 const main_o = addObject(b, opts, .{
2080 .name = "main",2080 .name = "main",
...@@ -2089,14 +2089,14 @@ fn testLinkOrder(b: *Build, opts: Options) *Step {...@@ -2089,14 +2089,14 @@ fn testLinkOrder(b: *Build, opts: Options) *Step {
2089 // https://github.com/ziglang/zig/issues/174502089 // https://github.com/ziglang/zig/issues/17450
2090 // {2090 // {
2091 // const exe = addExecutable(b, opts, .{ .name = "main1"});2091 // const exe = addExecutable(b, opts, .{ .name = "main1"});
2092 // exe.addObject(main_o);2092 // exe.root_module.addObject(main_o);
2093 // exe.linkSystemLibrary2("a", .{});2093 // exe.root_module.linkSystemLibrary("a", .{});
2094 // exe.addLibraryPath(dso.getEmittedBinDirectory());2094 // exe.root_module.addLibraryPath(dso.getEmittedBinDirectory());
2095 // exe.addRPath(dso.getEmittedBinDirectory());2095 // exe.root_module.addRPath(dso.getEmittedBinDirectory());
2096 // exe.linkSystemLibrary2("b", .{});2096 // exe.root_module.linkSystemLibrary("b", .{});
2097 // exe.addLibraryPath(lib.getEmittedBinDirectory());2097 // exe.root_module.addLibraryPath(lib.getEmittedBinDirectory());
2098 // exe.addRPath(lib.getEmittedBinDirectory());2098 // exe.root_module.addRPath(lib.getEmittedBinDirectory());
2099 // exe.linkLibC();2099 // exe.root_module.link_libc = true;
21002100
2101 // const check = exe.checkObject();2101 // const check = exe.checkObject();
2102 // check.checkInDynamicSection();2102 // check.checkInDynamicSection();
...@@ -2106,14 +2106,14 @@ fn testLinkOrder(b: *Build, opts: Options) *Step {...@@ -2106,14 +2106,14 @@ fn testLinkOrder(b: *Build, opts: Options) *Step {
21062106
2107 {2107 {
2108 const exe = addExecutable(b, opts, .{ .name = "main2" });2108 const exe = addExecutable(b, opts, .{ .name = "main2" });
2109 exe.addObject(main_o);2109 exe.root_module.addObject(main_o);
2110 exe.linkSystemLibrary2("b", .{});2110 exe.root_module.linkSystemLibrary("b", .{});
2111 exe.addLibraryPath(lib.getEmittedBinDirectory());2111 exe.root_module.addLibraryPath(lib.getEmittedBinDirectory());
2112 exe.addRPath(lib.getEmittedBinDirectory());2112 exe.root_module.addRPath(lib.getEmittedBinDirectory());
2113 exe.linkSystemLibrary2("a", .{});2113 exe.root_module.linkSystemLibrary("a", .{});
2114 exe.addLibraryPath(dso.getEmittedBinDirectory());2114 exe.root_module.addLibraryPath(dso.getEmittedBinDirectory());
2115 exe.addRPath(dso.getEmittedBinDirectory());2115 exe.root_module.addRPath(dso.getEmittedBinDirectory());
2116 exe.linkLibC();2116 exe.root_module.link_libc = true;
21172117
2118 const check = exe.checkObject();2118 const check = exe.checkObject();
2119 check.checkInDynamicSection();2119 check.checkInDynamicSection();
...@@ -2149,14 +2149,14 @@ fn testLdScript(b: *Build, opts: Options) *Step {...@@ -2149,14 +2149,14 @@ fn testLdScript(b: *Build, opts: Options) *Step {
2149 \\ return bar() - baz();2149 \\ return bar() - baz();
2150 \\}2150 \\}
2151 , &.{});2151 , &.{});
2152 exe.linkSystemLibrary2("a", .{});2152 exe.root_module.linkSystemLibrary("a", .{});
2153 exe.addLibraryPath(scripts.getDirectory());2153 exe.root_module.addLibraryPath(scripts.getDirectory());
2154 exe.addLibraryPath(scripts2.getDirectory());2154 exe.root_module.addLibraryPath(scripts2.getDirectory());
2155 exe.addLibraryPath(bar.getEmittedBinDirectory());2155 exe.root_module.addLibraryPath(bar.getEmittedBinDirectory());
2156 exe.addLibraryPath(baz.getEmittedBinDirectory());2156 exe.root_module.addLibraryPath(baz.getEmittedBinDirectory());
2157 exe.addRPath(bar.getEmittedBinDirectory());2157 exe.root_module.addRPath(bar.getEmittedBinDirectory());
2158 exe.addRPath(baz.getEmittedBinDirectory());2158 exe.root_module.addRPath(baz.getEmittedBinDirectory());
2159 exe.linkLibC();2159 exe.root_module.link_libc = true;
2160 exe.allow_so_scripts = true;2160 exe.allow_so_scripts = true;
21612161
2162 const run = addRunArtifact(exe);2162 const run = addRunArtifact(exe);
...@@ -2174,9 +2174,9 @@ fn testLdScriptPathError(b: *Build, opts: Options) *Step {...@@ -2174,9 +2174,9 @@ fn testLdScriptPathError(b: *Build, opts: Options) *Step {
21742174
2175 const exe = addExecutable(b, opts, .{ .name = "main" });2175 const exe = addExecutable(b, opts, .{ .name = "main" });
2176 addCSourceBytes(exe, "int main() { return 0; }", &.{});2176 addCSourceBytes(exe, "int main() { return 0; }", &.{});
2177 exe.linkSystemLibrary2("a", .{});2177 exe.root_module.linkSystemLibrary("a", .{});
2178 exe.addLibraryPath(scripts.getDirectory());2178 exe.root_module.addLibraryPath(scripts.getDirectory());
2179 exe.linkLibC();2179 exe.root_module.link_libc = true;
2180 exe.allow_so_scripts = true;2180 exe.allow_so_scripts = true;
21812181
2182 // TODO: A future enhancement could make this error message also mention2182 // TODO: A future enhancement could make this error message also mention
...@@ -2213,8 +2213,8 @@ fn testLdScriptAllowUndefinedVersion(b: *Build, opts: Options) *Step {...@@ -2213,8 +2213,8 @@ fn testLdScriptAllowUndefinedVersion(b: *Build, opts: Options) *Step {
2213 \\}2213 \\}
2214 ,2214 ,
2215 });2215 });
2216 exe.linkLibrary(so);2216 exe.root_module.linkLibrary(so);
2217 exe.linkLibC();2217 exe.root_module.link_libc = true;
2218 exe.allow_so_scripts = true;2218 exe.allow_so_scripts = true;
22192219
2220 const run = addRunArtifact(exe);2220 const run = addRunArtifact(exe);
...@@ -2269,8 +2269,8 @@ fn testMismatchedCpuArchitectureError(b: *Build, opts: Options) *Step {...@@ -2269,8 +2269,8 @@ fn testMismatchedCpuArchitectureError(b: *Build, opts: Options) *Step {
2269 \\ return foo;2269 \\ return foo;
2270 \\}2270 \\}
2271 , &.{});2271 , &.{});
2272 exe.addObject(obj);2272 exe.root_module.addObject(obj);
2273 exe.linkLibC();2273 exe.root_module.link_libc = true;
22742274
2275 expectLinkErrors(exe, test_step, .{ .exact = &.{2275 expectLinkErrors(exe, test_step, .{ .exact = &.{
2276 "invalid ELF machine type: AARCH64",2276 "invalid ELF machine type: AARCH64",
...@@ -2291,7 +2291,7 @@ fn testLinkingC(b: *Build, opts: Options) *Step {...@@ -2291,7 +2291,7 @@ fn testLinkingC(b: *Build, opts: Options) *Step {
2291 \\ return 0;2291 \\ return 0;
2292 \\}2292 \\}
2293 , &.{});2293 , &.{});
2294 exe.linkLibC();2294 exe.root_module.link_libc = true;
22952295
2296 const run = addRunArtifact(exe);2296 const run = addRunArtifact(exe);
2297 run.expectStdOutEqual("Hello World!\n");2297 run.expectStdOutEqual("Hello World!\n");
...@@ -2320,8 +2320,8 @@ fn testLinkingCpp(b: *Build, opts: Options) *Step {...@@ -2320,8 +2320,8 @@ fn testLinkingCpp(b: *Build, opts: Options) *Step {
2320 \\ return 0;2320 \\ return 0;
2321 \\}2321 \\}
2322 , &.{});2322 , &.{});
2323 exe.linkLibC();2323 exe.root_module.link_libc = true;
2324 exe.linkLibCpp();2324 exe.root_module.link_libcpp = true;
23252325
2326 const run = addRunArtifact(exe);2326 const run = addRunArtifact(exe);
2327 run.expectStdOutEqual("Hello World!\n");2327 run.expectStdOutEqual("Hello World!\n");
...@@ -2364,7 +2364,7 @@ fn testLinkingObj(b: *Build, opts: Options) *Step {...@@ -2364,7 +2364,7 @@ fn testLinkingObj(b: *Build, opts: Options) *Step {
2364 \\}2364 \\}
2365 ,2365 ,
2366 });2366 });
2367 exe.addObject(obj);2367 exe.root_module.addObject(obj);
23682368
2369 const run = addRunArtifact(exe);2369 const run = addRunArtifact(exe);
2370 run.expectStdErrEqual("84\n");2370 run.expectStdErrEqual("84\n");
...@@ -2389,7 +2389,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {...@@ -2389,7 +2389,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
2389 \\}2389 \\}
2390 ,2390 ,
2391 });2391 });
2392 lib.addObject(obj);2392 lib.root_module.addObject(obj);
23932393
2394 const exe = addExecutable(b, opts, .{2394 const exe = addExecutable(b, opts, .{
2395 .name = "testlib",2395 .name = "testlib",
...@@ -2402,7 +2402,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {...@@ -2402,7 +2402,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
2402 \\}2402 \\}
2403 ,2403 ,
2404 });2404 });
2405 exe.linkLibrary(lib);2405 exe.root_module.linkLibrary(lib);
24062406
2407 const run = addRunArtifact(exe);2407 const run = addRunArtifact(exe);
2408 run.expectStdErrEqual("0\n");2408 run.expectStdErrEqual("0\n");
...@@ -2452,7 +2452,7 @@ fn testMergeStrings(b: *Build, opts: Options) *Step {...@@ -2452,7 +2452,7 @@ fn testMergeStrings(b: *Build, opts: Options) *Step {
2452 \\char16_t *utf16_1 = u"foo";2452 \\char16_t *utf16_1 = u"foo";
2453 \\char32_t *utf32_1 = U"foo";2453 \\char32_t *utf32_1 = U"foo";
2454 , &.{"-O2"});2454 , &.{"-O2"});
2455 obj1.linkLibC();2455 obj1.root_module.link_libc = true;
24562456
2457 const obj2 = addObject(b, opts, .{ .name = "b.o" });2457 const obj2 = addObject(b, opts, .{ .name = "b.o" });
2458 addCSourceBytes(obj2,2458 addCSourceBytes(obj2,
...@@ -2481,12 +2481,12 @@ fn testMergeStrings(b: *Build, opts: Options) *Step {...@@ -2481,12 +2481,12 @@ fn testMergeStrings(b: *Build, opts: Options) *Step {
2481 \\ assert((void*)wide1 != (void*)utf16_1);2481 \\ assert((void*)wide1 != (void*)utf16_1);
2482 \\}2482 \\}
2483 , &.{"-O2"});2483 , &.{"-O2"});
2484 obj2.linkLibC();2484 obj2.root_module.link_libc = true;
24852485
2486 const exe = addExecutable(b, opts, .{ .name = "main" });2486 const exe = addExecutable(b, opts, .{ .name = "main" });
2487 exe.addObject(obj1);2487 exe.root_module.addObject(obj1);
2488 exe.addObject(obj2);2488 exe.root_module.addObject(obj2);
2489 exe.linkLibC();2489 exe.root_module.link_libc = true;
24902490
2491 const run = addRunArtifact(exe);2491 const run = addRunArtifact(exe);
2492 run.expectExitCode(0);2492 run.expectExitCode(0);
...@@ -2520,8 +2520,8 @@ fn testMergeStrings2(b: *Build, opts: Options) *Step {...@@ -2520,8 +2520,8 @@ fn testMergeStrings2(b: *Build, opts: Options) *Step {
25202520
2521 {2521 {
2522 const exe = addExecutable(b, opts, .{ .name = "main1" });2522 const exe = addExecutable(b, opts, .{ .name = "main1" });
2523 exe.addObject(obj1);2523 exe.root_module.addObject(obj1);
2524 exe.addObject(obj2);2524 exe.root_module.addObject(obj2);
25252525
2526 const run = addRunArtifact(exe);2526 const run = addRunArtifact(exe);
2527 run.expectExitCode(0);2527 run.expectExitCode(0);
...@@ -2537,11 +2537,11 @@ fn testMergeStrings2(b: *Build, opts: Options) *Step {...@@ -2537,11 +2537,11 @@ fn testMergeStrings2(b: *Build, opts: Options) *Step {
25372537
2538 {2538 {
2539 const obj3 = addObject(b, opts, .{ .name = "c" });2539 const obj3 = addObject(b, opts, .{ .name = "c" });
2540 obj3.addObject(obj1);2540 obj3.root_module.addObject(obj1);
2541 obj3.addObject(obj2);2541 obj3.root_module.addObject(obj2);
25422542
2543 const exe = addExecutable(b, opts, .{ .name = "main2" });2543 const exe = addExecutable(b, opts, .{ .name = "main2" });
2544 exe.addObject(obj3);2544 exe.root_module.addObject(obj3);
25452545
2546 const run = addRunArtifact(exe);2546 const run = addRunArtifact(exe);
2547 run.expectExitCode(0);2547 run.expectExitCode(0);
...@@ -2564,7 +2564,7 @@ fn testNoEhFrameHdr(b: *Build, opts: Options) *Step {...@@ -2564,7 +2564,7 @@ fn testNoEhFrameHdr(b: *Build, opts: Options) *Step {
2564 const exe = addExecutable(b, opts, .{ .name = "main" });2564 const exe = addExecutable(b, opts, .{ .name = "main" });
2565 addCSourceBytes(exe, "int main() { return 0; }", &.{});2565 addCSourceBytes(exe, "int main() { return 0; }", &.{});
2566 exe.link_eh_frame_hdr = false;2566 exe.link_eh_frame_hdr = false;
2567 exe.linkLibC();2567 exe.root_module.link_libc = true;
25682568
2569 const check = exe.checkObject();2569 const check = exe.checkObject();
2570 check.checkInHeaders();2570 check.checkInHeaders();
...@@ -2586,7 +2586,7 @@ fn testPie(b: *Build, opts: Options) *Step {...@@ -2586,7 +2586,7 @@ fn testPie(b: *Build, opts: Options) *Step {
2586 \\ return 0;2586 \\ return 0;
2587 \\}2587 \\}
2588 , &.{});2588 , &.{});
2589 exe.linkLibC();2589 exe.root_module.link_libc = true;
2590 exe.root_module.pic = true;2590 exe.root_module.pic = true;
2591 exe.pie = true;2591 exe.pie = true;
25922592
...@@ -2617,7 +2617,7 @@ fn testPltGot(b: *Build, opts: Options) *Step {...@@ -2617,7 +2617,7 @@ fn testPltGot(b: *Build, opts: Options) *Step {
2617 \\ printf("Hello world\n");2617 \\ printf("Hello world\n");
2618 \\}2618 \\}
2619 , &.{});2619 , &.{});
2620 dso.linkLibC();2620 dso.root_module.link_libc = true;
26212621
2622 const exe = addExecutable(b, opts, .{ .name = "main" });2622 const exe = addExecutable(b, opts, .{ .name = "main" });
2623 addCSourceBytes(exe,2623 addCSourceBytes(exe,
...@@ -2626,9 +2626,9 @@ fn testPltGot(b: *Build, opts: Options) *Step {...@@ -2626,9 +2626,9 @@ fn testPltGot(b: *Build, opts: Options) *Step {
2626 \\void foo() { ignore(hello); }2626 \\void foo() { ignore(hello); }
2627 \\int main() { hello(); }2627 \\int main() { hello(); }
2628 , &.{});2628 , &.{});
2629 exe.linkLibrary(dso);2629 exe.root_module.linkLibrary(dso);
2630 exe.root_module.pic = true;2630 exe.root_module.pic = true;
2631 exe.linkLibC();2631 exe.root_module.link_libc = true;
26322632
2633 const run = addRunArtifact(exe);2633 const run = addRunArtifact(exe);
2634 run.expectStdOutEqual("Hello world\n");2634 run.expectStdOutEqual("Hello world\n");
...@@ -2647,7 +2647,7 @@ fn testPreinitArray(b: *Build, opts: Options) *Step {...@@ -2647,7 +2647,7 @@ fn testPreinitArray(b: *Build, opts: Options) *Step {
2647 });2647 });
26482648
2649 const exe = addExecutable(b, opts, .{ .name = "main1" });2649 const exe = addExecutable(b, opts, .{ .name = "main1" });
2650 exe.addObject(obj);2650 exe.root_module.addObject(obj);
26512651
2652 const check = exe.checkObject();2652 const check = exe.checkObject();
2653 check.checkInDynamicSection();2653 check.checkInDynamicSection();
...@@ -2662,7 +2662,7 @@ fn testPreinitArray(b: *Build, opts: Options) *Step {...@@ -2662,7 +2662,7 @@ fn testPreinitArray(b: *Build, opts: Options) *Step {
2662 \\__attribute__((section(".preinit_array")))2662 \\__attribute__((section(".preinit_array")))
2663 \\void *preinit[] = { preinit_fn };2663 \\void *preinit[] = { preinit_fn };
2664 , &.{});2664 , &.{});
2665 exe.linkLibC();2665 exe.root_module.link_libc = true;
26662666
2667 const check = exe.checkObject();2667 const check = exe.checkObject();
2668 check.checkInDynamicSection();2668 check.checkInDynamicSection();
...@@ -2710,15 +2710,15 @@ fn testRelocatableArchive(b: *Build, opts: Options) *Step {...@@ -2710,15 +2710,15 @@ fn testRelocatableArchive(b: *Build, opts: Options) *Step {
2710 });2710 });
27112711
2712 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });2712 const lib = addStaticLibrary(b, opts, .{ .name = "lib" });
2713 lib.addObject(obj1);2713 lib.root_module.addObject(obj1);
2714 lib.addObject(obj2);2714 lib.root_module.addObject(obj2);
2715 lib.addObject(obj3);2715 lib.root_module.addObject(obj3);
27162716
2717 const obj5 = addObject(b, opts, .{2717 const obj5 = addObject(b, opts, .{
2718 .name = "obj5",2718 .name = "obj5",
2719 });2719 });
2720 obj5.addObject(obj4);2720 obj5.root_module.addObject(obj4);
2721 obj5.linkLibrary(lib);2721 obj5.root_module.linkLibrary(lib);
27222722
2723 const check = obj5.checkObject();2723 const check = obj5.checkObject();
2724 check.checkInSymtab();2724 check.checkInSymtab();
...@@ -2744,7 +2744,7 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {...@@ -2744,7 +2744,7 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {
2744 \\}2744 \\}
2745 ,2745 ,
2746 });2746 });
2747 obj1.linkLibCpp();2747 obj1.root_module.link_libcpp = true;
2748 const obj2 = addObject(b, opts, .{2748 const obj2 = addObject(b, opts, .{
2749 .name = "obj2",2749 .name = "obj2",
2750 .cpp_source_bytes =2750 .cpp_source_bytes =
...@@ -2754,7 +2754,7 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {...@@ -2754,7 +2754,7 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {
2754 \\}2754 \\}
2755 ,2755 ,
2756 });2756 });
2757 obj2.linkLibCpp();2757 obj2.root_module.link_libcpp = true;
2758 const obj3 = addObject(b, opts, .{ .name = "obj3", .cpp_source_bytes = 2758 const obj3 = addObject(b, opts, .{ .name = "obj3", .cpp_source_bytes =
2759 \\#include <iostream>2759 \\#include <iostream>
2760 \\#include <stdexcept>2760 \\#include <stdexcept>
...@@ -2768,18 +2768,18 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {...@@ -2768,18 +2768,18 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {
2768 \\ return 0;2768 \\ return 0;
2769 \\}2769 \\}
2770 });2770 });
2771 obj3.linkLibCpp();2771 obj3.root_module.link_libcpp = true;
27722772
2773 {2773 {
2774 const obj = addObject(b, opts, .{ .name = "obj" });2774 const obj = addObject(b, opts, .{ .name = "obj" });
2775 obj.addObject(obj1);2775 obj.root_module.addObject(obj1);
2776 obj.addObject(obj2);2776 obj.root_module.addObject(obj2);
2777 obj.linkLibCpp();2777 obj.root_module.link_libcpp = true;
27782778
2779 const exe = addExecutable(b, opts, .{ .name = "test1" });2779 const exe = addExecutable(b, opts, .{ .name = "test1" });
2780 exe.addObject(obj3);2780 exe.root_module.addObject(obj3);
2781 exe.addObject(obj);2781 exe.root_module.addObject(obj);
2782 exe.linkLibCpp();2782 exe.root_module.link_libcpp = true;
27832783
2784 const run = addRunArtifact(exe);2784 const run = addRunArtifact(exe);
2785 run.expectStdOutEqual("exception=Oh no!");2785 run.expectStdOutEqual("exception=Oh no!");
...@@ -2788,14 +2788,14 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {...@@ -2788,14 +2788,14 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {
2788 {2788 {
2789 // Flipping the order should not influence the end result.2789 // Flipping the order should not influence the end result.
2790 const obj = addObject(b, opts, .{ .name = "obj" });2790 const obj = addObject(b, opts, .{ .name = "obj" });
2791 obj.addObject(obj2);2791 obj.root_module.addObject(obj2);
2792 obj.addObject(obj1);2792 obj.root_module.addObject(obj1);
2793 obj.linkLibCpp();2793 obj.root_module.link_libcpp = true;
27942794
2795 const exe = addExecutable(b, opts, .{ .name = "test2" });2795 const exe = addExecutable(b, opts, .{ .name = "test2" });
2796 exe.addObject(obj3);2796 exe.root_module.addObject(obj3);
2797 exe.addObject(obj);2797 exe.root_module.addObject(obj);
2798 exe.linkLibCpp();2798 exe.root_module.link_libcpp = true;
27992799
2800 const run = addRunArtifact(exe);2800 const run = addRunArtifact(exe);
2801 run.expectStdOutEqual("exception=Oh no!");2801 run.expectStdOutEqual("exception=Oh no!");
...@@ -2817,7 +2817,7 @@ fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step {...@@ -2817,7 +2817,7 @@ fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step {
2817 \\}2817 \\}
2818 ,2818 ,
2819 });2819 });
2820 obj1.linkLibCpp();2820 obj1.root_module.link_libcpp = true;
2821 const obj2 = addObject(b, opts, .{2821 const obj2 = addObject(b, opts, .{
2822 .name = "obj2",2822 .name = "obj2",
2823 .cpp_source_bytes =2823 .cpp_source_bytes =
...@@ -2827,7 +2827,7 @@ fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step {...@@ -2827,7 +2827,7 @@ fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step {
2827 \\}2827 \\}
2828 ,2828 ,
2829 });2829 });
2830 obj2.linkLibCpp();2830 obj2.root_module.link_libcpp = true;
2831 const obj3 = addObject(b, opts, .{2831 const obj3 = addObject(b, opts, .{
2832 .name = "obj3",2832 .name = "obj3",
2833 .cpp_source_bytes =2833 .cpp_source_bytes =
...@@ -2844,17 +2844,17 @@ fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step {...@@ -2844,17 +2844,17 @@ fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step {
2844 \\}2844 \\}
2845 ,2845 ,
2846 });2846 });
2847 obj3.linkLibCpp();2847 obj3.root_module.link_libcpp = true;
28482848
2849 const obj = addObject(b, opts, .{ .name = "obj" });2849 const obj = addObject(b, opts, .{ .name = "obj" });
2850 obj.addObject(obj1);2850 obj.root_module.addObject(obj1);
2851 obj.addObject(obj2);2851 obj.root_module.addObject(obj2);
2852 obj.addObject(obj3);2852 obj.root_module.addObject(obj3);
2853 obj.linkLibCpp();2853 obj.root_module.link_libcpp = true;
28542854
2855 const exe = addExecutable(b, opts, .{ .name = "test2" });2855 const exe = addExecutable(b, opts, .{ .name = "test2" });
2856 exe.addObject(obj);2856 exe.root_module.addObject(obj);
2857 exe.linkLibCpp();2857 exe.root_module.link_libcpp = true;
28582858
2859 const run = addRunArtifact(exe);2859 const run = addRunArtifact(exe);
2860 run.expectStdOutEqual("exception=Oh no!");2860 run.expectStdOutEqual("exception=Oh no!");
...@@ -2880,7 +2880,7 @@ fn testRelocatableMergeStrings(b: *Build, opts: Options) *Step {...@@ -2880,7 +2880,7 @@ fn testRelocatableMergeStrings(b: *Build, opts: Options) *Step {
2880 });2880 });
28812881
2882 const obj2 = addObject(b, opts, .{ .name = "b" });2882 const obj2 = addObject(b, opts, .{ .name = "b" });
2883 obj2.addObject(obj1);2883 obj2.root_module.addObject(obj1);
28842884
2885 const check = obj2.checkObject();2885 const check = obj2.checkObject();
2886 check.dumpSection(".rodata.str1.1");2886 check.dumpSection(".rodata.str1.1");
...@@ -2905,7 +2905,7 @@ fn testRelocatableNoEhFrame(b: *Build, opts: Options) *Step {...@@ -2905,7 +2905,7 @@ fn testRelocatableNoEhFrame(b: *Build, opts: Options) *Step {
2905 const obj2 = addObject(b, opts, .{2905 const obj2 = addObject(b, opts, .{
2906 .name = "obj2",2906 .name = "obj2",
2907 });2907 });
2908 obj2.addObject(obj1);2908 obj2.root_module.addObject(obj1);
29092909
2910 const check1 = obj1.checkObject();2910 const check1 = obj1.checkObject();
2911 check1.checkInHeaders();2911 check1.checkInHeaders();
...@@ -2940,12 +2940,12 @@ fn testSharedAbsSymbol(b: *Build, opts: Options) *Step {...@@ -2940,12 +2940,12 @@ fn testSharedAbsSymbol(b: *Build, opts: Options) *Step {
2940 ,2940 ,
2941 .pic = true,2941 .pic = true,
2942 });2942 });
2943 obj.linkLibC();2943 obj.root_module.link_libc = true;
29442944
2945 {2945 {
2946 const exe = addExecutable(b, opts, .{ .name = "main1" });2946 const exe = addExecutable(b, opts, .{ .name = "main1" });
2947 exe.addObject(obj);2947 exe.root_module.addObject(obj);
2948 exe.linkLibrary(dso);2948 exe.root_module.linkLibrary(dso);
2949 exe.pie = true;2949 exe.pie = true;
29502950
2951 const run = addRunArtifact(exe);2951 const run = addRunArtifact(exe);
...@@ -2965,8 +2965,8 @@ fn testSharedAbsSymbol(b: *Build, opts: Options) *Step {...@@ -2965,8 +2965,8 @@ fn testSharedAbsSymbol(b: *Build, opts: Options) *Step {
2965 // https://github.com/ziglang/zig/issues/174302965 // https://github.com/ziglang/zig/issues/17430
2966 // {2966 // {
2967 // const exe = addExecutable(b, opts, .{ .name = "main2"});2967 // const exe = addExecutable(b, opts, .{ .name = "main2"});
2968 // exe.addObject(obj);2968 // exe.root_module.addObject(obj);
2969 // exe.linkLibrary(dso);2969 // exe.root_module.linkLibrary(dso);
2970 // exe.pie = false;2970 // exe.pie = false;
29712971
2972 // const run = addRunArtifact(exe);2972 // const run = addRunArtifact(exe);
...@@ -2999,13 +2999,13 @@ fn testStrip(b: *Build, opts: Options) *Step {...@@ -2999,13 +2999,13 @@ fn testStrip(b: *Build, opts: Options) *Step {
2999 \\}2999 \\}
3000 ,3000 ,
3001 });3001 });
3002 obj.linkLibC();3002 obj.root_module.link_libc = true;
30033003
3004 {3004 {
3005 const exe = addExecutable(b, opts, .{ .name = "main1" });3005 const exe = addExecutable(b, opts, .{ .name = "main1" });
3006 exe.addObject(obj);3006 exe.root_module.addObject(obj);
3007 exe.root_module.strip = false;3007 exe.root_module.strip = false;
3008 exe.linkLibC();3008 exe.root_module.link_libc = true;
30093009
3010 const check = exe.checkObject();3010 const check = exe.checkObject();
3011 check.checkInHeaders();3011 check.checkInHeaders();
...@@ -3016,9 +3016,9 @@ fn testStrip(b: *Build, opts: Options) *Step {...@@ -3016,9 +3016,9 @@ fn testStrip(b: *Build, opts: Options) *Step {
30163016
3017 {3017 {
3018 const exe = addExecutable(b, opts, .{ .name = "main2" });3018 const exe = addExecutable(b, opts, .{ .name = "main2" });
3019 exe.addObject(obj);3019 exe.root_module.addObject(obj);
3020 exe.root_module.strip = true;3020 exe.root_module.strip = true;
3021 exe.linkLibC();3021 exe.root_module.link_libc = true;
30223022
3023 const check = exe.checkObject();3023 const check = exe.checkObject();
3024 check.checkInHeaders();3024 check.checkInHeaders();
...@@ -3074,7 +3074,7 @@ fn testTlsDfStaticTls(b: *Build, opts: Options) *Step {...@@ -3074,7 +3074,7 @@ fn testTlsDfStaticTls(b: *Build, opts: Options) *Step {
30743074
3075 {3075 {
3076 const dso = addSharedLibrary(b, opts, .{ .name = "a" });3076 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
3077 dso.addObject(obj);3077 dso.root_module.addObject(obj);
3078 // dso.link_relax = true;3078 // dso.link_relax = true;
30793079
3080 const check = dso.checkObject();3080 const check = dso.checkObject();
...@@ -3086,7 +3086,7 @@ fn testTlsDfStaticTls(b: *Build, opts: Options) *Step {...@@ -3086,7 +3086,7 @@ fn testTlsDfStaticTls(b: *Build, opts: Options) *Step {
3086 // TODO add -Wl,--no-relax3086 // TODO add -Wl,--no-relax
3087 // {3087 // {
3088 // const dso = addSharedLibrary(b, opts, .{ .name = "a"});3088 // const dso = addSharedLibrary(b, opts, .{ .name = "a"});
3089 // dso.addObject(obj);3089 // dso.root_module.addObject(obj);
3090 // dso.link_relax = false;3090 // dso.link_relax = false;
30913091
3092 // const check = dso.checkObject();3092 // const check = dso.checkObject();
...@@ -3128,8 +3128,8 @@ fn testTlsDso(b: *Build, opts: Options) *Step {...@@ -3128,8 +3128,8 @@ fn testTlsDso(b: *Build, opts: Options) *Step {
3128 \\ return 0;3128 \\ return 0;
3129 \\}3129 \\}
3130 , &.{});3130 , &.{});
3131 exe.linkLibrary(dso);3131 exe.root_module.linkLibrary(dso);
3132 exe.linkLibC();3132 exe.root_module.link_libc = true;
31333133
3134 const run = addRunArtifact(exe);3134 const run = addRunArtifact(exe);
3135 run.expectStdOutEqual("5 3 5 3 5 3\n");3135 run.expectStdOutEqual("5 3 5 3 5 3\n");
...@@ -3159,7 +3159,7 @@ fn testTlsGd(b: *Build, opts: Options) *Step {...@@ -3159,7 +3159,7 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
3159 ,3159 ,
3160 .pic = true,3160 .pic = true,
3161 });3161 });
3162 main_o.linkLibC();3162 main_o.root_module.link_libc = true;
31633163
3164 const a_o = addObject(b, opts, .{3164 const a_o = addObject(b, opts, .{
3165 .name = "a",3165 .name = "a",
...@@ -3184,17 +3184,17 @@ fn testTlsGd(b: *Build, opts: Options) *Step {...@@ -3184,17 +3184,17 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
3184 const exp_stdout = "1 2 3 4 5 6\n";3184 const exp_stdout = "1 2 3 4 5 6\n";
31853185
3186 const dso1 = addSharedLibrary(b, opts, .{ .name = "a" });3186 const dso1 = addSharedLibrary(b, opts, .{ .name = "a" });
3187 dso1.addObject(a_o);3187 dso1.root_module.addObject(a_o);
31883188
3189 const dso2 = addSharedLibrary(b, opts, .{ .name = "b" });3189 const dso2 = addSharedLibrary(b, opts, .{ .name = "b" });
3190 dso2.addObject(b_o);3190 dso2.root_module.addObject(b_o);
3191 // dso2.link_relax = false; // TODO3191 // dso2.link_relax = false; // TODO
31923192
3193 {3193 {
3194 const exe = addExecutable(b, opts, .{ .name = "main1" });3194 const exe = addExecutable(b, opts, .{ .name = "main1" });
3195 exe.addObject(main_o);3195 exe.root_module.addObject(main_o);
3196 exe.linkLibrary(dso1);3196 exe.root_module.linkLibrary(dso1);
3197 exe.linkLibrary(dso2);3197 exe.root_module.linkLibrary(dso2);
31983198
3199 const run = addRunArtifact(exe);3199 const run = addRunArtifact(exe);
3200 run.expectStdOutEqual(exp_stdout);3200 run.expectStdOutEqual(exp_stdout);
...@@ -3203,10 +3203,10 @@ fn testTlsGd(b: *Build, opts: Options) *Step {...@@ -3203,10 +3203,10 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
32033203
3204 {3204 {
3205 const exe = addExecutable(b, opts, .{ .name = "main2" });3205 const exe = addExecutable(b, opts, .{ .name = "main2" });
3206 exe.addObject(main_o);3206 exe.root_module.addObject(main_o);
3207 // exe.link_relax = false; // TODO3207 // exe.link_relax = false; // TODO
3208 exe.linkLibrary(dso1);3208 exe.root_module.linkLibrary(dso1);
3209 exe.linkLibrary(dso2);3209 exe.root_module.linkLibrary(dso2);
32103210
3211 const run = addRunArtifact(exe);3211 const run = addRunArtifact(exe);
3212 run.expectStdOutEqual(exp_stdout);3212 run.expectStdOutEqual(exp_stdout);
...@@ -3216,9 +3216,9 @@ fn testTlsGd(b: *Build, opts: Options) *Step {...@@ -3216,9 +3216,9 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
3216 // https://github.com/ziglang/zig/issues/17430 ??3216 // https://github.com/ziglang/zig/issues/17430 ??
3217 // {3217 // {
3218 // const exe = addExecutable(b, opts, .{ .name = "main3"});3218 // const exe = addExecutable(b, opts, .{ .name = "main3"});
3219 // exe.addObject(main_o);3219 // exe.root_module.addObject(main_o);
3220 // exe.linkLibrary(dso1);3220 // exe.root_module.linkLibrary(dso1);
3221 // exe.linkLibrary(dso2);3221 // exe.root_module.linkLibrary(dso2);
3222 // exe.linkage = .static;3222 // exe.linkage = .static;
32233223
3224 // const run = addRunArtifact(exe);3224 // const run = addRunArtifact(exe);
...@@ -3228,10 +3228,10 @@ fn testTlsGd(b: *Build, opts: Options) *Step {...@@ -3228,10 +3228,10 @@ fn testTlsGd(b: *Build, opts: Options) *Step {
32283228
3229 // {3229 // {
3230 // const exe = addExecutable(b, opts, .{ .name = "main4"});3230 // const exe = addExecutable(b, opts, .{ .name = "main4"});
3231 // exe.addObject(main_o);3231 // exe.root_module.addObject(main_o);
3232 // // exe.link_relax = false; // TODO3232 // // exe.link_relax = false; // TODO
3233 // exe.linkLibrary(dso1);3233 // exe.root_module.linkLibrary(dso1);
3234 // exe.linkLibrary(dso2);3234 // exe.root_module.linkLibrary(dso2);
3235 // exe.linkage = .static;3235 // exe.linkage = .static;
32363236
3237 // const run = addRunArtifact(exe);3237 // const run = addRunArtifact(exe);
...@@ -3265,7 +3265,7 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step {...@@ -3265,7 +3265,7 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step {
3265 .c_source_flags = &.{"-fno-plt"},3265 .c_source_flags = &.{"-fno-plt"},
3266 .pic = true,3266 .pic = true,
3267 });3267 });
3268 obj.linkLibC();3268 obj.root_module.link_libc = true;
32693269
3270 const a_so = addSharedLibrary(b, opts, .{ .name = "a" });3270 const a_so = addSharedLibrary(b, opts, .{ .name = "a" });
3271 addCSourceBytes(a_so,3271 addCSourceBytes(a_so,
...@@ -3284,10 +3284,10 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step {...@@ -3284,10 +3284,10 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step {
32843284
3285 {3285 {
3286 const exe = addExecutable(b, opts, .{ .name = "main1" });3286 const exe = addExecutable(b, opts, .{ .name = "main1" });
3287 exe.addObject(obj);3287 exe.root_module.addObject(obj);
3288 exe.linkLibrary(a_so);3288 exe.root_module.linkLibrary(a_so);
3289 exe.linkLibrary(b_so);3289 exe.root_module.linkLibrary(b_so);
3290 exe.linkLibC();3290 exe.root_module.link_libc = true;
32913291
3292 const run = addRunArtifact(exe);3292 const run = addRunArtifact(exe);
3293 run.expectStdOutEqual("1 2 3 4 5 6\n");3293 run.expectStdOutEqual("1 2 3 4 5 6\n");
...@@ -3296,10 +3296,10 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step {...@@ -3296,10 +3296,10 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step {
32963296
3297 {3297 {
3298 const exe = addExecutable(b, opts, .{ .name = "main2" });3298 const exe = addExecutable(b, opts, .{ .name = "main2" });
3299 exe.addObject(obj);3299 exe.root_module.addObject(obj);
3300 exe.linkLibrary(a_so);3300 exe.root_module.linkLibrary(a_so);
3301 exe.linkLibrary(b_so);3301 exe.root_module.linkLibrary(b_so);
3302 exe.linkLibC();3302 exe.root_module.link_libc = true;
3303 // exe.link_relax = false; // TODO3303 // exe.link_relax = false; // TODO
33043304
3305 const run = addRunArtifact(exe);3305 const run = addRunArtifact(exe);
...@@ -3329,7 +3329,7 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {...@@ -3329,7 +3329,7 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
3329 ,3329 ,
3330 .pic = true,3330 .pic = true,
3331 });3331 });
3332 a_o.linkLibC();3332 a_o.root_module.link_libc = true;
33333333
3334 const b_o = addObject(b, opts, .{3334 const b_o = addObject(b, opts, .{
3335 .name = "b",3335 .name = "b",
...@@ -3342,12 +3342,12 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {...@@ -3342,12 +3342,12 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
33423342
3343 {3343 {
3344 const dso = addSharedLibrary(b, opts, .{ .name = "a1" });3344 const dso = addSharedLibrary(b, opts, .{ .name = "a1" });
3345 dso.addObject(a_o);3345 dso.root_module.addObject(a_o);
33463346
3347 const exe = addExecutable(b, opts, .{ .name = "main1" });3347 const exe = addExecutable(b, opts, .{ .name = "main1" });
3348 exe.addObject(b_o);3348 exe.root_module.addObject(b_o);
3349 exe.linkLibrary(dso);3349 exe.root_module.linkLibrary(dso);
3350 exe.linkLibC();3350 exe.root_module.link_libc = true;
33513351
3352 const run = addRunArtifact(exe);3352 const run = addRunArtifact(exe);
3353 run.expectStdOutEqual("1 2 3\n");3353 run.expectStdOutEqual("1 2 3\n");
...@@ -3356,13 +3356,13 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {...@@ -3356,13 +3356,13 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
33563356
3357 {3357 {
3358 const dso = addSharedLibrary(b, opts, .{ .name = "a2" });3358 const dso = addSharedLibrary(b, opts, .{ .name = "a2" });
3359 dso.addObject(a_o);3359 dso.root_module.addObject(a_o);
3360 // dso.link_relax = false; // TODO3360 // dso.link_relax = false; // TODO
33613361
3362 const exe = addExecutable(b, opts, .{ .name = "main2" });3362 const exe = addExecutable(b, opts, .{ .name = "main2" });
3363 exe.addObject(b_o);3363 exe.root_module.addObject(b_o);
3364 exe.linkLibrary(dso);3364 exe.root_module.linkLibrary(dso);
3365 exe.linkLibC();3365 exe.root_module.link_libc = true;
33663366
3367 const run = addRunArtifact(exe);3367 const run = addRunArtifact(exe);
3368 run.expectStdOutEqual("1 2 3\n");3368 run.expectStdOutEqual("1 2 3\n");
...@@ -3371,12 +3371,12 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {...@@ -3371,12 +3371,12 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
33713371
3372 // {3372 // {
3373 // const dso = addSharedLibrary(b, opts, .{ .name = "a"});3373 // const dso = addSharedLibrary(b, opts, .{ .name = "a"});
3374 // dso.addObject(a_o);3374 // dso.root_module.addObject(a_o);
3375 // dso.link_z_nodlopen = true;3375 // dso.link_z_nodlopen = true;
33763376
3377 // const exe = addExecutable(b, opts, .{ .name = "main"});3377 // const exe = addExecutable(b, opts, .{ .name = "main"});
3378 // exe.addObject(b_o);3378 // exe.root_module.addObject(b_o);
3379 // exe.linkLibrary(dso);3379 // exe.root_module.linkLibrary(dso);
33803380
3381 // const run = addRunArtifact(exe);3381 // const run = addRunArtifact(exe);
3382 // run.expectStdOutEqual("1 2 3\n");3382 // run.expectStdOutEqual("1 2 3\n");
...@@ -3385,13 +3385,13 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {...@@ -3385,13 +3385,13 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step {
33853385
3386 // {3386 // {
3387 // const dso = addSharedLibrary(b, opts, .{ .name = "a"});3387 // const dso = addSharedLibrary(b, opts, .{ .name = "a"});
3388 // dso.addObject(a_o);3388 // dso.root_module.addObject(a_o);
3389 // dso.link_relax = false;3389 // dso.link_relax = false;
3390 // dso.link_z_nodlopen = true;3390 // dso.link_z_nodlopen = true;
33913391
3392 // const exe = addExecutable(b, opts, .{ .name = "main"});3392 // const exe = addExecutable(b, opts, .{ .name = "main"});
3393 // exe.addObject(b_o);3393 // exe.root_module.addObject(b_o);
3394 // exe.linkLibrary(dso);3394 // exe.root_module.linkLibrary(dso);
33953395
3396 // const run = addRunArtifact(exe);3396 // const run = addRunArtifact(exe);
3397 // run.expectStdOutEqual("1 2 3\n");3397 // run.expectStdOutEqual("1 2 3\n");
...@@ -3417,7 +3417,7 @@ fn testTlsIe(b: *Build, opts: Options) *Step {...@@ -3417,7 +3417,7 @@ fn testTlsIe(b: *Build, opts: Options) *Step {
3417 \\ printf("%d %d ", foo, bar);3417 \\ printf("%d %d ", foo, bar);
3418 \\}3418 \\}
3419 , &.{});3419 , &.{});
3420 dso.linkLibC();3420 dso.root_module.link_libc = true;
34213421
3422 const main_o = addObject(b, opts, .{3422 const main_o = addObject(b, opts, .{
3423 .name = "main",3423 .name = "main",
...@@ -3435,15 +3435,15 @@ fn testTlsIe(b: *Build, opts: Options) *Step {...@@ -3435,15 +3435,15 @@ fn testTlsIe(b: *Build, opts: Options) *Step {
3435 \\}3435 \\}
3436 ,3436 ,
3437 });3437 });
3438 main_o.linkLibC();3438 main_o.root_module.link_libc = true;
34393439
3440 const exp_stdout = "0 0 3 5 7\n";3440 const exp_stdout = "0 0 3 5 7\n";
34413441
3442 {3442 {
3443 const exe = addExecutable(b, opts, .{ .name = "main1" });3443 const exe = addExecutable(b, opts, .{ .name = "main1" });
3444 exe.addObject(main_o);3444 exe.root_module.addObject(main_o);
3445 exe.linkLibrary(dso);3445 exe.root_module.linkLibrary(dso);
3446 exe.linkLibC();3446 exe.root_module.link_libc = true;
34473447
3448 const run = addRunArtifact(exe);3448 const run = addRunArtifact(exe);
3449 run.expectStdOutEqual(exp_stdout);3449 run.expectStdOutEqual(exp_stdout);
...@@ -3452,9 +3452,9 @@ fn testTlsIe(b: *Build, opts: Options) *Step {...@@ -3452,9 +3452,9 @@ fn testTlsIe(b: *Build, opts: Options) *Step {
34523452
3453 {3453 {
3454 const exe = addExecutable(b, opts, .{ .name = "main2" });3454 const exe = addExecutable(b, opts, .{ .name = "main2" });
3455 exe.addObject(main_o);3455 exe.root_module.addObject(main_o);
3456 exe.linkLibrary(dso);3456 exe.root_module.linkLibrary(dso);
3457 exe.linkLibC();3457 exe.root_module.link_libc = true;
3458 // exe.link_relax = false; // TODO3458 // exe.link_relax = false; // TODO
34593459
3460 const run = addRunArtifact(exe);3460 const run = addRunArtifact(exe);
...@@ -3500,17 +3500,17 @@ fn testTlsLargeAlignment(b: *Build, opts: Options) *Step {...@@ -3500,17 +3500,17 @@ fn testTlsLargeAlignment(b: *Build, opts: Options) *Step {
3500 ,3500 ,
3501 .pic = true,3501 .pic = true,
3502 });3502 });
3503 c_o.linkLibC();3503 c_o.root_module.link_libc = true;
35043504
3505 {3505 {
3506 const dso = addSharedLibrary(b, opts, .{ .name = "a" });3506 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
3507 dso.addObject(a_o);3507 dso.root_module.addObject(a_o);
3508 dso.addObject(b_o);3508 dso.root_module.addObject(b_o);
35093509
3510 const exe = addExecutable(b, opts, .{ .name = "main" });3510 const exe = addExecutable(b, opts, .{ .name = "main" });
3511 exe.addObject(c_o);3511 exe.root_module.addObject(c_o);
3512 exe.linkLibrary(dso);3512 exe.root_module.linkLibrary(dso);
3513 exe.linkLibC();3513 exe.root_module.link_libc = true;
35143514
3515 const run = addRunArtifact(exe);3515 const run = addRunArtifact(exe);
3516 run.expectStdOutEqual("42 1 2 3\n");3516 run.expectStdOutEqual("42 1 2 3\n");
...@@ -3519,10 +3519,10 @@ fn testTlsLargeAlignment(b: *Build, opts: Options) *Step {...@@ -3519,10 +3519,10 @@ fn testTlsLargeAlignment(b: *Build, opts: Options) *Step {
35193519
3520 {3520 {
3521 const exe = addExecutable(b, opts, .{ .name = "main" });3521 const exe = addExecutable(b, opts, .{ .name = "main" });
3522 exe.addObject(a_o);3522 exe.root_module.addObject(a_o);
3523 exe.addObject(b_o);3523 exe.root_module.addObject(b_o);
3524 exe.addObject(c_o);3524 exe.root_module.addObject(c_o);
3525 exe.linkLibC();3525 exe.root_module.link_libc = true;
35263526
3527 const run = addRunArtifact(exe);3527 const run = addRunArtifact(exe);
3528 run.expectStdOutEqual("42 1 2 3\n");3528 run.expectStdOutEqual("42 1 2 3\n");
...@@ -3555,7 +3555,7 @@ fn testTlsLargeTbss(b: *Build, opts: Options) *Step {...@@ -3555,7 +3555,7 @@ fn testTlsLargeTbss(b: *Build, opts: Options) *Step {
3555 \\ printf("%d %d %d %d %d %d\n", x[0], x[1], x[1023], y[0], y[1], y[1023]);3555 \\ printf("%d %d %d %d %d %d\n", x[0], x[1], x[1023], y[0], y[1], y[1023]);
3556 \\}3556 \\}
3557 , &.{});3557 , &.{});
3558 exe.linkLibC();3558 exe.root_module.link_libc = true;
3559 // Disabled to work around the ELF linker crashing.3559 // Disabled to work around the ELF linker crashing.
3560 // Can be reproduced on a x86_64-linux host by commenting out the line below.3560 // Can be reproduced on a x86_64-linux host by commenting out the line below.
3561 exe.root_module.sanitize_c = .off;3561 exe.root_module.sanitize_c = .off;
...@@ -3580,7 +3580,7 @@ fn testTlsLargeStaticImage(b: *Build, opts: Options) *Step {...@@ -3580,7 +3580,7 @@ fn testTlsLargeStaticImage(b: *Build, opts: Options) *Step {
3580 \\}3580 \\}
3581 , &.{});3581 , &.{});
3582 exe.root_module.pic = true;3582 exe.root_module.pic = true;
3583 exe.linkLibC();3583 exe.root_module.link_libc = true;
35843584
3585 const run = addRunArtifact(exe);3585 const run = addRunArtifact(exe);
3586 run.expectStdOutEqual("1 2 3 0 5\n");3586 run.expectStdOutEqual("1 2 3 0 5\n");
...@@ -3609,7 +3609,7 @@ fn testTlsLd(b: *Build, opts: Options) *Step {...@@ -3609,7 +3609,7 @@ fn testTlsLd(b: *Build, opts: Options) *Step {
3609 .c_source_flags = &.{"-ftls-model=local-dynamic"},3609 .c_source_flags = &.{"-ftls-model=local-dynamic"},
3610 .pic = true,3610 .pic = true,
3611 });3611 });
3612 main_o.linkLibC();3612 main_o.root_module.link_libc = true;
36133613
3614 const a_o = addObject(b, opts, .{3614 const a_o = addObject(b, opts, .{
3615 .name = "a",3615 .name = "a",
...@@ -3622,9 +3622,9 @@ fn testTlsLd(b: *Build, opts: Options) *Step {...@@ -3622,9 +3622,9 @@ fn testTlsLd(b: *Build, opts: Options) *Step {
36223622
3623 {3623 {
3624 const exe = addExecutable(b, opts, .{ .name = "main1" });3624 const exe = addExecutable(b, opts, .{ .name = "main1" });
3625 exe.addObject(main_o);3625 exe.root_module.addObject(main_o);
3626 exe.addObject(a_o);3626 exe.root_module.addObject(a_o);
3627 exe.linkLibC();3627 exe.root_module.link_libc = true;
36283628
3629 const run = addRunArtifact(exe);3629 const run = addRunArtifact(exe);
3630 run.expectStdOutEqual(exp_stdout);3630 run.expectStdOutEqual(exp_stdout);
...@@ -3633,9 +3633,9 @@ fn testTlsLd(b: *Build, opts: Options) *Step {...@@ -3633,9 +3633,9 @@ fn testTlsLd(b: *Build, opts: Options) *Step {
36333633
3634 {3634 {
3635 const exe = addExecutable(b, opts, .{ .name = "main2" });3635 const exe = addExecutable(b, opts, .{ .name = "main2" });
3636 exe.addObject(main_o);3636 exe.root_module.addObject(main_o);
3637 exe.addObject(a_o);3637 exe.root_module.addObject(a_o);
3638 exe.linkLibC();3638 exe.root_module.link_libc = true;
3639 // exe.link_relax = false; // TODO3639 // exe.link_relax = false; // TODO
36403640
3641 const run = addRunArtifact(exe);3641 const run = addRunArtifact(exe);
...@@ -3668,8 +3668,8 @@ fn testTlsLdDso(b: *Build, opts: Options) *Step {...@@ -3668,8 +3668,8 @@ fn testTlsLdDso(b: *Build, opts: Options) *Step {
3668 \\ return 0;3668 \\ return 0;
3669 \\}3669 \\}
3670 , &.{});3670 , &.{});
3671 exe.linkLibrary(dso);3671 exe.root_module.linkLibrary(dso);
3672 exe.linkLibC();3672 exe.root_module.link_libc = true;
36733673
3674 const run = addRunArtifact(exe);3674 const run = addRunArtifact(exe);
3675 run.expectStdOutEqual("1 2\n");3675 run.expectStdOutEqual("1 2\n");
...@@ -3699,7 +3699,7 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step {...@@ -3699,7 +3699,7 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step {
3699 .c_source_flags = &.{ "-ftls-model=local-dynamic", "-fno-plt" },3699 .c_source_flags = &.{ "-ftls-model=local-dynamic", "-fno-plt" },
3700 .pic = true,3700 .pic = true,
3701 });3701 });
3702 a_o.linkLibC();3702 a_o.root_module.link_libc = true;
37033703
3704 const b_o = addObject(b, opts, .{3704 const b_o = addObject(b, opts, .{
3705 .name = "b",3705 .name = "b",
...@@ -3710,9 +3710,9 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step {...@@ -3710,9 +3710,9 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step {
37103710
3711 {3711 {
3712 const exe = addExecutable(b, opts, .{ .name = "main1" });3712 const exe = addExecutable(b, opts, .{ .name = "main1" });
3713 exe.addObject(a_o);3713 exe.root_module.addObject(a_o);
3714 exe.addObject(b_o);3714 exe.root_module.addObject(b_o);
3715 exe.linkLibC();3715 exe.root_module.link_libc = true;
37163716
3717 const run = addRunArtifact(exe);3717 const run = addRunArtifact(exe);
3718 run.expectStdOutEqual("3 5 3 5\n");3718 run.expectStdOutEqual("3 5 3 5\n");
...@@ -3721,9 +3721,9 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step {...@@ -3721,9 +3721,9 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step {
37213721
3722 {3722 {
3723 const exe = addExecutable(b, opts, .{ .name = "main2" });3723 const exe = addExecutable(b, opts, .{ .name = "main2" });
3724 exe.addObject(a_o);3724 exe.root_module.addObject(a_o);
3725 exe.addObject(b_o);3725 exe.root_module.addObject(b_o);
3726 exe.linkLibC();3726 exe.root_module.link_libc = true;
3727 // exe.link_relax = false; // TODO3727 // exe.link_relax = false; // TODO
37283728
3729 const run = addRunArtifact(exe);3729 const run = addRunArtifact(exe);
...@@ -3756,7 +3756,7 @@ fn testTlsNoPic(b: *Build, opts: Options) *Step {...@@ -3756,7 +3756,7 @@ fn testTlsNoPic(b: *Build, opts: Options) *Step {
3756 \\__attribute__((tls_model("global-dynamic"))) _Thread_local int foo;3756 \\__attribute__((tls_model("global-dynamic"))) _Thread_local int foo;
3757 , &.{});3757 , &.{});
3758 exe.root_module.pic = false;3758 exe.root_module.pic = false;
3759 exe.linkLibC();3759 exe.root_module.link_libc = true;
37603760
3761 const run = addRunArtifact(exe);3761 const run = addRunArtifact(exe);
3762 run.expectStdOutEqual("3 5 3 5\n");3762 run.expectStdOutEqual("3 5 3 5\n");
...@@ -3784,7 +3784,7 @@ fn testTlsOffsetAlignment(b: *Build, opts: Options) *Step {...@@ -3784,7 +3784,7 @@ fn testTlsOffsetAlignment(b: *Build, opts: Options) *Step {
3784 \\ return NULL;3784 \\ return NULL;
3785 \\}3785 \\}
3786 , &.{});3786 , &.{});
3787 dso.linkLibC();3787 dso.root_module.link_libc = true;
37883788
3789 const exe = addExecutable(b, opts, .{ .name = "main" });3789 const exe = addExecutable(b, opts, .{ .name = "main" });
3790 addCSourceBytes(exe,3790 addCSourceBytes(exe,
...@@ -3811,8 +3811,8 @@ fn testTlsOffsetAlignment(b: *Build, opts: Options) *Step {...@@ -3811,8 +3811,8 @@ fn testTlsOffsetAlignment(b: *Build, opts: Options) *Step {
3811 \\ pthread_join(thread, NULL);3811 \\ pthread_join(thread, NULL);
3812 \\}3812 \\}
3813 , &.{});3813 , &.{});
3814 exe.addRPath(dso.getEmittedBinDirectory());3814 exe.root_module.addRPath(dso.getEmittedBinDirectory());
3815 exe.linkLibC();3815 exe.root_module.link_libc = true;
3816 exe.root_module.pic = true;3816 exe.root_module.pic = true;
38173817
3818 const run = addRunArtifact(exe);3818 const run = addRunArtifact(exe);
...@@ -3842,14 +3842,14 @@ fn testTlsPic(b: *Build, opts: Options) *Step {...@@ -3842,14 +3842,14 @@ fn testTlsPic(b: *Build, opts: Options) *Step {
3842 ,3842 ,
3843 .pic = true,3843 .pic = true,
3844 });3844 });
3845 obj.linkLibC();3845 obj.root_module.link_libc = true;
38463846
3847 const exe = addExecutable(b, opts, .{ .name = "main" });3847 const exe = addExecutable(b, opts, .{ .name = "main" });
3848 addCSourceBytes(exe,3848 addCSourceBytes(exe,
3849 \\__attribute__((tls_model("global-dynamic"))) _Thread_local int foo = 3;3849 \\__attribute__((tls_model("global-dynamic"))) _Thread_local int foo = 3;
3850 , &.{});3850 , &.{});
3851 exe.addObject(obj);3851 exe.root_module.addObject(obj);
3852 exe.linkLibC();3852 exe.root_module.link_libc = true;
38533853
3854 const run = addRunArtifact(exe);3854 const run = addRunArtifact(exe);
3855 run.expectStdOutEqual("3 5 3 5\n");3855 run.expectStdOutEqual("3 5 3 5\n");
...@@ -3889,14 +3889,14 @@ fn testTlsSmallAlignment(b: *Build, opts: Options) *Step {...@@ -3889,14 +3889,14 @@ fn testTlsSmallAlignment(b: *Build, opts: Options) *Step {
3889 ,3889 ,
3890 .pic = true,3890 .pic = true,
3891 });3891 });
3892 c_o.linkLibC();3892 c_o.root_module.link_libc = true;
38933893
3894 {3894 {
3895 const exe = addExecutable(b, opts, .{ .name = "main" });3895 const exe = addExecutable(b, opts, .{ .name = "main" });
3896 exe.addObject(a_o);3896 exe.root_module.addObject(a_o);
3897 exe.addObject(b_o);3897 exe.root_module.addObject(b_o);
3898 exe.addObject(c_o);3898 exe.root_module.addObject(c_o);
3899 exe.linkLibC();3899 exe.root_module.link_libc = true;
39003900
3901 const run = addRunArtifact(exe);3901 const run = addRunArtifact(exe);
3902 run.expectStdOutEqual("42\n");3902 run.expectStdOutEqual("42\n");
...@@ -3905,13 +3905,13 @@ fn testTlsSmallAlignment(b: *Build, opts: Options) *Step {...@@ -3905,13 +3905,13 @@ fn testTlsSmallAlignment(b: *Build, opts: Options) *Step {
39053905
3906 {3906 {
3907 const dso = addSharedLibrary(b, opts, .{ .name = "a" });3907 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
3908 dso.addObject(a_o);3908 dso.root_module.addObject(a_o);
3909 dso.addObject(b_o);3909 dso.root_module.addObject(b_o);
39103910
3911 const exe = addExecutable(b, opts, .{ .name = "main" });3911 const exe = addExecutable(b, opts, .{ .name = "main" });
3912 exe.addObject(c_o);3912 exe.root_module.addObject(c_o);
3913 exe.linkLibrary(dso);3913 exe.root_module.linkLibrary(dso);
3914 exe.linkLibC();3914 exe.root_module.link_libc = true;
39153915
3916 const run = addRunArtifact(exe);3916 const run = addRunArtifact(exe);
3917 run.expectStdOutEqual("42\n");3917 run.expectStdOutEqual("42\n");
...@@ -3939,7 +3939,7 @@ fn testTlsStatic(b: *Build, opts: Options) *Step {...@@ -3939,7 +3939,7 @@ fn testTlsStatic(b: *Build, opts: Options) *Step {
3939 \\ return 0;3939 \\ return 0;
3940 \\}3940 \\}
3941 , &.{});3941 , &.{});
3942 exe.linkLibC();3942 exe.root_module.link_libc = true;
39433943
3944 const run = addRunArtifact(exe);3944 const run = addRunArtifact(exe);
3945 run.expectStdOutEqual(3945 run.expectStdOutEqual(
...@@ -3969,8 +3969,8 @@ fn testUnknownFileTypeError(b: *Build, opts: Options) *Step {...@@ -3969,8 +3969,8 @@ fn testUnknownFileTypeError(b: *Build, opts: Options) *Step {
3969 \\ return foo;3969 \\ return foo;
3970 \\}3970 \\}
3971 , &.{});3971 , &.{});
3972 exe.linkLibrary(dylib);3972 exe.root_module.linkLibrary(dylib);
3973 exe.linkLibC();3973 exe.root_module.link_libc = true;
39743974
3975 expectLinkErrors(exe, test_step, .{3975 expectLinkErrors(exe, test_step, .{
3976 .contains = "error: failed to parse shared library: BadMagic",3976 .contains = "error: failed to parse shared library: BadMagic",
...@@ -3993,7 +3993,7 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step {...@@ -3993,7 +3993,7 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step {
3993 ,3993 ,
3994 .c_source_flags = &.{"-ffunction-sections"},3994 .c_source_flags = &.{"-ffunction-sections"},
3995 });3995 });
3996 obj1.linkLibC();3996 obj1.root_module.link_libc = true;
39973997
3998 const obj2 = addObject(b, opts, .{3998 const obj2 = addObject(b, opts, .{
3999 .name = "b",3999 .name = "b",
...@@ -4007,12 +4007,12 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step {...@@ -4007,12 +4007,12 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step {
4007 ,4007 ,
4008 .c_source_flags = &.{"-ffunction-sections"},4008 .c_source_flags = &.{"-ffunction-sections"},
4009 });4009 });
4010 obj2.linkLibC();4010 obj2.root_module.link_libc = true;
40114011
4012 const exe = addExecutable(b, opts, .{ .name = "main" });4012 const exe = addExecutable(b, opts, .{ .name = "main" });
4013 exe.addObject(obj1);4013 exe.root_module.addObject(obj1);
4014 exe.addObject(obj2);4014 exe.root_module.addObject(obj2);
4015 exe.linkLibC();4015 exe.root_module.link_libc = true;
40164016
4017 expectLinkErrors(exe, test_step, .{ .exact = &.{4017 expectLinkErrors(exe, test_step, .{ .exact = &.{
4018 "error: undefined symbol: foo",4018 "error: undefined symbol: foo",
...@@ -4037,12 +4037,12 @@ fn testWeakExports(b: *Build, opts: Options) *Step {...@@ -4037,12 +4037,12 @@ fn testWeakExports(b: *Build, opts: Options) *Step {
4037 ,4037 ,
4038 .pic = true,4038 .pic = true,
4039 });4039 });
4040 obj.linkLibC();4040 obj.root_module.link_libc = true;
40414041
4042 {4042 {
4043 const dso = addSharedLibrary(b, opts, .{ .name = "a" });4043 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
4044 dso.addObject(obj);4044 dso.root_module.addObject(obj);
4045 dso.linkLibC();4045 dso.root_module.link_libc = true;
40464046
4047 const check = dso.checkObject();4047 const check = dso.checkObject();
4048 check.checkInDynamicSymtab();4048 check.checkInDynamicSymtab();
...@@ -4052,8 +4052,8 @@ fn testWeakExports(b: *Build, opts: Options) *Step {...@@ -4052,8 +4052,8 @@ fn testWeakExports(b: *Build, opts: Options) *Step {
40524052
4053 {4053 {
4054 const exe = addExecutable(b, opts, .{ .name = "main" });4054 const exe = addExecutable(b, opts, .{ .name = "main" });
4055 exe.addObject(obj);4055 exe.root_module.addObject(obj);
4056 exe.linkLibC();4056 exe.root_module.link_libc = true;
40574057
4058 const check = exe.checkObject();4058 const check = exe.checkObject();
4059 check.checkInDynamicSymtab();4059 check.checkInDynamicSymtab();
...@@ -4084,8 +4084,8 @@ fn testWeakUndefsDso(b: *Build, opts: Options) *Step {...@@ -4084,8 +4084,8 @@ fn testWeakUndefsDso(b: *Build, opts: Options) *Step {
4084 \\int bar();4084 \\int bar();
4085 \\int main() { printf("bar=%d\n", bar()); }4085 \\int main() { printf("bar=%d\n", bar()); }
4086 , &.{});4086 , &.{});
4087 exe.linkLibrary(dso);4087 exe.root_module.linkLibrary(dso);
4088 exe.linkLibC();4088 exe.root_module.link_libc = true;
40894089
4090 const run = addRunArtifact(exe);4090 const run = addRunArtifact(exe);
4091 run.expectStdOutEqual("bar=-1\n");4091 run.expectStdOutEqual("bar=-1\n");
...@@ -4100,8 +4100,8 @@ fn testWeakUndefsDso(b: *Build, opts: Options) *Step {...@@ -4100,8 +4100,8 @@ fn testWeakUndefsDso(b: *Build, opts: Options) *Step {
4100 \\int bar();4100 \\int bar();
4101 \\int main() { printf("bar=%d\n", bar()); }4101 \\int main() { printf("bar=%d\n", bar()); }
4102 , &.{});4102 , &.{});
4103 exe.linkLibrary(dso);4103 exe.root_module.linkLibrary(dso);
4104 exe.linkLibC();4104 exe.root_module.link_libc = true;
41054105
4106 const run = addRunArtifact(exe);4106 const run = addRunArtifact(exe);
4107 run.expectStdOutEqual("bar=5\n");4107 run.expectStdOutEqual("bar=5\n");
...@@ -4122,7 +4122,7 @@ fn testZNow(b: *Build, opts: Options) *Step {...@@ -4122,7 +4122,7 @@ fn testZNow(b: *Build, opts: Options) *Step {
41224122
4123 {4123 {
4124 const dso = addSharedLibrary(b, opts, .{ .name = "a" });4124 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
4125 dso.addObject(obj);4125 dso.root_module.addObject(obj);
41264126
4127 const check = dso.checkObject();4127 const check = dso.checkObject();
4128 check.checkInDynamicSection();4128 check.checkInDynamicSection();
...@@ -4132,7 +4132,7 @@ fn testZNow(b: *Build, opts: Options) *Step {...@@ -4132,7 +4132,7 @@ fn testZNow(b: *Build, opts: Options) *Step {
41324132
4133 {4133 {
4134 const dso = addSharedLibrary(b, opts, .{ .name = "a" });4134 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
4135 dso.addObject(obj);4135 dso.root_module.addObject(obj);
4136 dso.link_z_lazy = true;4136 dso.link_z_lazy = true;
41374137
4138 const check = dso.checkObject();4138 const check = dso.checkObject();
...@@ -4150,7 +4150,7 @@ fn testZStackSize(b: *Build, opts: Options) *Step {...@@ -4150,7 +4150,7 @@ fn testZStackSize(b: *Build, opts: Options) *Step {
4150 const exe = addExecutable(b, opts, .{ .name = "main" });4150 const exe = addExecutable(b, opts, .{ .name = "main" });
4151 addCSourceBytes(exe, "int main() { return 0; }", &.{});4151 addCSourceBytes(exe, "int main() { return 0; }", &.{});
4152 exe.stack_size = 0x800000;4152 exe.stack_size = 0x800000;
4153 exe.linkLibC();4153 exe.root_module.link_libc = true;
41544154
4155 const check = exe.checkObject();4155 const check = exe.checkObject();
4156 check.checkInHeaders();4156 check.checkInHeaders();
...@@ -4202,8 +4202,8 @@ fn testZText(b: *Build, opts: Options) *Step {...@@ -4202,8 +4202,8 @@ fn testZText(b: *Build, opts: Options) *Step {
4202 });4202 });
42034203
4204 const dso = addSharedLibrary(b, opts, .{ .name = "a" });4204 const dso = addSharedLibrary(b, opts, .{ .name = "a" });
4205 dso.addObject(a_o);4205 dso.root_module.addObject(a_o);
4206 dso.addObject(b_o);4206 dso.root_module.addObject(b_o);
4207 dso.link_z_notext = true;4207 dso.link_z_notext = true;
42084208
4209 const exe = addExecutable(b, opts, .{ .name = "main" });4209 const exe = addExecutable(b, opts, .{ .name = "main" });
...@@ -4214,8 +4214,8 @@ fn testZText(b: *Build, opts: Options) *Step {...@@ -4214,8 +4214,8 @@ fn testZText(b: *Build, opts: Options) *Step {
4214 \\ printf("%d\n", fnn());4214 \\ printf("%d\n", fnn());
4215 \\}4215 \\}
4216 , &.{});4216 , &.{});
4217 exe.linkLibrary(dso);4217 exe.root_module.linkLibrary(dso);
4218 exe.linkLibC();4218 exe.root_module.link_libc = true;
42194219
4220 const run = addRunArtifact(exe);4220 const run = addRunArtifact(exe);
4221 run.expectStdOutEqual("3\n");4221 run.expectStdOutEqual("3\n");
test/link/link.zig+3-3
...@@ -140,20 +140,20 @@ pub fn addRunArtifact(comp: *Compile) *Run {...@@ -140,20 +140,20 @@ pub fn addRunArtifact(comp: *Compile) *Run {
140pub fn addCSourceBytes(comp: *Compile, bytes: []const u8, flags: []const []const u8) void {140pub fn addCSourceBytes(comp: *Compile, bytes: []const u8, flags: []const []const u8) void {
141 const b = comp.step.owner;141 const b = comp.step.owner;
142 const file = WriteFile.create(b).add("a.c", bytes);142 const file = WriteFile.create(b).add("a.c", bytes);
143 comp.addCSourceFile(.{ .file = file, .flags = flags });143 comp.root_module.addCSourceFile(.{ .file = file, .flags = flags });
144}144}
145145
146pub fn addCppSourceBytes(comp: *Compile, bytes: []const u8, flags: []const []const u8) void {146pub fn addCppSourceBytes(comp: *Compile, bytes: []const u8, flags: []const []const u8) void {
147 const b = comp.step.owner;147 const b = comp.step.owner;
148 const file = WriteFile.create(b).add("a.cpp", bytes);148 const file = WriteFile.create(b).add("a.cpp", bytes);
149 comp.addCSourceFile(.{ .file = file, .flags = flags });149 comp.root_module.addCSourceFile(.{ .file = file, .flags = flags });
150}150}
151151
152pub fn addAsmSourceBytes(comp: *Compile, bytes: []const u8) void {152pub fn addAsmSourceBytes(comp: *Compile, bytes: []const u8) void {
153 const b = comp.step.owner;153 const b = comp.step.owner;
154 const actual_bytes = std.fmt.allocPrint(b.allocator, "{s}\n", .{bytes}) catch @panic("OOM");154 const actual_bytes = std.fmt.allocPrint(b.allocator, "{s}\n", .{bytes}) catch @panic("OOM");
155 const file = WriteFile.create(b).add("a.s", actual_bytes);155 const file = WriteFile.create(b).add("a.s", actual_bytes);
156 comp.addAssemblyFile(file);156 comp.root_module.addAssemblyFile(file);
157}157}
158158
159pub fn expectLinkErrors(comp: *Compile, test_step: *Step, expected_errors: Compile.ExpectedCompileErrors) void {159pub fn expectLinkErrors(comp: *Compile, test_step: *Step, expected_errors: Compile.ExpectedCompileErrors) void {
test/link/macho.zig+123-123
...@@ -127,7 +127,7 @@ fn testDeadStrip(b: *Build, opts: Options) *Step {...@@ -127,7 +127,7 @@ fn testDeadStrip(b: *Build, opts: Options) *Step {
127127
128 {128 {
129 const exe = addExecutable(b, opts, .{ .name = "no_dead_strip" });129 const exe = addExecutable(b, opts, .{ .name = "no_dead_strip" });
130 exe.addObject(obj);130 exe.root_module.addObject(obj);
131 exe.link_gc_sections = false;131 exe.link_gc_sections = false;
132132
133 const check = exe.checkObject();133 const check = exe.checkObject();
...@@ -156,7 +156,7 @@ fn testDeadStrip(b: *Build, opts: Options) *Step {...@@ -156,7 +156,7 @@ fn testDeadStrip(b: *Build, opts: Options) *Step {
156156
157 {157 {
158 const exe = addExecutable(b, opts, .{ .name = "yes_dead_strip" });158 const exe = addExecutable(b, opts, .{ .name = "yes_dead_strip" });
159 exe.addObject(obj);159 exe.root_module.addObject(obj);
160 exe.link_gc_sections = true;160 exe.link_gc_sections = true;
161161
162 const check = exe.checkObject();162 const check = exe.checkObject();
...@@ -206,7 +206,7 @@ fn testDuplicateDefinitions(b: *Build, opts: Options) *Step {...@@ -206,7 +206,7 @@ fn testDuplicateDefinitions(b: *Build, opts: Options) *Step {
206 \\ strong();206 \\ strong();
207 \\}207 \\}
208 });208 });
209 exe.addObject(obj);209 exe.root_module.addObject(obj);
210210
211 expectLinkErrors(exe, test_step, .{ .exact = &.{211 expectLinkErrors(exe, test_step, .{ .exact = &.{
212 "error: duplicate symbol definition: _strong",212 "error: duplicate symbol definition: _strong",
...@@ -235,7 +235,7 @@ fn testDeadStripDylibs(b: *Build, opts: Options) *Step {...@@ -235,7 +235,7 @@ fn testDeadStripDylibs(b: *Build, opts: Options) *Step {
235235
236 {236 {
237 const exe = addExecutable(b, opts, .{ .name = "main1" });237 const exe = addExecutable(b, opts, .{ .name = "main1" });
238 exe.addObject(main_o);238 exe.root_module.addObject(main_o);
239 exe.root_module.linkFramework("Cocoa", .{});239 exe.root_module.linkFramework("Cocoa", .{});
240240
241 const check = exe.checkObject();241 const check = exe.checkObject();
...@@ -254,7 +254,7 @@ fn testDeadStripDylibs(b: *Build, opts: Options) *Step {...@@ -254,7 +254,7 @@ fn testDeadStripDylibs(b: *Build, opts: Options) *Step {
254254
255 {255 {
256 const exe = addExecutable(b, opts, .{ .name = "main2" });256 const exe = addExecutable(b, opts, .{ .name = "main2" });
257 exe.addObject(main_o);257 exe.root_module.addObject(main_o);
258 exe.root_module.linkFramework("Cocoa", .{});258 exe.root_module.linkFramework("Cocoa", .{});
259 exe.dead_strip_dylibs = true;259 exe.dead_strip_dylibs = true;
260260
...@@ -350,7 +350,7 @@ fn testEmptyObject(b: *Build, opts: Options) *Step {...@@ -350,7 +350,7 @@ fn testEmptyObject(b: *Build, opts: Options) *Step {
350 \\ printf("Hello world!");350 \\ printf("Hello world!");
351 \\}351 \\}
352 });352 });
353 exe.addObject(empty);353 exe.root_module.addObject(empty);
354354
355 const run = addRunArtifact(exe);355 const run = addRunArtifact(exe);
356 run.expectStdOutEqual("Hello world!");356 run.expectStdOutEqual("Hello world!");
...@@ -451,7 +451,7 @@ fn testEntryPointDylib(b: *Build, opts: Options) *Step {...@@ -451,7 +451,7 @@ fn testEntryPointDylib(b: *Build, opts: Options) *Step {
451 \\ return 0;451 \\ return 0;
452 \\}452 \\}
453 , &.{});453 , &.{});
454 exe.linkLibrary(dylib);454 exe.root_module.linkLibrary(dylib);
455 exe.entry = .{ .symbol_name = "_bootstrap" };455 exe.entry = .{ .symbol_name = "_bootstrap" };
456 exe.forceUndefinedSymbol("_my_main");456 exe.forceUndefinedSymbol("_my_main");
457457
...@@ -604,11 +604,11 @@ fn testHeaderWeakFlags(b: *Build, opts: Options) *Step {...@@ -604,11 +604,11 @@ fn testHeaderWeakFlags(b: *Build, opts: Options) *Step {
604 });604 });
605605
606 const lib = addSharedLibrary(b, opts, .{ .name = "a" });606 const lib = addSharedLibrary(b, opts, .{ .name = "a" });
607 lib.addObject(obj1);607 lib.root_module.addObject(obj1);
608608
609 {609 {
610 const exe = addExecutable(b, opts, .{ .name = "main1", .c_source_bytes = "int main() { return 0; }" });610 const exe = addExecutable(b, opts, .{ .name = "main1", .c_source_bytes = "int main() { return 0; }" });
611 exe.addObject(obj1);611 exe.root_module.addObject(obj1);
612612
613 const check = exe.checkObject();613 const check = exe.checkObject();
614 check.checkInHeaders();614 check.checkInHeaders();
...@@ -642,8 +642,8 @@ fn testHeaderWeakFlags(b: *Build, opts: Options) *Step {...@@ -642,8 +642,8 @@ fn testHeaderWeakFlags(b: *Build, opts: Options) *Step {
642 }642 }
643643
644 const exe = addExecutable(b, opts, .{ .name = "main2" });644 const exe = addExecutable(b, opts, .{ .name = "main2" });
645 exe.linkLibrary(lib);645 exe.root_module.linkLibrary(lib);
646 exe.addObject(obj);646 exe.root_module.addObject(obj);
647647
648 const check = exe.checkObject();648 const check = exe.checkObject();
649 check.checkInHeaders();649 check.checkInHeaders();
...@@ -665,7 +665,7 @@ fn testHeaderWeakFlags(b: *Build, opts: Options) *Step {...@@ -665,7 +665,7 @@ fn testHeaderWeakFlags(b: *Build, opts: Options) *Step {
665 \\_main:665 \\_main:
666 \\ ret666 \\ ret
667 });667 });
668 exe.linkLibrary(lib);668 exe.root_module.linkLibrary(lib);
669669
670 const check = exe.checkObject();670 const check = exe.checkObject();
671 check.checkInHeaders();671 check.checkInHeaders();
...@@ -910,7 +910,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {...@@ -910,7 +910,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
910 \\}910 \\}
911 ,911 ,
912 });912 });
913 lib.addObject(obj);913 lib.root_module.addObject(obj);
914914
915 const exe = addExecutable(b, opts, .{915 const exe = addExecutable(b, opts, .{
916 .name = "testlib",916 .name = "testlib",
...@@ -923,7 +923,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {...@@ -923,7 +923,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step {
923 \\}923 \\}
924 ,924 ,
925 });925 });
926 exe.linkLibrary(lib);926 exe.root_module.linkLibrary(lib);
927927
928 const run = addRunArtifact(exe);928 const run = addRunArtifact(exe);
929 run.expectStdErrEqual("0\n");929 run.expectStdErrEqual("0\n");
...@@ -1051,28 +1051,28 @@ fn testMergeLiteralsX64(b: *Build, opts: Options) *Step {...@@ -1051,28 +1051,28 @@ fn testMergeLiteralsX64(b: *Build, opts: Options) *Step {
10511051
1052 {1052 {
1053 const exe = addExecutable(b, opts, .{ .name = "main1" });1053 const exe = addExecutable(b, opts, .{ .name = "main1" });
1054 exe.addObject(a_o);1054 exe.root_module.addObject(a_o);
1055 exe.addObject(b_o);1055 exe.root_module.addObject(b_o);
1056 exe.addObject(main_o);1056 exe.root_module.addObject(main_o);
1057 runWithChecks(test_step, exe);1057 runWithChecks(test_step, exe);
1058 }1058 }
10591059
1060 {1060 {
1061 const exe = addExecutable(b, opts, .{ .name = "main2" });1061 const exe = addExecutable(b, opts, .{ .name = "main2" });
1062 exe.addObject(b_o);1062 exe.root_module.addObject(b_o);
1063 exe.addObject(a_o);1063 exe.root_module.addObject(a_o);
1064 exe.addObject(main_o);1064 exe.root_module.addObject(main_o);
1065 runWithChecks(test_step, exe);1065 runWithChecks(test_step, exe);
1066 }1066 }
10671067
1068 {1068 {
1069 const c_o = addObject(b, opts, .{ .name = "c" });1069 const c_o = addObject(b, opts, .{ .name = "c" });
1070 c_o.addObject(a_o);1070 c_o.root_module.addObject(a_o);
1071 c_o.addObject(b_o);1071 c_o.root_module.addObject(b_o);
1072 c_o.addObject(main_o);1072 c_o.root_module.addObject(main_o);
10731073
1074 const exe = addExecutable(b, opts, .{ .name = "main3" });1074 const exe = addExecutable(b, opts, .{ .name = "main3" });
1075 exe.addObject(c_o);1075 exe.root_module.addObject(c_o);
1076 runWithChecks(test_step, exe);1076 runWithChecks(test_step, exe);
1077 }1077 }
10781078
...@@ -1167,28 +1167,28 @@ fn testMergeLiteralsArm64(b: *Build, opts: Options) *Step {...@@ -1167,28 +1167,28 @@ fn testMergeLiteralsArm64(b: *Build, opts: Options) *Step {
11671167
1168 {1168 {
1169 const exe = addExecutable(b, opts, .{ .name = "main1" });1169 const exe = addExecutable(b, opts, .{ .name = "main1" });
1170 exe.addObject(a_o);1170 exe.root_module.addObject(a_o);
1171 exe.addObject(b_o);1171 exe.root_module.addObject(b_o);
1172 exe.addObject(main_o);1172 exe.root_module.addObject(main_o);
1173 runWithChecks(test_step, exe);1173 runWithChecks(test_step, exe);
1174 }1174 }
11751175
1176 {1176 {
1177 const exe = addExecutable(b, opts, .{ .name = "main2" });1177 const exe = addExecutable(b, opts, .{ .name = "main2" });
1178 exe.addObject(b_o);1178 exe.root_module.addObject(b_o);
1179 exe.addObject(a_o);1179 exe.root_module.addObject(a_o);
1180 exe.addObject(main_o);1180 exe.root_module.addObject(main_o);
1181 runWithChecks(test_step, exe);1181 runWithChecks(test_step, exe);
1182 }1182 }
11831183
1184 {1184 {
1185 const c_o = addObject(b, opts, .{ .name = "c" });1185 const c_o = addObject(b, opts, .{ .name = "c" });
1186 c_o.addObject(a_o);1186 c_o.root_module.addObject(a_o);
1187 c_o.addObject(b_o);1187 c_o.root_module.addObject(b_o);
1188 c_o.addObject(main_o);1188 c_o.root_module.addObject(main_o);
11891189
1190 const exe = addExecutable(b, opts, .{ .name = "main3" });1190 const exe = addExecutable(b, opts, .{ .name = "main3" });
1191 exe.addObject(c_o);1191 exe.root_module.addObject(c_o);
1192 runWithChecks(test_step, exe);1192 runWithChecks(test_step, exe);
1193 }1193 }
11941194
...@@ -1259,9 +1259,9 @@ fn testMergeLiteralsArm642(b: *Build, opts: Options) *Step {...@@ -1259,9 +1259,9 @@ fn testMergeLiteralsArm642(b: *Build, opts: Options) *Step {
1259 });1259 });
12601260
1261 const exe = addExecutable(b, opts, .{ .name = "main1" });1261 const exe = addExecutable(b, opts, .{ .name = "main1" });
1262 exe.addObject(a_o);1262 exe.root_module.addObject(a_o);
1263 exe.addObject(b_o);1263 exe.root_module.addObject(b_o);
1264 exe.addObject(main_o);1264 exe.root_module.addObject(main_o);
12651265
1266 const check = exe.checkObject();1266 const check = exe.checkObject();
1267 check.dumpSection("__TEXT,__const");1267 check.dumpSection("__TEXT,__const");
...@@ -1335,17 +1335,17 @@ fn testMergeLiteralsAlignment(b: *Build, opts: Options) *Step {...@@ -1335,17 +1335,17 @@ fn testMergeLiteralsAlignment(b: *Build, opts: Options) *Step {
13351335
1336 {1336 {
1337 const exe = addExecutable(b, opts, .{ .name = "main1" });1337 const exe = addExecutable(b, opts, .{ .name = "main1" });
1338 exe.addObject(a_o);1338 exe.root_module.addObject(a_o);
1339 exe.addObject(b_o);1339 exe.root_module.addObject(b_o);
1340 exe.addObject(main_o);1340 exe.root_module.addObject(main_o);
1341 runWithChecks(test_step, exe);1341 runWithChecks(test_step, exe);
1342 }1342 }
13431343
1344 {1344 {
1345 const exe = addExecutable(b, opts, .{ .name = "main2" });1345 const exe = addExecutable(b, opts, .{ .name = "main2" });
1346 exe.addObject(b_o);1346 exe.root_module.addObject(b_o);
1347 exe.addObject(a_o);1347 exe.root_module.addObject(a_o);
1348 exe.addObject(main_o);1348 exe.root_module.addObject(main_o);
1349 runWithChecks(test_step, exe);1349 runWithChecks(test_step, exe);
1350 }1350 }
13511351
...@@ -1414,27 +1414,27 @@ fn testMergeLiteralsObjc(b: *Build, opts: Options) *Step {...@@ -1414,27 +1414,27 @@ fn testMergeLiteralsObjc(b: *Build, opts: Options) *Step {
14141414
1415 {1415 {
1416 const exe = addExecutable(b, opts, .{ .name = "main1" });1416 const exe = addExecutable(b, opts, .{ .name = "main1" });
1417 exe.addObject(main_o);1417 exe.root_module.addObject(main_o);
1418 exe.addObject(a_o);1418 exe.root_module.addObject(a_o);
1419 exe.root_module.linkFramework("Foundation", .{});1419 exe.root_module.linkFramework("Foundation", .{});
1420 runWithChecks(test_step, exe);1420 runWithChecks(test_step, exe);
1421 }1421 }
14221422
1423 {1423 {
1424 const exe = addExecutable(b, opts, .{ .name = "main2" });1424 const exe = addExecutable(b, opts, .{ .name = "main2" });
1425 exe.addObject(a_o);1425 exe.root_module.addObject(a_o);
1426 exe.addObject(main_o);1426 exe.root_module.addObject(main_o);
1427 exe.root_module.linkFramework("Foundation", .{});1427 exe.root_module.linkFramework("Foundation", .{});
1428 runWithChecks(test_step, exe);1428 runWithChecks(test_step, exe);
1429 }1429 }
14301430
1431 {1431 {
1432 const b_o = addObject(b, opts, .{ .name = "b" });1432 const b_o = addObject(b, opts, .{ .name = "b" });
1433 b_o.addObject(a_o);1433 b_o.root_module.addObject(a_o);
1434 b_o.addObject(main_o);1434 b_o.root_module.addObject(main_o);
14351435
1436 const exe = addExecutable(b, opts, .{ .name = "main3" });1436 const exe = addExecutable(b, opts, .{ .name = "main3" });
1437 exe.addObject(b_o);1437 exe.root_module.addObject(b_o);
1438 exe.root_module.linkFramework("Foundation", .{});1438 exe.root_module.linkFramework("Foundation", .{});
1439 runWithChecks(test_step, exe);1439 runWithChecks(test_step, exe);
1440 }1440 }
...@@ -1610,7 +1610,7 @@ fn testObjcpp(b: *Build, opts: Options) *Step {...@@ -1610,7 +1610,7 @@ fn testObjcpp(b: *Build, opts: Options) *Step {
1610 \\@end1610 \\@end
1611 });1611 });
1612 foo_o.root_module.addIncludePath(foo_h.dirname());1612 foo_o.root_module.addIncludePath(foo_h.dirname());
1613 foo_o.linkLibCpp();1613 foo_o.root_module.link_libcpp = true;
16141614
1615 const exe = addExecutable(b, opts, .{ .name = "main", .objcpp_source_bytes = 1615 const exe = addExecutable(b, opts, .{ .name = "main", .objcpp_source_bytes =
1616 \\#import "Foo.h"1616 \\#import "Foo.h"
...@@ -1628,8 +1628,8 @@ fn testObjcpp(b: *Build, opts: Options) *Step {...@@ -1628,8 +1628,8 @@ fn testObjcpp(b: *Build, opts: Options) *Step {
1628 \\}1628 \\}
1629 });1629 });
1630 exe.root_module.addIncludePath(foo_h.dirname());1630 exe.root_module.addIncludePath(foo_h.dirname());
1631 exe.addObject(foo_o);1631 exe.root_module.addObject(foo_o);
1632 exe.linkLibCpp();1632 exe.root_module.link_libcpp = true;
1633 exe.root_module.linkFramework("Foundation", .{});1633 exe.root_module.linkFramework("Foundation", .{});
16341634
1635 const run = addRunArtifact(exe);1635 const run = addRunArtifact(exe);
...@@ -1693,7 +1693,7 @@ fn testReexportsZig(b: *Build, opts: Options) *Step {...@@ -1693,7 +1693,7 @@ fn testReexportsZig(b: *Build, opts: Options) *Step {
1693 \\ return bar() - foo();1693 \\ return bar() - foo();
1694 \\}1694 \\}
1695 });1695 });
1696 exe.linkLibrary(lib);1696 exe.root_module.linkLibrary(lib);
16971697
1698 const run = addRunArtifact(exe);1698 const run = addRunArtifact(exe);
1699 run.expectExitCode(0);1699 run.expectExitCode(0);
...@@ -1711,7 +1711,7 @@ fn testRelocatable(b: *Build, opts: Options) *Step {...@@ -1711,7 +1711,7 @@ fn testRelocatable(b: *Build, opts: Options) *Step {
1711 \\ throw std::runtime_error("Oh no!");1711 \\ throw std::runtime_error("Oh no!");
1712 \\}1712 \\}
1713 });1713 });
1714 a_o.linkLibCpp();1714 a_o.root_module.link_libcpp = true;
17151715
1716 const b_o = addObject(b, opts, .{ .name = "b", .cpp_source_bytes = 1716 const b_o = addObject(b, opts, .{ .name = "b", .cpp_source_bytes =
1717 \\extern int try_me();1717 \\extern int try_me();
...@@ -1733,19 +1733,19 @@ fn testRelocatable(b: *Build, opts: Options) *Step {...@@ -1733,19 +1733,19 @@ fn testRelocatable(b: *Build, opts: Options) *Step {
1733 \\ return 0;1733 \\ return 0;
1734 \\}1734 \\}
1735 });1735 });
1736 main_o.linkLibCpp();1736 main_o.root_module.link_libcpp = true;
17371737
1738 const exp_stdout = "exception=Oh no!";1738 const exp_stdout = "exception=Oh no!";
17391739
1740 {1740 {
1741 const c_o = addObject(b, opts, .{ .name = "c" });1741 const c_o = addObject(b, opts, .{ .name = "c" });
1742 c_o.addObject(a_o);1742 c_o.root_module.addObject(a_o);
1743 c_o.addObject(b_o);1743 c_o.root_module.addObject(b_o);
17441744
1745 const exe = addExecutable(b, opts, .{ .name = "main1" });1745 const exe = addExecutable(b, opts, .{ .name = "main1" });
1746 exe.addObject(main_o);1746 exe.root_module.addObject(main_o);
1747 exe.addObject(c_o);1747 exe.root_module.addObject(c_o);
1748 exe.linkLibCpp();1748 exe.root_module.link_libcpp = true;
17491749
1750 const run = addRunArtifact(exe);1750 const run = addRunArtifact(exe);
1751 run.expectStdOutEqual(exp_stdout);1751 run.expectStdOutEqual(exp_stdout);
...@@ -1754,13 +1754,13 @@ fn testRelocatable(b: *Build, opts: Options) *Step {...@@ -1754,13 +1754,13 @@ fn testRelocatable(b: *Build, opts: Options) *Step {
17541754
1755 {1755 {
1756 const d_o = addObject(b, opts, .{ .name = "d" });1756 const d_o = addObject(b, opts, .{ .name = "d" });
1757 d_o.addObject(a_o);1757 d_o.root_module.addObject(a_o);
1758 d_o.addObject(b_o);1758 d_o.root_module.addObject(b_o);
1759 d_o.addObject(main_o);1759 d_o.root_module.addObject(main_o);
17601760
1761 const exe = addExecutable(b, opts, .{ .name = "main2" });1761 const exe = addExecutable(b, opts, .{ .name = "main2" });
1762 exe.addObject(d_o);1762 exe.root_module.addObject(d_o);
1763 exe.linkLibCpp();1763 exe.root_module.link_libcpp = true;
17641764
1765 const run = addRunArtifact(exe);1765 const run = addRunArtifact(exe);
1766 run.expectStdOutEqual(exp_stdout);1766 run.expectStdOutEqual(exp_stdout);
...@@ -1805,12 +1805,12 @@ fn testRelocatableZig(b: *Build, opts: Options) *Step {...@@ -1805,12 +1805,12 @@ fn testRelocatableZig(b: *Build, opts: Options) *Step {
1805 });1805 });
18061806
1807 const c_o = addObject(b, opts, .{ .name = "c" });1807 const c_o = addObject(b, opts, .{ .name = "c" });
1808 c_o.addObject(a_o);1808 c_o.root_module.addObject(a_o);
1809 c_o.addObject(b_o);1809 c_o.root_module.addObject(b_o);
1810 c_o.addObject(main_o);1810 c_o.root_module.addObject(main_o);
18111811
1812 const exe = addExecutable(b, opts, .{ .name = "main" });1812 const exe = addExecutable(b, opts, .{ .name = "main" });
1813 exe.addObject(c_o);1813 exe.root_module.addObject(c_o);
18141814
1815 const run = addRunArtifact(exe);1815 const run = addRunArtifact(exe);
1816 run.addCheck(.{ .expect_stderr_match = b.dupe("incrFoo=1") });1816 run.addCheck(.{ .expect_stderr_match = b.dupe("incrFoo=1") });
...@@ -1833,10 +1833,10 @@ fn testSearchStrategy(b: *Build, opts: Options) *Step {...@@ -1833,10 +1833,10 @@ fn testSearchStrategy(b: *Build, opts: Options) *Step {
1833 });1833 });
18341834
1835 const liba = addStaticLibrary(b, opts, .{ .name = "a" });1835 const liba = addStaticLibrary(b, opts, .{ .name = "a" });
1836 liba.addObject(obj);1836 liba.root_module.addObject(obj);
18371837
1838 const dylib = addSharedLibrary(b, opts, .{ .name = "a" });1838 const dylib = addSharedLibrary(b, opts, .{ .name = "a" });
1839 dylib.addObject(obj);1839 dylib.root_module.addObject(obj);
18401840
1841 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = 1841 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes =
1842 \\#include<stdio.h>1842 \\#include<stdio.h>
...@@ -1850,7 +1850,7 @@ fn testSearchStrategy(b: *Build, opts: Options) *Step {...@@ -1850,7 +1850,7 @@ fn testSearchStrategy(b: *Build, opts: Options) *Step {
18501850
1851 {1851 {
1852 const exe = addExecutable(b, opts, .{ .name = "main" });1852 const exe = addExecutable(b, opts, .{ .name = "main" });
1853 exe.addObject(main_o);1853 exe.root_module.addObject(main_o);
1854 exe.root_module.linkSystemLibrary("a", .{ .use_pkg_config = .no, .search_strategy = .mode_first });1854 exe.root_module.linkSystemLibrary("a", .{ .use_pkg_config = .no, .search_strategy = .mode_first });
1855 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());1855 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());
1856 exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory());1856 exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory());
...@@ -1869,7 +1869,7 @@ fn testSearchStrategy(b: *Build, opts: Options) *Step {...@@ -1869,7 +1869,7 @@ fn testSearchStrategy(b: *Build, opts: Options) *Step {
18691869
1870 {1870 {
1871 const exe = addExecutable(b, opts, .{ .name = "main" });1871 const exe = addExecutable(b, opts, .{ .name = "main" });
1872 exe.addObject(main_o);1872 exe.root_module.addObject(main_o);
1873 exe.root_module.linkSystemLibrary("a", .{ .use_pkg_config = .no, .search_strategy = .paths_first });1873 exe.root_module.linkSystemLibrary("a", .{ .use_pkg_config = .no, .search_strategy = .paths_first });
1874 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());1874 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());
1875 exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory());1875 exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory());
...@@ -1924,9 +1924,9 @@ fn testSectionBoundarySymbols(b: *Build, opts: Options) *Step {...@@ -1924,9 +1924,9 @@ fn testSectionBoundarySymbols(b: *Build, opts: Options) *Step {
1924 });1924 });
19251925
1926 const exe = addExecutable(b, opts, .{ .name = "test" });1926 const exe = addExecutable(b, opts, .{ .name = "test" });
1927 exe.addObject(obj1);1927 exe.root_module.addObject(obj1);
1928 exe.addObject(obj2);1928 exe.root_module.addObject(obj2);
1929 exe.addObject(main_o);1929 exe.root_module.addObject(main_o);
19301930
1931 const run = b.addRunArtifact(exe);1931 const run = b.addRunArtifact(exe);
1932 run.skip_foreign_checks = true;1932 run.skip_foreign_checks = true;
...@@ -1951,9 +1951,9 @@ fn testSectionBoundarySymbols(b: *Build, opts: Options) *Step {...@@ -1951,9 +1951,9 @@ fn testSectionBoundarySymbols(b: *Build, opts: Options) *Step {
1951 });1951 });
19521952
1953 const exe = addExecutable(b, opts, .{ .name = "test" });1953 const exe = addExecutable(b, opts, .{ .name = "test" });
1954 exe.addObject(obj1);1954 exe.root_module.addObject(obj1);
1955 exe.addObject(obj3);1955 exe.root_module.addObject(obj3);
1956 exe.addObject(main_o);1956 exe.root_module.addObject(main_o);
19571957
1958 const run = b.addRunArtifact(exe);1958 const run = b.addRunArtifact(exe);
1959 run.skip_foreign_checks = true;1959 run.skip_foreign_checks = true;
...@@ -2031,9 +2031,9 @@ fn testSegmentBoundarySymbols(b: *Build, opts: Options) *Step {...@@ -2031,9 +2031,9 @@ fn testSegmentBoundarySymbols(b: *Build, opts: Options) *Step {
2031 });2031 });
20322032
2033 const exe = addExecutable(b, opts, .{ .name = "main" });2033 const exe = addExecutable(b, opts, .{ .name = "main" });
2034 exe.addObject(obj1);2034 exe.root_module.addObject(obj1);
2035 exe.addObject(obj2);2035 exe.root_module.addObject(obj2);
2036 exe.addObject(main_o);2036 exe.root_module.addObject(main_o);
20372037
2038 const run = addRunArtifact(exe);2038 const run = addRunArtifact(exe);
2039 run.expectStdOutEqual("All your codebase are belong to us.\n");2039 run.expectStdOutEqual("All your codebase are belong to us.\n");
...@@ -2054,9 +2054,9 @@ fn testSegmentBoundarySymbols(b: *Build, opts: Options) *Step {...@@ -2054,9 +2054,9 @@ fn testSegmentBoundarySymbols(b: *Build, opts: Options) *Step {
2054 });2054 });
20552055
2056 const exe = addExecutable(b, opts, .{ .name = "main2" });2056 const exe = addExecutable(b, opts, .{ .name = "main2" });
2057 exe.addObject(obj1);2057 exe.root_module.addObject(obj1);
2058 exe.addObject(obj2);2058 exe.root_module.addObject(obj2);
2059 exe.addObject(main_o);2059 exe.root_module.addObject(main_o);
20602060
2061 const check = exe.checkObject();2061 const check = exe.checkObject();
2062 check.checkInHeaders();2062 check.checkInHeaders();
...@@ -2102,9 +2102,9 @@ fn testSymbolStabs(b: *Build, opts: Options) *Step {...@@ -2102,9 +2102,9 @@ fn testSymbolStabs(b: *Build, opts: Options) *Step {
2102 });2102 });
21032103
2104 const exe = addExecutable(b, opts, .{ .name = "main" });2104 const exe = addExecutable(b, opts, .{ .name = "main" });
2105 exe.addObject(a_o);2105 exe.root_module.addObject(a_o);
2106 exe.addObject(b_o);2106 exe.root_module.addObject(b_o);
2107 exe.addObject(main_o);2107 exe.root_module.addObject(main_o);
21082108
2109 const run = addRunArtifact(exe);2109 const run = addRunArtifact(exe);
2110 run.expectStdOutEqual("foo=42,bar=24");2110 run.expectStdOutEqual("foo=42,bar=24");
...@@ -2299,7 +2299,7 @@ fn testTlsPointers(b: *Build, opts: Options) *Step {...@@ -2299,7 +2299,7 @@ fn testTlsPointers(b: *Build, opts: Options) *Step {
2299 \\}2299 \\}
2300 });2300 });
2301 bar_o.root_module.addIncludePath(foo_h.dirname());2301 bar_o.root_module.addIncludePath(foo_h.dirname());
2302 bar_o.linkLibCpp();2302 bar_o.root_module.link_libcpp = true;
23032303
2304 const baz_o = addObject(b, opts, .{ .name = "baz", .cpp_source_bytes = 2304 const baz_o = addObject(b, opts, .{ .name = "baz", .cpp_source_bytes =
2305 \\#include "foo.h"2305 \\#include "foo.h"
...@@ -2309,7 +2309,7 @@ fn testTlsPointers(b: *Build, opts: Options) *Step {...@@ -2309,7 +2309,7 @@ fn testTlsPointers(b: *Build, opts: Options) *Step {
2309 \\}2309 \\}
2310 });2310 });
2311 baz_o.root_module.addIncludePath(foo_h.dirname());2311 baz_o.root_module.addIncludePath(foo_h.dirname());
2312 baz_o.linkLibCpp();2312 baz_o.root_module.link_libcpp = true;
23132313
2314 const main_o = addObject(b, opts, .{ .name = "main", .cpp_source_bytes = 2314 const main_o = addObject(b, opts, .{ .name = "main", .cpp_source_bytes =
2315 \\extern int bar();2315 \\extern int bar();
...@@ -2321,13 +2321,13 @@ fn testTlsPointers(b: *Build, opts: Options) *Step {...@@ -2321,13 +2321,13 @@ fn testTlsPointers(b: *Build, opts: Options) *Step {
2321 \\}2321 \\}
2322 });2322 });
2323 main_o.root_module.addIncludePath(foo_h.dirname());2323 main_o.root_module.addIncludePath(foo_h.dirname());
2324 main_o.linkLibCpp();2324 main_o.root_module.link_libcpp = true;
23252325
2326 const exe = addExecutable(b, opts, .{ .name = "main" });2326 const exe = addExecutable(b, opts, .{ .name = "main" });
2327 exe.addObject(bar_o);2327 exe.root_module.addObject(bar_o);
2328 exe.addObject(baz_o);2328 exe.root_module.addObject(baz_o);
2329 exe.addObject(main_o);2329 exe.root_module.addObject(main_o);
2330 exe.linkLibCpp();2330 exe.root_module.link_libcpp = true;
23312331
2332 const run = addRunArtifact(exe);2332 const run = addRunArtifact(exe);
2333 run.expectExitCode(0);2333 run.expectExitCode(0);
...@@ -2445,7 +2445,7 @@ fn testTwoLevelNamespace(b: *Build, opts: Options) *Step {...@@ -2445,7 +2445,7 @@ fn testTwoLevelNamespace(b: *Build, opts: Options) *Step {
24452445
2446 {2446 {
2447 const exe = addExecutable(b, opts, .{ .name = "main1" });2447 const exe = addExecutable(b, opts, .{ .name = "main1" });
2448 exe.addObject(main_o);2448 exe.root_module.addObject(main_o);
2449 exe.root_module.linkSystemLibrary("a", .{});2449 exe.root_module.linkSystemLibrary("a", .{});
2450 exe.root_module.linkSystemLibrary("b", .{});2450 exe.root_module.linkSystemLibrary("b", .{});
2451 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());2451 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());
...@@ -2474,7 +2474,7 @@ fn testTwoLevelNamespace(b: *Build, opts: Options) *Step {...@@ -2474,7 +2474,7 @@ fn testTwoLevelNamespace(b: *Build, opts: Options) *Step {
24742474
2475 {2475 {
2476 const exe = addExecutable(b, opts, .{ .name = "main2" });2476 const exe = addExecutable(b, opts, .{ .name = "main2" });
2477 exe.addObject(main_o);2477 exe.root_module.addObject(main_o);
2478 exe.root_module.linkSystemLibrary("b", .{});2478 exe.root_module.linkSystemLibrary("b", .{});
2479 exe.root_module.linkSystemLibrary("a", .{});2479 exe.root_module.linkSystemLibrary("a", .{});
2480 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());2480 exe.root_module.addLibraryPath(liba.getEmittedBinDirectory());
...@@ -2510,14 +2510,14 @@ fn testDiscardLocalSymbols(b: *Build, opts: Options) *Step {...@@ -2510,14 +2510,14 @@ fn testDiscardLocalSymbols(b: *Build, opts: Options) *Step {
2510 const obj = addObject(b, opts, .{ .name = "a", .c_source_bytes = "static int foo = 42;" });2510 const obj = addObject(b, opts, .{ .name = "a", .c_source_bytes = "static int foo = 42;" });
25112511
2512 const lib = addStaticLibrary(b, opts, .{ .name = "a" });2512 const lib = addStaticLibrary(b, opts, .{ .name = "a" });
2513 lib.addObject(obj);2513 lib.root_module.addObject(obj);
25142514
2515 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });2515 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });
25162516
2517 {2517 {
2518 const exe = addExecutable(b, opts, .{ .name = "main3" });2518 const exe = addExecutable(b, opts, .{ .name = "main3" });
2519 exe.addObject(main_o);2519 exe.root_module.addObject(main_o);
2520 exe.addObject(obj);2520 exe.root_module.addObject(obj);
2521 exe.discard_local_symbols = true;2521 exe.discard_local_symbols = true;
25222522
2523 const run = addRunArtifact(exe);2523 const run = addRunArtifact(exe);
...@@ -2532,8 +2532,8 @@ fn testDiscardLocalSymbols(b: *Build, opts: Options) *Step {...@@ -2532,8 +2532,8 @@ fn testDiscardLocalSymbols(b: *Build, opts: Options) *Step {
25322532
2533 {2533 {
2534 const exe = addExecutable(b, opts, .{ .name = "main4" });2534 const exe = addExecutable(b, opts, .{ .name = "main4" });
2535 exe.addObject(main_o);2535 exe.root_module.addObject(main_o);
2536 exe.linkLibrary(lib);2536 exe.root_module.linkLibrary(lib);
2537 exe.discard_local_symbols = true;2537 exe.discard_local_symbols = true;
25382538
2539 const run = addRunArtifact(exe);2539 const run = addRunArtifact(exe);
...@@ -2555,14 +2555,14 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {...@@ -2555,14 +2555,14 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {
2555 const obj = addObject(b, opts, .{ .name = "a", .c_source_bytes = "int foo = 42;" });2555 const obj = addObject(b, opts, .{ .name = "a", .c_source_bytes = "int foo = 42;" });
25562556
2557 const lib = addStaticLibrary(b, opts, .{ .name = "a" });2557 const lib = addStaticLibrary(b, opts, .{ .name = "a" });
2558 lib.addObject(obj);2558 lib.root_module.addObject(obj);
25592559
2560 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });2560 const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" });
25612561
2562 {2562 {
2563 const exe = addExecutable(b, opts, .{ .name = "main1" });2563 const exe = addExecutable(b, opts, .{ .name = "main1" });
2564 exe.addObject(main_o);2564 exe.root_module.addObject(main_o);
2565 exe.linkLibrary(lib);2565 exe.root_module.linkLibrary(lib);
2566 exe.forceUndefinedSymbol("_foo");2566 exe.forceUndefinedSymbol("_foo");
25672567
2568 const run = addRunArtifact(exe);2568 const run = addRunArtifact(exe);
...@@ -2577,8 +2577,8 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {...@@ -2577,8 +2577,8 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {
25772577
2578 {2578 {
2579 const exe = addExecutable(b, opts, .{ .name = "main2" });2579 const exe = addExecutable(b, opts, .{ .name = "main2" });
2580 exe.addObject(main_o);2580 exe.root_module.addObject(main_o);
2581 exe.linkLibrary(lib);2581 exe.root_module.linkLibrary(lib);
2582 exe.forceUndefinedSymbol("_foo");2582 exe.forceUndefinedSymbol("_foo");
2583 exe.link_gc_sections = true;2583 exe.link_gc_sections = true;
25842584
...@@ -2594,8 +2594,8 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {...@@ -2594,8 +2594,8 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {
25942594
2595 {2595 {
2596 const exe = addExecutable(b, opts, .{ .name = "main3" });2596 const exe = addExecutable(b, opts, .{ .name = "main3" });
2597 exe.addObject(main_o);2597 exe.root_module.addObject(main_o);
2598 exe.addObject(obj);2598 exe.root_module.addObject(obj);
25992599
2600 const run = addRunArtifact(exe);2600 const run = addRunArtifact(exe);
2601 run.expectExitCode(0);2601 run.expectExitCode(0);
...@@ -2609,8 +2609,8 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {...@@ -2609,8 +2609,8 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step {
26092609
2610 {2610 {
2611 const exe = addExecutable(b, opts, .{ .name = "main4" });2611 const exe = addExecutable(b, opts, .{ .name = "main4" });
2612 exe.addObject(main_o);2612 exe.root_module.addObject(main_o);
2613 exe.addObject(obj);2613 exe.root_module.addObject(obj);
2614 exe.link_gc_sections = true;2614 exe.link_gc_sections = true;
26152615
2616 const run = addRunArtifact(exe);2616 const run = addRunArtifact(exe);
...@@ -2642,7 +2642,7 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step {...@@ -2642,7 +2642,7 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step {
2642 \\ std.debug.print("foo() + bar() = {d}", .{foo() + bar()});2642 \\ std.debug.print("foo() + bar() = {d}", .{foo() + bar()});
2643 \\}2643 \\}
2644 });2644 });
2645 exe.addObject(obj);2645 exe.root_module.addObject(obj);
26462646
2647 // TODO order should match across backends if possible2647 // TODO order should match across backends if possible
2648 if (opts.use_llvm) {2648 if (opts.use_llvm) {
...@@ -2764,7 +2764,7 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {...@@ -2764,7 +2764,7 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {
2764 \\}2764 \\}
2765 });2765 });
2766 main_o.root_module.addIncludePath(all_h.dirname());2766 main_o.root_module.addIncludePath(all_h.dirname());
2767 main_o.linkLibCpp();2767 main_o.root_module.link_libcpp = true;
27682768
2769 const simple_string_o = addObject(b, opts, .{ .name = "simple_string", .cpp_source_bytes = 2769 const simple_string_o = addObject(b, opts, .{ .name = "simple_string", .cpp_source_bytes =
2770 \\#include "all.h"2770 \\#include "all.h"
...@@ -2799,7 +2799,7 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {...@@ -2799,7 +2799,7 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {
2799 \\}2799 \\}
2800 });2800 });
2801 simple_string_o.root_module.addIncludePath(all_h.dirname());2801 simple_string_o.root_module.addIncludePath(all_h.dirname());
2802 simple_string_o.linkLibCpp();2802 simple_string_o.root_module.link_libcpp = true;
28032803
2804 const simple_string_owner_o = addObject(b, opts, .{ .name = "simple_string_owner", .cpp_source_bytes = 2804 const simple_string_owner_o = addObject(b, opts, .{ .name = "simple_string_owner", .cpp_source_bytes =
2805 \\#include "all.h"2805 \\#include "all.h"
...@@ -2816,7 +2816,7 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {...@@ -2816,7 +2816,7 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {
2816 \\}2816 \\}
2817 });2817 });
2818 simple_string_owner_o.root_module.addIncludePath(all_h.dirname());2818 simple_string_owner_o.root_module.addIncludePath(all_h.dirname());
2819 simple_string_owner_o.linkLibCpp();2819 simple_string_owner_o.root_module.link_libcpp = true;
28202820
2821 const exp_stdout =2821 const exp_stdout =
2822 \\Constructed: a2822 \\Constructed: a
...@@ -2828,10 +2828,10 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {...@@ -2828,10 +2828,10 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {
2828 ;2828 ;
28292829
2830 const exe = addExecutable(b, opts, .{ .name = "main" });2830 const exe = addExecutable(b, opts, .{ .name = "main" });
2831 exe.addObject(main_o);2831 exe.root_module.addObject(main_o);
2832 exe.addObject(simple_string_o);2832 exe.root_module.addObject(simple_string_o);
2833 exe.addObject(simple_string_owner_o);2833 exe.root_module.addObject(simple_string_owner_o);
2834 exe.linkLibCpp();2834 exe.root_module.link_libcpp = true;
28352835
2836 const run = addRunArtifact(exe);2836 const run = addRunArtifact(exe);
2837 run.expectStdOutEqual(exp_stdout);2837 run.expectStdOutEqual(exp_stdout);
...@@ -2896,7 +2896,7 @@ fn testUnwindInfoNoSubsectionsArm64(b: *Build, opts: Options) *Step {...@@ -2896,7 +2896,7 @@ fn testUnwindInfoNoSubsectionsArm64(b: *Build, opts: Options) *Step {
2896 \\ return 0;2896 \\ return 0;
2897 \\}2897 \\}
2898 });2898 });
2899 exe.addObject(a_o);2899 exe.root_module.addObject(a_o);
29002900
2901 const run = addRunArtifact(exe);2901 const run = addRunArtifact(exe);
2902 run.expectStdOutEqual("4\n");2902 run.expectStdOutEqual("4\n");
...@@ -2948,7 +2948,7 @@ fn testUnwindInfoNoSubsectionsX64(b: *Build, opts: Options) *Step {...@@ -2948,7 +2948,7 @@ fn testUnwindInfoNoSubsectionsX64(b: *Build, opts: Options) *Step {
2948 \\ return 0;2948 \\ return 0;
2949 \\}2949 \\}
2950 });2950 });
2951 exe.addObject(a_o);2951 exe.root_module.addObject(a_o);
29522952
2953 const run = addRunArtifact(exe);2953 const run = addRunArtifact(exe);
2954 run.expectStdOutEqual("4\n");2954 run.expectStdOutEqual("4\n");
...@@ -3052,7 +3052,7 @@ fn testWeakBind(b: *Build, opts: Options) *Step {...@@ -3052,7 +3052,7 @@ fn testWeakBind(b: *Build, opts: Options) *Step {
3052 \\ .quad 03052 \\ .quad 0
3053 \\ .quad _weak_internal_tlv$tlv$init3053 \\ .quad _weak_internal_tlv$tlv$init
3054 });3054 });
3055 exe.linkLibrary(lib);3055 exe.root_module.linkLibrary(lib);
30563056
3057 {3057 {
3058 const check = exe.checkObject();3058 const check = exe.checkObject();
test/link/wasm/extern/build.zig+1-1
...@@ -16,7 +16,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize...@@ -16,7 +16,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
16 .target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .wasi }),16 .target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .wasi }),
17 }),17 }),
18 });18 });
19 exe.addCSourceFile(.{ .file = b.path("foo.c"), .flags = &.{} });19 exe.root_module.addCSourceFile(.{ .file = b.path("foo.c"), .flags = &.{} });
20 exe.use_llvm = false;20 exe.use_llvm = false;
21 exe.use_lld = false;21 exe.use_lld = false;
2222
test/src/Cases.zig+4-6
...@@ -436,7 +436,7 @@ fn addFromDirInner(...@@ -436,7 +436,7 @@ fn addFromDirInner(
436 const target = &resolved_target.result;436 const target = &resolved_target.result;
437 for (backends) |backend| {437 for (backends) |backend| {
438 if (backend == .stage2 and438 if (backend == .stage2 and
439 target.cpu.arch != .wasm32 and target.cpu.arch != .x86_64 and target.cpu.arch != .spirv64)439 target.cpu.arch != .aarch64 and target.cpu.arch != .wasm32 and target.cpu.arch != .x86_64 and target.cpu.arch != .spirv64)
440 {440 {
441 // Other backends don't support new liveness format441 // Other backends don't support new liveness format
442 continue;442 continue;
...@@ -447,10 +447,6 @@ fn addFromDirInner(...@@ -447,10 +447,6 @@ fn addFromDirInner(
447 // Rosetta has issues with ZLD447 // Rosetta has issues with ZLD
448 continue;448 continue;
449 }449 }
450 if (backend == .stage2 and target.ofmt == .coff) {
451 // COFF linker has bitrotted
452 continue;
453 }
454450
455 const next = ctx.cases.items.len;451 const next = ctx.cases.items.len;
456 try ctx.cases.append(.{452 try ctx.cases.append(.{
...@@ -560,7 +556,7 @@ pub fn lowerToTranslateCSteps(...@@ -560,7 +556,7 @@ pub fn lowerToTranslateCSteps(
560 .root_module = translate_c.createModule(),556 .root_module = translate_c.createModule(),
561 });557 });
562 run_exe.step.name = b.fmt("{s} build-exe", .{annotated_case_name});558 run_exe.step.name = b.fmt("{s} build-exe", .{annotated_case_name});
563 run_exe.linkLibC();559 run_exe.root_module.link_libc = true;
564 const run = b.addRunArtifact(run_exe);560 const run = b.addRunArtifact(run_exe);
565 run.step.name = b.fmt("{s} run", .{annotated_case_name});561 run.step.name = b.fmt("{s} run", .{annotated_case_name});
566 run.expectStdOutEqual(output);562 run.expectStdOutEqual(output);
...@@ -800,6 +796,8 @@ const TestManifestConfigDefaults = struct {...@@ -800,6 +796,8 @@ const TestManifestConfigDefaults = struct {
800 }796 }
801 // Windows797 // Windows
802 defaults = defaults ++ "x86_64-windows" ++ ",";798 defaults = defaults ++ "x86_64-windows" ++ ",";
799 // Wasm
800 defaults = defaults ++ "wasm32-wasi";
803 break :blk defaults;801 break :blk defaults;
804 };802 };
805 } else if (std.mem.eql(u8, key, "output_mode")) {803 } else if (std.mem.eql(u8, key, "output_mode")) {
test/src/RunTranslatedC.zig+1-1
...@@ -89,7 +89,7 @@ pub fn addCase(self: *RunTranslatedCContext, case: *const TestCase) void {...@@ -89,7 +89,7 @@ pub fn addCase(self: *RunTranslatedCContext, case: *const TestCase) void {
89 .root_module = translate_c.createModule(),89 .root_module = translate_c.createModule(),
90 });90 });
91 exe.step.name = b.fmt("{s} build-exe", .{annotated_case_name});91 exe.step.name = b.fmt("{s} build-exe", .{annotated_case_name});
92 exe.linkLibC();92 exe.root_module.link_libc = true;
93 const run = b.addRunArtifact(exe);93 const run = b.addRunArtifact(exe);
94 run.step.name = b.fmt("{s} run", .{annotated_case_name});94 run.step.name = b.fmt("{s} run", .{annotated_case_name});
95 if (!case.allow_warnings) {95 if (!case.allow_warnings) {
test/standalone/build.zig.zon+4-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1.{1.{
2 .name = .standalone_test_cases,2 .name = .standalone_test_cases,
3 .fingerprint = 0xc0dbdf9c818957be,3 .fingerprint = 0xc0dbdf9c3b92810b,
4 .version = "0.0.0",4 .version = "0.0.0",
5 .dependencies = .{5 .dependencies = .{
6 .simple = .{6 .simple = .{
...@@ -181,6 +181,9 @@...@@ -181,6 +181,9 @@
181 .install_headers = .{181 .install_headers = .{
182 .path = "install_headers",182 .path = "install_headers",
183 },183 },
184 .dependency_options = .{
185 .path = "dependency_options",
186 },
184 .dependencyFromBuildZig = .{187 .dependencyFromBuildZig = .{
185 .path = "dependencyFromBuildZig",188 .path = "dependencyFromBuildZig",
186 },189 },
test/standalone/c_embed_path/build.zig+3-3
...@@ -13,12 +13,12 @@ pub fn build(b: *std.Build) void {...@@ -13,12 +13,12 @@ pub fn build(b: *std.Build) void {
13 .optimize = optimize,13 .optimize = optimize,
14 }),14 }),
15 });15 });
16 exe.addCSourceFile(.{16 exe.root_module.addCSourceFile(.{
17 .file = b.path("test.c"),17 .file = b.path("test.c"),
18 .flags = &.{"-std=c23"},18 .flags = &.{"-std=c23"},
19 });19 });
20 exe.linkLibC();20 exe.root_module.link_libc = true;
21 exe.addEmbedPath(b.path("data"));21 exe.root_module.addEmbedPath(b.path("data"));
2222
23 const run_c_cmd = b.addRunArtifact(exe);23 const run_c_cmd = b.addRunArtifact(exe);
24 run_c_cmd.expectExitCode(0);24 run_c_cmd.expectExitCode(0);
test/standalone/dependencyFromBuildZig/build.zig.zon+2-1
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1.{1.{
2 .name = "dependencyFromBuildZig",2 .name = .dependencyFromBuildZig,
3 .fingerprint = 0xfd939a1eb8169080,
3 .version = "0.0.0",4 .version = "0.0.0",
4 .dependencies = .{5 .dependencies = .{
5 .other = .{6 .other = .{
test/standalone/dependencyFromBuildZig/other/build.zig.zon+2-1
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1.{1.{
2 .name = "other",2 .name = .other,
3 .fingerprint = 0xd9583520a2405f6c,
3 .version = "0.0.0",4 .version = "0.0.0",
4 .dependencies = .{},5 .dependencies = .{},
5 .paths = .{""},6 .paths = .{""},
test/standalone/dependency_options/build.zig created+148
...@@ -0,0 +1,148 @@
1const std = @import("std");
2
3pub const Enum = enum { alfa, bravo, charlie };
4
5pub fn build(b: *std.Build) !void {
6 const test_step = b.step("test", "Test passing options to a dependency");
7 b.default_step = test_step;
8
9 const none_specified = b.dependency("other", .{});
10
11 const none_specified_mod = none_specified.module("dummy");
12 if (!none_specified_mod.resolved_target.?.query.eql(b.graph.host.query)) return error.TestFailed;
13 const expected_optimize: std.builtin.OptimizeMode = switch (b.release_mode) {
14 .off => .Debug,
15 .any => unreachable,
16 .fast => .ReleaseFast,
17 .safe => .ReleaseSafe,
18 .small => .ReleaseSmall,
19 };
20 if (none_specified_mod.optimize.? != expected_optimize) return error.TestFailed;
21
22 // Passing null is the same as not specifying the option,
23 // so this should resolve to the same cached dependency instance.
24 const null_specified = b.dependency("other", .{
25 // Null literals
26 .target = null,
27 .optimize = null,
28 .bool = null,
29
30 // Optionals
31 .int = @as(?i64, null),
32 .float = @as(?f64, null),
33
34 // Optionals of the wrong type
35 .string = @as(?usize, null),
36 .@"enum" = @as(?bool, null),
37
38 // Non-defined option names
39 .this_option_does_not_exist = null,
40 .neither_does_this_one = @as(?[]const u8, null),
41 });
42
43 if (null_specified != none_specified) return error.TestFailed;
44
45 const all_specified = b.dependency("other", .{
46 .target = b.resolveTargetQuery(.{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu }),
47 .optimize = @as(std.builtin.OptimizeMode, .ReleaseSafe),
48 .bool = @as(bool, true),
49 .int = @as(i64, 123),
50 .float = @as(f64, 0.5),
51 .string = @as([]const u8, "abc"),
52 .string_list = @as([]const []const u8, &.{ "a", "b", "c" }),
53 .lazy_path = @as(std.Build.LazyPath, .{ .cwd_relative = "abc.txt" }),
54 .lazy_path_list = @as([]const std.Build.LazyPath, &.{
55 .{ .cwd_relative = "a.txt" },
56 .{ .cwd_relative = "b.txt" },
57 .{ .cwd_relative = "c.txt" },
58 }),
59 .@"enum" = @as(Enum, .alfa),
60 .enum_list = @as([]const Enum, &.{ .alfa, .bravo, .charlie }),
61 .build_id = @as(std.zig.BuildId, .uuid),
62 .hex_build_id = std.zig.BuildId.initHexString("\x12\x34\xcd\xef"),
63 });
64
65 const all_specified_mod = all_specified.module("dummy");
66 if (all_specified_mod.resolved_target.?.result.cpu.arch != .x86_64) return error.TestFailed;
67 if (all_specified_mod.resolved_target.?.result.os.tag != .windows) return error.TestFailed;
68 if (all_specified_mod.resolved_target.?.result.abi != .gnu) return error.TestFailed;
69 if (all_specified_mod.optimize.? != .ReleaseSafe) return error.TestFailed;
70
71 const all_specified_optional = b.dependency("other", .{
72 .target = @as(?std.Build.ResolvedTarget, b.resolveTargetQuery(.{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu })),
73 .optimize = @as(?std.builtin.OptimizeMode, .ReleaseSafe),
74 .bool = @as(?bool, true),
75 .int = @as(?i64, 123),
76 .float = @as(?f64, 0.5),
77 .string = @as(?[]const u8, "abc"),
78 .string_list = @as(?[]const []const u8, &.{ "a", "b", "c" }),
79 .lazy_path = @as(?std.Build.LazyPath, .{ .cwd_relative = "abc.txt" }),
80 .lazy_path_list = @as(?[]const std.Build.LazyPath, &.{
81 .{ .cwd_relative = "a.txt" },
82 .{ .cwd_relative = "b.txt" },
83 .{ .cwd_relative = "c.txt" },
84 }),
85 .@"enum" = @as(?Enum, .alfa),
86 .enum_list = @as(?[]const Enum, &.{ .alfa, .bravo, .charlie }),
87 .build_id = @as(?std.zig.BuildId, .uuid),
88 .hex_build_id = @as(?std.zig.BuildId, .initHexString("\x12\x34\xcd\xef")),
89 });
90
91 if (all_specified_optional != all_specified) return error.TestFailed;
92
93 const all_specified_literal = b.dependency("other", .{
94 .target = b.resolveTargetQuery(.{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu }),
95 .optimize = .ReleaseSafe,
96 .bool = true,
97 .int = 123,
98 .float = 0.5,
99 .string = "abc",
100 .string_list = &[_][]const u8{ "a", "b", "c" },
101 .lazy_path = @as(std.Build.LazyPath, .{ .cwd_relative = "abc.txt" }),
102 .lazy_path_list = &[_]std.Build.LazyPath{
103 .{ .cwd_relative = "a.txt" },
104 .{ .cwd_relative = "b.txt" },
105 .{ .cwd_relative = "c.txt" },
106 },
107 .@"enum" = .alfa,
108 .enum_list = &[_]Enum{ .alfa, .bravo, .charlie },
109 .build_id = .uuid,
110 .hex_build_id = std.zig.BuildId.initHexString("\x12\x34\xcd\xef"),
111 });
112
113 if (all_specified_literal != all_specified) return error.TestFailed;
114
115 var mut_string_buf = "abc".*;
116 const mut_string: []u8 = &mut_string_buf;
117 var mut_string_list_buf = [_][]const u8{ "a", "b", "c" };
118 const mut_string_list: [][]const u8 = &mut_string_list_buf;
119 var mut_lazy_path_list_buf = [_]std.Build.LazyPath{
120 .{ .cwd_relative = "a.txt" },
121 .{ .cwd_relative = "b.txt" },
122 .{ .cwd_relative = "c.txt" },
123 };
124 const mut_lazy_path_list: []std.Build.LazyPath = &mut_lazy_path_list_buf;
125 var mut_enum_list_buf = [_]Enum{ .alfa, .bravo, .charlie };
126 const mut_enum_list: []Enum = &mut_enum_list_buf;
127
128 // Most supported option types are serialized to a string representation,
129 // so alternative representations of the same option value should resolve
130 // to the same cached dependency instance.
131 const all_specified_alt = b.dependency("other", .{
132 .target = @as(std.Target.Query, .{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu }),
133 .optimize = "ReleaseSafe",
134 .bool = .true,
135 .int = "123",
136 .float = @as(f16, 0.5),
137 .string = mut_string,
138 .string_list = mut_string_list,
139 .lazy_path = @as(std.Build.LazyPath, .{ .cwd_relative = "abc.txt" }),
140 .lazy_path_list = mut_lazy_path_list,
141 .@"enum" = "alfa",
142 .enum_list = mut_enum_list,
143 .build_id = "uuid",
144 .hex_build_id = "0x1234cdef",
145 });
146
147 if (all_specified_alt != all_specified) return error.TestFailed;
148}
test/standalone/dependency_options/build.zig.zon created+11
...@@ -0,0 +1,11 @@
1.{
2 .name = .dependency_options,
3 .fingerprint = 0x3e3ce1c1f92ba47e,
4 .version = "0.0.0",
5 .dependencies = .{
6 .other = .{
7 .path = "other",
8 },
9 },
10 .paths = .{""},
11}
test/standalone/dependency_options/other/build.zig created+59
...@@ -0,0 +1,59 @@
1const std = @import("std");
2
3pub const Enum = enum { alfa, bravo, charlie };
4
5pub fn build(b: *std.Build) !void {
6 const target = b.standardTargetOptions(.{});
7 const optimize = b.standardOptimizeOption(.{});
8
9 const expected_bool: bool = true;
10 const expected_int: i64 = 123;
11 const expected_float: f64 = 0.5;
12 const expected_string: []const u8 = "abc";
13 const expected_string_list: []const []const u8 = &.{ "a", "b", "c" };
14 const expected_lazy_path: std.Build.LazyPath = .{ .cwd_relative = "abc.txt" };
15 const expected_lazy_path_list: []const std.Build.LazyPath = &.{
16 .{ .cwd_relative = "a.txt" },
17 .{ .cwd_relative = "b.txt" },
18 .{ .cwd_relative = "c.txt" },
19 };
20 const expected_enum: Enum = .alfa;
21 const expected_enum_list: []const Enum = &.{ .alfa, .bravo, .charlie };
22 const expected_build_id: std.zig.BuildId = .uuid;
23 const expected_hex_build_id: std.zig.BuildId = .initHexString("\x12\x34\xcd\xef");
24
25 const @"bool" = b.option(bool, "bool", "bool") orelse expected_bool;
26 const int = b.option(i64, "int", "int") orelse expected_int;
27 const float = b.option(f64, "float", "float") orelse expected_float;
28 const string = b.option([]const u8, "string", "string") orelse expected_string;
29 const string_list = b.option([]const []const u8, "string_list", "string_list") orelse expected_string_list;
30 const lazy_path = b.option(std.Build.LazyPath, "lazy_path", "lazy_path") orelse expected_lazy_path;
31 const lazy_path_list = b.option([]const std.Build.LazyPath, "lazy_path_list", "lazy_path_list") orelse expected_lazy_path_list;
32 const @"enum" = b.option(Enum, "enum", "enum") orelse expected_enum;
33 const enum_list = b.option([]const Enum, "enum_list", "enum_list") orelse expected_enum_list;
34 const build_id = b.option(std.zig.BuildId, "build_id", "build_id") orelse expected_build_id;
35 const hex_build_id = b.option(std.zig.BuildId, "hex_build_id", "hex_build_id") orelse expected_hex_build_id;
36
37 if (@"bool" != expected_bool) return error.TestFailed;
38 if (int != expected_int) return error.TestFailed;
39 if (float != expected_float) return error.TestFailed;
40 if (!std.mem.eql(u8, string, expected_string)) return error.TestFailed;
41 if (string_list.len != expected_string_list.len) return error.TestFailed;
42 for (string_list, expected_string_list) |x, y| {
43 if (!std.mem.eql(u8, x, y)) return error.TestFailed;
44 }
45 if (!std.mem.eql(u8, lazy_path.cwd_relative, expected_lazy_path.cwd_relative)) return error.TestFailed;
46 for (lazy_path_list, expected_lazy_path_list) |x, y| {
47 if (!std.mem.eql(u8, x.cwd_relative, y.cwd_relative)) return error.TestFailed;
48 }
49 if (@"enum" != expected_enum) return error.TestFailed;
50 if (!std.mem.eql(Enum, enum_list, expected_enum_list)) return error.TestFailed;
51 if (!std.meta.eql(build_id, expected_build_id)) return error.TestFailed;
52 if (!hex_build_id.eql(expected_hex_build_id)) return error.TestFailed;
53
54 _ = b.addModule("dummy", .{
55 .root_source_file = b.path("build.zig"),
56 .target = target,
57 .optimize = optimize,
58 });
59}
test/standalone/dependency_options/other/build.zig.zon created+7
...@@ -0,0 +1,7 @@
1.{
2 .name = .other,
3 .fingerprint = 0xd95835207bc8b630,
4 .version = "0.0.0",
5 .dependencies = .{},
6 .paths = .{""},
7}
test/standalone/extern/build.zig+2-2
...@@ -31,8 +31,8 @@ pub fn build(b: *std.Build) void {...@@ -31,8 +31,8 @@ pub fn build(b: *std.Build) void {
31 .target = b.graph.host,31 .target = b.graph.host,
32 .optimize = optimize,32 .optimize = optimize,
33 }) });33 }) });
34 test_exe.addObject(obj);34 test_exe.root_module.addObject(obj);
35 test_exe.linkLibrary(shared);35 test_exe.root_module.linkLibrary(shared);
3636
37 test_step.dependOn(&b.addRunArtifact(test_exe).step);37 test_step.dependOn(&b.addRunArtifact(test_exe).step);
38}38}
test/standalone/issue_794/build.zig+1-1
...@@ -8,7 +8,7 @@ pub fn build(b: *std.Build) void {...@@ -8,7 +8,7 @@ pub fn build(b: *std.Build) void {
8 .root_source_file = b.path("main.zig"),8 .root_source_file = b.path("main.zig"),
9 .target = b.graph.host,9 .target = b.graph.host,
10 }) });10 }) });
11 test_artifact.addIncludePath(b.path("a_directory"));11 test_artifact.root_module.addIncludePath(b.path("a_directory"));
1212
13 // TODO: actually check the output13 // TODO: actually check the output
14 _ = test_artifact.getEmittedBin();14 _ = test_artifact.getEmittedBin();
test/standalone/stack_iterator/build.zig+64-63
...@@ -65,69 +65,70 @@ pub fn build(b: *std.Build) void {...@@ -65,69 +65,70 @@ pub fn build(b: *std.Build) void {
65 test_step.dependOn(&run_cmd.step);65 test_step.dependOn(&run_cmd.step);
66 }66 }
6767
68 // Unwinding through a C shared library without a frame pointer (libc)68 // https://github.com/ziglang/zig/issues/24522
69 //69 //// Unwinding through a C shared library without a frame pointer (libc)
70 // getcontext version: libc70 ////
71 //71 //// getcontext version: libc
72 // Unwind info type:72 ////
73 // - ELF: DWARF .eh_frame + .debug_frame73 //// Unwind info type:
74 // - MachO: __unwind_info encodings:74 //// - ELF: DWARF .eh_frame + .debug_frame
75 // - x86_64: STACK_IMMD, STACK_IND75 //// - MachO: __unwind_info encodings:
76 // - aarch64: FRAMELESS, DWARF76 //// - x86_64: STACK_IMMD, STACK_IND
77 {77 //// - aarch64: FRAMELESS, DWARF
78 const c_shared_lib = b.addLibrary(.{78 //{
79 .linkage = .dynamic,79 // const c_shared_lib = b.addLibrary(.{
80 .name = "c_shared_lib",80 // .linkage = .dynamic,
81 .root_module = b.createModule(.{81 // .name = "c_shared_lib",
82 .root_source_file = null,82 // .root_module = b.createModule(.{
83 .target = target,83 // .root_source_file = null,
84 .optimize = optimize,84 // .target = target,
85 .link_libc = true,85 // .optimize = optimize,
86 .strip = false,86 // .link_libc = true,
87 }),87 // .strip = false,
88 });88 // }),
8989 // });
90 if (target.result.os.tag == .windows)90
91 c_shared_lib.root_module.addCMacro("LIB_API", "__declspec(dllexport)");91 // if (target.result.os.tag == .windows)
9292 // c_shared_lib.root_module.addCMacro("LIB_API", "__declspec(dllexport)");
93 c_shared_lib.root_module.addCSourceFile(.{93
94 .file = b.path("shared_lib.c"),94 // c_shared_lib.root_module.addCSourceFile(.{
95 .flags = &.{"-fomit-frame-pointer"},95 // .file = b.path("shared_lib.c"),
96 });96 // .flags = &.{"-fomit-frame-pointer"},
9797 // });
98 const exe = b.addExecutable(.{98
99 .name = "shared_lib_unwind",99 // const exe = b.addExecutable(.{
100 .root_module = b.createModule(.{100 // .name = "shared_lib_unwind",
101 .root_source_file = b.path("shared_lib_unwind.zig"),101 // .root_module = b.createModule(.{
102 .target = target,102 // .root_source_file = b.path("shared_lib_unwind.zig"),
103 .optimize = optimize,103 // .target = target,
104 .unwind_tables = if (target.result.os.tag.isDarwin()) .async else null,104 // .optimize = optimize,
105 .omit_frame_pointer = true,105 // .unwind_tables = if (target.result.os.tag.isDarwin()) .async else null,
106 }),106 // .omit_frame_pointer = true,
107 // zig objcopy doesn't support incremental binaries107 // }),
108 .use_llvm = true,108 // // zig objcopy doesn't support incremental binaries
109 });109 // .use_llvm = true,
110110 // });
111 exe.linkLibrary(c_shared_lib);111
112112 // exe.root_module.linkLibrary(c_shared_lib);
113 const run_cmd = b.addRunArtifact(exe);113
114 test_step.dependOn(&run_cmd.step);114 // const run_cmd = b.addRunArtifact(exe);
115115 // test_step.dependOn(&run_cmd.step);
116 // Separate debug info ELF file116
117 if (target.result.ofmt == .elf) {117 // // Separate debug info ELF file
118 const filename = b.fmt("{s}_stripped", .{exe.out_filename});118 // if (target.result.ofmt == .elf) {
119 const stripped_exe = b.addObjCopy(exe.getEmittedBin(), .{119 // const filename = b.fmt("{s}_stripped", .{exe.out_filename});
120 .basename = filename, // set the name for the debuglink120 // const stripped_exe = b.addObjCopy(exe.getEmittedBin(), .{
121 .compress_debug = true,121 // .basename = filename, // set the name for the debuglink
122 .strip = .debug,122 // .compress_debug = true,
123 .extract_to_separate_file = true,123 // .strip = .debug,
124 });124 // .extract_to_separate_file = true,
125125 // });
126 const run_stripped = std.Build.Step.Run.create(b, b.fmt("run {s}", .{filename}));126
127 run_stripped.addFileArg(stripped_exe.getOutput());127 // const run_stripped = std.Build.Step.Run.create(b, b.fmt("run {s}", .{filename}));
128 test_step.dependOn(&run_stripped.step);128 // run_stripped.addFileArg(stripped_exe.getOutput());
129 }129 // test_step.dependOn(&run_stripped.step);
130 }130 // }
131 //}
131132
132 // Unwinding without libc/posix133 // Unwinding without libc/posix
133 //134 //
test/tests.zig+58-15
...@@ -116,8 +116,6 @@ const test_targets = blk: {...@@ -116,8 +116,6 @@ const test_targets = blk: {
116 .abi = .eabihf,116 .abi = .eabihf,
117 },117 },
118 .link_libc = true,118 .link_libc = true,
119 // https://github.com/ziglang/zig/issues/23949
120 .skip_modules = &.{"std"},
121 },119 },
122120
123 .{121 .{
...@@ -191,6 +189,30 @@ const test_targets = blk: {...@@ -191,6 +189,30 @@ const test_targets = blk: {
191 .link_libc = true,189 .link_libc = true,
192 },190 },
193191
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 .target = .{217 .target = .{
196 .cpu_arch = .aarch64_be,218 .cpu_arch = .aarch64_be,
...@@ -1182,6 +1204,18 @@ const test_targets = blk: {...@@ -1182,6 +1204,18 @@ const test_targets = blk: {
1182 },1204 },
1183 },1205 },
11841206
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 .target = .{1220 .target = .{
1187 .cpu_arch = .x86_64,1221 .cpu_arch = .x86_64,
...@@ -1335,16 +1369,15 @@ const test_targets = blk: {...@@ -1335,16 +1369,15 @@ const test_targets = blk: {
13351369
1336 // WASI Targets1370 // WASI Targets
13371371
1338 // TODO: lowerTry for pointers1372 .{
1339 //.{1373 .target = .{
1340 // .target = .{1374 .cpu_arch = .wasm32,
1341 // .cpu_arch = .wasm32,1375 .os_tag = .wasi,
1342 // .os_tag = .wasi,1376 .abi = .none,
1343 // .abi = .none,1377 },
1344 // },1378 .use_llvm = false,
1345 // .use_llvm = false,1379 .use_lld = false,
1346 // .use_lld = false,1380 },
1347 //},
1348 .{1381 .{
1349 .target = .{1382 .target = .{
1350 .cpu_arch = .wasm32,1383 .cpu_arch = .wasm32,
...@@ -1983,6 +2016,16 @@ pub fn addCliTests(b: *std.Build) *Step {...@@ -1983,6 +2016,16 @@ pub fn addCliTests(b: *std.Build) *Step {
1983 step.dependOn(&cleanup.step);2016 step.dependOn(&cleanup.step);
1984 }2017 }
19852018
2019 {
2020 // Test `zig init -m`.
2021 const tmp_path = b.makeTempPath();
2022 const init_exe = b.addSystemCommand(&.{ b.graph.zig_exe, "init", "-m" });
2023 init_exe.setCwd(.{ .cwd_relative = tmp_path });
2024 init_exe.setName("zig init -m");
2025 init_exe.expectStdOutEqual("");
2026 init_exe.expectStdErrEqual("info: successfully populated 'build.zig.zon' and 'build.zig'\n");
2027 }
2028
1986 // Test Godbolt API2029 // Test Godbolt API
1987 if (builtin.os.tag == .linux and builtin.cpu.arch == .x86_64) {2030 if (builtin.os.tag == .linux and builtin.cpu.arch == .x86_64) {
1988 const tmp_path = b.makeTempPath();2031 const tmp_path = b.makeTempPath();
...@@ -2260,7 +2303,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {...@@ -2260,7 +2303,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
2260 continue;2303 continue;
22612304
2262 // TODO get compiler-rt tests passing for self-hosted backends.2305 // TODO get compiler-rt tests passing for self-hosted backends.
2263 if ((target.cpu.arch != .x86_64 or target.ofmt != .elf) and2306 if (((target.cpu.arch != .x86_64 and target.cpu.arch != .aarch64) or target.ofmt == .coff) and
2264 test_target.use_llvm == false and mem.eql(u8, options.name, "compiler-rt"))2307 test_target.use_llvm == false and mem.eql(u8, options.name, "compiler-rt"))
2265 continue;2308 continue;
22662309
...@@ -2328,10 +2371,10 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {...@@ -2328,10 +2371,10 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
2328 } else "";2371 } else "";
2329 const use_pic = if (test_target.pic == true) "-pic" else "";2372 const use_pic = if (test_target.pic == true) "-pic" else "";
23302373
2331 for (options.include_paths) |include_path| these_tests.addIncludePath(b.path(include_path));2374 for (options.include_paths) |include_path| these_tests.root_module.addIncludePath(b.path(include_path));
23322375
2333 if (target.os.tag == .windows) {2376 if (target.os.tag == .windows) {
2334 for (options.windows_libs) |lib| these_tests.linkSystemLibrary(lib);2377 for (options.windows_libs) |lib| these_tests.root_module.linkSystemLibrary(lib, .{});
2335 }2378 }
23362379
2337 const qualified_name = b.fmt("{s}-{s}-{s}-{s}{s}{s}{s}{s}{s}{s}", .{2380 const qualified_name = b.fmt("{s}-{s}-{s}-{s}{s}{s}{s}{s}{s}{s}", .{
tools/docgen.zig-1
...@@ -3,7 +3,6 @@ const builtin = @import("builtin");...@@ -3,7 +3,6 @@ const builtin = @import("builtin");
3const io = std.io;3const io = std.io;
4const fs = std.fs;4const fs = std.fs;
5const process = std.process;5const process = std.process;
6const ChildProcess = std.process.Child;
7const Progress = std.Progress;6const Progress = std.Progress;
8const print = std.debug.print;7const print = std.debug.print;
9const mem = std.mem;8const mem = std.mem;
tools/gen_stubs.zig+2-1
...@@ -310,7 +310,8 @@ pub fn main() !void {...@@ -310,7 +310,8 @@ pub fn main() !void {
310 build_all_path, libc_so_path, @errorName(err),310 build_all_path, libc_so_path, @errorName(err),
311 });311 });
312 };312 };
313 const header = try elf.Header.parse(elf_bytes[0..@sizeOf(elf.Elf64_Ehdr)]);313 var stream: std.Io.Reader = .fixed(elf_bytes);
314 const header = try elf.Header.read(&stream);
314315
315 const parse: Parse = .{316 const parse: Parse = .{
316 .arena = arena,317 .arena = arena,
tools/incr-check.zig+24-39
...@@ -186,7 +186,7 @@ pub fn main() !void {...@@ -186,7 +186,7 @@ pub fn main() !void {
186186
187 try child.spawn();187 try child.spawn();
188188
189 var poller = std.io.poll(arena, Eval.StreamEnum, .{189 var poller = std.Io.poll(arena, Eval.StreamEnum, .{
190 .stdout = child.stdout.?,190 .stdout = child.stdout.?,
191 .stderr = child.stderr.?,191 .stderr = child.stderr.?,
192 });192 });
...@@ -247,19 +247,15 @@ const Eval = struct {...@@ -247,19 +247,15 @@ const Eval = struct {
247247
248 fn check(eval: *Eval, poller: *Poller, update: Case.Update, prog_node: std.Progress.Node) !void {248 fn check(eval: *Eval, poller: *Poller, update: Case.Update, prog_node: std.Progress.Node) !void {
249 const arena = eval.arena;249 const arena = eval.arena;
250 const Header = std.zig.Server.Message.Header;250 const stdout = poller.reader(.stdout);
251 const stdout = poller.fifo(.stdout);251 const stderr = poller.reader(.stderr);
252 const stderr = poller.fifo(.stderr);
253252
254 poll: while (true) {253 poll: while (true) {
255 while (stdout.readableLength() < @sizeOf(Header)) {254 const Header = std.zig.Server.Message.Header;
256 if (!(try poller.poll())) break :poll;255 while (stdout.buffered().len < @sizeOf(Header)) if (!try poller.poll()) break :poll;
257 }256 const header = stdout.takeStruct(Header, .little) catch unreachable;
258 const header = stdout.reader().readStruct(Header) catch unreachable;257 while (stdout.buffered().len < header.bytes_len) if (!try poller.poll()) break :poll;
259 while (stdout.readableLength() < header.bytes_len) {258 const body = stdout.take(header.bytes_len) catch unreachable;
260 if (!(try poller.poll())) break :poll;
261 }
262 const body = stdout.readableSliceOfLen(header.bytes_len);
263259
264 switch (header.tag) {260 switch (header.tag) {
265 .error_bundle => {261 .error_bundle => {
...@@ -277,8 +273,8 @@ const Eval = struct {...@@ -277,8 +273,8 @@ const Eval = struct {
277 .string_bytes = try arena.dupe(u8, string_bytes),273 .string_bytes = try arena.dupe(u8, string_bytes),
278 .extra = extra_array,274 .extra = extra_array,
279 };275 };
280 if (stderr.readableLength() > 0) {276 if (stderr.bufferedLen() > 0) {
281 const stderr_data = try stderr.toOwnedSlice();277 const stderr_data = try poller.toOwnedSlice(.stderr);
282 if (eval.allow_stderr) {278 if (eval.allow_stderr) {
283 std.log.info("error_bundle included stderr:\n{s}", .{stderr_data});279 std.log.info("error_bundle included stderr:\n{s}", .{stderr_data});
284 } else {280 } else {
...@@ -289,15 +285,14 @@ const Eval = struct {...@@ -289,15 +285,14 @@ const Eval = struct {
289 try eval.checkErrorOutcome(update, result_error_bundle);285 try eval.checkErrorOutcome(update, result_error_bundle);
290 }286 }
291 // This message indicates the end of the update.287 // This message indicates the end of the update.
292 stdout.discard(body.len);
293 return;288 return;
294 },289 },
295 .emit_digest => {290 .emit_digest => {
296 const EbpHdr = std.zig.Server.Message.EmitDigest;291 const EbpHdr = std.zig.Server.Message.EmitDigest;
297 const ebp_hdr = @as(*align(1) const EbpHdr, @ptrCast(body));292 const ebp_hdr = @as(*align(1) const EbpHdr, @ptrCast(body));
298 _ = ebp_hdr;293 _ = ebp_hdr;
299 if (stderr.readableLength() > 0) {294 if (stderr.bufferedLen() > 0) {
300 const stderr_data = try stderr.toOwnedSlice();295 const stderr_data = try poller.toOwnedSlice(.stderr);
301 if (eval.allow_stderr) {296 if (eval.allow_stderr) {
302 std.log.info("emit_digest included stderr:\n{s}", .{stderr_data});297 std.log.info("emit_digest included stderr:\n{s}", .{stderr_data});
303 } else {298 } else {
...@@ -308,7 +303,6 @@ const Eval = struct {...@@ -308,7 +303,6 @@ const Eval = struct {
308 if (eval.target.backend == .sema) {303 if (eval.target.backend == .sema) {
309 try eval.checkSuccessOutcome(update, null, prog_node);304 try eval.checkSuccessOutcome(update, null, prog_node);
310 // This message indicates the end of the update.305 // This message indicates the end of the update.
311 stdout.discard(body.len);
312 }306 }
313307
314 const digest = body[@sizeOf(EbpHdr)..][0..Cache.bin_digest_len];308 const digest = body[@sizeOf(EbpHdr)..][0..Cache.bin_digest_len];
...@@ -323,21 +317,18 @@ const Eval = struct {...@@ -323,21 +317,18 @@ const Eval = struct {
323317
324 try eval.checkSuccessOutcome(update, bin_path, prog_node);318 try eval.checkSuccessOutcome(update, bin_path, prog_node);
325 // This message indicates the end of the update.319 // This message indicates the end of the update.
326 stdout.discard(body.len);
327 },320 },
328 else => {321 else => {
329 // Ignore other messages.322 // Ignore other messages.
330 stdout.discard(body.len);
331 },323 },
332 }324 }
333 }325 }
334326
335 if (stderr.readableLength() > 0) {327 if (stderr.bufferedLen() > 0) {
336 const stderr_data = try stderr.toOwnedSlice();
337 if (eval.allow_stderr) {328 if (eval.allow_stderr) {
338 std.log.info("update '{s}' included stderr:\n{s}", .{ update.name, stderr_data });329 std.log.info("update '{s}' included stderr:\n{s}", .{ update.name, stderr.buffered() });
339 } else {330 } else {
340 eval.fatal("update '{s}' failed:\n{s}", .{ update.name, stderr_data });331 eval.fatal("update '{s}' failed:\n{s}", .{ update.name, stderr.buffered() });
341 }332 }
342 }333 }
343334
...@@ -537,25 +528,19 @@ const Eval = struct {...@@ -537,25 +528,19 @@ const Eval = struct {
537 fn end(eval: *Eval, poller: *Poller) !void {528 fn end(eval: *Eval, poller: *Poller) !void {
538 requestExit(eval.child, eval);529 requestExit(eval.child, eval);
539530
540 const Header = std.zig.Server.Message.Header;531 const stdout = poller.reader(.stdout);
541 const stdout = poller.fifo(.stdout);532 const stderr = poller.reader(.stderr);
542 const stderr = poller.fifo(.stderr);
543533
544 poll: while (true) {534 poll: while (true) {
545 while (stdout.readableLength() < @sizeOf(Header)) {535 const Header = std.zig.Server.Message.Header;
546 if (!(try poller.poll())) break :poll;536 while (stdout.buffered().len < @sizeOf(Header)) if (!try poller.poll()) break :poll;
547 }537 const header = stdout.takeStruct(Header, .little) catch unreachable;
548 const header = stdout.reader().readStruct(Header) catch unreachable;538 while (stdout.buffered().len < header.bytes_len) if (!try poller.poll()) break :poll;
549 while (stdout.readableLength() < header.bytes_len) {539 stdout.toss(header.bytes_len);
550 if (!(try poller.poll())) break :poll;
551 }
552 const body = stdout.readableSliceOfLen(header.bytes_len);
553 stdout.discard(body.len);
554 }540 }
555541
556 if (stderr.readableLength() > 0) {542 if (stderr.bufferedLen() > 0) {
557 const stderr_data = try stderr.toOwnedSlice();543 eval.fatal("unexpected stderr:\n{s}", .{stderr.buffered()});
558 eval.fatal("unexpected stderr:\n{s}", .{stderr_data});
559 }544 }
560 }545 }
561546